xml/libxml2libs/src/libxml2/libxml2_dict.c
changeset 0 e35f40988205
equal deleted inserted replaced
-1:000000000000 0:e35f40988205
       
     1 /*
       
     2  * libxml2_dict.c: dictionary of reusable strings, just used to avoid allocation
       
     3  *                 and freeing operations.
       
     4  *
       
     5  * Copyright (C) 2003 Daniel Veillard.
       
     6  *
       
     7  * Permission to use, copy, modify, and distribute this software for any
       
     8  * purpose with or without fee is hereby granted, provided that the above
       
     9  * copyright notice and this permission notice appear in all copies.
       
    10  *
       
    11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
       
    12  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
       
    13  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
       
    14  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
       
    15  *
       
    16  * Author: daniel@veillard.com
       
    17  * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
       
    18  */
       
    19 
       
    20 #define IN_LIBXML
       
    21 #undef XE_ENABLE_GS_CACHING
       
    22 #include "xmlenglibxml.h"
       
    23 
       
    24 #include <string.h>
       
    25 #include <stdapis/libxml2/libxml2_globals.h>
       
    26 
       
    27 #define MAX_HASH_LEN 4
       
    28 
       
    29 
       
    30 #define MIN_DICT_SIZE 128
       
    31 #define MAX_DICT_HASH 8 * 2048
       
    32 
       
    33 /* #define ALLOW_REMOVAL */
       
    34 /* #define DEBUG_GROW */
       
    35 
       
    36 /*
       
    37  * xmlDictAddString:
       
    38  * @param dict the dictionnary
       
    39  * @param name the name of the userdata
       
    40  * @param len the length of the name, if -1 it is recomputed
       
    41  *
       
    42  * Add the string to the array[s]
       
    43  *
       
    44  * Returns the pointer of the local string, or NULL in case of error.
       
    45  *
       
    46  * OOM: possible --> NULL is returned, OOM flag is set
       
    47  */
       
    48 static const xmlChar*
       
    49 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
       
    50     xmlDictStringsPtr pool;
       
    51     const xmlChar *ret;
       
    52     int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
       
    53 
       
    54     pool = dict->strings;
       
    55     while (pool) {
       
    56         if (pool->end - pool->free > namelen)
       
    57             goto found_pool;
       
    58         if (pool->size > size) size = pool->size;
       
    59             pool = pool->next;
       
    60     }
       
    61     /*
       
    62      * Not found, need to allocate
       
    63      */
       
    64     if (!pool) {
       
    65         if (size == 0)
       
    66             size = 1000;
       
    67         else
       
    68             size *= 4; /* exponential growth */
       
    69 
       
    70         if (size < 4 * namelen)
       
    71             size = 4 * namelen; /* just in case ! */
       
    72 
       
    73         pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
       
    74         if (!pool)
       
    75             return(NULL); // OOM
       
    76         pool->size = size;
       
    77         pool->nbStrings = 0;
       
    78         pool->free = &pool->array[0];
       
    79         pool->end = &pool->array[size];
       
    80         pool->next = dict->strings;
       
    81         dict->strings = pool;
       
    82     }
       
    83 found_pool:
       
    84     ret = pool->free;
       
    85     memcpy(pool->free, name, namelen);
       
    86     pool->free += namelen;
       
    87     *(pool->free++) = 0;
       
    88     return(ret);
       
    89 }
       
    90 
       
    91 /*
       
    92  * xmlDictAddQString:
       
    93  * @param dict the dictionnary
       
    94  * @param prefix the prefix of the userdata
       
    95  * @param name the name of the userdata
       
    96  * @param len the length of the name, if -1 it is recomputed
       
    97  *
       
    98  * Add the QName to the array[s]
       
    99  *
       
   100  * Returns the pointer of the local string, or NULL in case of error.
       
   101  */
       
   102 static const xmlChar *
       
   103 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
       
   104                  const xmlChar *name, int namelen)
       
   105 {
       
   106     xmlDictStringsPtr pool;
       
   107     const xmlChar *ret;
       
   108     int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
       
   109     int plen;
       
   110 
       
   111     if (!prefix)
       
   112         return(xmlDictAddString(dict, name, namelen));
       
   113     plen = xmlStrlen(prefix);
       
   114 
       
   115     pool = dict->strings;
       
   116     while (pool) {
       
   117         if (pool->end - pool->free > namelen)
       
   118             goto found_pool;
       
   119         if (pool->size > size)
       
   120             size = pool->size;
       
   121         pool = pool->next;
       
   122     }
       
   123     /*
       
   124      * Not found, need to allocate
       
   125      */
       
   126     if (!pool) {
       
   127         if (size == 0)
       
   128             size = 1000;
       
   129         else
       
   130             size *= 4; /* exponential growth */
       
   131         if (size < 4 * namelen)
       
   132             size = 4 * namelen; /* just in case ! */
       
   133         pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
       
   134         if (!pool)
       
   135             return(NULL);
       
   136         pool->size = size;
       
   137         pool->nbStrings = 0;
       
   138         pool->free = &pool->array[0];
       
   139         pool->end = &pool->array[size];
       
   140         pool->next = dict->strings;
       
   141         dict->strings = pool;
       
   142     }
       
   143 found_pool:
       
   144     ret = pool->free;
       
   145     memcpy(pool->free, prefix, plen);
       
   146     pool->free += plen;
       
   147     *(pool->free++) = ':';
       
   148     namelen -= plen + 1;
       
   149     memcpy(pool->free, name, namelen);
       
   150     pool->free += namelen;
       
   151     *(pool->free++) = 0;
       
   152     return(ret);
       
   153 }
       
   154 
       
   155 /*
       
   156  * xmlDictComputeKey:
       
   157  * Calculate the hash key
       
   158  *
       
   159  * OOM: never
       
   160  */
       
   161  
       
   162  
       
   163 static unsigned long
       
   164 xmlDictComputeKey(const xmlChar *name, int namelen) {
       
   165     unsigned long value = 0L;
       
   166 
       
   167     if (!name)
       
   168         return(0);
       
   169     value = *name;
       
   170     value <<= 5;
       
   171     if (namelen > 10) {
       
   172         value += name[namelen - 1];
       
   173         namelen = 10;
       
   174     }
       
   175     // DONE: OPTIMIZE: Will it be better to rewrite SWITCH as IF? :
       
   176     //      if(namelen > 1) // namelen by this point is <= 10
       
   177     //             value+=name[namelen-1]
       
   178     //
       
   179     if (namelen > 1)
       
   180         value += name[namelen-1];
       
   181     /*
       
   182     switch (namelen) {
       
   183         case 10: value += name[9];
       
   184         case 9: value += name[8];
       
   185         case 8: value += name[7];
       
   186         case 7: value += name[6];
       
   187         case 6: value += name[5];
       
   188         case 5: value += name[4];
       
   189         case 4: value += name[3];
       
   190         case 3: value += name[2];
       
   191         case 2: value += name[1];
       
   192         default: break;
       
   193     }
       
   194     */
       
   195     return(value);
       
   196 }
       
   197 
       
   198 /*
       
   199  * xmlDictComputeQKey:
       
   200  * Calculate the hash key
       
   201  */
       
   202 static unsigned long
       
   203 xmlDictComputeQKey(const xmlChar *prefix, const xmlChar *name, int len)
       
   204 {
       
   205     unsigned long value; // = 0L;  //avoided initialization
       
   206     int plen;
       
   207 
       
   208     if (!prefix)
       
   209         return(xmlDictComputeKey(name, len));
       
   210 
       
   211     plen = xmlStrlen(prefix);
       
   212     value = 30 * (plen ? *prefix : (unsigned long) ':');
       
   213 
       
   214     if (len > 10) {
       
   215         value += name[len - (plen + 1 + 1)];
       
   216         len = 10;
       
   217         if (plen > 10)
       
   218             plen = 10;
       
   219     }
       
   220 
       
   221     // DONE: OPTIMIZE: see "Optimize-It" note in xmlDictComputeKey
       
   222     /*
       
   223     switch (plen) {
       
   224         case 10: value += prefix[9];
       
   225         case 9: value += prefix[8];
       
   226         case 8: value += prefix[7];
       
   227         case 7: value += prefix[6];
       
   228         case 6: value += prefix[5];
       
   229         case 5: value += prefix[4];
       
   230         case 4: value += prefix[3];
       
   231         case 3: value += prefix[2];
       
   232         case 2: value += prefix[1];
       
   233         case 1: value += prefix[0];
       
   234         default: break;
       
   235     }
       
   236     */
       
   237     // REPLACED WITH
       
   238     if (plen < 11 && plen >0)
       
   239         value += prefix[plen-1];
       
   240     //-------------------------------------
       
   241     len -= plen;
       
   242     if (len > 0) {
       
   243         value += (unsigned long) ':';
       
   244         len--;
       
   245     }
       
   246     /* --- REPLACED
       
   247     switch (len) {
       
   248         case 10: value += name[9];
       
   249         case 9: value += name[8];
       
   250         case 8: value += name[7];
       
   251         case 7: value += name[6];
       
   252         case 6: value += name[5];
       
   253         case 5: value += name[4];
       
   254         case 4: value += name[3];
       
   255         case 3: value += name[2];
       
   256         case 2: value += name[1];
       
   257         case 1: value += name[0];
       
   258         default: break;
       
   259     }
       
   260     */
       
   261     //-- REPLACED WITH
       
   262     if(len > 0 && len < 11)
       
   263         value += name[len-1];
       
   264     //--------------------
       
   265     return(value);
       
   266 }
       
   267 
       
   268 /**
       
   269  * xmlDictCreate:
       
   270  *
       
   271  * Create a new dictionary
       
   272  *
       
   273  * Returns the newly created dictionnary, or NULL if an error occured.
       
   274  *
       
   275  * OOM: possible --> NULL is returned; OOM flag is set
       
   276  */
       
   277 XMLPUBFUNEXPORT xmlDictPtr
       
   278 xmlDictCreate(void) {
       
   279     xmlDictPtr dict;
       
   280 
       
   281     dict = (xmlDictPtr)xmlMalloc(sizeof(xmlDict));
       
   282     if (dict) {
       
   283         dict->ref_counter = 1;
       
   284 
       
   285         dict->size = MIN_DICT_SIZE;
       
   286         dict->nbElems = 0;
       
   287         dict->dict = (xmlDictEntryPtr)xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
       
   288         dict->strings = NULL;
       
   289         dict->subdict = NULL;
       
   290         if (dict->dict) {
       
   291             memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
       
   292             return(dict);
       
   293         }
       
   294         xmlFree(dict); // OOM
       
   295     }
       
   296     return(NULL); // OOM
       
   297 }
       
   298 
       
   299 /**
       
   300  * xmlDictCreateSub:
       
   301  * @param sub an existing dictionnary
       
   302  *
       
   303  * Create a new dictionary, inheriting strings from the read-only
       
   304  * dictionnary sub. On lookup, strings are first searched in the
       
   305  * new dictionnary, then in sub, and if not found are created in the
       
   306  * new dictionnary.
       
   307  *
       
   308  * Returns the newly created dictionnary, or NULL if an error occured.
       
   309  */
       
   310 XMLPUBFUNEXPORT xmlDictPtr
       
   311 xmlDictCreateSub(xmlDictPtr sub) {
       
   312     xmlDictPtr dict = xmlDictCreate();
       
   313 
       
   314     if (dict && sub) {
       
   315         dict->subdict = sub;
       
   316         xmlDictReference(dict->subdict);
       
   317     }
       
   318     return(dict);
       
   319 }
       
   320 
       
   321 /**
       
   322  * xmlDictReference:
       
   323  * @param dict the dictionnary
       
   324  *
       
   325  * Increment the reference counter of a dictionary
       
   326  *
       
   327  * Returns 0 in case of success and -1 in case of error
       
   328  *
       
   329  * OOM: never
       
   330  */
       
   331 XMLPUBFUNEXPORT int
       
   332 xmlDictReference(xmlDictPtr dict) {
       
   333     if (!dict)
       
   334         return -1;
       
   335     dict->ref_counter++;
       
   336     return(0);
       
   337 }
       
   338 
       
   339 /**
       
   340  * xmlDictGrow:
       
   341  * @param dict the dictionnary
       
   342  * @param size the new size of the dictionnary
       
   343  *
       
   344  * resize the dictionnary
       
   345  *
       
   346  * Returns 0 in case of success, -1 in case of failure
       
   347  *
       
   348  * OOM: possible --> returns -1, OOM is set
       
   349  */
       
   350 static int
       
   351 xmlDictGrow(xmlDictPtr dict, int size) {
       
   352     unsigned long key;
       
   353     int oldsize, i;
       
   354     xmlDictEntryPtr iter, next;
       
   355     struct _xmlDictEntry *olddict;
       
   356 #ifdef DEBUG_GROW
       
   357     unsigned long nbElem = 0;
       
   358 #endif
       
   359 
       
   360     if (!dict || size < 8 || size > 8 * 2048)
       
   361         return(-1);
       
   362 
       
   363     oldsize = dict->size;
       
   364     olddict = dict->dict;
       
   365     if (!olddict)
       
   366         return(-1);
       
   367 
       
   368     dict->dict = (xmlDictEntryPtr)xmlMalloc(size * sizeof(xmlDictEntry));
       
   369     if (!dict->dict) {
       
   370         dict->dict = olddict;
       
   371         return(-1);
       
   372     }
       
   373     memset(dict->dict, 0, size * sizeof(xmlDictEntry));
       
   374     dict->size = size;
       
   375 
       
   376     /*  If the two loops are merged, there would be situations where
       
   377     a new entry needs to allocated and data copied into it from
       
   378     the main dict. So instead, we run through the array twice, first
       
   379     copying all the elements in the main array (where we can't get
       
   380     conflicts) and then the rest, so we only free (and don't allocate)
       
   381     */
       
   382     for (i = 0; i < oldsize; i++)
       
   383     {
       
   384         if (olddict[i].valid == 0)
       
   385             continue;
       
   386         key = xmlDictComputeKey(olddict[i].name, olddict[i].len) % dict->size;
       
   387         memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
       
   388         dict->dict[key].next = NULL;
       
   389 #ifdef DEBUG_GROW
       
   390         nbElem++;
       
   391 #endif
       
   392     }
       
   393 
       
   394     for (i = 0; i < oldsize; i++)
       
   395     {
       
   396         iter = olddict[i].next;
       
   397         while (iter) {
       
   398             next = iter->next;
       
   399             /*
       
   400             * put back the entry in the new dict
       
   401             */
       
   402             key = xmlDictComputeKey(iter->name, iter->len) % dict->size;
       
   403             if (dict->dict[key].valid == 0) {
       
   404                 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
       
   405                 dict->dict[key].next = NULL;
       
   406                 dict->dict[key].valid = 1;
       
   407                 xmlFree(iter);
       
   408             } else {
       
   409                 iter->next = dict->dict[key].next;
       
   410                 dict->dict[key].next = iter;
       
   411             }
       
   412 #ifdef DEBUG_GROW
       
   413             nbElem++;
       
   414 #endif
       
   415             iter = next;
       
   416         } // while (iter)
       
   417     } // for (i = 0; i < oldsize; i++)
       
   418 
       
   419     xmlFree(olddict);
       
   420 
       
   421 #ifdef DEBUG_GROW
       
   422     xmlGenericError(xmlGenericErrorContext,
       
   423         "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
       
   424 #endif
       
   425 
       
   426     return(0);
       
   427 }
       
   428 
       
   429 /**
       
   430  * xmlDictFree:
       
   431  * @param dict the dictionnary
       
   432  *
       
   433  * Free the hash dict and its contents. The userdata is
       
   434  * deallocated with f if provided.
       
   435  */
       
   436 XMLPUBFUNEXPORT void
       
   437 xmlDictFree(xmlDictPtr dict)
       
   438 {
       
   439     int i;
       
   440     xmlDictEntryPtr iter;
       
   441     xmlDictEntryPtr next;
       
   442     int inside_dict = 0;
       
   443     xmlDictStringsPtr pool, nextp;
       
   444 
       
   445     if (!dict)
       
   446         return;
       
   447 
       
   448     /* decrement the counter, it may be shared by a parser and docs */
       
   449     dict->ref_counter--;
       
   450     if (dict->ref_counter > 0)
       
   451         return;
       
   452 
       
   453     if (dict->subdict) {
       
   454         xmlDictFree(dict->subdict);
       
   455     }
       
   456 
       
   457     if (dict->dict) {
       
   458         for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++)
       
   459         {
       
   460             iter = &(dict->dict[i]);
       
   461             if (iter->valid == 0)
       
   462                 continue;
       
   463             inside_dict = 1;
       
   464             while (iter)
       
   465             {
       
   466                 next = iter->next;
       
   467                 if (!inside_dict)
       
   468                     xmlFree(iter);
       
   469                 dict->nbElems--;
       
   470                 inside_dict = 0;
       
   471                 iter = next;
       
   472             }
       
   473             inside_dict = 0;
       
   474         }
       
   475         xmlFree(dict->dict);
       
   476     }
       
   477 
       
   478     pool = dict->strings;
       
   479     while (pool) {
       
   480         nextp = pool->next;
       
   481         xmlFree(pool);
       
   482         pool = nextp;
       
   483     }
       
   484     xmlFree(dict);
       
   485 }
       
   486 
       
   487 /**
       
   488  * xmlDictLookup:
       
   489  * @param dict the dictionnary
       
   490  * @param name the name of the userdata
       
   491  * @param len the length of the name, if -1 it is recomputed
       
   492  *
       
   493  * Add the name to the hash dict if not present.
       
   494  *
       
   495  * Returns the internal copy of the name or NULL in case of internal error
       
   496  *
       
   497  * OOM: possible --> returns NULL and OOM flag is set
       
   498  */
       
   499 XMLPUBFUNEXPORT const xmlChar*
       
   500 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
       
   501     unsigned long key, okey, nbi = 0;
       
   502     xmlDictEntryPtr entry;
       
   503     xmlDictEntryPtr insert;
       
   504     const xmlChar *ret;
       
   505 
       
   506     if (!dict || !name)
       
   507         return(NULL);
       
   508 
       
   509     if (len < 0)
       
   510         len = xmlStrlen(name);
       
   511 
       
   512     /*
       
   513      * Check for duplicate and insertion location.
       
   514      */
       
   515     okey = xmlDictComputeKey(name, len);
       
   516     key = okey % dict->size;
       
   517     if (dict->dict[key].valid == 0) {
       
   518         insert = NULL;
       
   519     } else {
       
   520         for (insert = &(dict->dict[key]);
       
   521              insert->next;
       
   522              insert = insert->next)
       
   523         {
       
   524 
       
   525 #ifdef __GNUC__
       
   526             if (insert->len == len) {
       
   527                 if (!memcmp(insert->name, name, len))
       
   528                     return(insert->name);
       
   529             }
       
   530 #else
       
   531             if ((insert->len == len) && (!xmlStrncmp(insert->name, name, len)))
       
   532                 return(insert->name);
       
   533 #endif
       
   534             nbi++;
       
   535         }
       
   536 #ifdef __GNUC__
       
   537         if (insert->len == len) {
       
   538             if (!memcmp(insert->name, name, len))
       
   539                 return(insert->name);
       
   540         }
       
   541 #else
       
   542         if ((insert->len == len) && (!xmlStrncmp(insert->name, name, len)))
       
   543             return(insert->name);
       
   544 #endif
       
   545     }
       
   546 
       
   547     if (dict->subdict) {
       
   548         key = okey % dict->subdict->size;
       
   549         if (dict->subdict->dict[key].valid != 0) {
       
   550             xmlDictEntryPtr tmp;
       
   551 
       
   552             for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; tmp = tmp->next)
       
   553             {
       
   554 #ifdef __GNUC__
       
   555                 if (tmp->len == len) {
       
   556                     if (!memcmp(tmp->name, name, len))
       
   557                         return(tmp->name);
       
   558                 }
       
   559 #else
       
   560                 if ((tmp->len == len) && (!xmlStrncmp(tmp->name, name, len)))
       
   561                         return(tmp->name);
       
   562 #endif
       
   563                 nbi++;
       
   564             }
       
   565 #ifdef __GNUC__
       
   566             if (tmp->len == len) {
       
   567                 if (!memcmp(tmp->name, name, len))
       
   568                     return(tmp->name);
       
   569             }
       
   570 #else
       
   571             if ((tmp->len == len) && (!xmlStrncmp(tmp->name, name, len)))
       
   572                 return(tmp->name);
       
   573 #endif
       
   574         } // if (dict->subdict->dict[key].valid != 0)
       
   575 
       
   576         key = okey % dict->size;
       
   577     } // if (dict->subdict)
       
   578 
       
   579     ret = xmlDictAddString(dict, name, len); // may set OOM flag
       
   580     if (!ret)
       
   581         return(NULL);
       
   582 
       
   583     if (!insert) {
       
   584         entry = &(dict->dict[key]);
       
   585     } else {
       
   586         entry = (xmlDictEntryPtr)xmlMalloc(sizeof(xmlDictEntry));
       
   587         if (!entry)
       
   588              return(NULL); //OOM
       
   589     }
       
   590     entry->name = ret;
       
   591     entry->len = len;
       
   592     entry->next = NULL;
       
   593     entry->valid = 1;
       
   594 
       
   595     if (insert)
       
   596         insert->next = entry;
       
   597 
       
   598     dict->nbElems++;
       
   599 
       
   600     if ((nbi > MAX_HASH_LEN) &&
       
   601         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
       
   602     {
       
   603         xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
       
   604         if(OOM_FLAG)
       
   605             return NULL;
       
   606     }
       
   607 
       
   608     /* Note that entry may have been freed at this point by xmlDictGrow */
       
   609 
       
   610     return(ret);
       
   611 }
       
   612 
       
   613 /**
       
   614  * xmlDictQLookup:
       
   615  * @param dict the dictionnary
       
   616  * @param prefix the prefix
       
   617  * @param name the name
       
   618  *
       
   619  * Add the QName prefix:name to the hash dict if not present.
       
   620  *
       
   621  * Returns the internal copy of the QName or NULL in case of internal error
       
   622  */
       
   623 XMLPUBFUNEXPORT const xmlChar *
       
   624 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
       
   625     unsigned long okey, key, nbi = 0;
       
   626     xmlDictEntryPtr entry;
       
   627     xmlDictEntryPtr insert;
       
   628     const xmlChar *ret;
       
   629     int len;
       
   630 
       
   631     if (!dict || !name)
       
   632         return(NULL);
       
   633 
       
   634     len = xmlStrlen(name);
       
   635     if (prefix)
       
   636         len += 1 + xmlStrlen(prefix);
       
   637 
       
   638     /*
       
   639      * Check for duplicate and insertion location.
       
   640      */
       
   641     okey = xmlDictComputeQKey(prefix, name, len);
       
   642     key = okey % dict->size;
       
   643     if (dict->dict[key].valid == 0) {
       
   644         insert = NULL;
       
   645     } else {
       
   646         for (insert = &(dict->dict[key]);
       
   647              insert->next;
       
   648              insert = insert->next)
       
   649         {
       
   650             if ((insert->len == len) && xmlStrQEqual(prefix, name, insert->name))
       
   651                 return(insert->name);
       
   652             nbi++;
       
   653         }
       
   654         if ((insert->len == len) && xmlStrQEqual(prefix, name, insert->name))
       
   655             return(insert->name);
       
   656     }
       
   657 
       
   658     if (dict->subdict)
       
   659     {
       
   660         key = okey % dict->subdict->size;
       
   661         if (dict->subdict->dict[key].valid != 0)
       
   662         {
       
   663             xmlDictEntryPtr tmp;
       
   664             for (tmp = &(dict->subdict->dict[key]);
       
   665                  tmp->next;
       
   666                  tmp = tmp->next)
       
   667             {
       
   668                 if ((tmp->len == len) && xmlStrQEqual(prefix, name, tmp->name))
       
   669                     return(tmp->name);
       
   670                 nbi++;
       
   671             }
       
   672             if ((tmp->len == len) && xmlStrQEqual(prefix, name, tmp->name))
       
   673                 return(tmp->name);
       
   674         }
       
   675         key = okey % dict->size;
       
   676     }
       
   677 
       
   678     ret = xmlDictAddQString(dict, prefix, name, len);
       
   679     if (!ret)
       
   680         return(NULL);
       
   681     if (!insert) {
       
   682         entry = &(dict->dict[key]);
       
   683     } else {
       
   684         entry = (xmlDictEntryPtr)xmlMalloc(sizeof(xmlDictEntry));
       
   685         if (!entry)
       
   686             return(NULL);
       
   687     }
       
   688     entry->name = ret;
       
   689     entry->len = len;
       
   690     entry->next = NULL;
       
   691     entry->valid = 1;
       
   692 
       
   693     if (insert)
       
   694         insert->next = entry;
       
   695 
       
   696     dict->nbElems++;
       
   697 
       
   698     if ((nbi > MAX_HASH_LEN) &&
       
   699         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
       
   700     {
       
   701         xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
       
   702     }
       
   703     /* Note that entry may have been freed at this point by xmlDictGrow */
       
   704 
       
   705     return(ret);
       
   706 }
       
   707 
       
   708 
       
   709 /**
       
   710  * xmlDictOwns:
       
   711  * @param dict the dictionnary
       
   712  * @param str the string
       
   713  *
       
   714  * check if a string is owned by the disctionary
       
   715  *
       
   716  * Returns 1 if true, 0 if false and -1 in case of error
       
   717  * -1 in case of error
       
   718  *
       
   719  * OOM: impossible
       
   720  */
       
   721 XMLPUBFUNEXPORT int
       
   722 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
       
   723     xmlDictStringsPtr pool;
       
   724 
       
   725     if (!dict || !str)
       
   726     {
       
   727         return(-1);
       
   728     }
       
   729 
       
   730     pool = dict->strings;
       
   731     while (pool) {
       
   732         if ((str >= pool->array) && (str <= pool->free))
       
   733         {
       
   734             return(1);
       
   735         }
       
   736         pool = pool->next;
       
   737     }
       
   738 
       
   739     if (dict->subdict)
       
   740         return(xmlDictOwns(dict->subdict, str));
       
   741     return(0);
       
   742 }
       
   743 
       
   744 #ifndef XMLENGINE_EXCLUDE_UNUSED
       
   745 /**
       
   746  * xmlDictSize:
       
   747  * @param dict the dictionnary
       
   748  *
       
   749  * Query the number of elements installed in the hash dict.
       
   750  *
       
   751  * Returns the number of elements in the dictionnary or
       
   752  * -1 in case of error
       
   753  */
       
   754 int
       
   755 xmlDictSize(xmlDictPtr dict)
       
   756 {
       
   757     if (!dict)
       
   758         return(-1);
       
   759     if (dict->subdict)
       
   760         return(dict->nbElems + dict->subdict->nbElems);
       
   761     return(dict->nbElems);
       
   762 }
       
   763 #endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */