Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendict.c
Go to the documentation of this file.
00001 /* 00002 * dict.c: dictionary of reusable strings, just used to avoid allocation 00003 * and freeing operations. 00004 * 00005 * Copyright (C) 2003 Daniel Veillard. 00006 * 00007 * Permission to use, copy, modify, and distribute this software for any 00008 * purpose with or without fee is hereby granted, provided that the above 00009 * copyright notice and this permission notice appear in all copies. 00010 * 00011 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 00012 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 00013 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND 00014 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. 00015 * 00016 * Author: daniel@veillard.com 00017 */ 00018 00019 #define IN_LIBXML 00020 #include "libxml.h" 00021 00022 #include <string.h> 00023 #ifdef HAVE_STDINT_H 00024 #include <stdint.h> 00025 #else 00026 #ifdef HAVE_INTTYPES_H 00027 #include <inttypes.h> 00028 #elif defined(WIN32) 00029 typedef unsigned __int32 uint32_t; 00030 #endif 00031 #endif 00032 #include <libxml/tree.h> 00033 #include <libxml/dict.h> 00034 #include <libxml/xmlmemory.h> 00035 #include <libxml/xmlerror.h> 00036 #include <libxml/globals.h> 00037 00038 /* #define DEBUG_GROW */ 00039 /* #define DICT_DEBUG_PATTERNS */ 00040 00041 #define MAX_HASH_LEN 3 00042 #define MIN_DICT_SIZE 128 00043 #define MAX_DICT_HASH 8 * 2048 00044 #define WITH_BIG_KEY 00045 00046 #ifdef WITH_BIG_KEY 00047 #define xmlDictComputeKey(dict, name, len) \ 00048 (((dict)->size == MIN_DICT_SIZE) ? \ 00049 xmlDictComputeFastKey(name, len) : \ 00050 xmlDictComputeBigKey(name, len)) 00051 00052 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \ 00053 (((prefix) == NULL) ? \ 00054 (xmlDictComputeKey(dict, name, len)) : \ 00055 (((dict)->size == MIN_DICT_SIZE) ? \ 00056 xmlDictComputeFastQKey(prefix, plen, name, len) : \ 00057 xmlDictComputeBigQKey(prefix, plen, name, len))) 00058 00059 #else /* !WITH_BIG_KEY */ 00060 #define xmlDictComputeKey(dict, name, len) \ 00061 xmlDictComputeFastKey(name, len) 00062 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \ 00063 xmlDictComputeFastQKey(prefix, plen, name, len) 00064 #endif /* WITH_BIG_KEY */ 00065 00066 /* 00067 * An entry in the dictionnary 00068 */ 00069 typedef struct _xmlDictEntry xmlDictEntry; 00070 typedef xmlDictEntry *xmlDictEntryPtr; 00071 struct _xmlDictEntry { 00072 struct _xmlDictEntry *next; 00073 const xmlChar *name; 00074 int len; 00075 int valid; 00076 unsigned long okey; 00077 }; 00078 00079 typedef struct _xmlDictStrings xmlDictStrings; 00080 typedef xmlDictStrings *xmlDictStringsPtr; 00081 struct _xmlDictStrings { 00082 xmlDictStringsPtr next; 00083 xmlChar *free; 00084 xmlChar *end; 00085 int size; 00086 int nbStrings; 00087 xmlChar array[1]; 00088 }; 00089 /* 00090 * The entire dictionnary 00091 */ 00092 struct _xmlDict { 00093 int ref_counter; 00094 00095 struct _xmlDictEntry *dict; 00096 int size; 00097 int nbElems; 00098 xmlDictStringsPtr strings; 00099 00100 struct _xmlDict *subdict; 00101 }; 00102 00103 /* 00104 * A mutex for modifying the reference counter for shared 00105 * dictionaries. 00106 */ 00107 static xmlRMutexPtr xmlDictMutex = NULL; 00108 00109 /* 00110 * Whether the dictionary mutex was initialized. 00111 */ 00112 static int xmlDictInitialized = 0; 00113 00121 static int xmlInitializeDict(void) { 00122 if (xmlDictInitialized) 00123 return(1); 00124 00125 if ((xmlDictMutex = xmlNewRMutex()) == NULL) 00126 return(0); 00127 00128 xmlDictInitialized = 1; 00129 return(1); 00130 } 00131 00137 void 00138 xmlDictCleanup(void) { 00139 if (!xmlDictInitialized) 00140 return; 00141 00142 xmlFreeRMutex(xmlDictMutex); 00143 00144 xmlDictInitialized = 0; 00145 } 00146 00147 /* 00148 * xmlDictAddString: 00149 * @dict: the dictionnary 00150 * @name: the name of the userdata 00151 * @len: the length of the name, if -1 it is recomputed 00152 * 00153 * Add the string to the array[s] 00154 * 00155 * Returns the pointer of the local string, or NULL in case of error. 00156 */ 00157 static const xmlChar * 00158 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) { 00159 xmlDictStringsPtr pool; 00160 const xmlChar *ret; 00161 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ 00162 00163 #ifdef DICT_DEBUG_PATTERNS 00164 fprintf(stderr, "-"); 00165 #endif 00166 pool = dict->strings; 00167 while (pool != NULL) { 00168 if (pool->end - pool->free > namelen) 00169 goto found_pool; 00170 if (pool->size > size) size = pool->size; 00171 pool = pool->next; 00172 } 00173 /* 00174 * Not found, need to allocate 00175 */ 00176 if (pool == NULL) { 00177 if (size == 0) size = 1000; 00178 else size *= 4; /* exponential growth */ 00179 if (size < 4 * namelen) 00180 size = 4 * namelen; /* just in case ! */ 00181 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); 00182 if (pool == NULL) 00183 return(NULL); 00184 pool->size = size; 00185 pool->nbStrings = 0; 00186 pool->free = &pool->array[0]; 00187 pool->end = &pool->array[size]; 00188 pool->next = dict->strings; 00189 dict->strings = pool; 00190 #ifdef DICT_DEBUG_PATTERNS 00191 fprintf(stderr, "+"); 00192 #endif 00193 } 00194 found_pool: 00195 ret = pool->free; 00196 memcpy(pool->free, name, namelen); 00197 pool->free += namelen; 00198 *(pool->free++) = 0; 00199 pool->nbStrings++; 00200 return(ret); 00201 } 00202 00203 /* 00204 * xmlDictAddQString: 00205 * @dict: the dictionnary 00206 * @prefix: the prefix of the userdata 00207 * @plen: the prefix length 00208 * @name: the name of the userdata 00209 * @len: the length of the name, if -1 it is recomputed 00210 * 00211 * Add the QName to the array[s] 00212 * 00213 * Returns the pointer of the local string, or NULL in case of error. 00214 */ 00215 static const xmlChar * 00216 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen, 00217 const xmlChar *name, int namelen) 00218 { 00219 xmlDictStringsPtr pool; 00220 const xmlChar *ret; 00221 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ 00222 00223 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen)); 00224 00225 #ifdef DICT_DEBUG_PATTERNS 00226 fprintf(stderr, "="); 00227 #endif 00228 pool = dict->strings; 00229 while (pool != NULL) { 00230 if (pool->end - pool->free > namelen + plen + 1) 00231 goto found_pool; 00232 if (pool->size > size) size = pool->size; 00233 pool = pool->next; 00234 } 00235 /* 00236 * Not found, need to allocate 00237 */ 00238 if (pool == NULL) { 00239 if (size == 0) size = 1000; 00240 else size *= 4; /* exponential growth */ 00241 if (size < 4 * (namelen + plen + 1)) 00242 size = 4 * (namelen + plen + 1); /* just in case ! */ 00243 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); 00244 if (pool == NULL) 00245 return(NULL); 00246 pool->size = size; 00247 pool->nbStrings = 0; 00248 pool->free = &pool->array[0]; 00249 pool->end = &pool->array[size]; 00250 pool->next = dict->strings; 00251 dict->strings = pool; 00252 #ifdef DICT_DEBUG_PATTERNS 00253 fprintf(stderr, "+"); 00254 #endif 00255 } 00256 found_pool: 00257 ret = pool->free; 00258 memcpy(pool->free, prefix, plen); 00259 pool->free += plen; 00260 *(pool->free++) = ':'; 00261 memcpy(pool->free, name, namelen); 00262 pool->free += namelen; 00263 *(pool->free++) = 0; 00264 pool->nbStrings++; 00265 return(ret); 00266 } 00267 00268 #ifdef WITH_BIG_KEY 00269 /* 00270 * xmlDictComputeBigKey: 00271 * 00272 * Calculate a hash key using a good hash function that works well for 00273 * larger hash table sizes. 00274 * 00275 * Hash function by "One-at-a-Time Hash" see 00276 * http://burtleburtle.net/bob/hash/doobs.html 00277 */ 00278 00279 static uint32_t 00280 xmlDictComputeBigKey(const xmlChar* data, int namelen) { 00281 uint32_t hash; 00282 int i; 00283 00284 if (namelen <= 0 || data == NULL) return(0); 00285 00286 hash = 0; 00287 00288 for (i = 0;i < namelen; i++) { 00289 hash += data[i]; 00290 hash += (hash << 10); 00291 hash ^= (hash >> 6); 00292 } 00293 hash += (hash << 3); 00294 hash ^= (hash >> 11); 00295 hash += (hash << 15); 00296 00297 return hash; 00298 } 00299 00300 /* 00301 * xmlDictComputeBigQKey: 00302 * 00303 * Calculate a hash key for two strings using a good hash function 00304 * that works well for larger hash table sizes. 00305 * 00306 * Hash function by "One-at-a-Time Hash" see 00307 * http://burtleburtle.net/bob/hash/doobs.html 00308 * 00309 * Neither of the two strings must be NULL. 00310 */ 00311 static unsigned long 00312 xmlDictComputeBigQKey(const xmlChar *prefix, int plen, 00313 const xmlChar *name, int len) 00314 { 00315 uint32_t hash; 00316 int i; 00317 00318 hash = 0; 00319 00320 for (i = 0;i < plen; i++) { 00321 hash += prefix[i]; 00322 hash += (hash << 10); 00323 hash ^= (hash >> 6); 00324 } 00325 hash += ':'; 00326 hash += (hash << 10); 00327 hash ^= (hash >> 6); 00328 00329 for (i = 0;i < len; i++) { 00330 hash += name[i]; 00331 hash += (hash << 10); 00332 hash ^= (hash >> 6); 00333 } 00334 hash += (hash << 3); 00335 hash ^= (hash >> 11); 00336 hash += (hash << 15); 00337 00338 return hash; 00339 } 00340 #endif /* WITH_BIG_KEY */ 00341 00342 /* 00343 * xmlDictComputeFastKey: 00344 * 00345 * Calculate a hash key using a fast hash function that works well 00346 * for low hash table fill. 00347 */ 00348 static unsigned long 00349 xmlDictComputeFastKey(const xmlChar *name, int namelen) { 00350 unsigned long value = 0L; 00351 00352 if (name == NULL) return(0); 00353 value = *name; 00354 value <<= 5; 00355 if (namelen > 10) { 00356 value += name[namelen - 1]; 00357 namelen = 10; 00358 } 00359 switch (namelen) { 00360 case 10: value += name[9]; 00361 case 9: value += name[8]; 00362 case 8: value += name[7]; 00363 case 7: value += name[6]; 00364 case 6: value += name[5]; 00365 case 5: value += name[4]; 00366 case 4: value += name[3]; 00367 case 3: value += name[2]; 00368 case 2: value += name[1]; 00369 default: break; 00370 } 00371 return(value); 00372 } 00373 00374 /* 00375 * xmlDictComputeFastQKey: 00376 * 00377 * Calculate a hash key for two strings using a fast hash function 00378 * that works well for low hash table fill. 00379 * 00380 * Neither of the two strings must be NULL. 00381 */ 00382 static unsigned long 00383 xmlDictComputeFastQKey(const xmlChar *prefix, int plen, 00384 const xmlChar *name, int len) 00385 { 00386 unsigned long value = 0L; 00387 00388 if (plen == 0) 00389 value += 30 * (unsigned long) ':'; 00390 else 00391 value += 30 * (*prefix); 00392 00393 if (len > 10) { 00394 value += name[len - (plen + 1 + 1)]; 00395 len = 10; 00396 if (plen > 10) 00397 plen = 10; 00398 } 00399 switch (plen) { 00400 case 10: value += prefix[9]; 00401 case 9: value += prefix[8]; 00402 case 8: value += prefix[7]; 00403 case 7: value += prefix[6]; 00404 case 6: value += prefix[5]; 00405 case 5: value += prefix[4]; 00406 case 4: value += prefix[3]; 00407 case 3: value += prefix[2]; 00408 case 2: value += prefix[1]; 00409 case 1: value += prefix[0]; 00410 default: break; 00411 } 00412 len -= plen; 00413 if (len > 0) { 00414 value += (unsigned long) ':'; 00415 len--; 00416 } 00417 switch (len) { 00418 case 10: value += name[9]; 00419 case 9: value += name[8]; 00420 case 8: value += name[7]; 00421 case 7: value += name[6]; 00422 case 6: value += name[5]; 00423 case 5: value += name[4]; 00424 case 4: value += name[3]; 00425 case 3: value += name[2]; 00426 case 2: value += name[1]; 00427 case 1: value += name[0]; 00428 default: break; 00429 } 00430 return(value); 00431 } 00432 00440 xmlDictPtr 00441 xmlDictCreate(void) { 00442 xmlDictPtr dict; 00443 00444 if (!xmlDictInitialized) 00445 if (!xmlInitializeDict()) 00446 return(NULL); 00447 00448 #ifdef DICT_DEBUG_PATTERNS 00449 fprintf(stderr, "C"); 00450 #endif 00451 00452 dict = xmlMalloc(sizeof(xmlDict)); 00453 if (dict) { 00454 dict->ref_counter = 1; 00455 00456 dict->size = MIN_DICT_SIZE; 00457 dict->nbElems = 0; 00458 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry)); 00459 dict->strings = NULL; 00460 dict->subdict = NULL; 00461 if (dict->dict) { 00462 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry)); 00463 return(dict); 00464 } 00465 xmlFree(dict); 00466 } 00467 return(NULL); 00468 } 00469 00481 xmlDictPtr 00482 xmlDictCreateSub(xmlDictPtr sub) { 00483 xmlDictPtr dict = xmlDictCreate(); 00484 00485 if ((dict != NULL) && (sub != NULL)) { 00486 #ifdef DICT_DEBUG_PATTERNS 00487 fprintf(stderr, "R"); 00488 #endif 00489 dict->subdict = sub; 00490 xmlDictReference(dict->subdict); 00491 } 00492 return(dict); 00493 } 00494 00503 int 00504 xmlDictReference(xmlDictPtr dict) { 00505 if (!xmlDictInitialized) 00506 if (!xmlInitializeDict()) 00507 return(-1); 00508 00509 if (dict == NULL) return -1; 00510 xmlRMutexLock(xmlDictMutex); 00511 dict->ref_counter++; 00512 xmlRMutexUnlock(xmlDictMutex); 00513 return(0); 00514 } 00515 00525 static int 00526 xmlDictGrow(xmlDictPtr dict, int size) { 00527 unsigned long key, okey; 00528 int oldsize, i; 00529 xmlDictEntryPtr iter, next; 00530 struct _xmlDictEntry *olddict; 00531 #ifdef DEBUG_GROW 00532 unsigned long nbElem = 0; 00533 #endif 00534 int ret = 0; 00535 int keep_keys = 1; 00536 00537 if (dict == NULL) 00538 return(-1); 00539 if (size < 8) 00540 return(-1); 00541 if (size > 8 * 2048) 00542 return(-1); 00543 00544 #ifdef DICT_DEBUG_PATTERNS 00545 fprintf(stderr, "*"); 00546 #endif 00547 00548 oldsize = dict->size; 00549 olddict = dict->dict; 00550 if (olddict == NULL) 00551 return(-1); 00552 if (oldsize == MIN_DICT_SIZE) 00553 keep_keys = 0; 00554 00555 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry)); 00556 if (dict->dict == NULL) { 00557 dict->dict = olddict; 00558 return(-1); 00559 } 00560 memset(dict->dict, 0, size * sizeof(xmlDictEntry)); 00561 dict->size = size; 00562 00563 /* If the two loops are merged, there would be situations where 00564 a new entry needs to allocated and data copied into it from 00565 the main dict. It is nicer to run through the array twice, first 00566 copying all the elements in the main array (less probability of 00567 allocate) and then the rest, so we only free in the second loop. 00568 */ 00569 for (i = 0; i < oldsize; i++) { 00570 if (olddict[i].valid == 0) 00571 continue; 00572 00573 if (keep_keys) 00574 okey = olddict[i].okey; 00575 else 00576 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len); 00577 key = okey % dict->size; 00578 00579 if (dict->dict[key].valid == 0) { 00580 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry)); 00581 dict->dict[key].next = NULL; 00582 dict->dict[key].okey = okey; 00583 } else { 00584 xmlDictEntryPtr entry; 00585 00586 entry = xmlMalloc(sizeof(xmlDictEntry)); 00587 if (entry != NULL) { 00588 entry->name = olddict[i].name; 00589 entry->len = olddict[i].len; 00590 entry->okey = okey; 00591 entry->next = dict->dict[key].next; 00592 entry->valid = 1; 00593 dict->dict[key].next = entry; 00594 } else { 00595 /* 00596 * we don't have much ways to alert from herei 00597 * result is loosing an entry and unicity garantee 00598 */ 00599 ret = -1; 00600 } 00601 } 00602 #ifdef DEBUG_GROW 00603 nbElem++; 00604 #endif 00605 } 00606 00607 for (i = 0; i < oldsize; i++) { 00608 iter = olddict[i].next; 00609 while (iter) { 00610 next = iter->next; 00611 00612 /* 00613 * put back the entry in the new dict 00614 */ 00615 00616 if (keep_keys) 00617 okey = iter->okey; 00618 else 00619 okey = xmlDictComputeKey(dict, iter->name, iter->len); 00620 key = okey % dict->size; 00621 if (dict->dict[key].valid == 0) { 00622 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry)); 00623 dict->dict[key].next = NULL; 00624 dict->dict[key].valid = 1; 00625 dict->dict[key].okey = okey; 00626 xmlFree(iter); 00627 } else { 00628 iter->next = dict->dict[key].next; 00629 iter->okey = okey; 00630 dict->dict[key].next = iter; 00631 } 00632 00633 #ifdef DEBUG_GROW 00634 nbElem++; 00635 #endif 00636 00637 iter = next; 00638 } 00639 } 00640 00641 xmlFree(olddict); 00642 00643 #ifdef DEBUG_GROW 00644 xmlGenericError(xmlGenericErrorContext, 00645 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); 00646 #endif 00647 00648 return(ret); 00649 } 00650 00658 void 00659 xmlDictFree(xmlDictPtr dict) { 00660 int i; 00661 xmlDictEntryPtr iter; 00662 xmlDictEntryPtr next; 00663 int inside_dict = 0; 00664 xmlDictStringsPtr pool, nextp; 00665 00666 if (dict == NULL) 00667 return; 00668 00669 if (!xmlDictInitialized) 00670 if (!xmlInitializeDict()) 00671 return; 00672 00673 /* decrement the counter, it may be shared by a parser and docs */ 00674 xmlRMutexLock(xmlDictMutex); 00675 dict->ref_counter--; 00676 if (dict->ref_counter > 0) { 00677 xmlRMutexUnlock(xmlDictMutex); 00678 return; 00679 } 00680 00681 xmlRMutexUnlock(xmlDictMutex); 00682 00683 if (dict->subdict != NULL) { 00684 xmlDictFree(dict->subdict); 00685 } 00686 00687 if (dict->dict) { 00688 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) { 00689 iter = &(dict->dict[i]); 00690 if (iter->valid == 0) 00691 continue; 00692 inside_dict = 1; 00693 while (iter) { 00694 next = iter->next; 00695 if (!inside_dict) 00696 xmlFree(iter); 00697 dict->nbElems--; 00698 inside_dict = 0; 00699 iter = next; 00700 } 00701 } 00702 xmlFree(dict->dict); 00703 } 00704 pool = dict->strings; 00705 while (pool != NULL) { 00706 nextp = pool->next; 00707 xmlFree(pool); 00708 pool = nextp; 00709 } 00710 xmlFree(dict); 00711 } 00712 00723 const xmlChar * 00724 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { 00725 unsigned long key, okey, nbi = 0; 00726 xmlDictEntryPtr entry; 00727 xmlDictEntryPtr insert; 00728 const xmlChar *ret; 00729 00730 if ((dict == NULL) || (name == NULL)) 00731 return(NULL); 00732 00733 if (len < 0) 00734 len = strlen((const char *) name); 00735 00736 /* 00737 * Check for duplicate and insertion location. 00738 */ 00739 okey = xmlDictComputeKey(dict, name, len); 00740 key = okey % dict->size; 00741 if (dict->dict[key].valid == 0) { 00742 insert = NULL; 00743 } else { 00744 for (insert = &(dict->dict[key]); insert->next != NULL; 00745 insert = insert->next) { 00746 #ifdef __GNUC__ 00747 if ((insert->okey == okey) && (insert->len == len)) { 00748 if (!memcmp(insert->name, name, len)) 00749 return(insert->name); 00750 } 00751 #else 00752 if ((insert->okey == okey) && (insert->len == len) && 00753 (!xmlStrncmp(insert->name, name, len))) 00754 return(insert->name); 00755 #endif 00756 nbi++; 00757 } 00758 #ifdef __GNUC__ 00759 if ((insert->okey == okey) && (insert->len == len)) { 00760 if (!memcmp(insert->name, name, len)) 00761 return(insert->name); 00762 } 00763 #else 00764 if ((insert->okey == okey) && (insert->len == len) && 00765 (!xmlStrncmp(insert->name, name, len))) 00766 return(insert->name); 00767 #endif 00768 } 00769 00770 if (dict->subdict) { 00771 unsigned long skey; 00772 00773 /* we cannot always reuse the same okey for the subdict */ 00774 if (((dict->size == MIN_DICT_SIZE) && 00775 (dict->subdict->size != MIN_DICT_SIZE)) || 00776 ((dict->size != MIN_DICT_SIZE) && 00777 (dict->subdict->size == MIN_DICT_SIZE))) 00778 skey = xmlDictComputeKey(dict->subdict, name, len); 00779 else 00780 skey = okey; 00781 00782 key = skey % dict->subdict->size; 00783 if (dict->subdict->dict[key].valid != 0) { 00784 xmlDictEntryPtr tmp; 00785 00786 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; 00787 tmp = tmp->next) { 00788 #ifdef __GNUC__ 00789 if ((tmp->okey == skey) && (tmp->len == len)) { 00790 if (!memcmp(tmp->name, name, len)) 00791 return(tmp->name); 00792 } 00793 #else 00794 if ((tmp->okey == skey) && (tmp->len == len) && 00795 (!xmlStrncmp(tmp->name, name, len))) 00796 return(tmp->name); 00797 #endif 00798 nbi++; 00799 } 00800 #ifdef __GNUC__ 00801 if ((tmp->okey == skey) && (tmp->len == len)) { 00802 if (!memcmp(tmp->name, name, len)) 00803 return(tmp->name); 00804 } 00805 #else 00806 if ((tmp->okey == skey) && (tmp->len == len) && 00807 (!xmlStrncmp(tmp->name, name, len))) 00808 return(tmp->name); 00809 #endif 00810 } 00811 key = okey % dict->size; 00812 } 00813 00814 ret = xmlDictAddString(dict, name, len); 00815 if (ret == NULL) 00816 return(NULL); 00817 if (insert == NULL) { 00818 entry = &(dict->dict[key]); 00819 } else { 00820 entry = xmlMalloc(sizeof(xmlDictEntry)); 00821 if (entry == NULL) 00822 return(NULL); 00823 } 00824 entry->name = ret; 00825 entry->len = len; 00826 entry->next = NULL; 00827 entry->valid = 1; 00828 entry->okey = okey; 00829 00830 00831 if (insert != NULL) 00832 insert->next = entry; 00833 00834 dict->nbElems++; 00835 00836 if ((nbi > MAX_HASH_LEN) && 00837 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) { 00838 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0) 00839 return(NULL); 00840 } 00841 /* Note that entry may have been freed at this point by xmlDictGrow */ 00842 00843 return(ret); 00844 } 00845 00856 const xmlChar * 00857 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) { 00858 unsigned long key, okey, nbi = 0; 00859 xmlDictEntryPtr insert; 00860 00861 if ((dict == NULL) || (name == NULL)) 00862 return(NULL); 00863 00864 if (len < 0) 00865 len = strlen((const char *) name); 00866 00867 /* 00868 * Check for duplicate and insertion location. 00869 */ 00870 okey = xmlDictComputeKey(dict, name, len); 00871 key = okey % dict->size; 00872 if (dict->dict[key].valid == 0) { 00873 insert = NULL; 00874 } else { 00875 for (insert = &(dict->dict[key]); insert->next != NULL; 00876 insert = insert->next) { 00877 #ifdef __GNUC__ 00878 if ((insert->okey == okey) && (insert->len == len)) { 00879 if (!memcmp(insert->name, name, len)) 00880 return(insert->name); 00881 } 00882 #else 00883 if ((insert->okey == okey) && (insert->len == len) && 00884 (!xmlStrncmp(insert->name, name, len))) 00885 return(insert->name); 00886 #endif 00887 nbi++; 00888 } 00889 #ifdef __GNUC__ 00890 if ((insert->okey == okey) && (insert->len == len)) { 00891 if (!memcmp(insert->name, name, len)) 00892 return(insert->name); 00893 } 00894 #else 00895 if ((insert->okey == okey) && (insert->len == len) && 00896 (!xmlStrncmp(insert->name, name, len))) 00897 return(insert->name); 00898 #endif 00899 } 00900 00901 if (dict->subdict) { 00902 unsigned long skey; 00903 00904 /* we cannot always reuse the same okey for the subdict */ 00905 if (((dict->size == MIN_DICT_SIZE) && 00906 (dict->subdict->size != MIN_DICT_SIZE)) || 00907 ((dict->size != MIN_DICT_SIZE) && 00908 (dict->subdict->size == MIN_DICT_SIZE))) 00909 skey = xmlDictComputeKey(dict->subdict, name, len); 00910 else 00911 skey = okey; 00912 00913 key = skey % dict->subdict->size; 00914 if (dict->subdict->dict[key].valid != 0) { 00915 xmlDictEntryPtr tmp; 00916 00917 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; 00918 tmp = tmp->next) { 00919 #ifdef __GNUC__ 00920 if ((tmp->okey == skey) && (tmp->len == len)) { 00921 if (!memcmp(tmp->name, name, len)) 00922 return(tmp->name); 00923 } 00924 #else 00925 if ((tmp->okey == skey) && (tmp->len == len) && 00926 (!xmlStrncmp(tmp->name, name, len))) 00927 return(tmp->name); 00928 #endif 00929 nbi++; 00930 } 00931 #ifdef __GNUC__ 00932 if ((tmp->okey == skey) && (tmp->len == len)) { 00933 if (!memcmp(tmp->name, name, len)) 00934 return(tmp->name); 00935 } 00936 #else 00937 if ((tmp->okey == skey) && (tmp->len == len) && 00938 (!xmlStrncmp(tmp->name, name, len))) 00939 return(tmp->name); 00940 #endif 00941 } 00942 } 00943 00944 /* not found */ 00945 return(NULL); 00946 } 00947 00958 const xmlChar * 00959 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { 00960 unsigned long okey, key, nbi = 0; 00961 xmlDictEntryPtr entry; 00962 xmlDictEntryPtr insert; 00963 const xmlChar *ret; 00964 int len, plen, l; 00965 00966 if ((dict == NULL) || (name == NULL)) 00967 return(NULL); 00968 if (prefix == NULL) 00969 return(xmlDictLookup(dict, name, -1)); 00970 00971 l = len = strlen((const char *) name); 00972 plen = strlen((const char *) prefix); 00973 len += 1 + plen; 00974 00975 /* 00976 * Check for duplicate and insertion location. 00977 */ 00978 okey = xmlDictComputeQKey(dict, prefix, plen, name, l); 00979 key = okey % dict->size; 00980 if (dict->dict[key].valid == 0) { 00981 insert = NULL; 00982 } else { 00983 for (insert = &(dict->dict[key]); insert->next != NULL; 00984 insert = insert->next) { 00985 if ((insert->okey == okey) && (insert->len == len) && 00986 (xmlStrQEqual(prefix, name, insert->name))) 00987 return(insert->name); 00988 nbi++; 00989 } 00990 if ((insert->okey == okey) && (insert->len == len) && 00991 (xmlStrQEqual(prefix, name, insert->name))) 00992 return(insert->name); 00993 } 00994 00995 if (dict->subdict) { 00996 unsigned long skey; 00997 00998 /* we cannot always reuse the same okey for the subdict */ 00999 if (((dict->size == MIN_DICT_SIZE) && 01000 (dict->subdict->size != MIN_DICT_SIZE)) || 01001 ((dict->size != MIN_DICT_SIZE) && 01002 (dict->subdict->size == MIN_DICT_SIZE))) 01003 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l); 01004 else 01005 skey = okey; 01006 01007 key = skey % dict->subdict->size; 01008 if (dict->subdict->dict[key].valid != 0) { 01009 xmlDictEntryPtr tmp; 01010 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; 01011 tmp = tmp->next) { 01012 if ((tmp->okey == skey) && (tmp->len == len) && 01013 (xmlStrQEqual(prefix, name, tmp->name))) 01014 return(tmp->name); 01015 nbi++; 01016 } 01017 if ((tmp->okey == skey) && (tmp->len == len) && 01018 (xmlStrQEqual(prefix, name, tmp->name))) 01019 return(tmp->name); 01020 } 01021 key = okey % dict->size; 01022 } 01023 01024 ret = xmlDictAddQString(dict, prefix, plen, name, l); 01025 if (ret == NULL) 01026 return(NULL); 01027 if (insert == NULL) { 01028 entry = &(dict->dict[key]); 01029 } else { 01030 entry = xmlMalloc(sizeof(xmlDictEntry)); 01031 if (entry == NULL) 01032 return(NULL); 01033 } 01034 entry->name = ret; 01035 entry->len = len; 01036 entry->next = NULL; 01037 entry->valid = 1; 01038 entry->okey = okey; 01039 01040 if (insert != NULL) 01041 insert->next = entry; 01042 01043 dict->nbElems++; 01044 01045 if ((nbi > MAX_HASH_LEN) && 01046 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) 01047 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); 01048 /* Note that entry may have been freed at this point by xmlDictGrow */ 01049 01050 return(ret); 01051 } 01052 01063 int 01064 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) { 01065 xmlDictStringsPtr pool; 01066 01067 if ((dict == NULL) || (str == NULL)) 01068 return(-1); 01069 pool = dict->strings; 01070 while (pool != NULL) { 01071 if ((str >= &pool->array[0]) && (str <= pool->free)) 01072 return(1); 01073 pool = pool->next; 01074 } 01075 if (dict->subdict) 01076 return(xmlDictOwns(dict->subdict, str)); 01077 return(0); 01078 } 01079 01089 int 01090 xmlDictSize(xmlDictPtr dict) { 01091 if (dict == NULL) 01092 return(-1); 01093 if (dict->subdict) 01094 return(dict->nbElems + dict->subdict->nbElems); 01095 return(dict->nbElems); 01096 } 01097 01098 01099 #define bottom_dict 01100 #include "elfgcchack.h" Generated on Fri May 25 2012 04:21:58 for ReactOS by
1.7.6.1
|