File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / dict.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:29 2014 UTC (10 years ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    1: /*
    2:  * dict.c: dictionary of reusable strings, just used to avoid allocation
    3:  *         and freeing operations.
    4:  *
    5:  * Copyright (C) 2003-2012 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:  */
   18: 
   19: #define IN_LIBXML
   20: #include "libxml.h"
   21: 
   22: #include <limits.h>
   23: #ifdef HAVE_STDLIB_H
   24: #include <stdlib.h>
   25: #endif
   26: #ifdef HAVE_TIME_H
   27: #include <time.h>
   28: #endif
   29: 
   30: /*
   31:  * Following http://www.ocert.org/advisories/ocert-2011-003.html
   32:  * it seems that having hash randomization might be a good idea
   33:  * when using XML with untrusted data
   34:  * Note1: that it works correctly only if compiled with WITH_BIG_KEY
   35:  *  which is the default.
   36:  * Note2: the fast function used for a small dict won't protect very
   37:  *  well but since the attack is based on growing a very big hash
   38:  *  list we will use the BigKey algo as soon as the hash size grows
   39:  *  over MIN_DICT_SIZE so this actually works
   40:  */
   41: #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
   42: #define DICT_RANDOMIZATION
   43: #endif
   44: 
   45: #include <string.h>
   46: #ifdef HAVE_STDINT_H
   47: #include <stdint.h>
   48: #else
   49: #ifdef HAVE_INTTYPES_H
   50: #include <inttypes.h>
   51: #elif defined(WIN32)
   52: typedef unsigned __int32 uint32_t;
   53: #endif
   54: #endif
   55: #include <libxml/tree.h>
   56: #include <libxml/dict.h>
   57: #include <libxml/xmlmemory.h>
   58: #include <libxml/xmlerror.h>
   59: #include <libxml/globals.h>
   60: 
   61: /* #define DEBUG_GROW */
   62: /* #define DICT_DEBUG_PATTERNS */
   63: 
   64: #define MAX_HASH_LEN 3
   65: #define MIN_DICT_SIZE 128
   66: #define MAX_DICT_HASH 8 * 2048
   67: #define WITH_BIG_KEY
   68: 
   69: #ifdef WITH_BIG_KEY
   70: #define xmlDictComputeKey(dict, name, len)                              \
   71:     (((dict)->size == MIN_DICT_SIZE) ?                                  \
   72:      xmlDictComputeFastKey(name, len, (dict)->seed) :                   \
   73:      xmlDictComputeBigKey(name, len, (dict)->seed))
   74: 
   75: #define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
   76:     (((prefix) == NULL) ?                                               \
   77:       (xmlDictComputeKey(dict, name, len)) :                             \
   78:       (((dict)->size == MIN_DICT_SIZE) ?                                \
   79:        xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) :	\
   80:        xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
   81: 
   82: #else /* !WITH_BIG_KEY */
   83: #define xmlDictComputeKey(dict, name, len)                              \
   84:         xmlDictComputeFastKey(name, len, (dict)->seed)
   85: #define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
   86:         xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
   87: #endif /* WITH_BIG_KEY */
   88: 
   89: /*
   90:  * An entry in the dictionnary
   91:  */
   92: typedef struct _xmlDictEntry xmlDictEntry;
   93: typedef xmlDictEntry *xmlDictEntryPtr;
   94: struct _xmlDictEntry {
   95:     struct _xmlDictEntry *next;
   96:     const xmlChar *name;
   97:     unsigned int len;
   98:     int valid;
   99:     unsigned long okey;
  100: };
  101: 
  102: typedef struct _xmlDictStrings xmlDictStrings;
  103: typedef xmlDictStrings *xmlDictStringsPtr;
  104: struct _xmlDictStrings {
  105:     xmlDictStringsPtr next;
  106:     xmlChar *free;
  107:     xmlChar *end;
  108:     size_t size;
  109:     size_t nbStrings;
  110:     xmlChar array[1];
  111: };
  112: /*
  113:  * The entire dictionnary
  114:  */
  115: struct _xmlDict {
  116:     int ref_counter;
  117: 
  118:     struct _xmlDictEntry *dict;
  119:     size_t size;
  120:     unsigned int nbElems;
  121:     xmlDictStringsPtr strings;
  122: 
  123:     struct _xmlDict *subdict;
  124:     /* used for randomization */
  125:     int seed;
  126:     /* used to impose a limit on size */
  127:     size_t limit;
  128: };
  129: 
  130: /*
  131:  * A mutex for modifying the reference counter for shared
  132:  * dictionaries.
  133:  */
  134: static xmlRMutexPtr xmlDictMutex = NULL;
  135: 
  136: /*
  137:  * Whether the dictionary mutex was initialized.
  138:  */
  139: static int xmlDictInitialized = 0;
  140: 
  141: #ifdef DICT_RANDOMIZATION
  142: #ifdef HAVE_RAND_R
  143: /*
  144:  * Internal data for random function, protected by xmlDictMutex
  145:  */
  146: static unsigned int rand_seed = 0;
  147: #endif
  148: #endif
  149: 
  150: /**
  151:  * xmlInitializeDict:
  152:  *
  153:  * Do the dictionary mutex initialization.
  154:  * this function is deprecated
  155:  *
  156:  * Returns 0 if initialization was already done, and 1 if that
  157:  * call led to the initialization
  158:  */
  159: int xmlInitializeDict(void) {
  160:     return(0);
  161: }
  162: 
  163: /**
  164:  * __xmlInitializeDict:
  165:  *
  166:  * This function is not public
  167:  * Do the dictionary mutex initialization.
  168:  * this function is not thread safe, initialization should
  169:  * normally be done once at setup when called from xmlOnceInit()
  170:  * we may also land in this code if thread support is not compiled in
  171:  *
  172:  * Returns 0 if initialization was already done, and 1 if that
  173:  * call led to the initialization
  174:  */
  175: int __xmlInitializeDict(void) {
  176:     if (xmlDictInitialized)
  177:         return(1);
  178: 
  179:     if ((xmlDictMutex = xmlNewRMutex()) == NULL)
  180:         return(0);
  181:     xmlRMutexLock(xmlDictMutex);
  182: 
  183: #ifdef DICT_RANDOMIZATION
  184: #ifdef HAVE_RAND_R
  185:     rand_seed = time(NULL);
  186:     rand_r(& rand_seed);
  187: #else
  188:     srand(time(NULL));
  189: #endif
  190: #endif
  191:     xmlDictInitialized = 1;
  192:     xmlRMutexUnlock(xmlDictMutex);
  193:     return(1);
  194: }
  195: 
  196: #ifdef DICT_RANDOMIZATION
  197: int __xmlRandom(void) {
  198:     int ret;
  199: 
  200:     if (xmlDictInitialized == 0)
  201:         __xmlInitializeDict();
  202: 
  203:     xmlRMutexLock(xmlDictMutex);
  204: #ifdef HAVE_RAND_R
  205:     ret = rand_r(& rand_seed);
  206: #else
  207:     ret = rand();
  208: #endif
  209:     xmlRMutexUnlock(xmlDictMutex);
  210:     return(ret);
  211: }
  212: #endif
  213: 
  214: /**
  215:  * xmlDictCleanup:
  216:  *
  217:  * Free the dictionary mutex. Do not call unless sure the library
  218:  * is not in use anymore !
  219:  */
  220: void
  221: xmlDictCleanup(void) {
  222:     if (!xmlDictInitialized)
  223:         return;
  224: 
  225:     xmlFreeRMutex(xmlDictMutex);
  226: 
  227:     xmlDictInitialized = 0;
  228: }
  229: 
  230: /*
  231:  * xmlDictAddString:
  232:  * @dict: the dictionnary
  233:  * @name: the name of the userdata
  234:  * @len: the length of the name
  235:  *
  236:  * Add the string to the array[s]
  237:  *
  238:  * Returns the pointer of the local string, or NULL in case of error.
  239:  */
  240: static const xmlChar *
  241: xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
  242:     xmlDictStringsPtr pool;
  243:     const xmlChar *ret;
  244:     size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
  245:     size_t limit = 0;
  246: 
  247: #ifdef DICT_DEBUG_PATTERNS
  248:     fprintf(stderr, "-");
  249: #endif
  250:     pool = dict->strings;
  251:     while (pool != NULL) {
  252: 	if (pool->end - pool->free > namelen)
  253: 	    goto found_pool;
  254: 	if (pool->size > size) size = pool->size;
  255:         limit += pool->size;
  256: 	pool = pool->next;
  257:     }
  258:     /*
  259:      * Not found, need to allocate
  260:      */
  261:     if (pool == NULL) {
  262:         if ((dict->limit > 0) && (limit > dict->limit)) {
  263:             return(NULL);
  264:         }
  265: 
  266:         if (size == 0) size = 1000;
  267: 	else size *= 4; /* exponential growth */
  268:         if (size < 4 * namelen)
  269: 	    size = 4 * namelen; /* just in case ! */
  270: 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
  271: 	if (pool == NULL)
  272: 	    return(NULL);
  273: 	pool->size = size;
  274: 	pool->nbStrings = 0;
  275: 	pool->free = &pool->array[0];
  276: 	pool->end = &pool->array[size];
  277: 	pool->next = dict->strings;
  278: 	dict->strings = pool;
  279: #ifdef DICT_DEBUG_PATTERNS
  280:         fprintf(stderr, "+");
  281: #endif
  282:     }
  283: found_pool:
  284:     ret = pool->free;
  285:     memcpy(pool->free, name, namelen);
  286:     pool->free += namelen;
  287:     *(pool->free++) = 0;
  288:     pool->nbStrings++;
  289:     return(ret);
  290: }
  291: 
  292: /*
  293:  * xmlDictAddQString:
  294:  * @dict: the dictionnary
  295:  * @prefix: the prefix of the userdata
  296:  * @plen: the prefix length
  297:  * @name: the name of the userdata
  298:  * @len: the length of the name
  299:  *
  300:  * Add the QName to the array[s]
  301:  *
  302:  * Returns the pointer of the local string, or NULL in case of error.
  303:  */
  304: static const xmlChar *
  305: xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
  306:                  const xmlChar *name, unsigned int namelen)
  307: {
  308:     xmlDictStringsPtr pool;
  309:     const xmlChar *ret;
  310:     size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
  311:     size_t limit = 0;
  312: 
  313:     if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
  314: 
  315: #ifdef DICT_DEBUG_PATTERNS
  316:     fprintf(stderr, "=");
  317: #endif
  318:     pool = dict->strings;
  319:     while (pool != NULL) {
  320: 	if (pool->end - pool->free > namelen + plen + 1)
  321: 	    goto found_pool;
  322: 	if (pool->size > size) size = pool->size;
  323:         limit += pool->size;
  324: 	pool = pool->next;
  325:     }
  326:     /*
  327:      * Not found, need to allocate
  328:      */
  329:     if (pool == NULL) {
  330:         if ((dict->limit > 0) && (limit > dict->limit)) {
  331:             return(NULL);
  332:         }
  333: 
  334:         if (size == 0) size = 1000;
  335: 	else size *= 4; /* exponential growth */
  336:         if (size < 4 * (namelen + plen + 1))
  337: 	    size = 4 * (namelen + plen + 1); /* just in case ! */
  338: 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
  339: 	if (pool == NULL)
  340: 	    return(NULL);
  341: 	pool->size = size;
  342: 	pool->nbStrings = 0;
  343: 	pool->free = &pool->array[0];
  344: 	pool->end = &pool->array[size];
  345: 	pool->next = dict->strings;
  346: 	dict->strings = pool;
  347: #ifdef DICT_DEBUG_PATTERNS
  348:         fprintf(stderr, "+");
  349: #endif
  350:     }
  351: found_pool:
  352:     ret = pool->free;
  353:     memcpy(pool->free, prefix, plen);
  354:     pool->free += plen;
  355:     *(pool->free++) = ':';
  356:     memcpy(pool->free, name, namelen);
  357:     pool->free += namelen;
  358:     *(pool->free++) = 0;
  359:     pool->nbStrings++;
  360:     return(ret);
  361: }
  362: 
  363: #ifdef WITH_BIG_KEY
  364: /*
  365:  * xmlDictComputeBigKey:
  366:  *
  367:  * Calculate a hash key using a good hash function that works well for
  368:  * larger hash table sizes.
  369:  *
  370:  * Hash function by "One-at-a-Time Hash" see
  371:  * http://burtleburtle.net/bob/hash/doobs.html
  372:  */
  373: 
  374: static uint32_t
  375: xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
  376:     uint32_t hash;
  377:     int i;
  378: 
  379:     if (namelen <= 0 || data == NULL) return(0);
  380: 
  381:     hash = seed;
  382: 
  383:     for (i = 0;i < namelen; i++) {
  384:         hash += data[i];
  385: 	hash += (hash << 10);
  386: 	hash ^= (hash >> 6);
  387:     }
  388:     hash += (hash << 3);
  389:     hash ^= (hash >> 11);
  390:     hash += (hash << 15);
  391: 
  392:     return hash;
  393: }
  394: 
  395: /*
  396:  * xmlDictComputeBigQKey:
  397:  *
  398:  * Calculate a hash key for two strings using a good hash function
  399:  * that works well for larger hash table sizes.
  400:  *
  401:  * Hash function by "One-at-a-Time Hash" see
  402:  * http://burtleburtle.net/bob/hash/doobs.html
  403:  *
  404:  * Neither of the two strings must be NULL.
  405:  */
  406: static unsigned long
  407: xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
  408:                       const xmlChar *name, int len, int seed)
  409: {
  410:     uint32_t hash;
  411:     int i;
  412: 
  413:     hash = seed;
  414: 
  415:     for (i = 0;i < plen; i++) {
  416:         hash += prefix[i];
  417: 	hash += (hash << 10);
  418: 	hash ^= (hash >> 6);
  419:     }
  420:     hash += ':';
  421:     hash += (hash << 10);
  422:     hash ^= (hash >> 6);
  423: 
  424:     for (i = 0;i < len; i++) {
  425:         hash += name[i];
  426: 	hash += (hash << 10);
  427: 	hash ^= (hash >> 6);
  428:     }
  429:     hash += (hash << 3);
  430:     hash ^= (hash >> 11);
  431:     hash += (hash << 15);
  432: 
  433:     return hash;
  434: }
  435: #endif /* WITH_BIG_KEY */
  436: 
  437: /*
  438:  * xmlDictComputeFastKey:
  439:  *
  440:  * Calculate a hash key using a fast hash function that works well
  441:  * for low hash table fill.
  442:  */
  443: static unsigned long
  444: xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
  445:     unsigned long value = seed;
  446: 
  447:     if (name == NULL) return(0);
  448:     value = *name;
  449:     value <<= 5;
  450:     if (namelen > 10) {
  451:         value += name[namelen - 1];
  452:         namelen = 10;
  453:     }
  454:     switch (namelen) {
  455:         case 10: value += name[9];
  456:         case 9: value += name[8];
  457:         case 8: value += name[7];
  458:         case 7: value += name[6];
  459:         case 6: value += name[5];
  460:         case 5: value += name[4];
  461:         case 4: value += name[3];
  462:         case 3: value += name[2];
  463:         case 2: value += name[1];
  464:         default: break;
  465:     }
  466:     return(value);
  467: }
  468: 
  469: /*
  470:  * xmlDictComputeFastQKey:
  471:  *
  472:  * Calculate a hash key for two strings using a fast hash function
  473:  * that works well for low hash table fill.
  474:  *
  475:  * Neither of the two strings must be NULL.
  476:  */
  477: static unsigned long
  478: xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
  479:                        const xmlChar *name, int len, int seed)
  480: {
  481:     unsigned long value = (unsigned long) seed;
  482: 
  483:     if (plen == 0)
  484: 	value += 30 * (unsigned long) ':';
  485:     else
  486: 	value += 30 * (*prefix);
  487: 
  488:     if (len > 10) {
  489:         value += name[len - (plen + 1 + 1)];
  490:         len = 10;
  491: 	if (plen > 10)
  492: 	    plen = 10;
  493:     }
  494:     switch (plen) {
  495:         case 10: value += prefix[9];
  496:         case 9: value += prefix[8];
  497:         case 8: value += prefix[7];
  498:         case 7: value += prefix[6];
  499:         case 6: value += prefix[5];
  500:         case 5: value += prefix[4];
  501:         case 4: value += prefix[3];
  502:         case 3: value += prefix[2];
  503:         case 2: value += prefix[1];
  504:         case 1: value += prefix[0];
  505:         default: break;
  506:     }
  507:     len -= plen;
  508:     if (len > 0) {
  509:         value += (unsigned long) ':';
  510: 	len--;
  511:     }
  512:     switch (len) {
  513:         case 10: value += name[9];
  514:         case 9: value += name[8];
  515:         case 8: value += name[7];
  516:         case 7: value += name[6];
  517:         case 6: value += name[5];
  518:         case 5: value += name[4];
  519:         case 4: value += name[3];
  520:         case 3: value += name[2];
  521:         case 2: value += name[1];
  522:         case 1: value += name[0];
  523:         default: break;
  524:     }
  525:     return(value);
  526: }
  527: 
  528: /**
  529:  * xmlDictCreate:
  530:  *
  531:  * Create a new dictionary
  532:  *
  533:  * Returns the newly created dictionnary, or NULL if an error occured.
  534:  */
  535: xmlDictPtr
  536: xmlDictCreate(void) {
  537:     xmlDictPtr dict;
  538: 
  539:     if (!xmlDictInitialized)
  540:         if (!__xmlInitializeDict())
  541:             return(NULL);
  542: 
  543: #ifdef DICT_DEBUG_PATTERNS
  544:     fprintf(stderr, "C");
  545: #endif
  546: 
  547:     dict = xmlMalloc(sizeof(xmlDict));
  548:     if (dict) {
  549:         dict->ref_counter = 1;
  550:         dict->limit = 0;
  551: 
  552:         dict->size = MIN_DICT_SIZE;
  553: 	dict->nbElems = 0;
  554:         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
  555: 	dict->strings = NULL;
  556: 	dict->subdict = NULL;
  557:         if (dict->dict) {
  558: 	    memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
  559: #ifdef DICT_RANDOMIZATION
  560:             dict->seed = __xmlRandom();
  561: #else
  562:             dict->seed = 0;
  563: #endif
  564: 	    return(dict);
  565:         }
  566:         xmlFree(dict);
  567:     }
  568:     return(NULL);
  569: }
  570: 
  571: /**
  572:  * xmlDictCreateSub:
  573:  * @sub: an existing dictionnary
  574:  *
  575:  * Create a new dictionary, inheriting strings from the read-only
  576:  * dictionnary @sub. On lookup, strings are first searched in the
  577:  * new dictionnary, then in @sub, and if not found are created in the
  578:  * new dictionnary.
  579:  *
  580:  * Returns the newly created dictionnary, or NULL if an error occured.
  581:  */
  582: xmlDictPtr
  583: xmlDictCreateSub(xmlDictPtr sub) {
  584:     xmlDictPtr dict = xmlDictCreate();
  585: 
  586:     if ((dict != NULL) && (sub != NULL)) {
  587: #ifdef DICT_DEBUG_PATTERNS
  588:         fprintf(stderr, "R");
  589: #endif
  590:         dict->seed = sub->seed;
  591:         dict->subdict = sub;
  592: 	xmlDictReference(dict->subdict);
  593:     }
  594:     return(dict);
  595: }
  596: 
  597: /**
  598:  * xmlDictReference:
  599:  * @dict: the dictionnary
  600:  *
  601:  * Increment the reference counter of a dictionary
  602:  *
  603:  * Returns 0 in case of success and -1 in case of error
  604:  */
  605: int
  606: xmlDictReference(xmlDictPtr dict) {
  607:     if (!xmlDictInitialized)
  608:         if (!__xmlInitializeDict())
  609:             return(-1);
  610: 
  611:     if (dict == NULL) return -1;
  612:     xmlRMutexLock(xmlDictMutex);
  613:     dict->ref_counter++;
  614:     xmlRMutexUnlock(xmlDictMutex);
  615:     return(0);
  616: }
  617: 
  618: /**
  619:  * xmlDictGrow:
  620:  * @dict: the dictionnary
  621:  * @size: the new size of the dictionnary
  622:  *
  623:  * resize the dictionnary
  624:  *
  625:  * Returns 0 in case of success, -1 in case of failure
  626:  */
  627: static int
  628: xmlDictGrow(xmlDictPtr dict, size_t size) {
  629:     unsigned long key, okey;
  630:     size_t oldsize, i;
  631:     xmlDictEntryPtr iter, next;
  632:     struct _xmlDictEntry *olddict;
  633: #ifdef DEBUG_GROW
  634:     unsigned long nbElem = 0;
  635: #endif
  636:     int ret = 0;
  637:     int keep_keys = 1;
  638: 
  639:     if (dict == NULL)
  640: 	return(-1);
  641:     if (size < 8)
  642:         return(-1);
  643:     if (size > 8 * 2048)
  644: 	return(-1);
  645: 
  646: #ifdef DICT_DEBUG_PATTERNS
  647:     fprintf(stderr, "*");
  648: #endif
  649: 
  650:     oldsize = dict->size;
  651:     olddict = dict->dict;
  652:     if (olddict == NULL)
  653:         return(-1);
  654:     if (oldsize == MIN_DICT_SIZE)
  655:         keep_keys = 0;
  656: 
  657:     dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
  658:     if (dict->dict == NULL) {
  659: 	dict->dict = olddict;
  660: 	return(-1);
  661:     }
  662:     memset(dict->dict, 0, size * sizeof(xmlDictEntry));
  663:     dict->size = size;
  664: 
  665:     /*	If the two loops are merged, there would be situations where
  666: 	a new entry needs to allocated and data copied into it from
  667: 	the main dict. It is nicer to run through the array twice, first
  668: 	copying all the elements in the main array (less probability of
  669: 	allocate) and then the rest, so we only free in the second loop.
  670:     */
  671:     for (i = 0; i < oldsize; i++) {
  672: 	if (olddict[i].valid == 0)
  673: 	    continue;
  674: 
  675: 	if (keep_keys)
  676: 	    okey = olddict[i].okey;
  677: 	else
  678: 	    okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
  679: 	key = okey % dict->size;
  680: 
  681: 	if (dict->dict[key].valid == 0) {
  682: 	    memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
  683: 	    dict->dict[key].next = NULL;
  684: 	    dict->dict[key].okey = okey;
  685: 	} else {
  686: 	    xmlDictEntryPtr entry;
  687: 
  688: 	    entry = xmlMalloc(sizeof(xmlDictEntry));
  689: 	    if (entry != NULL) {
  690: 		entry->name = olddict[i].name;
  691: 		entry->len = olddict[i].len;
  692: 		entry->okey = okey;
  693: 		entry->next = dict->dict[key].next;
  694: 		entry->valid = 1;
  695: 		dict->dict[key].next = entry;
  696: 	    } else {
  697: 	        /*
  698: 		 * we don't have much ways to alert from herei
  699: 		 * result is loosing an entry and unicity garantee
  700: 		 */
  701: 	        ret = -1;
  702: 	    }
  703: 	}
  704: #ifdef DEBUG_GROW
  705: 	nbElem++;
  706: #endif
  707:     }
  708: 
  709:     for (i = 0; i < oldsize; i++) {
  710: 	iter = olddict[i].next;
  711: 	while (iter) {
  712: 	    next = iter->next;
  713: 
  714: 	    /*
  715: 	     * put back the entry in the new dict
  716: 	     */
  717: 
  718: 	    if (keep_keys)
  719: 		okey = iter->okey;
  720: 	    else
  721: 		okey = xmlDictComputeKey(dict, iter->name, iter->len);
  722: 	    key = okey % dict->size;
  723: 	    if (dict->dict[key].valid == 0) {
  724: 		memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
  725: 		dict->dict[key].next = NULL;
  726: 		dict->dict[key].valid = 1;
  727: 		dict->dict[key].okey = okey;
  728: 		xmlFree(iter);
  729: 	    } else {
  730: 		iter->next = dict->dict[key].next;
  731: 		iter->okey = okey;
  732: 		dict->dict[key].next = iter;
  733: 	    }
  734: 
  735: #ifdef DEBUG_GROW
  736: 	    nbElem++;
  737: #endif
  738: 
  739: 	    iter = next;
  740: 	}
  741:     }
  742: 
  743:     xmlFree(olddict);
  744: 
  745: #ifdef DEBUG_GROW
  746:     xmlGenericError(xmlGenericErrorContext,
  747: 	    "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
  748: #endif
  749: 
  750:     return(ret);
  751: }
  752: 
  753: /**
  754:  * xmlDictFree:
  755:  * @dict: the dictionnary
  756:  *
  757:  * Free the hash @dict and its contents. The userdata is
  758:  * deallocated with @f if provided.
  759:  */
  760: void
  761: xmlDictFree(xmlDictPtr dict) {
  762:     size_t i;
  763:     xmlDictEntryPtr iter;
  764:     xmlDictEntryPtr next;
  765:     int inside_dict = 0;
  766:     xmlDictStringsPtr pool, nextp;
  767: 
  768:     if (dict == NULL)
  769: 	return;
  770: 
  771:     if (!xmlDictInitialized)
  772:         if (!__xmlInitializeDict())
  773:             return;
  774: 
  775:     /* decrement the counter, it may be shared by a parser and docs */
  776:     xmlRMutexLock(xmlDictMutex);
  777:     dict->ref_counter--;
  778:     if (dict->ref_counter > 0) {
  779:         xmlRMutexUnlock(xmlDictMutex);
  780:         return;
  781:     }
  782: 
  783:     xmlRMutexUnlock(xmlDictMutex);
  784: 
  785:     if (dict->subdict != NULL) {
  786:         xmlDictFree(dict->subdict);
  787:     }
  788: 
  789:     if (dict->dict) {
  790: 	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
  791: 	    iter = &(dict->dict[i]);
  792: 	    if (iter->valid == 0)
  793: 		continue;
  794: 	    inside_dict = 1;
  795: 	    while (iter) {
  796: 		next = iter->next;
  797: 		if (!inside_dict)
  798: 		    xmlFree(iter);
  799: 		dict->nbElems--;
  800: 		inside_dict = 0;
  801: 		iter = next;
  802: 	    }
  803: 	}
  804: 	xmlFree(dict->dict);
  805:     }
  806:     pool = dict->strings;
  807:     while (pool != NULL) {
  808:         nextp = pool->next;
  809: 	xmlFree(pool);
  810: 	pool = nextp;
  811:     }
  812:     xmlFree(dict);
  813: }
  814: 
  815: /**
  816:  * xmlDictLookup:
  817:  * @dict: the dictionnary
  818:  * @name: the name of the userdata
  819:  * @len: the length of the name, if -1 it is recomputed
  820:  *
  821:  * Add the @name to the dictionnary @dict if not present.
  822:  *
  823:  * Returns the internal copy of the name or NULL in case of internal error
  824:  */
  825: const xmlChar *
  826: xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
  827:     unsigned long key, okey, nbi = 0;
  828:     xmlDictEntryPtr entry;
  829:     xmlDictEntryPtr insert;
  830:     const xmlChar *ret;
  831:     unsigned int l;
  832: 
  833:     if ((dict == NULL) || (name == NULL))
  834: 	return(NULL);
  835: 
  836:     if (len < 0)
  837:         l = strlen((const char *) name);
  838:     else
  839:         l = len;
  840: 
  841:     if (((dict->limit > 0) && (l >= dict->limit)) ||
  842:         (l > INT_MAX / 2))
  843:         return(NULL);
  844: 
  845:     /*
  846:      * Check for duplicate and insertion location.
  847:      */
  848:     okey = xmlDictComputeKey(dict, name, l);
  849:     key = okey % dict->size;
  850:     if (dict->dict[key].valid == 0) {
  851: 	insert = NULL;
  852:     } else {
  853: 	for (insert = &(dict->dict[key]); insert->next != NULL;
  854: 	     insert = insert->next) {
  855: #ifdef __GNUC__
  856: 	    if ((insert->okey == okey) && (insert->len == l)) {
  857: 		if (!memcmp(insert->name, name, l))
  858: 		    return(insert->name);
  859: 	    }
  860: #else
  861: 	    if ((insert->okey == okey) && (insert->len == l) &&
  862: 	        (!xmlStrncmp(insert->name, name, l)))
  863: 		return(insert->name);
  864: #endif
  865: 	    nbi++;
  866: 	}
  867: #ifdef __GNUC__
  868: 	if ((insert->okey == okey) && (insert->len == l)) {
  869: 	    if (!memcmp(insert->name, name, l))
  870: 		return(insert->name);
  871: 	}
  872: #else
  873: 	if ((insert->okey == okey) && (insert->len == l) &&
  874: 	    (!xmlStrncmp(insert->name, name, l)))
  875: 	    return(insert->name);
  876: #endif
  877:     }
  878: 
  879:     if (dict->subdict) {
  880:         unsigned long skey;
  881: 
  882:         /* we cannot always reuse the same okey for the subdict */
  883:         if (((dict->size == MIN_DICT_SIZE) &&
  884: 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
  885:             ((dict->size != MIN_DICT_SIZE) &&
  886: 	     (dict->subdict->size == MIN_DICT_SIZE)))
  887: 	    skey = xmlDictComputeKey(dict->subdict, name, l);
  888: 	else
  889: 	    skey = okey;
  890: 
  891: 	key = skey % dict->subdict->size;
  892: 	if (dict->subdict->dict[key].valid != 0) {
  893: 	    xmlDictEntryPtr tmp;
  894: 
  895: 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
  896: 		 tmp = tmp->next) {
  897: #ifdef __GNUC__
  898: 		if ((tmp->okey == skey) && (tmp->len == l)) {
  899: 		    if (!memcmp(tmp->name, name, l))
  900: 			return(tmp->name);
  901: 		}
  902: #else
  903: 		if ((tmp->okey == skey) && (tmp->len == l) &&
  904: 		    (!xmlStrncmp(tmp->name, name, l)))
  905: 		    return(tmp->name);
  906: #endif
  907: 		nbi++;
  908: 	    }
  909: #ifdef __GNUC__
  910: 	    if ((tmp->okey == skey) && (tmp->len == l)) {
  911: 		if (!memcmp(tmp->name, name, l))
  912: 		    return(tmp->name);
  913: 	    }
  914: #else
  915: 	    if ((tmp->okey == skey) && (tmp->len == l) &&
  916: 		(!xmlStrncmp(tmp->name, name, l)))
  917: 		return(tmp->name);
  918: #endif
  919: 	}
  920: 	key = okey % dict->size;
  921:     }
  922: 
  923:     ret = xmlDictAddString(dict, name, l);
  924:     if (ret == NULL)
  925:         return(NULL);
  926:     if (insert == NULL) {
  927: 	entry = &(dict->dict[key]);
  928:     } else {
  929: 	entry = xmlMalloc(sizeof(xmlDictEntry));
  930: 	if (entry == NULL)
  931: 	     return(NULL);
  932:     }
  933:     entry->name = ret;
  934:     entry->len = l;
  935:     entry->next = NULL;
  936:     entry->valid = 1;
  937:     entry->okey = okey;
  938: 
  939: 
  940:     if (insert != NULL)
  941: 	insert->next = entry;
  942: 
  943:     dict->nbElems++;
  944: 
  945:     if ((nbi > MAX_HASH_LEN) &&
  946:         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
  947: 	if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
  948: 	    return(NULL);
  949:     }
  950:     /* Note that entry may have been freed at this point by xmlDictGrow */
  951: 
  952:     return(ret);
  953: }
  954: 
  955: /**
  956:  * xmlDictExists:
  957:  * @dict: the dictionnary
  958:  * @name: the name of the userdata
  959:  * @len: the length of the name, if -1 it is recomputed
  960:  *
  961:  * Check if the @name exists in the dictionnary @dict.
  962:  *
  963:  * Returns the internal copy of the name or NULL if not found.
  964:  */
  965: const xmlChar *
  966: xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
  967:     unsigned long key, okey, nbi = 0;
  968:     xmlDictEntryPtr insert;
  969:     unsigned int l;
  970: 
  971:     if ((dict == NULL) || (name == NULL))
  972: 	return(NULL);
  973: 
  974:     if (len < 0)
  975:         l = strlen((const char *) name);
  976:     else
  977:         l = len;
  978:     if (((dict->limit > 0) && (l >= dict->limit)) ||
  979:         (l > INT_MAX / 2))
  980:         return(NULL);
  981: 
  982:     /*
  983:      * Check for duplicate and insertion location.
  984:      */
  985:     okey = xmlDictComputeKey(dict, name, l);
  986:     key = okey % dict->size;
  987:     if (dict->dict[key].valid == 0) {
  988: 	insert = NULL;
  989:     } else {
  990: 	for (insert = &(dict->dict[key]); insert->next != NULL;
  991: 	     insert = insert->next) {
  992: #ifdef __GNUC__
  993: 	    if ((insert->okey == okey) && (insert->len == l)) {
  994: 		if (!memcmp(insert->name, name, l))
  995: 		    return(insert->name);
  996: 	    }
  997: #else
  998: 	    if ((insert->okey == okey) && (insert->len == l) &&
  999: 	        (!xmlStrncmp(insert->name, name, l)))
 1000: 		return(insert->name);
 1001: #endif
 1002: 	    nbi++;
 1003: 	}
 1004: #ifdef __GNUC__
 1005: 	if ((insert->okey == okey) && (insert->len == l)) {
 1006: 	    if (!memcmp(insert->name, name, l))
 1007: 		return(insert->name);
 1008: 	}
 1009: #else
 1010: 	if ((insert->okey == okey) && (insert->len == l) &&
 1011: 	    (!xmlStrncmp(insert->name, name, l)))
 1012: 	    return(insert->name);
 1013: #endif
 1014:     }
 1015: 
 1016:     if (dict->subdict) {
 1017:         unsigned long skey;
 1018: 
 1019:         /* we cannot always reuse the same okey for the subdict */
 1020:         if (((dict->size == MIN_DICT_SIZE) &&
 1021: 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
 1022:             ((dict->size != MIN_DICT_SIZE) &&
 1023: 	     (dict->subdict->size == MIN_DICT_SIZE)))
 1024: 	    skey = xmlDictComputeKey(dict->subdict, name, l);
 1025: 	else
 1026: 	    skey = okey;
 1027: 
 1028: 	key = skey % dict->subdict->size;
 1029: 	if (dict->subdict->dict[key].valid != 0) {
 1030: 	    xmlDictEntryPtr tmp;
 1031: 
 1032: 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
 1033: 		 tmp = tmp->next) {
 1034: #ifdef __GNUC__
 1035: 		if ((tmp->okey == skey) && (tmp->len == l)) {
 1036: 		    if (!memcmp(tmp->name, name, l))
 1037: 			return(tmp->name);
 1038: 		}
 1039: #else
 1040: 		if ((tmp->okey == skey) && (tmp->len == l) &&
 1041: 		    (!xmlStrncmp(tmp->name, name, l)))
 1042: 		    return(tmp->name);
 1043: #endif
 1044: 		nbi++;
 1045: 	    }
 1046: #ifdef __GNUC__
 1047: 	    if ((tmp->okey == skey) && (tmp->len == l)) {
 1048: 		if (!memcmp(tmp->name, name, l))
 1049: 		    return(tmp->name);
 1050: 	    }
 1051: #else
 1052: 	    if ((tmp->okey == skey) && (tmp->len == l) &&
 1053: 		(!xmlStrncmp(tmp->name, name, l)))
 1054: 		return(tmp->name);
 1055: #endif
 1056: 	}
 1057:     }
 1058: 
 1059:     /* not found */
 1060:     return(NULL);
 1061: }
 1062: 
 1063: /**
 1064:  * xmlDictQLookup:
 1065:  * @dict: the dictionnary
 1066:  * @prefix: the prefix
 1067:  * @name: the name
 1068:  *
 1069:  * Add the QName @prefix:@name to the hash @dict if not present.
 1070:  *
 1071:  * Returns the internal copy of the QName or NULL in case of internal error
 1072:  */
 1073: const xmlChar *
 1074: xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
 1075:     unsigned long okey, key, nbi = 0;
 1076:     xmlDictEntryPtr entry;
 1077:     xmlDictEntryPtr insert;
 1078:     const xmlChar *ret;
 1079:     unsigned int len, plen, l;
 1080: 
 1081:     if ((dict == NULL) || (name == NULL))
 1082: 	return(NULL);
 1083:     if (prefix == NULL)
 1084:         return(xmlDictLookup(dict, name, -1));
 1085: 
 1086:     l = len = strlen((const char *) name);
 1087:     plen = strlen((const char *) prefix);
 1088:     len += 1 + plen;
 1089: 
 1090:     /*
 1091:      * Check for duplicate and insertion location.
 1092:      */
 1093:     okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
 1094:     key = okey % dict->size;
 1095:     if (dict->dict[key].valid == 0) {
 1096: 	insert = NULL;
 1097:     } else {
 1098: 	for (insert = &(dict->dict[key]); insert->next != NULL;
 1099: 	     insert = insert->next) {
 1100: 	    if ((insert->okey == okey) && (insert->len == len) &&
 1101: 	        (xmlStrQEqual(prefix, name, insert->name)))
 1102: 		return(insert->name);
 1103: 	    nbi++;
 1104: 	}
 1105: 	if ((insert->okey == okey) && (insert->len == len) &&
 1106: 	    (xmlStrQEqual(prefix, name, insert->name)))
 1107: 	    return(insert->name);
 1108:     }
 1109: 
 1110:     if (dict->subdict) {
 1111:         unsigned long skey;
 1112: 
 1113:         /* we cannot always reuse the same okey for the subdict */
 1114:         if (((dict->size == MIN_DICT_SIZE) &&
 1115: 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
 1116:             ((dict->size != MIN_DICT_SIZE) &&
 1117: 	     (dict->subdict->size == MIN_DICT_SIZE)))
 1118: 	    skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
 1119: 	else
 1120: 	    skey = okey;
 1121: 
 1122: 	key = skey % dict->subdict->size;
 1123: 	if (dict->subdict->dict[key].valid != 0) {
 1124: 	    xmlDictEntryPtr tmp;
 1125: 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
 1126: 		 tmp = tmp->next) {
 1127: 		if ((tmp->okey == skey) && (tmp->len == len) &&
 1128: 		    (xmlStrQEqual(prefix, name, tmp->name)))
 1129: 		    return(tmp->name);
 1130: 		nbi++;
 1131: 	    }
 1132: 	    if ((tmp->okey == skey) && (tmp->len == len) &&
 1133: 		(xmlStrQEqual(prefix, name, tmp->name)))
 1134: 		return(tmp->name);
 1135: 	}
 1136: 	key = okey % dict->size;
 1137:     }
 1138: 
 1139:     ret = xmlDictAddQString(dict, prefix, plen, name, l);
 1140:     if (ret == NULL)
 1141:         return(NULL);
 1142:     if (insert == NULL) {
 1143: 	entry = &(dict->dict[key]);
 1144:     } else {
 1145: 	entry = xmlMalloc(sizeof(xmlDictEntry));
 1146: 	if (entry == NULL)
 1147: 	     return(NULL);
 1148:     }
 1149:     entry->name = ret;
 1150:     entry->len = len;
 1151:     entry->next = NULL;
 1152:     entry->valid = 1;
 1153:     entry->okey = okey;
 1154: 
 1155:     if (insert != NULL)
 1156: 	insert->next = entry;
 1157: 
 1158:     dict->nbElems++;
 1159: 
 1160:     if ((nbi > MAX_HASH_LEN) &&
 1161:         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
 1162: 	xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
 1163:     /* Note that entry may have been freed at this point by xmlDictGrow */
 1164: 
 1165:     return(ret);
 1166: }
 1167: 
 1168: /**
 1169:  * xmlDictOwns:
 1170:  * @dict: the dictionnary
 1171:  * @str: the string
 1172:  *
 1173:  * check if a string is owned by the disctionary
 1174:  *
 1175:  * Returns 1 if true, 0 if false and -1 in case of error
 1176:  * -1 in case of error
 1177:  */
 1178: int
 1179: xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
 1180:     xmlDictStringsPtr pool;
 1181: 
 1182:     if ((dict == NULL) || (str == NULL))
 1183: 	return(-1);
 1184:     pool = dict->strings;
 1185:     while (pool != NULL) {
 1186:         if ((str >= &pool->array[0]) && (str <= pool->free))
 1187: 	    return(1);
 1188: 	pool = pool->next;
 1189:     }
 1190:     if (dict->subdict)
 1191:         return(xmlDictOwns(dict->subdict, str));
 1192:     return(0);
 1193: }
 1194: 
 1195: /**
 1196:  * xmlDictSize:
 1197:  * @dict: the dictionnary
 1198:  *
 1199:  * Query the number of elements installed in the hash @dict.
 1200:  *
 1201:  * Returns the number of elements in the dictionnary or
 1202:  * -1 in case of error
 1203:  */
 1204: int
 1205: xmlDictSize(xmlDictPtr dict) {
 1206:     if (dict == NULL)
 1207: 	return(-1);
 1208:     if (dict->subdict)
 1209:         return(dict->nbElems + dict->subdict->nbElems);
 1210:     return(dict->nbElems);
 1211: }
 1212: 
 1213: /**
 1214:  * xmlDictSetLimit:
 1215:  * @dict: the dictionnary
 1216:  * @limit: the limit in bytes
 1217:  *
 1218:  * Set a size limit for the dictionary
 1219:  * Added in 2.9.0
 1220:  *
 1221:  * Returns the previous limit of the dictionary or 0
 1222:  */
 1223: size_t
 1224: xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
 1225:     size_t ret;
 1226: 
 1227:     if (dict == NULL)
 1228: 	return(0);
 1229:     ret = dict->limit;
 1230:     dict->limit = limit;
 1231:     return(ret);
 1232: }
 1233: 
 1234: /**
 1235:  * xmlDictGetUsage:
 1236:  * @dict: the dictionnary
 1237:  *
 1238:  * Get how much memory is used by a dictionary for strings
 1239:  * Added in 2.9.0
 1240:  *
 1241:  * Returns the amount of strings allocated
 1242:  */
 1243: size_t
 1244: xmlDictGetUsage(xmlDictPtr dict) {
 1245:     xmlDictStringsPtr pool;
 1246:     size_t limit = 0;
 1247: 
 1248:     if (dict == NULL)
 1249: 	return(0);
 1250:     pool = dict->strings;
 1251:     while (pool != NULL) {
 1252:         limit += pool->size;
 1253: 	pool = pool->next;
 1254:     }
 1255:     return(limit);
 1256: }
 1257: 
 1258: #define bottom_dict
 1259: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>