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