|
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"
|