| 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 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 <string.h> | 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 |
| 23 #include <libxml/tree.h> | 32 #include <libxml/tree.h> |
| 24 #include <libxml/dict.h> | 33 #include <libxml/dict.h> |
| 25 #include <libxml/xmlmemory.h> | 34 #include <libxml/xmlmemory.h> |
| 26 #include <libxml/xmlerror.h> | 35 #include <libxml/xmlerror.h> |
| 27 #include <libxml/globals.h> | 36 #include <libxml/globals.h> |
| 28 | 37 |
| 29 #define MAX_HASH_LEN 4 | 38 /* #define DEBUG_GROW */ |
| 39 /* #define DICT_DEBUG_PATTERNS */ |
| 40 |
| 41 #define MAX_HASH_LEN 3 |
| 30 #define MIN_DICT_SIZE 128 | 42 #define MIN_DICT_SIZE 128 |
| 31 #define MAX_DICT_HASH 8 * 2048 | 43 #define MAX_DICT_HASH 8 * 2048 |
| 44 #define WITH_BIG_KEY |
| 32 | 45 |
| 33 /* #define ALLOW_REMOVAL */ | 46 #ifdef WITH_BIG_KEY |
| 34 /* #define DEBUG_GROW */ | 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 */ |
| 35 | 65 |
| 36 /* | 66 /* |
| 37 * An entry in the dictionnary | 67 * An entry in the dictionnary |
| 38 */ | 68 */ |
| 39 typedef struct _xmlDictEntry xmlDictEntry; | 69 typedef struct _xmlDictEntry xmlDictEntry; |
| 40 typedef xmlDictEntry *xmlDictEntryPtr; | 70 typedef xmlDictEntry *xmlDictEntryPtr; |
| 41 struct _xmlDictEntry { | 71 struct _xmlDictEntry { |
| 42 struct _xmlDictEntry *next; | 72 struct _xmlDictEntry *next; |
| 43 const xmlChar *name; | 73 const xmlChar *name; |
| 44 int len; | 74 int len; |
| 45 int valid; | 75 int valid; |
| 76 unsigned long okey; |
| 46 }; | 77 }; |
| 47 | 78 |
| 48 typedef struct _xmlDictStrings xmlDictStrings; | 79 typedef struct _xmlDictStrings xmlDictStrings; |
| 49 typedef xmlDictStrings *xmlDictStringsPtr; | 80 typedef xmlDictStrings *xmlDictStringsPtr; |
| 50 struct _xmlDictStrings { | 81 struct _xmlDictStrings { |
| 51 xmlDictStringsPtr next; | 82 xmlDictStringsPtr next; |
| 52 xmlChar *free; | 83 xmlChar *free; |
| 53 xmlChar *end; | 84 xmlChar *end; |
| 54 int size; | 85 int size; |
| 55 int nbStrings; | 86 int nbStrings; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 * Add the string to the array[s] | 153 * Add the string to the array[s] |
| 123 * | 154 * |
| 124 * Returns the pointer of the local string, or NULL in case of error. | 155 * Returns the pointer of the local string, or NULL in case of error. |
| 125 */ | 156 */ |
| 126 static const xmlChar * | 157 static const xmlChar * |
| 127 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) { | 158 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) { |
| 128 xmlDictStringsPtr pool; | 159 xmlDictStringsPtr pool; |
| 129 const xmlChar *ret; | 160 const xmlChar *ret; |
| 130 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ | 161 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ |
| 131 | 162 |
| 163 #ifdef DICT_DEBUG_PATTERNS |
| 164 fprintf(stderr, "-"); |
| 165 #endif |
| 132 pool = dict->strings; | 166 pool = dict->strings; |
| 133 while (pool != NULL) { | 167 while (pool != NULL) { |
| 134 if (pool->end - pool->free > namelen) | 168 if (pool->end - pool->free > namelen) |
| 135 goto found_pool; | 169 goto found_pool; |
| 136 if (pool->size > size) size = pool->size; | 170 if (pool->size > size) size = pool->size; |
| 137 pool = pool->next; | 171 pool = pool->next; |
| 138 } | 172 } |
| 139 /* | 173 /* |
| 140 * Not found, need to allocate | 174 * Not found, need to allocate |
| 141 */ | 175 */ |
| 142 if (pool == NULL) { | 176 if (pool == NULL) { |
| 143 if (size == 0) size = 1000; | 177 if (size == 0) size = 1000; |
| 144 else size *= 4; /* exponential growth */ | 178 else size *= 4; /* exponential growth */ |
| 145 if (size < 4 * namelen) | 179 if (size < 4 * namelen) |
| 146 size = 4 * namelen; /* just in case ! */ | 180 size = 4 * namelen; /* just in case ! */ |
| 147 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); | 181 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); |
| 148 if (pool == NULL) | 182 if (pool == NULL) |
| 149 return(NULL); | 183 return(NULL); |
| 150 pool->size = size; | 184 pool->size = size; |
| 151 pool->nbStrings = 0; | 185 pool->nbStrings = 0; |
| 152 pool->free = &pool->array[0]; | 186 pool->free = &pool->array[0]; |
| 153 pool->end = &pool->array[size]; | 187 pool->end = &pool->array[size]; |
| 154 pool->next = dict->strings; | 188 pool->next = dict->strings; |
| 155 dict->strings = pool; | 189 dict->strings = pool; |
| 190 #ifdef DICT_DEBUG_PATTERNS |
| 191 fprintf(stderr, "+"); |
| 192 #endif |
| 156 } | 193 } |
| 157 found_pool: | 194 found_pool: |
| 158 ret = pool->free; | 195 ret = pool->free; |
| 159 memcpy(pool->free, name, namelen); | 196 memcpy(pool->free, name, namelen); |
| 160 pool->free += namelen; | 197 pool->free += namelen; |
| 161 *(pool->free++) = 0; | 198 *(pool->free++) = 0; |
| 199 pool->nbStrings++; |
| 162 return(ret); | 200 return(ret); |
| 163 } | 201 } |
| 164 | 202 |
| 165 /* | 203 /* |
| 166 * xmlDictAddQString: | 204 * xmlDictAddQString: |
| 167 * @dict: the dictionnary | 205 * @dict: the dictionnary |
| 168 * @prefix: the prefix of the userdata | 206 * @prefix: the prefix of the userdata |
| 207 * @plen: the prefix length |
| 169 * @name: the name of the userdata | 208 * @name: the name of the userdata |
| 170 * @len: the length of the name, if -1 it is recomputed | 209 * @len: the length of the name, if -1 it is recomputed |
| 171 * | 210 * |
| 172 * Add the QName to the array[s] | 211 * Add the QName to the array[s] |
| 173 * | 212 * |
| 174 * Returns the pointer of the local string, or NULL in case of error. | 213 * Returns the pointer of the local string, or NULL in case of error. |
| 175 */ | 214 */ |
| 176 static const xmlChar * | 215 static const xmlChar * |
| 177 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, | 216 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen, |
| 178 const xmlChar *name, int namelen) | 217 const xmlChar *name, int namelen) |
| 179 { | 218 { |
| 180 xmlDictStringsPtr pool; | 219 xmlDictStringsPtr pool; |
| 181 const xmlChar *ret; | 220 const xmlChar *ret; |
| 182 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ | 221 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ |
| 183 int plen; | |
| 184 | 222 |
| 185 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen)); | 223 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen)); |
| 186 plen = xmlStrlen(prefix); | |
| 187 | 224 |
| 225 #ifdef DICT_DEBUG_PATTERNS |
| 226 fprintf(stderr, "="); |
| 227 #endif |
| 188 pool = dict->strings; | 228 pool = dict->strings; |
| 189 while (pool != NULL) { | 229 while (pool != NULL) { |
| 190 » if (pool->end - pool->free > namelen) | 230 » if (pool->end - pool->free > namelen + plen + 1) |
| 191 goto found_pool; | 231 goto found_pool; |
| 192 if (pool->size > size) size = pool->size; | 232 if (pool->size > size) size = pool->size; |
| 193 pool = pool->next; | 233 pool = pool->next; |
| 194 } | 234 } |
| 195 /* | 235 /* |
| 196 * Not found, need to allocate | 236 * Not found, need to allocate |
| 197 */ | 237 */ |
| 198 if (pool == NULL) { | 238 if (pool == NULL) { |
| 199 if (size == 0) size = 1000; | 239 if (size == 0) size = 1000; |
| 200 else size *= 4; /* exponential growth */ | 240 else size *= 4; /* exponential growth */ |
| 201 if (size < 4 * namelen) | 241 if (size < 4 * (namelen + plen + 1)) |
| 202 » size = 4 * namelen; /* just in case ! */ | 242 » size = 4 * (namelen + plen + 1); /* just in case ! */ |
| 203 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); | 243 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); |
| 204 if (pool == NULL) | 244 if (pool == NULL) |
| 205 return(NULL); | 245 return(NULL); |
| 206 pool->size = size; | 246 pool->size = size; |
| 207 pool->nbStrings = 0; | 247 pool->nbStrings = 0; |
| 208 pool->free = &pool->array[0]; | 248 pool->free = &pool->array[0]; |
| 209 pool->end = &pool->array[size]; | 249 pool->end = &pool->array[size]; |
| 210 pool->next = dict->strings; | 250 pool->next = dict->strings; |
| 211 dict->strings = pool; | 251 dict->strings = pool; |
| 252 #ifdef DICT_DEBUG_PATTERNS |
| 253 fprintf(stderr, "+"); |
| 254 #endif |
| 212 } | 255 } |
| 213 found_pool: | 256 found_pool: |
| 214 ret = pool->free; | 257 ret = pool->free; |
| 215 memcpy(pool->free, prefix, plen); | 258 memcpy(pool->free, prefix, plen); |
| 216 pool->free += plen; | 259 pool->free += plen; |
| 217 *(pool->free++) = ':'; | 260 *(pool->free++) = ':'; |
| 218 namelen -= plen + 1; | |
| 219 memcpy(pool->free, name, namelen); | 261 memcpy(pool->free, name, namelen); |
| 220 pool->free += namelen; | 262 pool->free += namelen; |
| 221 *(pool->free++) = 0; | 263 *(pool->free++) = 0; |
| 264 pool->nbStrings++; |
| 222 return(ret); | 265 return(ret); |
| 223 } | 266 } |
| 224 | 267 |
| 268 #ifdef WITH_BIG_KEY |
| 225 /* | 269 /* |
| 226 * xmlDictComputeKey: | 270 * xmlDictComputeBigKey: |
| 227 * Calculate the hash key | 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. |
| 228 */ | 310 */ |
| 229 static unsigned long | 311 static unsigned long |
| 230 xmlDictComputeKey(const xmlChar *name, int namelen) { | 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) { |
| 231 unsigned long value = 0L; | 350 unsigned long value = 0L; |
| 232 | 351 |
| 233 if (name == NULL) return(0); | 352 if (name == NULL) return(0); |
| 234 value = *name; | 353 value = *name; |
| 235 value <<= 5; | 354 value <<= 5; |
| 236 if (namelen > 10) { | 355 if (namelen > 10) { |
| 237 value += name[namelen - 1]; | 356 value += name[namelen - 1]; |
| 238 namelen = 10; | 357 namelen = 10; |
| 239 } | 358 } |
| 240 switch (namelen) { | 359 switch (namelen) { |
| 241 case 10: value += name[9]; | 360 case 10: value += name[9]; |
| 242 case 9: value += name[8]; | 361 case 9: value += name[8]; |
| 243 case 8: value += name[7]; | 362 case 8: value += name[7]; |
| 244 case 7: value += name[6]; | 363 case 7: value += name[6]; |
| 245 case 6: value += name[5]; | 364 case 6: value += name[5]; |
| 246 case 5: value += name[4]; | 365 case 5: value += name[4]; |
| 247 case 4: value += name[3]; | 366 case 4: value += name[3]; |
| 248 case 3: value += name[2]; | 367 case 3: value += name[2]; |
| 249 case 2: value += name[1]; | 368 case 2: value += name[1]; |
| 250 default: break; | 369 default: break; |
| 251 } | 370 } |
| 252 return(value); | 371 return(value); |
| 253 } | 372 } |
| 254 | 373 |
| 255 /* | 374 /* |
| 256 * xmlDictComputeQKey: | 375 * xmlDictComputeFastQKey: |
| 257 * Calculate the hash key | 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. |
| 258 */ | 381 */ |
| 259 static unsigned long | 382 static unsigned long |
| 260 xmlDictComputeQKey(const xmlChar *prefix, const xmlChar *name, int len) | 383 xmlDictComputeFastQKey(const xmlChar *prefix, int plen, |
| 384 const xmlChar *name, int len) |
| 261 { | 385 { |
| 262 unsigned long value = 0L; | 386 unsigned long value = 0L; |
| 263 int plen; | |
| 264 | |
| 265 if (prefix == NULL) | |
| 266 return(xmlDictComputeKey(name, len)); | |
| 267 | 387 |
| 268 plen = xmlStrlen(prefix); | |
| 269 if (plen == 0) | 388 if (plen == 0) |
| 270 value += 30 * (unsigned long) ':'; | 389 value += 30 * (unsigned long) ':'; |
| 271 else | 390 else |
| 272 value += 30 * (*prefix); | 391 value += 30 * (*prefix); |
| 273 | 392 |
| 274 if (len > 10) { | 393 if (len > 10) { |
| 275 value += name[len - (plen + 1 + 1)]; | 394 value += name[len - (plen + 1 + 1)]; |
| 276 len = 10; | 395 len = 10; |
| 277 if (plen > 10) | 396 if (plen > 10) |
| 278 plen = 10; | 397 plen = 10; |
| 279 } | 398 } |
| 280 switch (plen) { | 399 switch (plen) { |
| 281 case 10: value += prefix[9]; | 400 case 10: value += prefix[9]; |
| 282 case 9: value += prefix[8]; | 401 case 9: value += prefix[8]; |
| 283 case 8: value += prefix[7]; | 402 case 8: value += prefix[7]; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 * | 437 * |
| 319 * Returns the newly created dictionnary, or NULL if an error occured. | 438 * Returns the newly created dictionnary, or NULL if an error occured. |
| 320 */ | 439 */ |
| 321 xmlDictPtr | 440 xmlDictPtr |
| 322 xmlDictCreate(void) { | 441 xmlDictCreate(void) { |
| 323 xmlDictPtr dict; | 442 xmlDictPtr dict; |
| 324 | 443 |
| 325 if (!xmlDictInitialized) | 444 if (!xmlDictInitialized) |
| 326 if (!xmlInitializeDict()) | 445 if (!xmlInitializeDict()) |
| 327 return(NULL); | 446 return(NULL); |
| 328 | 447 |
| 448 #ifdef DICT_DEBUG_PATTERNS |
| 449 fprintf(stderr, "C"); |
| 450 #endif |
| 451 |
| 329 dict = xmlMalloc(sizeof(xmlDict)); | 452 dict = xmlMalloc(sizeof(xmlDict)); |
| 330 if (dict) { | 453 if (dict) { |
| 331 dict->ref_counter = 1; | 454 dict->ref_counter = 1; |
| 332 | 455 |
| 333 dict->size = MIN_DICT_SIZE; | 456 dict->size = MIN_DICT_SIZE; |
| 334 dict->nbElems = 0; | 457 dict->nbElems = 0; |
| 335 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry)); | 458 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry)); |
| 336 dict->strings = NULL; | 459 dict->strings = NULL; |
| 337 dict->subdict = NULL; | 460 dict->subdict = NULL; |
| 338 if (dict->dict) { | 461 if (dict->dict) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 351 * Create a new dictionary, inheriting strings from the read-only | 474 * Create a new dictionary, inheriting strings from the read-only |
| 352 * dictionnary @sub. On lookup, strings are first searched in the | 475 * dictionnary @sub. On lookup, strings are first searched in the |
| 353 * new dictionnary, then in @sub, and if not found are created in the | 476 * new dictionnary, then in @sub, and if not found are created in the |
| 354 * new dictionnary. | 477 * new dictionnary. |
| 355 * | 478 * |
| 356 * Returns the newly created dictionnary, or NULL if an error occured. | 479 * Returns the newly created dictionnary, or NULL if an error occured. |
| 357 */ | 480 */ |
| 358 xmlDictPtr | 481 xmlDictPtr |
| 359 xmlDictCreateSub(xmlDictPtr sub) { | 482 xmlDictCreateSub(xmlDictPtr sub) { |
| 360 xmlDictPtr dict = xmlDictCreate(); | 483 xmlDictPtr dict = xmlDictCreate(); |
| 361 | 484 |
| 362 if ((dict != NULL) && (sub != NULL)) { | 485 if ((dict != NULL) && (sub != NULL)) { |
| 486 #ifdef DICT_DEBUG_PATTERNS |
| 487 fprintf(stderr, "R"); |
| 488 #endif |
| 363 dict->subdict = sub; | 489 dict->subdict = sub; |
| 364 xmlDictReference(dict->subdict); | 490 xmlDictReference(dict->subdict); |
| 365 } | 491 } |
| 366 return(dict); | 492 return(dict); |
| 367 } | 493 } |
| 368 | 494 |
| 369 /** | 495 /** |
| 370 * xmlDictReference: | 496 * xmlDictReference: |
| 371 * @dict: the dictionnary | 497 * @dict: the dictionnary |
| 372 * | 498 * |
| (...skipping 18 matching lines...) Expand all Loading... |
| 391 * xmlDictGrow: | 517 * xmlDictGrow: |
| 392 * @dict: the dictionnary | 518 * @dict: the dictionnary |
| 393 * @size: the new size of the dictionnary | 519 * @size: the new size of the dictionnary |
| 394 * | 520 * |
| 395 * resize the dictionnary | 521 * resize the dictionnary |
| 396 * | 522 * |
| 397 * Returns 0 in case of success, -1 in case of failure | 523 * Returns 0 in case of success, -1 in case of failure |
| 398 */ | 524 */ |
| 399 static int | 525 static int |
| 400 xmlDictGrow(xmlDictPtr dict, int size) { | 526 xmlDictGrow(xmlDictPtr dict, int size) { |
| 401 unsigned long key; | 527 unsigned long key, okey; |
| 402 int oldsize, i; | 528 int oldsize, i; |
| 403 xmlDictEntryPtr iter, next; | 529 xmlDictEntryPtr iter, next; |
| 404 struct _xmlDictEntry *olddict; | 530 struct _xmlDictEntry *olddict; |
| 405 #ifdef DEBUG_GROW | 531 #ifdef DEBUG_GROW |
| 406 unsigned long nbElem = 0; | 532 unsigned long nbElem = 0; |
| 407 #endif | 533 #endif |
| 408 | 534 int ret = 0; |
| 535 int keep_keys = 1; |
| 536 |
| 409 if (dict == NULL) | 537 if (dict == NULL) |
| 410 return(-1); | 538 return(-1); |
| 411 if (size < 8) | 539 if (size < 8) |
| 412 return(-1); | 540 return(-1); |
| 413 if (size > 8 * 2048) | 541 if (size > 8 * 2048) |
| 414 return(-1); | 542 return(-1); |
| 415 | 543 |
| 544 #ifdef DICT_DEBUG_PATTERNS |
| 545 fprintf(stderr, "*"); |
| 546 #endif |
| 547 |
| 416 oldsize = dict->size; | 548 oldsize = dict->size; |
| 417 olddict = dict->dict; | 549 olddict = dict->dict; |
| 418 if (olddict == NULL) | 550 if (olddict == NULL) |
| 419 return(-1); | 551 return(-1); |
| 420 | 552 if (oldsize == MIN_DICT_SIZE) |
| 553 keep_keys = 0; |
| 554 |
| 421 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry)); | 555 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry)); |
| 422 if (dict->dict == NULL) { | 556 if (dict->dict == NULL) { |
| 423 dict->dict = olddict; | 557 dict->dict = olddict; |
| 424 return(-1); | 558 return(-1); |
| 425 } | 559 } |
| 426 memset(dict->dict, 0, size * sizeof(xmlDictEntry)); | 560 memset(dict->dict, 0, size * sizeof(xmlDictEntry)); |
| 427 dict->size = size; | 561 dict->size = size; |
| 428 | 562 |
| 429 /* If the two loops are merged, there would be situations where | 563 /* If the two loops are merged, there would be situations where |
| 430 » a new entry needs to allocated and data copied into it from | 564 » a new entry needs to allocated and data copied into it from |
| 431 » the main dict. So instead, we run through the array twice, first | 565 » the main dict. It is nicer to run through the array twice, first |
| 432 » copying all the elements in the main array (where we can't get | 566 » copying all the elements in the main array (less probability of |
| 433 » conflicts) and then the rest, so we only free (and don't allocate) | 567 » allocate) and then the rest, so we only free in the second loop. |
| 434 */ | 568 */ |
| 435 for (i = 0; i < oldsize; i++) { | 569 for (i = 0; i < oldsize; i++) { |
| 436 » if (olddict[i].valid == 0) | 570 » if (olddict[i].valid == 0) |
| 437 continue; | 571 continue; |
| 438 » key = xmlDictComputeKey(olddict[i].name, olddict[i].len) % dict->size; | 572 |
| 439 » memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry)); | 573 » if (keep_keys) |
| 440 » dict->dict[key].next = NULL; | 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 » } |
| 441 #ifdef DEBUG_GROW | 602 #ifdef DEBUG_GROW |
| 442 nbElem++; | 603 nbElem++; |
| 443 #endif | 604 #endif |
| 444 } | 605 } |
| 445 | 606 |
| 446 for (i = 0; i < oldsize; i++) { | 607 for (i = 0; i < oldsize; i++) { |
| 447 iter = olddict[i].next; | 608 iter = olddict[i].next; |
| 448 while (iter) { | 609 while (iter) { |
| 449 next = iter->next; | 610 next = iter->next; |
| 450 | 611 |
| 451 /* | 612 /* |
| 452 * put back the entry in the new dict | 613 * put back the entry in the new dict |
| 453 */ | 614 */ |
| 454 | 615 |
| 455 » key = xmlDictComputeKey(iter->name, iter->len) % dict->size; | 616 » if (keep_keys) |
| 617 » » okey = iter->okey; |
| 618 » else |
| 619 » » okey = xmlDictComputeKey(dict, iter->name, iter->len); |
| 620 » key = okey % dict->size; |
| 456 if (dict->dict[key].valid == 0) { | 621 if (dict->dict[key].valid == 0) { |
| 457 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry)); | 622 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry)); |
| 458 dict->dict[key].next = NULL; | 623 dict->dict[key].next = NULL; |
| 459 dict->dict[key].valid = 1; | 624 dict->dict[key].valid = 1; |
| 625 dict->dict[key].okey = okey; |
| 460 xmlFree(iter); | 626 xmlFree(iter); |
| 461 } else { | 627 } else { |
| 462 » » iter->next = dict->dict[key].next; | 628 » » iter->next = dict->dict[key].next; |
| 463 » » dict->dict[key].next = iter; | 629 » » iter->okey = okey; |
| 630 » » dict->dict[key].next = iter; |
| 464 } | 631 } |
| 465 | 632 |
| 466 #ifdef DEBUG_GROW | 633 #ifdef DEBUG_GROW |
| 467 nbElem++; | 634 nbElem++; |
| 468 #endif | 635 #endif |
| 469 | 636 |
| 470 iter = next; | 637 iter = next; |
| 471 } | 638 } |
| 472 } | 639 } |
| 473 | 640 |
| 474 xmlFree(olddict); | 641 xmlFree(olddict); |
| 475 | 642 |
| 476 #ifdef DEBUG_GROW | 643 #ifdef DEBUG_GROW |
| 477 xmlGenericError(xmlGenericErrorContext, | 644 xmlGenericError(xmlGenericErrorContext, |
| 478 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); | 645 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); |
| 479 #endif | 646 #endif |
| 480 | 647 |
| 481 return(0); | 648 return(ret); |
| 482 } | 649 } |
| 483 | 650 |
| 484 /** | 651 /** |
| 485 * xmlDictFree: | 652 * xmlDictFree: |
| 486 * @dict: the dictionnary | 653 * @dict: the dictionnary |
| 487 * | 654 * |
| 488 * Free the hash @dict and its contents. The userdata is | 655 * Free the hash @dict and its contents. The userdata is |
| 489 * deallocated with @f if provided. | 656 * deallocated with @f if provided. |
| 490 */ | 657 */ |
| 491 void | 658 void |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 continue; | 691 continue; |
| 525 inside_dict = 1; | 692 inside_dict = 1; |
| 526 while (iter) { | 693 while (iter) { |
| 527 next = iter->next; | 694 next = iter->next; |
| 528 if (!inside_dict) | 695 if (!inside_dict) |
| 529 xmlFree(iter); | 696 xmlFree(iter); |
| 530 dict->nbElems--; | 697 dict->nbElems--; |
| 531 inside_dict = 0; | 698 inside_dict = 0; |
| 532 iter = next; | 699 iter = next; |
| 533 } | 700 } |
| 534 inside_dict = 0; | |
| 535 } | 701 } |
| 536 xmlFree(dict->dict); | 702 xmlFree(dict->dict); |
| 537 } | 703 } |
| 538 pool = dict->strings; | 704 pool = dict->strings; |
| 539 while (pool != NULL) { | 705 while (pool != NULL) { |
| 540 nextp = pool->next; | 706 nextp = pool->next; |
| 541 xmlFree(pool); | 707 xmlFree(pool); |
| 542 pool = nextp; | 708 pool = nextp; |
| 543 } | 709 } |
| 544 xmlFree(dict); | 710 xmlFree(dict); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 558 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { | 724 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { |
| 559 unsigned long key, okey, nbi = 0; | 725 unsigned long key, okey, nbi = 0; |
| 560 xmlDictEntryPtr entry; | 726 xmlDictEntryPtr entry; |
| 561 xmlDictEntryPtr insert; | 727 xmlDictEntryPtr insert; |
| 562 const xmlChar *ret; | 728 const xmlChar *ret; |
| 563 | 729 |
| 564 if ((dict == NULL) || (name == NULL)) | 730 if ((dict == NULL) || (name == NULL)) |
| 565 return(NULL); | 731 return(NULL); |
| 566 | 732 |
| 567 if (len < 0) | 733 if (len < 0) |
| 568 len = xmlStrlen(name); | 734 len = strlen((const char *) name); |
| 569 | 735 |
| 570 /* | 736 /* |
| 571 * Check for duplicate and insertion location. | 737 * Check for duplicate and insertion location. |
| 572 */ | 738 */ |
| 573 okey = xmlDictComputeKey(name, len); | 739 okey = xmlDictComputeKey(dict, name, len); |
| 574 key = okey % dict->size; | 740 key = okey % dict->size; |
| 575 if (dict->dict[key].valid == 0) { | 741 if (dict->dict[key].valid == 0) { |
| 576 insert = NULL; | 742 insert = NULL; |
| 577 } else { | 743 } else { |
| 578 for (insert = &(dict->dict[key]); insert->next != NULL; | 744 for (insert = &(dict->dict[key]); insert->next != NULL; |
| 579 insert = insert->next) { | 745 insert = insert->next) { |
| 580 #ifdef __GNUC__ | 746 #ifdef __GNUC__ |
| 581 » if (insert->len == len) { | 747 » if ((insert->okey == okey) && (insert->len == len)) { |
| 582 if (!memcmp(insert->name, name, len)) | 748 if (!memcmp(insert->name, name, len)) |
| 583 return(insert->name); | 749 return(insert->name); |
| 584 } | 750 } |
| 585 #else | 751 #else |
| 586 » if ((insert->len == len) && | 752 » if ((insert->okey == okey) && (insert->len == len) && |
| 587 (!xmlStrncmp(insert->name, name, len))) | 753 (!xmlStrncmp(insert->name, name, len))) |
| 588 return(insert->name); | 754 return(insert->name); |
| 589 #endif | 755 #endif |
| 590 nbi++; | 756 nbi++; |
| 591 } | 757 } |
| 592 #ifdef __GNUC__ | 758 #ifdef __GNUC__ |
| 593 » if (insert->len == len) { | 759 » if ((insert->okey == okey) && (insert->len == len)) { |
| 594 if (!memcmp(insert->name, name, len)) | 760 if (!memcmp(insert->name, name, len)) |
| 595 return(insert->name); | 761 return(insert->name); |
| 596 } | 762 } |
| 597 #else | 763 #else |
| 598 » if ((insert->len == len) && | 764 » if ((insert->okey == okey) && (insert->len == len) && |
| 599 (!xmlStrncmp(insert->name, name, len))) | 765 (!xmlStrncmp(insert->name, name, len))) |
| 600 return(insert->name); | 766 return(insert->name); |
| 601 #endif | 767 #endif |
| 602 } | 768 } |
| 603 | 769 |
| 604 if (dict->subdict) { | 770 if (dict->subdict) { |
| 605 » key = okey % dict->subdict->size; | 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; |
| 606 if (dict->subdict->dict[key].valid != 0) { | 783 if (dict->subdict->dict[key].valid != 0) { |
| 607 xmlDictEntryPtr tmp; | 784 xmlDictEntryPtr tmp; |
| 608 | 785 |
| 609 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; | 786 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; |
| 610 tmp = tmp->next) { | 787 tmp = tmp->next) { |
| 611 #ifdef __GNUC__ | 788 #ifdef __GNUC__ |
| 612 » » if (tmp->len == len) { | 789 » » if ((tmp->okey == skey) && (tmp->len == len)) { |
| 613 if (!memcmp(tmp->name, name, len)) | 790 if (!memcmp(tmp->name, name, len)) |
| 614 return(tmp->name); | 791 return(tmp->name); |
| 615 } | 792 } |
| 616 #else | 793 #else |
| 617 » » if ((tmp->len == len) && | 794 » » if ((tmp->okey == skey) && (tmp->len == len) && |
| 618 (!xmlStrncmp(tmp->name, name, len))) | 795 (!xmlStrncmp(tmp->name, name, len))) |
| 619 return(tmp->name); | 796 return(tmp->name); |
| 620 #endif | 797 #endif |
| 621 nbi++; | 798 nbi++; |
| 622 } | 799 } |
| 623 #ifdef __GNUC__ | 800 #ifdef __GNUC__ |
| 624 » if (tmp->len == len) { | 801 » if ((tmp->okey == skey) && (tmp->len == len)) { |
| 625 if (!memcmp(tmp->name, name, len)) | 802 if (!memcmp(tmp->name, name, len)) |
| 626 return(tmp->name); | 803 return(tmp->name); |
| 627 } | 804 } |
| 628 #else | 805 #else |
| 629 » if ((tmp->len == len) && | 806 » if ((tmp->okey == skey) && (tmp->len == len) && |
| 630 (!xmlStrncmp(tmp->name, name, len))) | 807 (!xmlStrncmp(tmp->name, name, len))) |
| 631 return(tmp->name); | 808 return(tmp->name); |
| 632 #endif | 809 #endif |
| 633 } | 810 } |
| 634 key = okey % dict->size; | 811 key = okey % dict->size; |
| 635 } | 812 } |
| 636 | 813 |
| 637 ret = xmlDictAddString(dict, name, len); | 814 ret = xmlDictAddString(dict, name, len); |
| 638 if (ret == NULL) | 815 if (ret == NULL) |
| 639 return(NULL); | 816 return(NULL); |
| 640 if (insert == NULL) { | 817 if (insert == NULL) { |
| 641 entry = &(dict->dict[key]); | 818 entry = &(dict->dict[key]); |
| 642 } else { | 819 } else { |
| 643 entry = xmlMalloc(sizeof(xmlDictEntry)); | 820 entry = xmlMalloc(sizeof(xmlDictEntry)); |
| 644 if (entry == NULL) | 821 if (entry == NULL) |
| 645 return(NULL); | 822 return(NULL); |
| 646 } | 823 } |
| 647 entry->name = ret; | 824 entry->name = ret; |
| 648 entry->len = len; | 825 entry->len = len; |
| 649 entry->next = NULL; | 826 entry->next = NULL; |
| 650 entry->valid = 1; | 827 entry->valid = 1; |
| 828 entry->okey = okey; |
| 651 | 829 |
| 652 | 830 |
| 653 if (insert != NULL) | 831 if (insert != NULL) |
| 654 insert->next = entry; | 832 insert->next = entry; |
| 655 | 833 |
| 656 dict->nbElems++; | 834 dict->nbElems++; |
| 657 | 835 |
| 658 if ((nbi > MAX_HASH_LEN) && | 836 if ((nbi > MAX_HASH_LEN) && |
| 659 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) | 837 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) { |
| 660 » xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); | 838 » if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0) |
| 839 » return(NULL); |
| 840 } |
| 661 /* Note that entry may have been freed at this point by xmlDictGrow */ | 841 /* Note that entry may have been freed at this point by xmlDictGrow */ |
| 662 | 842 |
| 663 return(ret); | 843 return(ret); |
| 664 } | 844 } |
| 665 | 845 |
| 666 /** | 846 /** |
| 667 * xmlDictExists: | 847 * xmlDictExists: |
| 668 * @dict: the dictionnary | 848 * @dict: the dictionnary |
| 669 * @name: the name of the userdata | 849 * @name: the name of the userdata |
| 670 * @len: the length of the name, if -1 it is recomputed | 850 * @len: the length of the name, if -1 it is recomputed |
| 671 * | 851 * |
| 672 * Check if the @name exists in the dictionnary @dict. | 852 * Check if the @name exists in the dictionnary @dict. |
| 673 * | 853 * |
| 674 * Returns the internal copy of the name or NULL if not found. | 854 * Returns the internal copy of the name or NULL if not found. |
| 675 */ | 855 */ |
| 676 const xmlChar * | 856 const xmlChar * |
| 677 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) { | 857 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) { |
| 678 unsigned long key, okey, nbi = 0; | 858 unsigned long key, okey, nbi = 0; |
| 679 xmlDictEntryPtr insert; | 859 xmlDictEntryPtr insert; |
| 680 | 860 |
| 681 if ((dict == NULL) || (name == NULL)) | 861 if ((dict == NULL) || (name == NULL)) |
| 682 return(NULL); | 862 return(NULL); |
| 683 | 863 |
| 684 if (len < 0) | 864 if (len < 0) |
| 685 len = xmlStrlen(name); | 865 len = strlen((const char *) name); |
| 686 | 866 |
| 687 /* | 867 /* |
| 688 * Check for duplicate and insertion location. | 868 * Check for duplicate and insertion location. |
| 689 */ | 869 */ |
| 690 okey = xmlDictComputeKey(name, len); | 870 okey = xmlDictComputeKey(dict, name, len); |
| 691 key = okey % dict->size; | 871 key = okey % dict->size; |
| 692 if (dict->dict[key].valid == 0) { | 872 if (dict->dict[key].valid == 0) { |
| 693 insert = NULL; | 873 insert = NULL; |
| 694 } else { | 874 } else { |
| 695 for (insert = &(dict->dict[key]); insert->next != NULL; | 875 for (insert = &(dict->dict[key]); insert->next != NULL; |
| 696 insert = insert->next) { | 876 insert = insert->next) { |
| 697 #ifdef __GNUC__ | 877 #ifdef __GNUC__ |
| 698 » if (insert->len == len) { | 878 » if ((insert->okey == okey) && (insert->len == len)) { |
| 699 if (!memcmp(insert->name, name, len)) | 879 if (!memcmp(insert->name, name, len)) |
| 700 return(insert->name); | 880 return(insert->name); |
| 701 } | 881 } |
| 702 #else | 882 #else |
| 703 » if ((insert->len == len) && | 883 » if ((insert->okey == okey) && (insert->len == len) && |
| 704 (!xmlStrncmp(insert->name, name, len))) | 884 (!xmlStrncmp(insert->name, name, len))) |
| 705 return(insert->name); | 885 return(insert->name); |
| 706 #endif | 886 #endif |
| 707 nbi++; | 887 nbi++; |
| 708 } | 888 } |
| 709 #ifdef __GNUC__ | 889 #ifdef __GNUC__ |
| 710 » if (insert->len == len) { | 890 » if ((insert->okey == okey) && (insert->len == len)) { |
| 711 if (!memcmp(insert->name, name, len)) | 891 if (!memcmp(insert->name, name, len)) |
| 712 return(insert->name); | 892 return(insert->name); |
| 713 } | 893 } |
| 714 #else | 894 #else |
| 715 » if ((insert->len == len) && | 895 » if ((insert->okey == okey) && (insert->len == len) && |
| 716 (!xmlStrncmp(insert->name, name, len))) | 896 (!xmlStrncmp(insert->name, name, len))) |
| 717 return(insert->name); | 897 return(insert->name); |
| 718 #endif | 898 #endif |
| 719 } | 899 } |
| 720 | 900 |
| 721 if (dict->subdict) { | 901 if (dict->subdict) { |
| 722 » key = okey % dict->subdict->size; | 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; |
| 723 if (dict->subdict->dict[key].valid != 0) { | 914 if (dict->subdict->dict[key].valid != 0) { |
| 724 xmlDictEntryPtr tmp; | 915 xmlDictEntryPtr tmp; |
| 725 | 916 |
| 726 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; | 917 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; |
| 727 tmp = tmp->next) { | 918 tmp = tmp->next) { |
| 728 #ifdef __GNUC__ | 919 #ifdef __GNUC__ |
| 729 » » if (tmp->len == len) { | 920 » » if ((tmp->okey == skey) && (tmp->len == len)) { |
| 730 if (!memcmp(tmp->name, name, len)) | 921 if (!memcmp(tmp->name, name, len)) |
| 731 return(tmp->name); | 922 return(tmp->name); |
| 732 } | 923 } |
| 733 #else | 924 #else |
| 734 » » if ((tmp->len == len) && | 925 » » if ((tmp->okey == skey) && (tmp->len == len) && |
| 735 (!xmlStrncmp(tmp->name, name, len))) | 926 (!xmlStrncmp(tmp->name, name, len))) |
| 736 return(tmp->name); | 927 return(tmp->name); |
| 737 #endif | 928 #endif |
| 738 nbi++; | 929 nbi++; |
| 739 } | 930 } |
| 740 #ifdef __GNUC__ | 931 #ifdef __GNUC__ |
| 741 » if (tmp->len == len) { | 932 » if ((tmp->okey == skey) && (tmp->len == len)) { |
| 742 if (!memcmp(tmp->name, name, len)) | 933 if (!memcmp(tmp->name, name, len)) |
| 743 return(tmp->name); | 934 return(tmp->name); |
| 744 } | 935 } |
| 745 #else | 936 #else |
| 746 » if ((tmp->len == len) && | 937 » if ((tmp->okey == skey) && (tmp->len == len) && |
| 747 (!xmlStrncmp(tmp->name, name, len))) | 938 (!xmlStrncmp(tmp->name, name, len))) |
| 748 return(tmp->name); | 939 return(tmp->name); |
| 749 #endif | 940 #endif |
| 750 } | 941 } |
| 751 key = okey % dict->size; | |
| 752 } | 942 } |
| 753 | 943 |
| 754 /* not found */ | 944 /* not found */ |
| 755 return(NULL); | 945 return(NULL); |
| 756 } | 946 } |
| 757 | 947 |
| 758 /** | 948 /** |
| 759 * xmlDictQLookup: | 949 * xmlDictQLookup: |
| 760 * @dict: the dictionnary | 950 * @dict: the dictionnary |
| 761 * @prefix: the prefix | 951 * @prefix: the prefix |
| 762 * @name: the name | 952 * @name: the name |
| 763 * | 953 * |
| 764 * Add the QName @prefix:@name to the hash @dict if not present. | 954 * Add the QName @prefix:@name to the hash @dict if not present. |
| 765 * | 955 * |
| 766 * Returns the internal copy of the QName or NULL in case of internal error | 956 * Returns the internal copy of the QName or NULL in case of internal error |
| 767 */ | 957 */ |
| 768 const xmlChar * | 958 const xmlChar * |
| 769 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { | 959 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { |
| 770 unsigned long okey, key, nbi = 0; | 960 unsigned long okey, key, nbi = 0; |
| 771 xmlDictEntryPtr entry; | 961 xmlDictEntryPtr entry; |
| 772 xmlDictEntryPtr insert; | 962 xmlDictEntryPtr insert; |
| 773 const xmlChar *ret; | 963 const xmlChar *ret; |
| 774 int len; | 964 int len, plen, l; |
| 775 | 965 |
| 776 if ((dict == NULL) || (name == NULL)) | 966 if ((dict == NULL) || (name == NULL)) |
| 777 return(NULL); | 967 return(NULL); |
| 968 if (prefix == NULL) |
| 969 return(xmlDictLookup(dict, name, -1)); |
| 778 | 970 |
| 779 len = xmlStrlen(name); | 971 l = len = strlen((const char *) name); |
| 780 if (prefix != NULL) | 972 plen = strlen((const char *) prefix); |
| 781 len += 1 + xmlStrlen(prefix); | 973 len += 1 + plen; |
| 782 | 974 |
| 783 /* | 975 /* |
| 784 * Check for duplicate and insertion location. | 976 * Check for duplicate and insertion location. |
| 785 */ | 977 */ |
| 786 okey = xmlDictComputeQKey(prefix, name, len); | 978 okey = xmlDictComputeQKey(dict, prefix, plen, name, l); |
| 787 key = okey % dict->size; | 979 key = okey % dict->size; |
| 788 if (dict->dict[key].valid == 0) { | 980 if (dict->dict[key].valid == 0) { |
| 789 insert = NULL; | 981 insert = NULL; |
| 790 } else { | 982 } else { |
| 791 for (insert = &(dict->dict[key]); insert->next != NULL; | 983 for (insert = &(dict->dict[key]); insert->next != NULL; |
| 792 insert = insert->next) { | 984 insert = insert->next) { |
| 793 » if ((insert->len == len) && | 985 » if ((insert->okey == okey) && (insert->len == len) && |
| 794 (xmlStrQEqual(prefix, name, insert->name))) | 986 (xmlStrQEqual(prefix, name, insert->name))) |
| 795 return(insert->name); | 987 return(insert->name); |
| 796 nbi++; | 988 nbi++; |
| 797 } | 989 } |
| 798 » if ((insert->len == len) && | 990 » if ((insert->okey == okey) && (insert->len == len) && |
| 799 (xmlStrQEqual(prefix, name, insert->name))) | 991 (xmlStrQEqual(prefix, name, insert->name))) |
| 800 return(insert->name); | 992 return(insert->name); |
| 801 } | 993 } |
| 802 | 994 |
| 803 if (dict->subdict) { | 995 if (dict->subdict) { |
| 804 » key = okey % dict->subdict->size; | 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; |
| 805 if (dict->subdict->dict[key].valid != 0) { | 1008 if (dict->subdict->dict[key].valid != 0) { |
| 806 xmlDictEntryPtr tmp; | 1009 xmlDictEntryPtr tmp; |
| 807 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; | 1010 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; |
| 808 tmp = tmp->next) { | 1011 tmp = tmp->next) { |
| 809 » » if ((tmp->len == len) && | 1012 » » if ((tmp->okey == skey) && (tmp->len == len) && |
| 810 (xmlStrQEqual(prefix, name, tmp->name))) | 1013 (xmlStrQEqual(prefix, name, tmp->name))) |
| 811 return(tmp->name); | 1014 return(tmp->name); |
| 812 nbi++; | 1015 nbi++; |
| 813 } | 1016 } |
| 814 » if ((tmp->len == len) && | 1017 » if ((tmp->okey == skey) && (tmp->len == len) && |
| 815 (xmlStrQEqual(prefix, name, tmp->name))) | 1018 (xmlStrQEqual(prefix, name, tmp->name))) |
| 816 return(tmp->name); | 1019 return(tmp->name); |
| 817 } | 1020 } |
| 818 key = okey % dict->size; | 1021 key = okey % dict->size; |
| 819 } | 1022 } |
| 820 | 1023 |
| 821 ret = xmlDictAddQString(dict, prefix, name, len); | 1024 ret = xmlDictAddQString(dict, prefix, plen, name, l); |
| 822 if (ret == NULL) | 1025 if (ret == NULL) |
| 823 return(NULL); | 1026 return(NULL); |
| 824 if (insert == NULL) { | 1027 if (insert == NULL) { |
| 825 entry = &(dict->dict[key]); | 1028 entry = &(dict->dict[key]); |
| 826 } else { | 1029 } else { |
| 827 entry = xmlMalloc(sizeof(xmlDictEntry)); | 1030 entry = xmlMalloc(sizeof(xmlDictEntry)); |
| 828 if (entry == NULL) | 1031 if (entry == NULL) |
| 829 return(NULL); | 1032 return(NULL); |
| 830 } | 1033 } |
| 831 entry->name = ret; | 1034 entry->name = ret; |
| 832 entry->len = len; | 1035 entry->len = len; |
| 833 entry->next = NULL; | 1036 entry->next = NULL; |
| 834 entry->valid = 1; | 1037 entry->valid = 1; |
| 1038 entry->okey = okey; |
| 835 | 1039 |
| 836 if (insert != NULL) | 1040 if (insert != NULL) |
| 837 insert->next = entry; | 1041 insert->next = entry; |
| 838 | 1042 |
| 839 dict->nbElems++; | 1043 dict->nbElems++; |
| 840 | 1044 |
| 841 if ((nbi > MAX_HASH_LEN) && | 1045 if ((nbi > MAX_HASH_LEN) && |
| 842 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) | 1046 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) |
| 843 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); | 1047 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); |
| 844 /* Note that entry may have been freed at this point by xmlDictGrow */ | 1048 /* Note that entry may have been freed at this point by xmlDictGrow */ |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 if (dict == NULL) | 1091 if (dict == NULL) |
| 888 return(-1); | 1092 return(-1); |
| 889 if (dict->subdict) | 1093 if (dict->subdict) |
| 890 return(dict->nbElems + dict->subdict->nbElems); | 1094 return(dict->nbElems + dict->subdict->nbElems); |
| 891 return(dict->nbElems); | 1095 return(dict->nbElems); |
| 892 } | 1096 } |
| 893 | 1097 |
| 894 | 1098 |
| 895 #define bottom_dict | 1099 #define bottom_dict |
| 896 #include "elfgcchack.h" | 1100 #include "elfgcchack.h" |
| OLD | NEW |