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 |