Annotation of embedaddon/libxml2/dict.c, revision 1.1.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>