Blame dict.c

Packit 423ecb
/*
Packit 423ecb
 * dict.c: dictionary of reusable strings, just used to avoid allocation
Packit 423ecb
 *         and freeing operations.
Packit 423ecb
 *
Packit 423ecb
 * Copyright (C) 2003-2012 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: daniel@veillard.com
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IN_LIBXML
Packit 423ecb
#include "libxml.h"
Packit 423ecb
Packit 423ecb
#include <limits.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
 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
Packit 423ecb
 *  which is the default.
Packit 423ecb
 * Note2: the fast function used for a small dict won't protect very
Packit 423ecb
 *  well but since the attack is based on growing a very big hash
Packit 423ecb
 *  list we will use the BigKey algo as soon as the hash size grows
Packit 423ecb
 *  over MIN_DICT_SIZE so this actually works
Packit 423ecb
 */
Packit 423ecb
#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
Packit 423ecb
#define DICT_RANDOMIZATION
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
#include <string.h>
Packit 423ecb
#ifdef HAVE_STDINT_H
Packit 423ecb
#include <stdint.h>
Packit 423ecb
#else
Packit 423ecb
#ifdef HAVE_INTTYPES_H
Packit 423ecb
#include <inttypes.h>
Packit 423ecb
#elif defined(_WIN32)
Packit 423ecb
typedef unsigned __int32 uint32_t;
Packit 423ecb
#endif
Packit 423ecb
#endif
Packit 423ecb
#include <libxml/tree.h>
Packit 423ecb
#include <libxml/dict.h>
Packit 423ecb
#include <libxml/xmlmemory.h>
Packit 423ecb
#include <libxml/xmlerror.h>
Packit 423ecb
#include <libxml/globals.h>
Packit 423ecb
Packit 423ecb
/* #define DEBUG_GROW */
Packit 423ecb
/* #define DICT_DEBUG_PATTERNS */
Packit 423ecb
Packit 423ecb
#define MAX_HASH_LEN 3
Packit 423ecb
#define MIN_DICT_SIZE 128
Packit 423ecb
#define MAX_DICT_HASH 8 * 2048
Packit 423ecb
#define WITH_BIG_KEY
Packit 423ecb
Packit 423ecb
#ifdef WITH_BIG_KEY
Packit 423ecb
#define xmlDictComputeKey(dict, name, len)                              \
Packit 423ecb
    (((dict)->size == MIN_DICT_SIZE) ?                                  \
Packit 423ecb
     xmlDictComputeFastKey(name, len, (dict)->seed) :                   \
Packit 423ecb
     xmlDictComputeBigKey(name, len, (dict)->seed))
