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 |