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

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

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