Annotation of embedaddon/libxml2/dict.c, revision 1.1

1.1     ! misho       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>