Packit 423ecb
Packit 423ecb
#define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
Packit 423ecb
    (((prefix) == NULL) ?                                               \
Packit 423ecb
      (xmlDictComputeKey(dict, name, len)) :                             \
Packit 423ecb
      (((dict)->size == MIN_DICT_SIZE) ?                                \
Packit 423ecb
       xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) :	\
Packit 423ecb
       xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Packit 423ecb
Packit 423ecb
#else /* !WITH_BIG_KEY */
Packit 423ecb
#define xmlDictComputeKey(dict, name, len)                              \
Packit 423ecb
        xmlDictComputeFastKey(name, len, (dict)->seed)
Packit 423ecb
#define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
Packit 423ecb
        xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Packit 423ecb
#endif /* WITH_BIG_KEY */
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * An entry in the dictionary
Packit 423ecb
 */
Packit 423ecb
typedef struct _xmlDictEntry xmlDictEntry;
Packit 423ecb
typedef xmlDictEntry *xmlDictEntryPtr;
Packit 423ecb
struct _xmlDictEntry {
Packit 423ecb
    struct _xmlDictEntry *next;
Packit 423ecb
    const xmlChar *name;
Packit 423ecb
    unsigned int len;
Packit 423ecb
    int valid;
Packit 423ecb
    unsigned long okey;
Packit 423ecb
};
Packit 423ecb
Packit 423ecb
typedef struct _xmlDictStrings xmlDictStrings;
Packit 423ecb
typedef xmlDictStrings *xmlDictStringsPtr;
Packit 423ecb
struct _xmlDictStrings {
Packit 423ecb
    xmlDictStringsPtr next;
Packit 423ecb
    xmlChar *free;
Packit 423ecb
    xmlChar *end;
Packit 423ecb
    size_t size;
Packit 423ecb
    size_t nbStrings;
Packit 423ecb
    xmlChar array[1];
Packit 423ecb
};
Packit 423ecb
/*
Packit 423ecb
 * The entire dictionary
Packit 423ecb
 */
Packit 423ecb
struct _xmlDict {
Packit 423ecb
    int ref_counter;
Packit 423ecb
Packit 423ecb
    struct _xmlDictEntry *dict;
Packit 423ecb
    size_t size;
Packit 423ecb
    unsigned int nbElems;
Packit 423ecb
    xmlDictStringsPtr strings;
Packit 423ecb
Packit 423ecb
    struct _xmlDict *subdict;
Packit 423ecb
    /* used for randomization */
Packit 423ecb
    int seed;
Packit 423ecb
    /* used to impose a limit on size */
Packit 423ecb
    size_t limit;
Packit 423ecb
};
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * A mutex for modifying the reference counter for shared
Packit 423ecb
 * dictionaries.
Packit 423ecb
 */
Packit 423ecb
static xmlRMutexPtr xmlDictMutex = NULL;
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * Whether the dictionary mutex was initialized.
Packit 423ecb
 */
Packit 423ecb
static int xmlDictInitialized = 0;
Packit 423ecb
Packit 423ecb
#ifdef DICT_RANDOMIZATION
Packit 423ecb
#ifdef HAVE_RAND_R
Packit 423ecb
/*
Packit 423ecb
 * Internal data for random function, protected by xmlDictMutex
Packit 423ecb
 */
Packit 423ecb
static unsigned int rand_seed = 0;
Packit 423ecb
#endif
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlInitializeDict:
Packit 423ecb
 *
Packit 423ecb
 * Do the dictionary mutex initialization.
Packit 423ecb
 * this function is deprecated
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 if initialization was already done, and 1 if that
Packit 423ecb
 * call led to the initialization
Packit 423ecb
 */
Packit 423ecb
int xmlInitializeDict(void) {
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * __xmlInitializeDict:
Packit 423ecb
 *
Packit 423ecb
 * This function is not public
Packit 423ecb
 * Do the dictionary mutex initialization.
Packit 423ecb
 * this function is not thread safe, initialization should
Packit 423ecb
 * normally be done once at setup when called from xmlOnceInit()
Packit 423ecb
 * we may also land in this code if thread support is not compiled in
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 if initialization was already done, and 1 if that
Packit 423ecb
 * call led to the initialization
Packit 423ecb
 */
Packit 423ecb
int __xmlInitializeDict(void) {
Packit 423ecb
    if (xmlDictInitialized)
Packit 423ecb
        return(1);
Packit 423ecb
Packit 423ecb
    if ((xmlDictMutex = xmlNewRMutex()) == NULL)
Packit 423ecb
        return(0);
Packit 423ecb
    xmlRMutexLock(xmlDictMutex);
Packit 423ecb
Packit 423ecb
#ifdef DICT_RANDOMIZATION
Packit 423ecb
#ifdef HAVE_RAND_R
Packit 423ecb
    rand_seed = time(NULL);
Packit 423ecb
    rand_r(& rand_seed);
Packit 423ecb
#else
Packit 423ecb
    srand(time(NULL));
Packit 423ecb
#endif
Packit 423ecb
#endif
Packit 423ecb
    xmlDictInitialized = 1;
Packit 423ecb
    xmlRMutexUnlock(xmlDictMutex);
Packit 423ecb
    return(1);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
#ifdef DICT_RANDOMIZATION
Packit 423ecb
int __xmlRandom(void) {
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    if (xmlDictInitialized == 0)
Packit 423ecb
        __xmlInitializeDict();
Packit 423ecb
Packit 423ecb
    xmlRMutexLock(xmlDictMutex);
Packit 423ecb
#ifdef HAVE_RAND_R
Packit 423ecb
    ret = rand_r(& rand_seed);
Packit 423ecb
#else
Packit 423ecb
    ret = rand();
Packit 423ecb
#endif
Packit 423ecb
    xmlRMutexUnlock(xmlDictMutex);
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictCleanup:
Packit 423ecb
 *
Packit 423ecb
 * Free the dictionary mutex. Do not call unless sure the library
Packit 423ecb
 * is not in use anymore !
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlDictCleanup(void) {
Packit 423ecb
    if (!xmlDictInitialized)
Packit 423ecb
        return;
Packit 423ecb
Packit 423ecb
    xmlFreeRMutex(xmlDictMutex);
Packit 423ecb
Packit 423ecb
    xmlDictInitialized = 0;
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * xmlDictAddString:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @len: the length of the name
Packit 423ecb
 *
Packit 423ecb
 * Add the string to the array[s]
Packit 423ecb
 *
Packit 423ecb
 * Returns the pointer of the local string, or NULL in case of error.
Packit 423ecb
 */
Packit 423ecb
static const xmlChar *
Packit 423ecb
xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Packit 423ecb
    xmlDictStringsPtr pool;
Packit 423ecb
    const xmlChar *ret;
Packit 423ecb
    size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
Packit 423ecb
    size_t limit = 0;
Packit 423ecb
Packit 423ecb
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
    fprintf(stderr, "-");
Packit 423ecb
#endif
Packit 423ecb
    pool = dict->strings;
Packit 423ecb
    while (pool != NULL) {
Packit 423ecb
	if ((size_t)(pool->end - pool->free) > namelen)
Packit 423ecb
	    goto found_pool;
Packit 423ecb
	if (pool->size > size) size = pool->size;
Packit 423ecb
        limit += pool->size;
Packit 423ecb
	pool = pool->next;
Packit 423ecb
    }
Packit 423ecb
    /*
Packit 423ecb
     * Not found, need to allocate
Packit 423ecb
     */
Packit 423ecb
    if (pool == NULL) {
Packit 423ecb
        if ((dict->limit > 0) && (limit > dict->limit)) {
Packit 423ecb
            return(NULL);
Packit 423ecb
        }
Packit 423ecb
Packit 423ecb
        if (size == 0) size = 1000;
Packit 423ecb
	else size *= 4; /* exponential growth */
Packit 423ecb
        if (size < 4 * namelen)
Packit 423ecb
	    size = 4 * namelen; /* just in case ! */
Packit 423ecb
	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
Packit 423ecb
	if (pool == NULL)
Packit 423ecb
	    return(NULL);
Packit 423ecb
	pool->size = size;
Packit 423ecb
	pool->nbStrings = 0;
Packit 423ecb
	pool->free = &pool->array[0];
Packit 423ecb
	pool->end = &pool->array[size];
Packit 423ecb
	pool->next = dict->strings;
Packit 423ecb
	dict->strings = pool;
Packit 423ecb
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
        fprintf(stderr, "+");
Packit 423ecb
#endif
Packit 423ecb
    }
Packit 423ecb
found_pool:
Packit 423ecb
    ret = pool->free;
Packit 423ecb
    memcpy(pool->free, name, namelen);
Packit 423ecb
    pool->free += namelen;
Packit 423ecb
    *(pool->free++) = 0;
Packit 423ecb
    pool->nbStrings++;
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * xmlDictAddQString:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @prefix: the prefix of the userdata
Packit 423ecb
 * @plen: the prefix length
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @len: the length of the name
Packit 423ecb
 *
Packit 423ecb
 * Add the QName to the array[s]
Packit 423ecb
 *
Packit 423ecb
 * Returns the pointer of the local string, or NULL in case of error.
Packit 423ecb
 */
Packit 423ecb
static const xmlChar *
Packit 423ecb
xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
Packit 423ecb
                 const xmlChar *name, unsigned int namelen)
Packit 423ecb
{
Packit 423ecb
    xmlDictStringsPtr pool;
Packit 423ecb
    const xmlChar *ret;
Packit 423ecb
    size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
Packit 423ecb
    size_t limit = 0;
Packit 423ecb
Packit 423ecb
    if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Packit 423ecb
Packit 423ecb
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
    fprintf(stderr, "=");
Packit 423ecb
#endif
Packit 423ecb
    pool = dict->strings;
Packit 423ecb
    while (pool != NULL) {
Packit 423ecb
	if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
Packit 423ecb
	    goto found_pool;
Packit 423ecb
	if (pool->size > size) size = pool->size;
Packit 423ecb
        limit += pool->size;
Packit 423ecb
	pool = pool->next;
Packit 423ecb
    }
Packit 423ecb
    /*
Packit 423ecb
     * Not found, need to allocate
Packit 423ecb
     */
Packit 423ecb
    if (pool == NULL) {
Packit 423ecb
        if ((dict->limit > 0) && (limit > dict->limit)) {
Packit 423ecb
            return(NULL);
Packit 423ecb
        }
Packit 423ecb
Packit 423ecb
        if (size == 0) size = 1000;
Packit 423ecb
	else size *= 4; /* exponential growth */
Packit 423ecb
        if (size < 4 * (namelen + plen + 1))
Packit 423ecb
	    size = 4 * (namelen + plen + 1); /* just in case ! */
Packit 423ecb
	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
Packit 423ecb
	if (pool == NULL)
Packit 423ecb
	    return(NULL);
Packit 423ecb
	pool->size = size;
Packit 423ecb
	pool->nbStrings = 0;
Packit 423ecb
	pool->free = &pool->array[0];
Packit 423ecb
	pool->end = &pool->array[size];
Packit 423ecb
	pool->next = dict->strings;
Packit 423ecb
	dict->strings = pool;
Packit 423ecb
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
        fprintf(stderr, "+");
Packit 423ecb
#endif
Packit 423ecb
    }
Packit 423ecb
found_pool:
Packit 423ecb
    ret = pool->free;
Packit 423ecb
    memcpy(pool->free, prefix, plen);
Packit 423ecb
    pool->free += plen;
Packit 423ecb
    *(pool->free++) = ':';
Packit 423ecb
    memcpy(pool->free, name, namelen);
Packit 423ecb
    pool->free += namelen;
Packit 423ecb
    *(pool->free++) = 0;
Packit 423ecb
    pool->nbStrings++;
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
#ifdef WITH_BIG_KEY
Packit 423ecb
/*
Packit 423ecb
 * xmlDictComputeBigKey:
Packit 423ecb
 *
Packit 423ecb
 * Calculate a hash key using a good hash function that works well for
Packit 423ecb
 * larger hash table sizes.
Packit 423ecb
 *
Packit 423ecb
 * Hash function by "One-at-a-Time Hash" see
Packit 423ecb
 * http://burtleburtle.net/bob/hash/doobs.html
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
static uint32_t
Packit 423ecb
xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Packit 423ecb
    uint32_t hash;
Packit 423ecb
    int i;
Packit 423ecb
Packit 423ecb
    if (namelen <= 0 || data == NULL) return(0);
Packit 423ecb
Packit 423ecb
    hash = seed;
Packit 423ecb
Packit 423ecb
    for (i = 0;i < namelen; i++) {
Packit 423ecb
        hash += data[i];
Packit 423ecb
	hash += (hash << 10);
Packit 423ecb
	hash ^= (hash >> 6);
Packit 423ecb
    }
Packit 423ecb
    hash += (hash << 3);
Packit 423ecb
    hash ^= (hash >> 11);
Packit 423ecb
    hash += (hash << 15);
Packit 423ecb
Packit 423ecb
    return hash;
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * xmlDictComputeBigQKey:
Packit 423ecb
 *
Packit 423ecb
 * Calculate a hash key for two strings using a good hash function
Packit 423ecb
 * that works well for larger hash table sizes.
Packit 423ecb
 *
Packit 423ecb
 * Hash function by "One-at-a-Time Hash" see
Packit 423ecb
 * http://burtleburtle.net/bob/hash/doobs.html
Packit 423ecb
 *
Packit 423ecb
 * Neither of the two strings must be NULL.
Packit 423ecb
 */
Packit 423ecb
static unsigned long
Packit 423ecb
xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Packit 423ecb
                      const xmlChar *name, int len, int seed)
Packit 423ecb
{
Packit 423ecb
    uint32_t hash;
Packit 423ecb
    int i;
Packit 423ecb
Packit 423ecb
    hash = seed;
Packit 423ecb
Packit 423ecb
    for (i = 0;i < plen; i++) {
Packit 423ecb
        hash += prefix[i];
Packit 423ecb
	hash += (hash << 10);
Packit 423ecb
	hash ^= (hash >> 6);
Packit 423ecb
    }
Packit 423ecb
    hash += ':';
Packit 423ecb
    hash += (hash << 10);
Packit 423ecb
    hash ^= (hash >> 6);
Packit 423ecb
Packit 423ecb
    for (i = 0;i < len; i++) {
Packit 423ecb
        hash += name[i];
Packit 423ecb
	hash += (hash << 10);
Packit 423ecb
	hash ^= (hash >> 6);
Packit 423ecb
    }
Packit 423ecb
    hash += (hash << 3);
Packit 423ecb
    hash ^= (hash >> 11);
Packit 423ecb
    hash += (hash << 15);
Packit 423ecb
Packit 423ecb
    return hash;
Packit 423ecb
}
Packit 423ecb
#endif /* WITH_BIG_KEY */
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * xmlDictComputeFastKey:
Packit 423ecb
 *
Packit 423ecb
 * Calculate a hash key using a fast hash function that works well
Packit 423ecb
 * for low hash table fill.
Packit 423ecb
 */
Packit 423ecb
static unsigned long
Packit 423ecb
xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
Packit 423ecb
    unsigned long value = seed;
Packit 423ecb
Packit 423ecb
    if (name == NULL) return(0);
Packit 423ecb
    value = *name;
Packit 423ecb
    value <<= 5;
Packit 423ecb
    if (namelen > 10) {
Packit 423ecb
        value += name[namelen - 1];
Packit 423ecb
        namelen = 10;
Packit 423ecb
    }
Packit 423ecb
    switch (namelen) {
Packit 423ecb
        case 10: value += name[9];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 9: value += name[8];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 8: value += name[7];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 7: value += name[6];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 6: value += name[5];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 5: value += name[4];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 4: value += name[3];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 3: value += name[2];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 2: value += name[1];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        default: break;
Packit 423ecb
    }
Packit 423ecb
    return(value);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * xmlDictComputeFastQKey:
Packit 423ecb
 *
Packit 423ecb
 * Calculate a hash key for two strings using a fast hash function
Packit 423ecb
 * that works well for low hash table fill.
Packit 423ecb
 *
Packit 423ecb
 * Neither of the two strings must be NULL.
Packit 423ecb
 */
Packit 423ecb
static unsigned long
Packit 423ecb
xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Packit 423ecb
                       const xmlChar *name, int len, int seed)
Packit 423ecb
{
Packit 423ecb
    unsigned long value = (unsigned long) seed;
Packit 423ecb
Packit 423ecb
    if (plen == 0)
Packit 423ecb
	value += 30 * (unsigned long) ':';
Packit 423ecb
    else
Packit 423ecb
	value += 30 * (*prefix);
Packit 423ecb
Packit 423ecb
    if (len > 10) {
Packit 423ecb
        int offset = len - (plen + 1 + 1);
Packit 423ecb
	if (offset < 0)
Packit 423ecb
	    offset = len - (10 + 1);
Packit 423ecb
	value += name[offset];
Packit 423ecb
        len = 10;
Packit 423ecb
	if (plen > 10)
Packit 423ecb
	    plen = 10;
Packit 423ecb
    }
Packit 423ecb
    switch (plen) {
Packit 423ecb
        case 10: value += prefix[9];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 9: value += prefix[8];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 8: value += prefix[7];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 7: value += prefix[6];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 6: value += prefix[5];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 5: value += prefix[4];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 4: value += prefix[3];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 3: value += prefix[2];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 2: value += prefix[1];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 1: value += prefix[0];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        default: break;
Packit 423ecb
    }
Packit 423ecb
    len -= plen;
Packit 423ecb
    if (len > 0) {
Packit 423ecb
        value += (unsigned long) ':';
Packit 423ecb
	len--;
Packit 423ecb
    }
Packit 423ecb
    switch (len) {
Packit 423ecb
        case 10: value += name[9];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 9: value += name[8];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 8: value += name[7];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 7: value += name[6];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 6: value += name[5];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 5: value += name[4];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 4: value += name[3];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 3: value += name[2];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 2: value += name[1];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        case 1: value += name[0];
Packit 423ecb
        /* Falls through. */
Packit 423ecb
        default: break;
Packit 423ecb
    }
Packit 423ecb
    return(value);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictCreate:
Packit 423ecb
 *
Packit 423ecb
 * Create a new dictionary
Packit 423ecb
 *
Packit 423ecb
 * Returns the newly created dictionary, or NULL if an error occurred.
Packit 423ecb
 */
Packit 423ecb
xmlDictPtr
Packit 423ecb
xmlDictCreate(void) {
Packit 423ecb
    xmlDictPtr dict;
Packit 423ecb
Packit 423ecb
    if (!xmlDictInitialized)
Packit 423ecb
        if (!__xmlInitializeDict())
Packit 423ecb
            return(NULL);
Packit 423ecb
Packit 423ecb
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
    fprintf(stderr, "C");
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
    dict = xmlMalloc(sizeof(xmlDict));
Packit 423ecb
    if (dict) {
Packit 423ecb
        dict->ref_counter = 1;
Packit 423ecb
        dict->limit = 0;
Packit 423ecb
Packit 423ecb
        dict->size = MIN_DICT_SIZE;
Packit 423ecb
	dict->nbElems = 0;
Packit 423ecb
        dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Packit 423ecb
	dict->strings = NULL;
Packit 423ecb
	dict->subdict = NULL;
Packit 423ecb
        if (dict->dict) {
Packit 423ecb
	    memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Packit 423ecb
#ifdef DICT_RANDOMIZATION
Packit 423ecb
            dict->seed = __xmlRandom();
Packit 423ecb
#else
Packit 423ecb
            dict->seed = 0;
Packit 423ecb
#endif
Packit 423ecb
	    return(dict);
Packit 423ecb
        }
Packit 423ecb
        xmlFree(dict);
Packit 423ecb
    }
Packit 423ecb
    return(NULL);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictCreateSub:
Packit 423ecb
 * @sub: an existing dictionary
Packit 423ecb
 *
Packit 423ecb
 * Create a new dictionary, inheriting strings from the read-only
Packit 423ecb
 * dictionary @sub. On lookup, strings are first searched in the
Packit 423ecb
 * new dictionary, then in @sub, and if not found are created in the
Packit 423ecb
 * new dictionary.
Packit 423ecb
 *
Packit 423ecb
 * Returns the newly created dictionary, or NULL if an error occurred.
Packit 423ecb
 */
Packit 423ecb
xmlDictPtr
Packit 423ecb
xmlDictCreateSub(xmlDictPtr sub) {
Packit 423ecb
    xmlDictPtr dict = xmlDictCreate();
Packit 423ecb
Packit 423ecb
    if ((dict != NULL) && (sub != NULL)) {
Packit 423ecb
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
        fprintf(stderr, "R");
Packit 423ecb
#endif
Packit 423ecb
        dict->seed = sub->seed;
Packit 423ecb
        dict->subdict = sub;
Packit 423ecb
	xmlDictReference(dict->subdict);
Packit 423ecb
    }
Packit 423ecb
    return(dict);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictReference:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 *
Packit 423ecb
 * Increment the reference counter of a dictionary
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 in case of success and -1 in case of error
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlDictReference(xmlDictPtr dict) {
Packit 423ecb
    if (!xmlDictInitialized)
Packit 423ecb
        if (!__xmlInitializeDict())
Packit 423ecb
            return(-1);
Packit 423ecb
Packit 423ecb
    if (dict == NULL) return -1;
Packit 423ecb
    xmlRMutexLock(xmlDictMutex);
Packit 423ecb
    dict->ref_counter++;
Packit 423ecb
    xmlRMutexUnlock(xmlDictMutex);
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictGrow:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @size: the new size of the dictionary
Packit 423ecb
 *
Packit 423ecb
 * resize the dictionary
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 in case of success, -1 in case of failure
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlDictGrow(xmlDictPtr dict, size_t size) {
Packit 423ecb
    unsigned long key, okey;
Packit 423ecb
    size_t oldsize, i;
Packit 423ecb
    xmlDictEntryPtr iter, next;
Packit 423ecb
    struct _xmlDictEntry *olddict;
Packit 423ecb
#ifdef DEBUG_GROW
Packit 423ecb
    unsigned long nbElem = 0;
Packit 423ecb
#endif
Packit 423ecb
    int ret = 0;
Packit 423ecb
    int keep_keys = 1;
Packit 423ecb
Packit 423ecb
    if (dict == 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
#ifdef DICT_DEBUG_PATTERNS
Packit 423ecb
    fprintf(stderr, "*");
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
    oldsize = dict->size;
Packit 423ecb
    olddict = dict->dict;
Packit 423ecb
    if (olddict == NULL)
Packit 423ecb
        return(-1);
Packit 423ecb
    if (oldsize == MIN_DICT_SIZE)
Packit 423ecb
        keep_keys = 0;
Packit 423ecb
Packit 423ecb
    dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
Packit 423ecb
    if (dict->dict == NULL) {
Packit 423ecb
	dict->dict = olddict;
Packit 423ecb
	return(-1);
Packit 423ecb
    }
Packit 423ecb
    memset(dict->dict, 0, size * sizeof(xmlDictEntry));
Packit 423ecb
    dict->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 dict. It is nicer to run through the array twice, first
Packit 423ecb
	copying all the elements in the main array (less probability of
Packit 423ecb
	allocate) and then the rest, so we only free in the second loop.
Packit 423ecb
    */
Packit 423ecb
    for (i = 0; i < oldsize; i++) {
Packit 423ecb
	if (olddict[i].valid == 0)
Packit 423ecb
	    continue;
Packit 423ecb
Packit 423ecb
	if (keep_keys)
Packit 423ecb
	    okey = olddict[i].okey;
Packit 423ecb
	else
Packit 423ecb
	    okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
Packit 423ecb
	key = okey % dict->size;
Packit 423ecb
Packit 423ecb
	if (dict->dict[key].valid == 0) {
Packit 423ecb
	    memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
Packit 423ecb
	    dict->dict[key].next = NULL;
Packit 423ecb
	    dict->dict[key].okey = okey;
Packit 423ecb
	} else {
Packit 423ecb
	    xmlDictEntryPtr entry;
Packit 423ecb
Packit 423ecb
	    entry = xmlMalloc(sizeof(xmlDictEntry));
Packit 423ecb
	    if (entry != NULL) {
Packit 423ecb
		entry->name = olddict[i].name;
Packit 423ecb
		entry->len = olddict[i].len;
Packit 423ecb
		entry->okey = okey;
Packit 423ecb
		entry->next = dict->dict[key].next;
Packit 423ecb
		entry->valid = 1;
Packit 423ecb
		dict->dict[key].next = entry;
Packit 423ecb
	    } else {
Packit 423ecb
	        /*
Packit 423ecb
		 * we don't have much ways to alert from herei
Packit 423ecb
		 * result is losing an entry and unicity guarantee
Packit 423ecb
		 */
Packit 423ecb
	        ret = -1;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
#ifdef DEBUG_GROW
Packit 423ecb
	nbElem++;
Packit 423ecb
#endif
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    for (i = 0; i < oldsize; i++) {
Packit 423ecb
	iter = olddict[i].next;
Packit 423ecb
	while (iter) {
Packit 423ecb
	    next = iter->next;
Packit 423ecb
Packit 423ecb
	    /*
Packit 423ecb
	     * put back the entry in the new dict
Packit 423ecb
	     */
Packit 423ecb
Packit 423ecb
	    if (keep_keys)
Packit 423ecb
		okey = iter->okey;
Packit 423ecb
	    else
Packit 423ecb
		okey = xmlDictComputeKey(dict, iter->name, iter->len);
Packit 423ecb
	    key = okey % dict->size;
Packit 423ecb
	    if (dict->dict[key].valid == 0) {
Packit 423ecb
		memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
Packit 423ecb
		dict->dict[key].next = NULL;
Packit 423ecb
		dict->dict[key].valid = 1;
Packit 423ecb
		dict->dict[key].okey = okey;
Packit 423ecb
		xmlFree(iter);
Packit 423ecb
	    } else {
Packit 423ecb
		iter->next = dict->dict[key].next;
Packit 423ecb
		iter->okey = okey;
Packit 423ecb
		dict->dict[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(olddict);
Packit 423ecb
Packit 423ecb
#ifdef DEBUG_GROW
Packit 423ecb
    xmlGenericError(xmlGenericErrorContext,
Packit 423ecb
	    "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictFree:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 *
Packit 423ecb
 * Free the hash @dict and its contents. The userdata is
Packit 423ecb
 * deallocated with @f if provided.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlDictFree(xmlDictPtr dict) {
Packit 423ecb
    size_t i;
Packit 423ecb
    xmlDictEntryPtr iter;
Packit 423ecb
    xmlDictEntryPtr next;
Packit 423ecb
    int inside_dict = 0;
Packit 423ecb
    xmlDictStringsPtr pool, nextp;
Packit 423ecb
Packit 423ecb
    if (dict == NULL)
Packit 423ecb
	return;
Packit 423ecb
Packit 423ecb
    if (!xmlDictInitialized)
Packit 423ecb
        if (!__xmlInitializeDict())
Packit 423ecb
            return;
Packit 423ecb
Packit 423ecb
    /* decrement the counter, it may be shared by a parser and docs */
Packit 423ecb
    xmlRMutexLock(xmlDictMutex);
Packit 423ecb
    dict->ref_counter--;
Packit 423ecb
    if (dict->ref_counter > 0) {
Packit 423ecb
        xmlRMutexUnlock(xmlDictMutex);
Packit 423ecb
        return;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    xmlRMutexUnlock(xmlDictMutex);
Packit 423ecb
Packit 423ecb
    if (dict->subdict != NULL) {
Packit 423ecb
        xmlDictFree(dict->subdict);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (dict->dict) {
Packit 423ecb
	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Packit 423ecb
	    iter = &(dict->dict[i]);
Packit 423ecb
	    if (iter->valid == 0)
Packit 423ecb
		continue;
Packit 423ecb
	    inside_dict = 1;
Packit 423ecb
	    while (iter) {
Packit 423ecb
		next = iter->next;
Packit 423ecb
		if (!inside_dict)
Packit 423ecb
		    xmlFree(iter);
Packit 423ecb
		dict->nbElems--;
Packit 423ecb
		inside_dict = 0;
Packit 423ecb
		iter = next;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
	xmlFree(dict->dict);
Packit 423ecb
    }
Packit 423ecb
    pool = dict->strings;
Packit 423ecb
    while (pool != NULL) {
Packit 423ecb
        nextp = pool->next;
Packit 423ecb
	xmlFree(pool);
Packit 423ecb
	pool = nextp;
Packit 423ecb
    }
Packit 423ecb
    xmlFree(dict);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictLookup:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @len: the length of the name, if -1 it is recomputed
Packit 423ecb
 *
Packit 423ecb
 * Add the @name to the dictionary @dict if not present.
Packit 423ecb
 *
Packit 423ecb
 * Returns the internal copy of the name or NULL in case of internal error
Packit 423ecb
 */
Packit 423ecb
const xmlChar *
Packit 423ecb
xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Packit 423ecb
    unsigned long key, okey, nbi = 0;
Packit 423ecb
    xmlDictEntryPtr entry;
Packit 423ecb
    xmlDictEntryPtr insert;
Packit 423ecb
    const xmlChar *ret;
Packit 423ecb
    unsigned int l;
Packit 423ecb
Packit 423ecb
    if ((dict == NULL) || (name == NULL))
Packit 423ecb
	return(NULL);
Packit 423ecb
Packit 423ecb
    if (len < 0)
Packit 423ecb
        l = strlen((const char *) name);
Packit 423ecb
    else
Packit 423ecb
        l = len;
Packit 423ecb
Packit 423ecb
    if (((dict->limit > 0) && (l >= dict->limit)) ||
Packit 423ecb
        (l > INT_MAX / 2))
Packit 423ecb
        return(NULL);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Check for duplicate and insertion location.
Packit 423ecb
     */
Packit 423ecb
    okey = xmlDictComputeKey(dict, name, l);
Packit 423ecb
    key = okey % dict->size;
Packit 423ecb
    if (dict->dict[key].valid == 0) {
Packit 423ecb
	insert = NULL;
Packit 423ecb
    } else {
Packit 423ecb
	for (insert = &(dict->dict[key]); insert->next != NULL;
Packit 423ecb
	     insert = insert->next) {
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
	    if ((insert->okey == okey) && (insert->len == l)) {
Packit 423ecb
		if (!memcmp(insert->name, name, l))
Packit 423ecb
		    return(insert->name);
Packit 423ecb
	    }
Packit 423ecb
#else
Packit 423ecb
	    if ((insert->okey == okey) && (insert->len == l) &&
Packit 423ecb
	        (!xmlStrncmp(insert->name, name, l)))
Packit 423ecb
		return(insert->name);
Packit 423ecb
#endif
Packit 423ecb
	    nbi++;
Packit 423ecb
	}
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
	if ((insert->okey == okey) && (insert->len == l)) {
Packit 423ecb
	    if (!memcmp(insert->name, name, l))
Packit 423ecb
		return(insert->name);
Packit 423ecb
	}
Packit 423ecb
#else
Packit 423ecb
	if ((insert->okey == okey) && (insert->len == l) &&
Packit 423ecb
	    (!xmlStrncmp(insert->name, name, l)))
Packit 423ecb
	    return(insert->name);
Packit 423ecb
#endif
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (dict->subdict) {
Packit 423ecb
        unsigned long skey;
Packit 423ecb
Packit 423ecb
        /* we cannot always reuse the same okey for the subdict */
Packit 423ecb
        if (((dict->size == MIN_DICT_SIZE) &&
Packit 423ecb
	     (dict->subdict->size != MIN_DICT_SIZE)) ||
Packit 423ecb
            ((dict->size != MIN_DICT_SIZE) &&
Packit 423ecb
	     (dict->subdict->size == MIN_DICT_SIZE)))
Packit 423ecb
	    skey = xmlDictComputeKey(dict->subdict, name, l);
Packit 423ecb
	else
Packit 423ecb
	    skey = okey;
Packit 423ecb
Packit 423ecb
	key = skey % dict->subdict->size;
Packit 423ecb
	if (dict->subdict->dict[key].valid != 0) {
Packit 423ecb
	    xmlDictEntryPtr tmp;
Packit 423ecb
Packit 423ecb
	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
Packit 423ecb
		 tmp = tmp->next) {
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
		if ((tmp->okey == skey) && (tmp->len == l)) {
Packit 423ecb
		    if (!memcmp(tmp->name, name, l))
Packit 423ecb
			return(tmp->name);
Packit 423ecb
		}
Packit 423ecb
#else
Packit 423ecb
		if ((tmp->okey == skey) && (tmp->len == l) &&
Packit 423ecb
		    (!xmlStrncmp(tmp->name, name, l)))
Packit 423ecb
		    return(tmp->name);
Packit 423ecb
#endif
Packit 423ecb
		nbi++;
Packit 423ecb
	    }
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
	    if ((tmp->okey == skey) && (tmp->len == l)) {
Packit 423ecb
		if (!memcmp(tmp->name, name, l))
Packit 423ecb
		    return(tmp->name);
Packit 423ecb
	    }
Packit 423ecb
#else
Packit 423ecb
	    if ((tmp->okey == skey) && (tmp->len == l) &&
Packit 423ecb
		(!xmlStrncmp(tmp->name, name, l)))
Packit 423ecb
		return(tmp->name);
Packit 423ecb
#endif
Packit 423ecb
	}
Packit 423ecb
	key = okey % dict->size;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    ret = xmlDictAddString(dict, name, l);
Packit 423ecb
    if (ret == NULL)
Packit 423ecb
        return(NULL);
Packit 423ecb
    if (insert == NULL) {
Packit 423ecb
	entry = &(dict->dict[key]);
Packit 423ecb
    } else {
Packit 423ecb
	entry = xmlMalloc(sizeof(xmlDictEntry));
Packit 423ecb
	if (entry == NULL)
Packit 423ecb
	     return(NULL);
Packit 423ecb
    }
Packit 423ecb
    entry->name = ret;
Packit 423ecb
    entry->len = l;
Packit 423ecb
    entry->next = NULL;
Packit 423ecb
    entry->valid = 1;
Packit 423ecb
    entry->okey = okey;
Packit 423ecb
Packit 423ecb
Packit 423ecb
    if (insert != NULL)
Packit 423ecb
	insert->next = entry;
Packit 423ecb
Packit 423ecb
    dict->nbElems++;
Packit 423ecb
Packit 423ecb
    if ((nbi > MAX_HASH_LEN) &&
Packit 423ecb
        (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
Packit 423ecb
	if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
Packit 423ecb
	    return(NULL);
Packit 423ecb
    }
Packit 423ecb
    /* Note that entry may have been freed at this point by xmlDictGrow */
Packit 423ecb
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictExists:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @len: the length of the name, if -1 it is recomputed
Packit 423ecb
 *
Packit 423ecb
 * Check if the @name exists in the dictionary @dict.
Packit 423ecb
 *
Packit 423ecb
 * Returns the internal copy of the name or NULL if not found.
Packit 423ecb
 */
Packit 423ecb
const xmlChar *
Packit 423ecb
xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
Packit 423ecb
    unsigned long key, okey, nbi = 0;
Packit 423ecb
    xmlDictEntryPtr insert;
Packit 423ecb
    unsigned int l;
Packit 423ecb
Packit 423ecb
    if ((dict == NULL) || (name == NULL))
Packit 423ecb
	return(NULL);
Packit 423ecb
Packit 423ecb
    if (len < 0)
Packit 423ecb
        l = strlen((const char *) name);
Packit 423ecb
    else
Packit 423ecb
        l = len;
Packit 423ecb
    if (((dict->limit > 0) && (l >= dict->limit)) ||
Packit 423ecb
        (l > INT_MAX / 2))
Packit 423ecb
        return(NULL);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Check for duplicate and insertion location.
Packit 423ecb
     */
Packit 423ecb
    okey = xmlDictComputeKey(dict, name, l);
Packit 423ecb
    key = okey % dict->size;
Packit 423ecb
    if (dict->dict[key].valid == 0) {
Packit 423ecb
	insert = NULL;
Packit 423ecb
    } else {
Packit 423ecb
	for (insert = &(dict->dict[key]); insert->next != NULL;
Packit 423ecb
	     insert = insert->next) {
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
	    if ((insert->okey == okey) && (insert->len == l)) {
Packit 423ecb
		if (!memcmp(insert->name, name, l))
Packit 423ecb
		    return(insert->name);
Packit 423ecb
	    }
Packit 423ecb
#else
Packit 423ecb
	    if ((insert->okey == okey) && (insert->len == l) &&
Packit 423ecb
	        (!xmlStrncmp(insert->name, name, l)))
Packit 423ecb
		return(insert->name);
Packit 423ecb
#endif
Packit 423ecb
	    nbi++;
Packit 423ecb
	}
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
	if ((insert->okey == okey) && (insert->len == l)) {
Packit 423ecb
	    if (!memcmp(insert->name, name, l))
Packit 423ecb
		return(insert->name);
Packit 423ecb
	}
Packit 423ecb
#else
Packit 423ecb
	if ((insert->okey == okey) && (insert->len == l) &&
Packit 423ecb
	    (!xmlStrncmp(insert->name, name, l)))
Packit 423ecb
	    return(insert->name);
Packit 423ecb
#endif
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (dict->subdict) {
Packit 423ecb
        unsigned long skey;
Packit 423ecb
Packit 423ecb
        /* we cannot always reuse the same okey for the subdict */
Packit 423ecb
        if (((dict->size == MIN_DICT_SIZE) &&
Packit 423ecb
	     (dict->subdict->size != MIN_DICT_SIZE)) ||
Packit 423ecb
            ((dict->size != MIN_DICT_SIZE) &&
Packit 423ecb
	     (dict->subdict->size == MIN_DICT_SIZE)))
Packit 423ecb
	    skey = xmlDictComputeKey(dict->subdict, name, l);
Packit 423ecb
	else
Packit 423ecb
	    skey = okey;
Packit 423ecb
Packit 423ecb
	key = skey % dict->subdict->size;
Packit 423ecb
	if (dict->subdict->dict[key].valid != 0) {
Packit 423ecb
	    xmlDictEntryPtr tmp;
Packit 423ecb
Packit 423ecb
	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
Packit 423ecb
		 tmp = tmp->next) {
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
		if ((tmp->okey == skey) && (tmp->len == l)) {
Packit 423ecb
		    if (!memcmp(tmp->name, name, l))
Packit 423ecb
			return(tmp->name);
Packit 423ecb
		}
Packit 423ecb
#else
Packit 423ecb
		if ((tmp->okey == skey) && (tmp->len == l) &&
Packit 423ecb
		    (!xmlStrncmp(tmp->name, name, l)))
Packit 423ecb
		    return(tmp->name);
Packit 423ecb
#endif
Packit 423ecb
		nbi++;
Packit 423ecb
	    }
Packit 423ecb
#ifdef __GNUC__
Packit 423ecb
	    if ((tmp->okey == skey) && (tmp->len == l)) {
Packit 423ecb
		if (!memcmp(tmp->name, name, l))
Packit 423ecb
		    return(tmp->name);
Packit 423ecb
	    }
Packit 423ecb
#else
Packit 423ecb
	    if ((tmp->okey == skey) && (tmp->len == l) &&
Packit 423ecb
		(!xmlStrncmp(tmp->name, name, l)))
Packit 423ecb
		return(tmp->name);
Packit 423ecb
#endif
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /* not found */
Packit 423ecb
    return(NULL);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictQLookup:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @prefix: the prefix
Packit 423ecb
 * @name: the name
Packit 423ecb
 *
Packit 423ecb
 * Add the QName @prefix:@name to the hash @dict if not present.
Packit 423ecb
 *
Packit 423ecb
 * Returns the internal copy of the QName or NULL in case of internal error
Packit 423ecb
 */
Packit 423ecb
const xmlChar *
Packit 423ecb
xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Packit 423ecb
    unsigned long okey, key, nbi = 0;
Packit 423ecb
    xmlDictEntryPtr entry;
Packit 423ecb
    xmlDictEntryPtr insert;
Packit 423ecb
    const xmlChar *ret;
Packit 423ecb
    unsigned int len, plen, l;
Packit 423ecb
Packit 423ecb
    if ((dict == NULL) || (name == NULL))
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (prefix == NULL)
Packit 423ecb
        return(xmlDictLookup(dict, name, -1));
Packit 423ecb
Packit 423ecb
    l = len = strlen((const char *) name);
Packit 423ecb
    plen = strlen((const char *) prefix);
Packit 423ecb
    len += 1 + plen;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Check for duplicate and insertion location.
Packit 423ecb
     */
Packit 423ecb
    okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Packit 423ecb
    key = okey % dict->size;
Packit 423ecb
    if (dict->dict[key].valid == 0) {
Packit 423ecb
	insert = NULL;
Packit 423ecb
    } else {
Packit 423ecb
	for (insert = &(dict->dict[key]); insert->next != NULL;
Packit 423ecb
	     insert = insert->next) {
Packit 423ecb
	    if ((insert->okey == okey) && (insert->len == len) &&
Packit 423ecb
	        (xmlStrQEqual(prefix, name, insert->name)))
Packit 423ecb
		return(insert->name);
Packit 423ecb
	    nbi++;
Packit 423ecb
	}
Packit 423ecb
	if ((insert->okey == okey) && (insert->len == len) &&
Packit 423ecb
	    (xmlStrQEqual(prefix, name, insert->name)))
Packit 423ecb
	    return(insert->name);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (dict->subdict) {
Packit 423ecb
        unsigned long skey;
Packit 423ecb
Packit 423ecb
        /* we cannot always reuse the same okey for the subdict */
Packit 423ecb
        if (((dict->size == MIN_DICT_SIZE) &&
Packit 423ecb
	     (dict->subdict->size != MIN_DICT_SIZE)) ||
Packit 423ecb
            ((dict->size != MIN_DICT_SIZE) &&
Packit 423ecb
	     (dict->subdict->size == MIN_DICT_SIZE)))
Packit 423ecb
	    skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Packit 423ecb
	else
Packit 423ecb
	    skey = okey;
Packit 423ecb
Packit 423ecb
	key = skey % dict->subdict->size;
Packit 423ecb
	if (dict->subdict->dict[key].valid != 0) {
Packit 423ecb
	    xmlDictEntryPtr tmp;
Packit 423ecb
	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
Packit 423ecb
		 tmp = tmp->next) {
Packit 423ecb
		if ((tmp->okey == skey) && (tmp->len == len) &&
Packit 423ecb
		    (xmlStrQEqual(prefix, name, tmp->name)))
Packit 423ecb
		    return(tmp->name);
Packit 423ecb
		nbi++;
Packit 423ecb
	    }
Packit 423ecb
	    if ((tmp->okey == skey) && (tmp->len == len) &&
Packit 423ecb
		(xmlStrQEqual(prefix, name, tmp->name)))
Packit 423ecb
		return(tmp->name);
Packit 423ecb
	}
Packit 423ecb
	key = okey % dict->size;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    ret = xmlDictAddQString(dict, prefix, plen, name, l);
Packit 423ecb
    if (ret == NULL)
Packit 423ecb
        return(NULL);
Packit 423ecb
    if (insert == NULL) {
Packit 423ecb
	entry = &(dict->dict[key]);
Packit 423ecb
    } else {
Packit 423ecb
	entry = xmlMalloc(sizeof(xmlDictEntry));
Packit 423ecb
	if (entry == NULL)
Packit 423ecb
	     return(NULL);
Packit 423ecb
    }
Packit 423ecb
    entry->name = ret;
Packit 423ecb
    entry->len = len;
Packit 423ecb
    entry->next = NULL;
Packit 423ecb
    entry->valid = 1;
Packit 423ecb
    entry->okey = okey;
Packit 423ecb
Packit 423ecb
    if (insert != NULL)
Packit 423ecb
	insert->next = entry;
Packit 423ecb
Packit 423ecb
    dict->nbElems++;
Packit 423ecb
Packit 423ecb
    if ((nbi > MAX_HASH_LEN) &&
Packit 423ecb
        (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
Packit 423ecb
	xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
Packit 423ecb
    /* Note that entry may have been freed at this point by xmlDictGrow */
Packit 423ecb
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictOwns:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @str: the string
Packit 423ecb
 *
Packit 423ecb
 * check if a string is owned by the disctionary
Packit 423ecb
 *
Packit 423ecb
 * Returns 1 if true, 0 if false and -1 in case of error
Packit 423ecb
 * -1 in case of error
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
Packit 423ecb
    xmlDictStringsPtr pool;
Packit 423ecb
Packit 423ecb
    if ((dict == NULL) || (str == NULL))
Packit 423ecb
	return(-1);
Packit 423ecb
    pool = dict->strings;
Packit 423ecb
    while (pool != NULL) {
Packit 423ecb
        if ((str >= &pool->array[0]) && (str <= pool->free))
Packit 423ecb
	    return(1);
Packit 423ecb
	pool = pool->next;
Packit 423ecb
    }
Packit 423ecb
    if (dict->subdict)
Packit 423ecb
        return(xmlDictOwns(dict->subdict, str));
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictSize:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 *
Packit 423ecb
 * Query the number of elements installed in the hash @dict.
Packit 423ecb
 *
Packit 423ecb
 * Returns the number of elements in the dictionary or
Packit 423ecb
 * -1 in case of error
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlDictSize(xmlDictPtr dict) {
Packit 423ecb
    if (dict == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
    if (dict->subdict)
Packit 423ecb
        return(dict->nbElems + dict->subdict->nbElems);
Packit 423ecb
    return(dict->nbElems);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictSetLimit:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 * @limit: the limit in bytes
Packit 423ecb
 *
Packit 423ecb
 * Set a size limit for the dictionary
Packit 423ecb
 * Added in 2.9.0
Packit 423ecb
 *
Packit 423ecb
 * Returns the previous limit of the dictionary or 0
Packit 423ecb
 */
Packit 423ecb
size_t
Packit 423ecb
xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
Packit 423ecb
    size_t ret;
Packit 423ecb
Packit 423ecb
    if (dict == NULL)
Packit 423ecb
	return(0);
Packit 423ecb
    ret = dict->limit;
Packit 423ecb
    dict->limit = limit;
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlDictGetUsage:
Packit 423ecb
 * @dict: the dictionary
Packit 423ecb
 *
Packit 423ecb
 * Get how much memory is used by a dictionary for strings
Packit 423ecb
 * Added in 2.9.0
Packit 423ecb
 *
Packit 423ecb
 * Returns the amount of strings allocated
Packit 423ecb
 */
Packit 423ecb
size_t
Packit 423ecb
xmlDictGetUsage(xmlDictPtr dict) {
Packit 423ecb
    xmlDictStringsPtr pool;
Packit 423ecb
    size_t limit = 0;
Packit 423ecb
Packit 423ecb
    if (dict == NULL)
Packit 423ecb
	return(0);
Packit 423ecb
    pool = dict->strings;
Packit 423ecb
    while (pool != NULL) {
Packit 423ecb
        limit += pool->size;
Packit 423ecb
	pool = pool->next;
Packit 423ecb
    }
Packit 423ecb
    return(limit);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
#define bottom_dict
Packit 423ecb
#include "elfgcchack.h"