webengine/osswebengine/WebCore/platform/symbian/Libxml2/Libxml2_dict.c
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/symbian/Libxml2/Libxml2_dict.c	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,709 @@
+/*
+ * dict.c: dictionary of reusable strings, just used to avoid allocation
+ *         and freeing operations.
+ *
+ * Copyright (C) 2003 Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: daniel@veillard.com
+ */
+
+#define IN_LIBXML
+#include "XmlEnglibxml.h"
+
+#include <string.h>
+#include "Libxml2_globals.h"
+
+#define MAX_HASH_LEN 4
+// TODO: Optimize: "Magic number" -- make it configurable global parameter
+//       1 entry is 16 bytes
+#define MIN_DICT_SIZE 128
+#define MAX_DICT_HASH 8 * 2048
+
+/* #define ALLOW_REMOVAL */
+/* #define DEBUG_GROW */
+
+/*
+ * xmlDictAddString:
+ * @dict: the dictionnary
+ * @name: the name of the userdata
+ * @len: the length of the name, if -1 it is recomputed
+ *
+ * Add the string to the array[s]
+ *
+ * Returns the pointer of the local string, or NULL in case of error.
+ *
+ * OOM: possible --> NULL is returned, OOM flag is set
+ */
+static const xmlChar*
+xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
+    xmlDictStringsPtr pool;
+    const xmlChar *ret;
+    int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
+
+    pool = dict->strings;
+    while (pool != NULL) {
+        if (pool->end - pool->free > namelen)
+            goto found_pool;
+        if (pool->size > size) size = pool->size;
+            pool = pool->next;
+    }
+    /*
+     * Not found, need to allocate
+     */
+    if (pool == NULL) {
+        if (size == 0) 
+            size = 1000;
+        else 
+            size *= 4; /* exponential growth */
+
+        if (size < 4 * namelen)
+            size = 4 * namelen; /* just in case ! */
+
+        pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
+        if (pool == NULL)
+            return(NULL);
+        pool->size = size;
+        pool->nbStrings = 0;
+        pool->free = &pool->array[0];
+        pool->end = &pool->array[size];
+        pool->next = dict->strings;
+        dict->strings = pool;
+    }
+found_pool:
+    ret = pool->free;
+    memcpy(pool->free, name, namelen);
+    pool->free += namelen;
+    *(pool->free++) = 0;
+    return(ret);
+}
+
+/*
+ * xmlDictAddQString:
+ * @dict: the dictionnary
+ * @prefix: the prefix of the userdata
+ * @name: the name of the userdata
+ * @len: the length of the name, if -1 it is recomputed
+ *
+ * Add the QName to the array[s]
+ *
+ * Returns the pointer of the local string, or NULL in case of error.
+ */
+static const xmlChar *
+xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
+                 const xmlChar *name, int namelen)
+{
+    xmlDictStringsPtr pool;
+    const xmlChar *ret;
+    int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
+    int plen;
+
+    if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
+    plen = xmlStrlen(prefix);
+
+    pool = dict->strings;
+    while (pool != NULL) {
+    if (pool->end - pool->free > namelen)
+        goto found_pool;
+    if (pool->size > size) size = pool->size;
+    pool = pool->next;
+    }
+    /*
+     * Not found, need to allocate
+     */
+    if (pool == NULL) {
+        if (size == 0) size = 1000;
+    else size *= 4; /* exponential growth */
+        if (size < 4 * namelen)
+        size = 4 * namelen; /* just in case ! */
+    pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
+    if (pool == NULL)
+        return(NULL);
+    pool->size = size;
+    pool->nbStrings = 0;
+    pool->free = &pool->array[0];
+    pool->end = &pool->array[size];
+    pool->next = dict->strings;
+    dict->strings = pool;
+    }
+found_pool:
+    ret = pool->free;
+    memcpy(pool->free, prefix, plen);
+    pool->free += plen;
+    *(pool->free++) = ':';
+    namelen -= plen + 1;
+    memcpy(pool->free, name, namelen);
+    pool->free += namelen;
+    *(pool->free++) = 0;
+    return(ret);
+}
+
+/*
+ * xmlDictComputeKey:
+ * Calculate the hash key
+ *
+ * OOM: never
+ */
+static unsigned long
+xmlDictComputeKey(const xmlChar *name, int namelen) {
+    unsigned long value = 0L;
+
+    if (name == NULL) return(0);
+    value = *name;
+    value <<= 5;
+    if (namelen > 10) {
+        value += name[namelen - 1];
+        namelen = 10;
+    }
+    switch (namelen) {
+        case 10: value += name[9];
+        case 9: value += name[8];
+        case 8: value += name[7];
+        case 7: value += name[6];
+        case 6: value += name[5];
+        case 5: value += name[4];
+        case 4: value += name[3];
+        case 3: value += name[2];
+        case 2: value += name[1];
+        default: break;
+    }
+    return(value);
+}
+
+/*
+ * xmlDictComputeQKey:
+ * Calculate the hash key
+ */
+static unsigned long
+xmlDictComputeQKey(const xmlChar *prefix, const xmlChar *name, int len)
+{
+    unsigned long value = 0L;
+    int plen;
+
+    if (prefix == NULL)
+        return(xmlDictComputeKey(name, len));
+
+    plen = xmlStrlen(prefix);
+    if (plen == 0)
+    value += 30 * (unsigned long) ':';
+    else
+    value += 30 * (*prefix);
+
+    if (len > 10) {
+        value += name[len - (plen + 1 + 1)];
+        len = 10;
+    if (plen > 10)
+        plen = 10;
+    }
+    switch (plen) {
+        case 10: value += prefix[9];
+        case 9: value += prefix[8];
+        case 8: value += prefix[7];
+        case 7: value += prefix[6];
+        case 6: value += prefix[5];
+        case 5: value += prefix[4];
+        case 4: value += prefix[3];
+        case 3: value += prefix[2];
+        case 2: value += prefix[1];
+        case 1: value += prefix[0];
+        default: break;
+    }
+    len -= plen;
+    if (len > 0) {
+        value += (unsigned long) ':';
+    len--;
+    }
+    switch (len) {
+        case 10: value += name[9];
+        case 9: value += name[8];
+        case 8: value += name[7];
+        case 7: value += name[6];
+        case 6: value += name[5];
+        case 5: value += name[4];
+        case 4: value += name[3];
+        case 3: value += name[2];
+        case 2: value += name[1];
+        case 1: value += name[0];
+        default: break;
+    }
+    return(value);
+}
+
+/**
+ * xmlDictCreate:
+ *
+ * Create a new dictionary
+ *
+ * Returns the newly created dictionnary, or NULL if an error occured.
+ *
+ * OOM: possible --> NULL is returned; OOM flag is set
+ */
+xmlDictPtr
+xmlDictCreate(void) {
+    xmlDictPtr dict;
+
+    dict = (xmlDictPtr)xmlMalloc(sizeof(xmlDict));
+    if (dict) {
+        dict->ref_counter = 1;
+
+        dict->size = MIN_DICT_SIZE;
+        dict->nbElems = 0;
+        dict->dict = (xmlDictEntryPtr)xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
+        dict->strings = NULL;
+        dict->subdict = NULL;
+        if (dict->dict) {
+            memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
+            return(dict);
+        }
+        xmlFree(dict); // OOM
+    }
+    return(NULL); // OOM
+}
+
+/**
+ * xmlDictCreateSub:
+ * @sub: an existing dictionnary
+ *
+ * Create a new dictionary, inheriting strings from the read-only
+ * dictionnary @sub. On lookup, strings are first searched in the
+ * new dictionnary, then in @sub, and if not found are created in the
+ * new dictionnary.
+ *
+ * Returns the newly created dictionnary, or NULL if an error occured.
+ */
+xmlDictPtr
+xmlDictCreateSub(xmlDictPtr sub) {
+    xmlDictPtr dict = xmlDictCreate();
+
+    if ((dict != NULL) && (sub != NULL)) {
+        dict->subdict = sub;
+    xmlDictReference(dict->subdict);
+    }
+    return(dict);
+}
+
+/**
+ * xmlDictReference:
+ * @dict: the dictionnary
+ *
+ * Increment the reference counter of a dictionary
+ *
+ * Returns 0 in case of success and -1 in case of error
+ *
+ * OOM: never
+ */
+int
+xmlDictReference(xmlDictPtr dict) {
+    if (dict == NULL) return -1;
+    dict->ref_counter++;
+    return(0);
+}
+
+/**
+ * xmlDictGrow:
+ * @dict: the dictionnary
+ * @size: the new size of the dictionnary
+ *
+ * resize the dictionnary
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ *
+ * OOM: possible --> returns -1, OOM is set
+ */
+static int
+xmlDictGrow(xmlDictPtr dict, int size) {
+    unsigned long key;
+    int oldsize, i;
+    xmlDictEntryPtr iter, next;
+    struct _xmlDictEntry *olddict;
+#ifdef DEBUG_GROW
+    unsigned long nbElem = 0;
+#endif
+
+    if (dict == NULL)
+        return(-1);
+    if (size < 8)
+        return(-1);
+    if (size > 8 * 2048)
+        return(-1);
+
+    oldsize = dict->size;
+    olddict = dict->dict;
+    if (olddict == NULL)
+        return(-1);
+
+    dict->dict = (xmlDictEntryPtr)xmlMalloc(size * sizeof(xmlDictEntry));
+    if (dict->dict == NULL) {
+        dict->dict = olddict;
+        return(-1);
+    }
+    memset(dict->dict, 0, size * sizeof(xmlDictEntry));
+    dict->size = size;
+
+    /*  If the two loops are merged, there would be situations where
+    a new entry needs to allocated and data copied into it from
+    the main dict. So instead, we run through the array twice, first
+    copying all the elements in the main array (where we can't get
+    conflicts) and then the rest, so we only free (and don't allocate)
+    */
+    for (i = 0; i < oldsize; i++) {
+        if (olddict[i].valid == 0)
+            continue;
+        key = xmlDictComputeKey(olddict[i].name, olddict[i].len) % dict->size;
+        memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
+        dict->dict[key].next = NULL;
+#ifdef DEBUG_GROW
+        nbElem++;
+#endif
+    }
+
+    for (i = 0; i < oldsize; i++) {
+        iter = olddict[i].next;
+        while (iter) {
+            next = iter->next;
+            /*
+            * put back the entry in the new dict
+            */
+            key = xmlDictComputeKey(iter->name, iter->len) % dict->size;
+            if (dict->dict[key].valid == 0) {
+                memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
+                dict->dict[key].next = NULL;
+                dict->dict[key].valid = 1;
+                xmlFree(iter);
+            } else {
+                iter->next = dict->dict[key].next;
+                dict->dict[key].next = iter;
+            }
+#ifdef DEBUG_GROW
+            nbElem++;
+#endif
+            iter = next;
+        } // while (iter)
+    } // for (i = 0; i < oldsize; i++)
+
+    xmlFree(olddict);
+
+#ifdef DEBUG_GROW
+    xmlGenericError(xmlGenericErrorContext,
+        "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
+#endif
+
+    return(0);
+}
+
+/**
+ * xmlDictFree:
+ * @dict: the dictionnary
+ *
+ * Free the hash @dict and its contents. The userdata is
+ * deallocated with @f if provided.
+ */
+void
+xmlDictFree(xmlDictPtr dict) {
+    int i;
+    xmlDictEntryPtr iter;
+    xmlDictEntryPtr next;
+    int inside_dict = 0;
+    xmlDictStringsPtr pool, nextp;
+
+    if (dict == NULL)
+        return;
+
+    /* decrement the counter, it may be shared by a parser and docs */
+    dict->ref_counter--;
+    if (dict->ref_counter > 0)
+        return;
+
+    if (dict->subdict != NULL) {
+        xmlDictFree(dict->subdict);
+    }
+
+    if (dict->dict) {
+        for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++)
+        {
+            iter = &(dict->dict[i]);
+            if (iter->valid == 0)
+                continue;
+            inside_dict = 1;
+            while (iter)
+            {
+                next = iter->next;
+                if (!inside_dict)
+                    xmlFree(iter);
+                dict->nbElems--;
+                inside_dict = 0;
+                iter = next;
+            }
+            inside_dict = 0;
+        }
+        xmlFree(dict->dict);
+    }
+
+    pool = dict->strings;
+    while (pool != NULL) {
+        nextp = pool->next;
+        xmlFree(pool);
+        pool = nextp;
+    }
+    xmlFree(dict);
+}
+
+/**
+ * xmlDictLookup:
+ * @dict: the dictionnary
+ * @name: the name of the userdata
+ * @len: the length of the name, if -1 it is recomputed
+ *
+ * Add the @name to the hash @dict if not present.
+ *
+ * Returns the internal copy of the name or NULL in case of internal error
+ *
+ * OOM: possible --> returns NULL and OOM flag is set
+ */
+const xmlChar*
+xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
+    unsigned long key, okey, nbi = 0;
+    xmlDictEntryPtr entry;
+    xmlDictEntryPtr insert;
+    const xmlChar *ret;
+
+    if ((dict == NULL) || (name == NULL))
+        return(NULL);
+
+    if (len < 0)
+        len = xmlStrlen(name);
+
+    /*
+     * Check for duplicate and insertion location.
+     */
+    okey = xmlDictComputeKey(name, len);
+    key = okey % dict->size;
+    if (dict->dict[key].valid == 0) {
+        insert = NULL;
+    } else {
+        for (insert = &(dict->dict[key]); 
+             insert->next != NULL; 
+             insert = insert->next)
+        {
+#ifdef __GNUC__
+            if (insert->len == len) {
+                if (!memcmp(insert->name, name, len))
+                    return(insert->name);
+            }
+#else
+            if ((insert->len == len) && (!xmlStrncmp(insert->name, name, len)))
+                return(insert->name);
+#endif
+            nbi++;
+        }
+#ifdef __GNUC__
+        if (insert->len == len) {
+            if (!memcmp(insert->name, name, len))
+                return(insert->name);
+        }
+#else
+        if ((insert->len == len) && (!xmlStrncmp(insert->name, name, len)))
+            return(insert->name);
+#endif
+    }
+
+    if (dict->subdict) {
+        key = okey % dict->subdict->size;
+        if (dict->subdict->dict[key].valid != 0) {
+            xmlDictEntryPtr tmp;
+    
+            for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; tmp = tmp->next)
+            {
+#ifdef __GNUC__
+                if (tmp->len == len) {
+                    if (!memcmp(tmp->name, name, len))
+                        return(tmp->name);
+                }
+#else
+                if ((tmp->len == len) && (!xmlStrncmp(tmp->name, name, len)))
+                        return(tmp->name);
+#endif
+                nbi++;
+            }
+#ifdef __GNUC__
+            if (tmp->len == len) {
+                if (!memcmp(tmp->name, name, len))
+                    return(tmp->name);
+            }
+#else
+            if ((tmp->len == len) && (!xmlStrncmp(tmp->name, name, len)))
+                return(tmp->name);
+#endif
+        } // if (dict->subdict->dict[key].valid != 0)
+
+        key = okey % dict->size;
+    } // if (dict->subdict)
+
+    ret = xmlDictAddString(dict, name, len); // may set OOM flag
+    if (!ret)
+        return(NULL);
+
+    if (insert == NULL) {
+        entry = &(dict->dict[key]);
+    } else {
+        entry = (xmlDictEntryPtr)xmlMalloc(sizeof(xmlDictEntry));
+        if (entry == NULL)
+             return(NULL); //OOM
+    }
+    entry->name = ret;
+    entry->len = len;
+    entry->next = NULL;
+    entry->valid = 1;
+
+    if (insert != NULL)
+        insert->next = entry;
+
+    dict->nbElems++;
+
+    if ((nbi > MAX_HASH_LEN) && 
+        (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
+    {
+        xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
+        if(OOM_FLAG)
+            return NULL;
+    }
+
+    /* Note that entry may have been freed at this point by xmlDictGrow */
+
+    return(ret);
+}
+
+/**
+ * xmlDictQLookup:
+ * @dict: the dictionnary
+ * @prefix: the prefix
+ * @name: the name
+ *
+ * Add the QName @prefix:@name to the hash @dict if not present.
+ *
+ * Returns the internal copy of the QName or NULL in case of internal error
+ */
+const xmlChar *
+xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
+    unsigned long okey, key, nbi = 0;
+    xmlDictEntryPtr entry;
+    xmlDictEntryPtr insert;
+    const xmlChar *ret;
+    int len;
+
+    if ((dict == NULL) || (name == NULL))
+    return(NULL);
+
+    len = xmlStrlen(name);
+    if (prefix != NULL)
+        len += 1 + xmlStrlen(prefix);
+
+    /*
+     * Check for duplicate and insertion location.
+     */
+    okey = xmlDictComputeQKey(prefix, name, len);
+    key = okey % dict->size;
+    if (dict->dict[key].valid == 0) {
+    insert = NULL;
+    } else {
+    for (insert = &(dict->dict[key]); insert->next != NULL;
+         insert = insert->next) {
+        if ((insert->len == len) &&
+            (xmlStrQEqual(prefix, name, insert->name)))
+        return(insert->name);
+        nbi++;
+    }
+    if ((insert->len == len) &&
+        (xmlStrQEqual(prefix, name, insert->name)))
+        return(insert->name);
+    }
+
+    if (dict->subdict) {
+    key = okey % dict->subdict->size;
+    if (dict->subdict->dict[key].valid != 0) {
+        xmlDictEntryPtr tmp;
+        for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
+         tmp = tmp->next) {
+        if ((tmp->len == len) &&
+            (xmlStrQEqual(prefix, name, tmp->name)))
+            return(tmp->name);
+        nbi++;
+        }
+        if ((tmp->len == len) &&
+        (xmlStrQEqual(prefix, name, tmp->name)))
+        return(tmp->name);
+    }
+    key = okey % dict->size;
+    }
+
+    ret = xmlDictAddQString(dict, prefix, name, len);
+    if (ret == NULL)
+        return(NULL);
+    if (insert == NULL) {
+    entry = &(dict->dict[key]);
+    } else {
+        entry = (xmlDictEntryPtr)xmlMalloc(sizeof(xmlDictEntry));
+    if (entry == NULL)
+         return(NULL);
+    }
+    entry->name = ret;
+    entry->len = len;
+    entry->next = NULL;
+    entry->valid = 1;
+
+    if (insert != NULL)
+    insert->next = entry;
+
+    dict->nbElems++;
+
+    if ((nbi > MAX_HASH_LEN) &&
+        (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
+    xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
+    /* Note that entry may have been freed at this point by xmlDictGrow */
+
+    return(ret);
+}
+
+
+/**
+ * xmlDictOwns:
+ * @dict: the dictionnary
+ * @str: the string
+ *
+ * check if a string is owned by the disctionary
+ *
+ * Returns 1 if true, 0 if false and -1 in case of error
+ * -1 in case of error
+ *
+ * OOM: impossible
+ */
+int
+xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
+    xmlDictStringsPtr pool;
+
+    if ((dict == NULL) || (str == NULL))
+    {
+        return(-1);
+    }
+    pool = dict->strings;
+    while (pool != NULL) {
+        if ((str >= pool->array) && (str <= pool->free))
+        {
+            return(1);
+        }
+        pool = pool->next;
+    }
+    if (dict->subdict)
+        return(xmlDictOwns(dict->subdict, str));
+    return(0);
+}
+
+