Blame dict.c

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