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

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

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