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