File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / dict.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 4 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_7_8, HEAD
libxml2

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

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