blob: 164c7f287640c9caecf63c2ef407196fb0627480 [file] [log] [blame]
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001/*
2 * dict.c: dictionary of reusable strings, just used to avoid allocation
3 * and freeing operations.
4 *
Daniel Veillard8973d582012-02-04 19:07:44 +08005 * Copyright (C) 2003-2012 Daniel Veillard.
Daniel Veillard2fdbd322003-08-18 12:15:38 +00006 *
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
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 * Author: daniel@veillard.com
17 */
18
19#define IN_LIBXML
20#include "libxml.h"
21
Daniel Veillard7c693da2012-07-25 16:32:18 +080022#include <limits.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080023#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
Daniel Veillard2fdbd322003-08-18 12:15:38 +000045#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000046#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000047#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000048#else
49#ifdef HAVE_INTTYPES_H
50#include <inttypes.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000051#elif defined(WIN32)
52typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000053#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000054#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000055#include <libxml/tree.h>
56#include <libxml/dict.h>
57#include <libxml/xmlmemory.h>
58#include <libxml/xmlerror.h>
59#include <libxml/globals.h>
60
Daniel Veillard424785e2008-08-06 09:35:25 +000061/* #define DEBUG_GROW */
62/* #define DICT_DEBUG_PATTERNS */
63
Daniel Veillarde9100a52008-04-22 08:28:50 +000064#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000065#define MIN_DICT_SIZE 128
66#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000067#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000068
Daniel Veillard424785e2008-08-06 09:35:25 +000069#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080070#define xmlDictComputeKey(dict, name, len) \
71 (((dict)->size == MIN_DICT_SIZE) ? \
72 xmlDictComputeFastKey(name, len, (dict)->seed) : \
73 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000074
Daniel Veillard8973d582012-02-04 19:07:44 +080075#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
76 (((prefix) == NULL) ? \
77 (xmlDictComputeKey(dict, name, len)) : \
78 (((dict)->size == MIN_DICT_SIZE) ? \
79 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
80 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000081
Daniel Veillard424785e2008-08-06 09:35:25 +000082#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080083#define xmlDictComputeKey(dict, name, len) \
84 xmlDictComputeFastKey(name, len, (dict)->seed)
85#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
86 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000087#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000088
89/*
90 * An entry in the dictionnary
91 */
92typedef struct _xmlDictEntry xmlDictEntry;
93typedef xmlDictEntry *xmlDictEntryPtr;
94struct _xmlDictEntry {
95 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000096 const xmlChar *name;
Daniel Veillard7c693da2012-07-25 16:32:18 +080097 unsigned int len;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000098 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000099 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000100};
101
Daniel Veillard81514ba2003-09-16 23:17:26 +0000102typedef struct _xmlDictStrings xmlDictStrings;
103typedef xmlDictStrings *xmlDictStringsPtr;
104struct _xmlDictStrings {
105 xmlDictStringsPtr next;
106 xmlChar *free;
107 xmlChar *end;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800108 size_t size;
109 size_t nbStrings;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000110 xmlChar array[1];
111};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000112/*
113 * The entire dictionnary
114 */
115struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000116 int ref_counter;
117
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000118 struct _xmlDictEntry *dict;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800119 size_t size;
120 unsigned int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000121 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000122
123 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800124 /* used for randomization */
125 int seed;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800126 /* used to impose a limit on size */
127 size_t limit;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000128};
129
130/*
Daniel Veillard14412512005-01-21 23:53:26 +0000131 * A mutex for modifying the reference counter for shared
132 * dictionaries.
133 */
134static xmlRMutexPtr xmlDictMutex = NULL;
135
136/*
137 * Whether the dictionary mutex was initialized.
138 */
139static int xmlDictInitialized = 0;
140
Daniel Veillard379ebc12012-05-18 15:41:31 +0800141#ifdef DICT_RANDOMIZATION
142#ifdef HAVE_RAND_R
143/*
144 * Internal data for random function, protected by xmlDictMutex
145 */
Wouter Van Rooye7715a52012-09-14 14:39:42 +0800146static unsigned int rand_seed = 0;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800147#endif
148#endif
149
Daniel Veillard14412512005-01-21 23:53:26 +0000150/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000151 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000152 *
153 * Do the dictionary mutex initialization.
154 * this function is not thread safe, initialization should
155 * preferably be done once at startup
Daniel Veillardee8f1d42012-05-21 11:16:12 +0800156 *
157 * Returns 0 if initialization was already done, and 1 if that
158 * call led to the initialization
Daniel Veillard14412512005-01-21 23:53:26 +0000159 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800160int xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000161 if (xmlDictInitialized)
162 return(1);
163
164 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
165 return(0);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800166 xmlRMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000167
Daniel Veillard8973d582012-02-04 19:07:44 +0800168#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800169#ifdef HAVE_RAND_R
170 rand_seed = time(NULL);
171 rand_r(& rand_seed);
172#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800173 srand(time(NULL));
174#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800175#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000176 xmlDictInitialized = 1;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800177 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000178 return(1);
179}
180
Daniel Veillard379ebc12012-05-18 15:41:31 +0800181#ifdef DICT_RANDOMIZATION
182int __xmlRandom(void) {
183 int ret;
184
185 if (xmlDictInitialized == 0)
186 xmlInitializeDict();
187
188 xmlRMutexLock(xmlDictMutex);
189#ifdef HAVE_RAND_R
190 ret = rand_r(& rand_seed);
191#else
192 ret = rand();
193#endif
194 xmlRMutexUnlock(xmlDictMutex);
195 return(ret);
196}
197#endif
198
Daniel Veillard14412512005-01-21 23:53:26 +0000199/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000200 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000201 *
Daniel Veillard379ebc12012-05-18 15:41:31 +0800202 * Free the dictionary mutex. Do not call unless sure the library
203 * is not in use anymore !
Daniel Veillard14412512005-01-21 23:53:26 +0000204 */
205void
206xmlDictCleanup(void) {
207 if (!xmlDictInitialized)
208 return;
209
210 xmlFreeRMutex(xmlDictMutex);
211
212 xmlDictInitialized = 0;
213}
214
215/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000216 * xmlDictAddString:
217 * @dict: the dictionnary
218 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800219 * @len: the length of the name
Daniel Veillard81514ba2003-09-16 23:17:26 +0000220 *
221 * Add the string to the array[s]
222 *
223 * Returns the pointer of the local string, or NULL in case of error.
224 */
225static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800226xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Daniel Veillard81514ba2003-09-16 23:17:26 +0000227 xmlDictStringsPtr pool;
228 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800229 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
230 size_t limit = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000231
Daniel Veillard424785e2008-08-06 09:35:25 +0000232#ifdef DICT_DEBUG_PATTERNS
233 fprintf(stderr, "-");
234#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000235 pool = dict->strings;
236 while (pool != NULL) {
237 if (pool->end - pool->free > namelen)
238 goto found_pool;
239 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800240 limit += pool->size;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000241 pool = pool->next;
242 }
243 /*
244 * Not found, need to allocate
245 */
246 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800247 if ((dict->limit > 0) && (limit > dict->limit)) {
248 return(NULL);
249 }
250
Daniel Veillard81514ba2003-09-16 23:17:26 +0000251 if (size == 0) size = 1000;
252 else size *= 4; /* exponential growth */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800253 if (size < 4 * namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000254 size = 4 * namelen; /* just in case ! */
255 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
256 if (pool == NULL)
257 return(NULL);
258 pool->size = size;
259 pool->nbStrings = 0;
260 pool->free = &pool->array[0];
261 pool->end = &pool->array[size];
262 pool->next = dict->strings;
263 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000264#ifdef DICT_DEBUG_PATTERNS
265 fprintf(stderr, "+");
266#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000267 }
268found_pool:
269 ret = pool->free;
270 memcpy(pool->free, name, namelen);
271 pool->free += namelen;
272 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000273 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000274 return(ret);
275}
276
277/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000278 * xmlDictAddQString:
279 * @dict: the dictionnary
280 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000281 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000282 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800283 * @len: the length of the name
Daniel Veillarde72c5082003-09-19 12:44:05 +0000284 *
285 * Add the QName to the array[s]
286 *
287 * Returns the pointer of the local string, or NULL in case of error.
288 */
289static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800290xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
291 const xmlChar *name, unsigned int namelen)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000292{
293 xmlDictStringsPtr pool;
294 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800295 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
296 size_t limit = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000297
298 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000299
Daniel Veillard424785e2008-08-06 09:35:25 +0000300#ifdef DICT_DEBUG_PATTERNS
301 fprintf(stderr, "=");
302#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000303 pool = dict->strings;
304 while (pool != NULL) {
Daniel Veillardffda65f2008-08-07 16:33:49 +0000305 if (pool->end - pool->free > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000306 goto found_pool;
307 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800308 limit += pool->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000309 pool = pool->next;
310 }
311 /*
312 * Not found, need to allocate
313 */
314 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800315 if ((dict->limit > 0) && (limit > dict->limit)) {
316 return(NULL);
317 }
318
Daniel Veillarde72c5082003-09-19 12:44:05 +0000319 if (size == 0) size = 1000;
320 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000321 if (size < 4 * (namelen + plen + 1))
322 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000323 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
324 if (pool == NULL)
325 return(NULL);
326 pool->size = size;
327 pool->nbStrings = 0;
328 pool->free = &pool->array[0];
329 pool->end = &pool->array[size];
330 pool->next = dict->strings;
331 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000332#ifdef DICT_DEBUG_PATTERNS
333 fprintf(stderr, "+");
334#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000335 }
336found_pool:
337 ret = pool->free;
338 memcpy(pool->free, prefix, plen);
339 pool->free += plen;
340 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000341 memcpy(pool->free, name, namelen);
342 pool->free += namelen;
343 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000344 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000345 return(ret);
346}
347
Daniel Veillard424785e2008-08-06 09:35:25 +0000348#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000349/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000350 * xmlDictComputeBigKey:
351 *
352 * Calculate a hash key using a good hash function that works well for
353 * larger hash table sizes.
354 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000355 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000356 * http://burtleburtle.net/bob/hash/doobs.html
357 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000358
359static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800360xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000361 uint32_t hash;
362 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000363
Daniel Veillard424785e2008-08-06 09:35:25 +0000364 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000365
Daniel Veillard8973d582012-02-04 19:07:44 +0800366 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000367
Daniel Veillard424785e2008-08-06 09:35:25 +0000368 for (i = 0;i < namelen; i++) {
369 hash += data[i];
370 hash += (hash << 10);
371 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000372 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000373 hash += (hash << 3);
374 hash ^= (hash >> 11);
375 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000376
377 return hash;
378}
379
380/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000381 * xmlDictComputeBigQKey:
382 *
383 * Calculate a hash key for two strings using a good hash function
384 * that works well for larger hash table sizes.
385 *
386 * Hash function by "One-at-a-Time Hash" see
387 * http://burtleburtle.net/bob/hash/doobs.html
388 *
389 * Neither of the two strings must be NULL.
390 */
391static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000392xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800393 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000394{
395 uint32_t hash;
396 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000397
Daniel Veillard8973d582012-02-04 19:07:44 +0800398 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000399
400 for (i = 0;i < plen; i++) {
401 hash += prefix[i];
402 hash += (hash << 10);
403 hash ^= (hash >> 6);
404 }
405 hash += ':';
406 hash += (hash << 10);
407 hash ^= (hash >> 6);
408
409 for (i = 0;i < len; i++) {
410 hash += name[i];
411 hash += (hash << 10);
412 hash ^= (hash >> 6);
413 }
414 hash += (hash << 3);
415 hash ^= (hash >> 11);
416 hash += (hash << 15);
417
418 return hash;
419}
420#endif /* WITH_BIG_KEY */
421
422/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000423 * xmlDictComputeFastKey:
424 *
425 * Calculate a hash key using a fast hash function that works well
426 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000427 */
428static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800429xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
430 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000431
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000432 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000433 value = *name;
434 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000435 if (namelen > 10) {
436 value += name[namelen - 1];
437 namelen = 10;
438 }
439 switch (namelen) {
440 case 10: value += name[9];
441 case 9: value += name[8];
442 case 8: value += name[7];
443 case 7: value += name[6];
444 case 6: value += name[5];
445 case 5: value += name[4];
446 case 4: value += name[3];
447 case 3: value += name[2];
448 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000449 default: break;
450 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000451 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000452}
453
454/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000455 * xmlDictComputeFastQKey:
456 *
457 * Calculate a hash key for two strings using a fast hash function
458 * that works well for low hash table fill.
459 *
460 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000461 */
462static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000463xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800464 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000465{
Daniel Veillard8973d582012-02-04 19:07:44 +0800466 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000467
Daniel Veillarde72c5082003-09-19 12:44:05 +0000468 if (plen == 0)
469 value += 30 * (unsigned long) ':';
470 else
471 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000472
Daniel Veillarde72c5082003-09-19 12:44:05 +0000473 if (len > 10) {
474 value += name[len - (plen + 1 + 1)];
475 len = 10;
476 if (plen > 10)
477 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000478 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000479 switch (plen) {
480 case 10: value += prefix[9];
481 case 9: value += prefix[8];
482 case 8: value += prefix[7];
483 case 7: value += prefix[6];
484 case 6: value += prefix[5];
485 case 5: value += prefix[4];
486 case 4: value += prefix[3];
487 case 3: value += prefix[2];
488 case 2: value += prefix[1];
489 case 1: value += prefix[0];
490 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000491 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000492 len -= plen;
493 if (len > 0) {
494 value += (unsigned long) ':';
495 len--;
496 }
497 switch (len) {
498 case 10: value += name[9];
499 case 9: value += name[8];
500 case 8: value += name[7];
501 case 7: value += name[6];
502 case 6: value += name[5];
503 case 5: value += name[4];
504 case 4: value += name[3];
505 case 3: value += name[2];
506 case 2: value += name[1];
507 case 1: value += name[0];
508 default: break;
509 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000510 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000511}
512
513/**
514 * xmlDictCreate:
515 *
516 * Create a new dictionary
517 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000518 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000519 */
520xmlDictPtr
521xmlDictCreate(void) {
522 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000523
524 if (!xmlDictInitialized)
525 if (!xmlInitializeDict())
526 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000527
528#ifdef DICT_DEBUG_PATTERNS
529 fprintf(stderr, "C");
530#endif
531
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000532 dict = xmlMalloc(sizeof(xmlDict));
533 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000534 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800535 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000536
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000537 dict->size = MIN_DICT_SIZE;
538 dict->nbElems = 0;
539 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000540 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000541 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000542 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000543 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800544#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800545 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800546#else
547 dict->seed = 0;
548#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000549 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000550 }
551 xmlFree(dict);
552 }
553 return(NULL);
554}
555
556/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000557 * xmlDictCreateSub:
558 * @sub: an existing dictionnary
559 *
560 * Create a new dictionary, inheriting strings from the read-only
561 * dictionnary @sub. On lookup, strings are first searched in the
562 * new dictionnary, then in @sub, and if not found are created in the
563 * new dictionnary.
564 *
565 * Returns the newly created dictionnary, or NULL if an error occured.
566 */
567xmlDictPtr
568xmlDictCreateSub(xmlDictPtr sub) {
569 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000570
Daniel Veillard4773df22004-01-23 13:15:13 +0000571 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000572#ifdef DICT_DEBUG_PATTERNS
573 fprintf(stderr, "R");
574#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800575 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000576 dict->subdict = sub;
577 xmlDictReference(dict->subdict);
578 }
579 return(dict);
580}
581
582/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000583 * xmlDictReference:
584 * @dict: the dictionnary
585 *
586 * Increment the reference counter of a dictionary
587 *
588 * Returns 0 in case of success and -1 in case of error
589 */
590int
591xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000592 if (!xmlDictInitialized)
593 if (!xmlInitializeDict())
594 return(-1);
595
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000596 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000597 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000598 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000599 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000600 return(0);
601}
602
603/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000604 * xmlDictGrow:
605 * @dict: the dictionnary
606 * @size: the new size of the dictionnary
607 *
608 * resize the dictionnary
609 *
610 * Returns 0 in case of success, -1 in case of failure
611 */
612static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800613xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000614 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800615 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000616 xmlDictEntryPtr iter, next;
617 struct _xmlDictEntry *olddict;
618#ifdef DEBUG_GROW
619 unsigned long nbElem = 0;
620#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000621 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000622 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000623
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000624 if (dict == NULL)
625 return(-1);
626 if (size < 8)
627 return(-1);
628 if (size > 8 * 2048)
629 return(-1);
630
Daniel Veillard424785e2008-08-06 09:35:25 +0000631#ifdef DICT_DEBUG_PATTERNS
632 fprintf(stderr, "*");
633#endif
634
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000635 oldsize = dict->size;
636 olddict = dict->dict;
637 if (olddict == NULL)
638 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000639 if (oldsize == MIN_DICT_SIZE)
640 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000641
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000642 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
643 if (dict->dict == NULL) {
644 dict->dict = olddict;
645 return(-1);
646 }
647 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
648 dict->size = size;
649
650 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000651 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000652 the main dict. It is nicer to run through the array twice, first
653 copying all the elements in the main array (less probability of
654 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000655 */
656 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000657 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000658 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000659
660 if (keep_keys)
661 okey = olddict[i].okey;
662 else
663 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
664 key = okey % dict->size;
665
Daniel Veillardffda65f2008-08-07 16:33:49 +0000666 if (dict->dict[key].valid == 0) {
667 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
668 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000669 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000670 } else {
671 xmlDictEntryPtr entry;
672
673 entry = xmlMalloc(sizeof(xmlDictEntry));
674 if (entry != NULL) {
675 entry->name = olddict[i].name;
676 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000677 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000678 entry->next = dict->dict[key].next;
679 entry->valid = 1;
680 dict->dict[key].next = entry;
681 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000682 /*
683 * we don't have much ways to alert from herei
684 * result is loosing an entry and unicity garantee
685 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000686 ret = -1;
687 }
688 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000689#ifdef DEBUG_GROW
690 nbElem++;
691#endif
692 }
693
694 for (i = 0; i < oldsize; i++) {
695 iter = olddict[i].next;
696 while (iter) {
697 next = iter->next;
698
699 /*
700 * put back the entry in the new dict
701 */
702
Daniel Veillardd68f8912008-08-08 10:09:19 +0000703 if (keep_keys)
704 okey = iter->okey;
705 else
706 okey = xmlDictComputeKey(dict, iter->name, iter->len);
707 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000708 if (dict->dict[key].valid == 0) {
709 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
710 dict->dict[key].next = NULL;
711 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000712 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000713 xmlFree(iter);
714 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000715 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000716 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000717 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000718 }
719
720#ifdef DEBUG_GROW
721 nbElem++;
722#endif
723
724 iter = next;
725 }
726 }
727
728 xmlFree(olddict);
729
730#ifdef DEBUG_GROW
731 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800732 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000733#endif
734
Daniel Veillardffda65f2008-08-07 16:33:49 +0000735 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000736}
737
738/**
739 * xmlDictFree:
740 * @dict: the dictionnary
741 *
742 * Free the hash @dict and its contents. The userdata is
743 * deallocated with @f if provided.
744 */
745void
746xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800747 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000748 xmlDictEntryPtr iter;
749 xmlDictEntryPtr next;
750 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000751 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000752
753 if (dict == NULL)
754 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000755
Daniel Veillard14412512005-01-21 23:53:26 +0000756 if (!xmlDictInitialized)
757 if (!xmlInitializeDict())
758 return;
759
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000760 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000761 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000762 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000763 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000764 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000765 return;
766 }
767
Daniel Veillard14412512005-01-21 23:53:26 +0000768 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000769
Daniel Veillard4773df22004-01-23 13:15:13 +0000770 if (dict->subdict != NULL) {
771 xmlDictFree(dict->subdict);
772 }
773
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000774 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000775 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000776 iter = &(dict->dict[i]);
777 if (iter->valid == 0)
778 continue;
779 inside_dict = 1;
780 while (iter) {
781 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000782 if (!inside_dict)
783 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000784 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000785 inside_dict = 0;
786 iter = next;
787 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000788 }
789 xmlFree(dict->dict);
790 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000791 pool = dict->strings;
792 while (pool != NULL) {
793 nextp = pool->next;
794 xmlFree(pool);
795 pool = nextp;
796 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000797 xmlFree(dict);
798}
799
800/**
801 * xmlDictLookup:
802 * @dict: the dictionnary
803 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000804 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000805 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000806 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000807 *
808 * Returns the internal copy of the name or NULL in case of internal error
809 */
810const xmlChar *
811xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000812 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000813 xmlDictEntryPtr entry;
814 xmlDictEntryPtr insert;
815 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800816 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000817
Daniel Veillard0fb18932003-09-07 09:14:37 +0000818 if ((dict == NULL) || (name == NULL))
819 return(NULL);
820
821 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800822 l = strlen((const char *) name);
823 else
824 l = len;
825
826 if (((dict->limit > 0) && (l >= dict->limit)) ||
827 (l > INT_MAX / 2))
828 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000829
830 /*
831 * Check for duplicate and insertion location.
832 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800833 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000834 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000835 if (dict->dict[key].valid == 0) {
836 insert = NULL;
837 } else {
838 for (insert = &(dict->dict[key]); insert->next != NULL;
839 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000840#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800841 if ((insert->okey == okey) && (insert->len == l)) {
842 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000843 return(insert->name);
844 }
845#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800846 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800847 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000848 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000849#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000850 nbi++;
851 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000852#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800853 if ((insert->okey == okey) && (insert->len == l)) {
854 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000855 return(insert->name);
856 }
857#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800858 if ((insert->okey == okey) && (insert->len == l) &&
859 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000860 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000861#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000862 }
863
Daniel Veillard4773df22004-01-23 13:15:13 +0000864 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000865 unsigned long skey;
866
867 /* we cannot always reuse the same okey for the subdict */
868 if (((dict->size == MIN_DICT_SIZE) &&
869 (dict->subdict->size != MIN_DICT_SIZE)) ||
870 ((dict->size != MIN_DICT_SIZE) &&
871 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800872 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000873 else
874 skey = okey;
875
876 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000877 if (dict->subdict->dict[key].valid != 0) {
878 xmlDictEntryPtr tmp;
879
880 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
881 tmp = tmp->next) {
882#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800883 if ((tmp->okey == skey) && (tmp->len == l)) {
884 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000885 return(tmp->name);
886 }
887#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800888 if ((tmp->okey == skey) && (tmp->len == l) &&
889 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000890 return(tmp->name);
891#endif
892 nbi++;
893 }
894#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800895 if ((tmp->okey == skey) && (tmp->len == l)) {
896 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000897 return(tmp->name);
898 }
899#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800900 if ((tmp->okey == skey) && (tmp->len == l) &&
901 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000902 return(tmp->name);
903#endif
904 }
905 key = okey % dict->size;
906 }
907
Daniel Veillard7c693da2012-07-25 16:32:18 +0800908 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000909 if (ret == NULL)
910 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000911 if (insert == NULL) {
912 entry = &(dict->dict[key]);
913 } else {
914 entry = xmlMalloc(sizeof(xmlDictEntry));
915 if (entry == NULL)
916 return(NULL);
917 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000918 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800919 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000920 entry->next = NULL;
921 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000922 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000923
924
Daniel Veillard7c693da2012-07-25 16:32:18 +0800925 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000926 insert->next = entry;
927
928 dict->nbElems++;
929
930 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000931 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
932 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
933 return(NULL);
934 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000935 /* Note that entry may have been freed at this point by xmlDictGrow */
936
937 return(ret);
938}
939
940/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000941 * xmlDictExists:
942 * @dict: the dictionnary
943 * @name: the name of the userdata
944 * @len: the length of the name, if -1 it is recomputed
945 *
946 * Check if the @name exists in the dictionnary @dict.
947 *
948 * Returns the internal copy of the name or NULL if not found.
949 */
950const xmlChar *
951xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
952 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000953 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800954 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000955
956 if ((dict == NULL) || (name == NULL))
957 return(NULL);
958
959 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800960 l = strlen((const char *) name);
961 else
962 l = len;
963 if (((dict->limit > 0) && (l >= dict->limit)) ||
964 (l > INT_MAX / 2))
965 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000966
967 /*
968 * Check for duplicate and insertion location.
969 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800970 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000971 key = okey % dict->size;
972 if (dict->dict[key].valid == 0) {
973 insert = NULL;
974 } else {
975 for (insert = &(dict->dict[key]); insert->next != NULL;
976 insert = insert->next) {
977#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800978 if ((insert->okey == okey) && (insert->len == l)) {
979 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000980 return(insert->name);
981 }
982#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800983 if ((insert->okey == okey) && (insert->len == l) &&
984 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000985 return(insert->name);
986#endif
987 nbi++;
988 }
989#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800990 if ((insert->okey == okey) && (insert->len == l)) {
991 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000992 return(insert->name);
993 }
994#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800995 if ((insert->okey == okey) && (insert->len == l) &&
996 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000997 return(insert->name);
998#endif
999 }
1000
1001 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001002 unsigned long skey;
1003
1004 /* we cannot always reuse the same okey for the subdict */
1005 if (((dict->size == MIN_DICT_SIZE) &&
1006 (dict->subdict->size != MIN_DICT_SIZE)) ||
1007 ((dict->size != MIN_DICT_SIZE) &&
1008 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001009 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001010 else
1011 skey = okey;
1012
1013 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001014 if (dict->subdict->dict[key].valid != 0) {
1015 xmlDictEntryPtr tmp;
1016
1017 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1018 tmp = tmp->next) {
1019#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001020 if ((tmp->okey == skey) && (tmp->len == l)) {
1021 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001022 return(tmp->name);
1023 }
1024#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001025 if ((tmp->okey == skey) && (tmp->len == l) &&
1026 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001027 return(tmp->name);
1028#endif
1029 nbi++;
1030 }
1031#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001032 if ((tmp->okey == skey) && (tmp->len == l)) {
1033 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001034 return(tmp->name);
1035 }
1036#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001037 if ((tmp->okey == skey) && (tmp->len == l) &&
1038 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001039 return(tmp->name);
1040#endif
1041 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001042 }
1043
1044 /* not found */
1045 return(NULL);
1046}
1047
1048/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001049 * xmlDictQLookup:
1050 * @dict: the dictionnary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001051 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001052 * @name: the name
1053 *
1054 * Add the QName @prefix:@name to the hash @dict if not present.
1055 *
1056 * Returns the internal copy of the QName or NULL in case of internal error
1057 */
1058const xmlChar *
1059xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001060 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001061 xmlDictEntryPtr entry;
1062 xmlDictEntryPtr insert;
1063 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001064 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001065
1066 if ((dict == NULL) || (name == NULL))
1067 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001068 if (prefix == NULL)
1069 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001070
Daniel Veillardffda65f2008-08-07 16:33:49 +00001071 l = len = strlen((const char *) name);
1072 plen = strlen((const char *) prefix);
1073 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001074
1075 /*
1076 * Check for duplicate and insertion location.
1077 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001078 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001079 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001080 if (dict->dict[key].valid == 0) {
1081 insert = NULL;
1082 } else {
1083 for (insert = &(dict->dict[key]); insert->next != NULL;
1084 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001085 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001086 (xmlStrQEqual(prefix, name, insert->name)))
1087 return(insert->name);
1088 nbi++;
1089 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001090 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001091 (xmlStrQEqual(prefix, name, insert->name)))
1092 return(insert->name);
1093 }
1094
Daniel Veillard4773df22004-01-23 13:15:13 +00001095 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001096 unsigned long skey;
1097
1098 /* we cannot always reuse the same okey for the subdict */
1099 if (((dict->size == MIN_DICT_SIZE) &&
1100 (dict->subdict->size != MIN_DICT_SIZE)) ||
1101 ((dict->size != MIN_DICT_SIZE) &&
1102 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001103 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001104 else
1105 skey = okey;
1106
1107 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001108 if (dict->subdict->dict[key].valid != 0) {
1109 xmlDictEntryPtr tmp;
1110 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1111 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001112 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001113 (xmlStrQEqual(prefix, name, tmp->name)))
1114 return(tmp->name);
1115 nbi++;
1116 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001117 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001118 (xmlStrQEqual(prefix, name, tmp->name)))
1119 return(tmp->name);
1120 }
1121 key = okey % dict->size;
1122 }
1123
Daniel Veillardffda65f2008-08-07 16:33:49 +00001124 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001125 if (ret == NULL)
1126 return(NULL);
1127 if (insert == NULL) {
1128 entry = &(dict->dict[key]);
1129 } else {
1130 entry = xmlMalloc(sizeof(xmlDictEntry));
1131 if (entry == NULL)
1132 return(NULL);
1133 }
1134 entry->name = ret;
1135 entry->len = len;
1136 entry->next = NULL;
1137 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001138 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001139
Daniel Veillard7c693da2012-07-25 16:32:18 +08001140 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001141 insert->next = entry;
1142
1143 dict->nbElems++;
1144
1145 if ((nbi > MAX_HASH_LEN) &&
1146 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1147 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1148 /* Note that entry may have been freed at this point by xmlDictGrow */
1149
1150 return(ret);
1151}
1152
1153/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001154 * xmlDictOwns:
1155 * @dict: the dictionnary
1156 * @str: the string
1157 *
1158 * check if a string is owned by the disctionary
1159 *
1160 * Returns 1 if true, 0 if false and -1 in case of error
1161 * -1 in case of error
1162 */
1163int
1164xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1165 xmlDictStringsPtr pool;
1166
1167 if ((dict == NULL) || (str == NULL))
1168 return(-1);
1169 pool = dict->strings;
1170 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001171 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001172 return(1);
1173 pool = pool->next;
1174 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001175 if (dict->subdict)
1176 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001177 return(0);
1178}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001179
Daniel Veillard81514ba2003-09-16 23:17:26 +00001180/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001181 * xmlDictSize:
1182 * @dict: the dictionnary
1183 *
1184 * Query the number of elements installed in the hash @dict.
1185 *
1186 * Returns the number of elements in the dictionnary or
1187 * -1 in case of error
1188 */
1189int
1190xmlDictSize(xmlDictPtr dict) {
1191 if (dict == NULL)
1192 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001193 if (dict->subdict)
1194 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001195 return(dict->nbElems);
1196}
1197
Daniel Veillard7c693da2012-07-25 16:32:18 +08001198/**
1199 * xmlDictSetLimit:
1200 * @dict: the dictionnary
1201 * @limit: the limit in bytes
1202 *
1203 * Set a size limit for the dictionary
1204 * Added in 2.9.0
1205 *
1206 * Returns the previous limit of the dictionary or 0
1207 */
1208size_t
1209xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1210 size_t ret;
1211
1212 if (dict == NULL)
1213 return(0);
1214 ret = dict->limit;
1215 dict->limit = limit;
1216 return(ret);
1217}
1218
1219/**
1220 * xmlDictGetUsage:
1221 * @dict: the dictionnary
1222 *
1223 * Get how much memory is used by a dictionary for strings
1224 * Added in 2.9.0
1225 *
1226 * Returns the amount of strings allocated
1227 */
1228size_t
1229xmlDictGetUsage(xmlDictPtr dict) {
1230 xmlDictStringsPtr pool;
1231 size_t limit = 0;
1232
1233 if (dict == NULL)
1234 return(0);
1235 pool = dict->strings;
1236 while (pool != NULL) {
1237 limit += pool->size;
1238 pool = pool->next;
1239 }
1240 return(limit);
1241}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001242
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001243#define bottom_dict
1244#include "elfgcchack.h"