blob: 6de2f03fb1c1d86039c0d497a97dcc9365033a76 [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 Veillard8973d582012-02-04 19:07:44 +080022#ifdef HAVE_STDLIB_H
23#include <stdlib.h>
24#endif
25#ifdef HAVE_TIME_H
26#include <time.h>
27#endif
28
29/*
30 * Following http://www.ocert.org/advisories/ocert-2011-003.html
31 * it seems that having hash randomization might be a good idea
32 * when using XML with untrusted data
33 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
34 * which is the default.
35 * Note2: the fast function used for a small dict won't protect very
36 * well but since the attack is based on growing a very big hash
37 * list we will use the BigKey algo as soon as the hash size grows
38 * over MIN_DICT_SIZE so this actually works
39 */
40#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
41#define DICT_RANDOMIZATION
42#endif
43
Daniel Veillard2fdbd322003-08-18 12:15:38 +000044#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000045#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000046#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000047#else
48#ifdef HAVE_INTTYPES_H
49#include <inttypes.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000050#elif defined(WIN32)
51typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000052#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000053#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000054#include <libxml/tree.h>
55#include <libxml/dict.h>
56#include <libxml/xmlmemory.h>
57#include <libxml/xmlerror.h>
58#include <libxml/globals.h>
59
Daniel Veillard424785e2008-08-06 09:35:25 +000060/* #define DEBUG_GROW */
61/* #define DICT_DEBUG_PATTERNS */
62
Daniel Veillarde9100a52008-04-22 08:28:50 +000063#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000064#define MIN_DICT_SIZE 128
65#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000066#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000067
Daniel Veillard424785e2008-08-06 09:35:25 +000068#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080069#define xmlDictComputeKey(dict, name, len) \
70 (((dict)->size == MIN_DICT_SIZE) ? \
71 xmlDictComputeFastKey(name, len, (dict)->seed) : \
72 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000073
Daniel Veillard8973d582012-02-04 19:07:44 +080074#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
75 (((prefix) == NULL) ? \
76 (xmlDictComputeKey(dict, name, len)) : \
77 (((dict)->size == MIN_DICT_SIZE) ? \
78 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
79 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000080
Daniel Veillard424785e2008-08-06 09:35:25 +000081#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080082#define xmlDictComputeKey(dict, name, len) \
83 xmlDictComputeFastKey(name, len, (dict)->seed)
84#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
85 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000086#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000087
88/*
89 * An entry in the dictionnary
90 */
91typedef struct _xmlDictEntry xmlDictEntry;
92typedef xmlDictEntry *xmlDictEntryPtr;
93struct _xmlDictEntry {
94 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000095 const xmlChar *name;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000096 int len;
97 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000098 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000099};
100
Daniel Veillard81514ba2003-09-16 23:17:26 +0000101typedef struct _xmlDictStrings xmlDictStrings;
102typedef xmlDictStrings *xmlDictStringsPtr;
103struct _xmlDictStrings {
104 xmlDictStringsPtr next;
105 xmlChar *free;
106 xmlChar *end;
107 int size;
108 int nbStrings;
109 xmlChar array[1];
110};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000111/*
112 * The entire dictionnary
113 */
114struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000115 int ref_counter;
116
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000117 struct _xmlDictEntry *dict;
118 int size;
119 int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000120 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000121
122 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800123 /* used for randomization */
124 int seed;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000125};
126
127/*
Daniel Veillard14412512005-01-21 23:53:26 +0000128 * A mutex for modifying the reference counter for shared
129 * dictionaries.
130 */
131static xmlRMutexPtr xmlDictMutex = NULL;
132
133/*
134 * Whether the dictionary mutex was initialized.
135 */
136static int xmlDictInitialized = 0;
137
Daniel Veillard379ebc12012-05-18 15:41:31 +0800138#ifdef DICT_RANDOMIZATION
139#ifdef HAVE_RAND_R
140/*
141 * Internal data for random function, protected by xmlDictMutex
142 */
143unsigned int rand_seed = 0;
144#endif
145#endif
146
Daniel Veillard14412512005-01-21 23:53:26 +0000147/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000148 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000149 *
150 * Do the dictionary mutex initialization.
151 * this function is not thread safe, initialization should
152 * preferably be done once at startup
Daniel Veillardee8f1d42012-05-21 11:16:12 +0800153 *
154 * Returns 0 if initialization was already done, and 1 if that
155 * call led to the initialization
Daniel Veillard14412512005-01-21 23:53:26 +0000156 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800157int xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000158 if (xmlDictInitialized)
159 return(1);
160
161 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
162 return(0);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800163 xmlRMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000164
Daniel Veillard8973d582012-02-04 19:07:44 +0800165#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800166#ifdef HAVE_RAND_R
167 rand_seed = time(NULL);
168 rand_r(& rand_seed);
169#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800170 srand(time(NULL));
171#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800172#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000173 xmlDictInitialized = 1;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800174 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000175 return(1);
176}
177
Daniel Veillard379ebc12012-05-18 15:41:31 +0800178#ifdef DICT_RANDOMIZATION
179int __xmlRandom(void) {
180 int ret;
181
182 if (xmlDictInitialized == 0)
183 xmlInitializeDict();
184
185 xmlRMutexLock(xmlDictMutex);
186#ifdef HAVE_RAND_R
187 ret = rand_r(& rand_seed);
188#else
189 ret = rand();
190#endif
191 xmlRMutexUnlock(xmlDictMutex);
192 return(ret);
193}
194#endif
195
Daniel Veillard14412512005-01-21 23:53:26 +0000196/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000197 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000198 *
Daniel Veillard379ebc12012-05-18 15:41:31 +0800199 * Free the dictionary mutex. Do not call unless sure the library
200 * is not in use anymore !
Daniel Veillard14412512005-01-21 23:53:26 +0000201 */
202void
203xmlDictCleanup(void) {
204 if (!xmlDictInitialized)
205 return;
206
207 xmlFreeRMutex(xmlDictMutex);
208
209 xmlDictInitialized = 0;
210}
211
212/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000213 * xmlDictAddString:
214 * @dict: the dictionnary
215 * @name: the name of the userdata
216 * @len: the length of the name, if -1 it is recomputed
217 *
218 * Add the string to the array[s]
219 *
220 * Returns the pointer of the local string, or NULL in case of error.
221 */
222static const xmlChar *
223xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
224 xmlDictStringsPtr pool;
225 const xmlChar *ret;
226 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
227
Daniel Veillard424785e2008-08-06 09:35:25 +0000228#ifdef DICT_DEBUG_PATTERNS
229 fprintf(stderr, "-");
230#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000231 pool = dict->strings;
232 while (pool != NULL) {
233 if (pool->end - pool->free > namelen)
234 goto found_pool;
235 if (pool->size > size) size = pool->size;
236 pool = pool->next;
237 }
238 /*
239 * Not found, need to allocate
240 */
241 if (pool == NULL) {
242 if (size == 0) size = 1000;
243 else size *= 4; /* exponential growth */
244 if (size < 4 * namelen)
245 size = 4 * namelen; /* just in case ! */
246 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
247 if (pool == NULL)
248 return(NULL);
249 pool->size = size;
250 pool->nbStrings = 0;
251 pool->free = &pool->array[0];
252 pool->end = &pool->array[size];
253 pool->next = dict->strings;
254 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000255#ifdef DICT_DEBUG_PATTERNS
256 fprintf(stderr, "+");
257#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000258 }
259found_pool:
260 ret = pool->free;
261 memcpy(pool->free, name, namelen);
262 pool->free += namelen;
263 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000264 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000265 return(ret);
266}
267
268/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000269 * xmlDictAddQString:
270 * @dict: the dictionnary
271 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000272 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000273 * @name: the name of the userdata
274 * @len: the length of the name, if -1 it is recomputed
275 *
276 * Add the QName to the array[s]
277 *
278 * Returns the pointer of the local string, or NULL in case of error.
279 */
280static const xmlChar *
Daniel Veillardffda65f2008-08-07 16:33:49 +0000281xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
Daniel Veillarde72c5082003-09-19 12:44:05 +0000282 const xmlChar *name, int namelen)
283{
284 xmlDictStringsPtr pool;
285 const xmlChar *ret;
286 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000287
288 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000289
Daniel Veillard424785e2008-08-06 09:35:25 +0000290#ifdef DICT_DEBUG_PATTERNS
291 fprintf(stderr, "=");
292#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000293 pool = dict->strings;
294 while (pool != NULL) {
Daniel Veillardffda65f2008-08-07 16:33:49 +0000295 if (pool->end - pool->free > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000296 goto found_pool;
297 if (pool->size > size) size = pool->size;
298 pool = pool->next;
299 }
300 /*
301 * Not found, need to allocate
302 */
303 if (pool == NULL) {
304 if (size == 0) size = 1000;
305 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000306 if (size < 4 * (namelen + plen + 1))
307 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000308 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
309 if (pool == NULL)
310 return(NULL);
311 pool->size = size;
312 pool->nbStrings = 0;
313 pool->free = &pool->array[0];
314 pool->end = &pool->array[size];
315 pool->next = dict->strings;
316 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000317#ifdef DICT_DEBUG_PATTERNS
318 fprintf(stderr, "+");
319#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000320 }
321found_pool:
322 ret = pool->free;
323 memcpy(pool->free, prefix, plen);
324 pool->free += plen;
325 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000326 memcpy(pool->free, name, namelen);
327 pool->free += namelen;
328 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000329 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000330 return(ret);
331}
332
Daniel Veillard424785e2008-08-06 09:35:25 +0000333#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000334/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000335 * xmlDictComputeBigKey:
336 *
337 * Calculate a hash key using a good hash function that works well for
338 * larger hash table sizes.
339 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000340 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000341 * http://burtleburtle.net/bob/hash/doobs.html
342 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000343
344static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800345xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000346 uint32_t hash;
347 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000348
Daniel Veillard424785e2008-08-06 09:35:25 +0000349 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000350
Daniel Veillard8973d582012-02-04 19:07:44 +0800351 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000352
Daniel Veillard424785e2008-08-06 09:35:25 +0000353 for (i = 0;i < namelen; i++) {
354 hash += data[i];
355 hash += (hash << 10);
356 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000357 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000358 hash += (hash << 3);
359 hash ^= (hash >> 11);
360 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000361
362 return hash;
363}
364
365/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000366 * xmlDictComputeBigQKey:
367 *
368 * Calculate a hash key for two strings using a good hash function
369 * that works well for larger hash table sizes.
370 *
371 * Hash function by "One-at-a-Time Hash" see
372 * http://burtleburtle.net/bob/hash/doobs.html
373 *
374 * Neither of the two strings must be NULL.
375 */
376static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000377xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800378 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000379{
380 uint32_t hash;
381 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000382
Daniel Veillard8973d582012-02-04 19:07:44 +0800383 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000384
385 for (i = 0;i < plen; i++) {
386 hash += prefix[i];
387 hash += (hash << 10);
388 hash ^= (hash >> 6);
389 }
390 hash += ':';
391 hash += (hash << 10);
392 hash ^= (hash >> 6);
393
394 for (i = 0;i < len; i++) {
395 hash += name[i];
396 hash += (hash << 10);
397 hash ^= (hash >> 6);
398 }
399 hash += (hash << 3);
400 hash ^= (hash >> 11);
401 hash += (hash << 15);
402
403 return hash;
404}
405#endif /* WITH_BIG_KEY */
406
407/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000408 * xmlDictComputeFastKey:
409 *
410 * Calculate a hash key using a fast hash function that works well
411 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000412 */
413static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800414xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
415 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000416
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000417 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000418 value = *name;
419 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000420 if (namelen > 10) {
421 value += name[namelen - 1];
422 namelen = 10;
423 }
424 switch (namelen) {
425 case 10: value += name[9];
426 case 9: value += name[8];
427 case 8: value += name[7];
428 case 7: value += name[6];
429 case 6: value += name[5];
430 case 5: value += name[4];
431 case 4: value += name[3];
432 case 3: value += name[2];
433 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000434 default: break;
435 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000436 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000437}
438
439/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000440 * xmlDictComputeFastQKey:
441 *
442 * Calculate a hash key for two strings using a fast hash function
443 * that works well for low hash table fill.
444 *
445 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000446 */
447static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000448xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800449 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000450{
Daniel Veillard8973d582012-02-04 19:07:44 +0800451 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000452
Daniel Veillarde72c5082003-09-19 12:44:05 +0000453 if (plen == 0)
454 value += 30 * (unsigned long) ':';
455 else
456 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000457
Daniel Veillarde72c5082003-09-19 12:44:05 +0000458 if (len > 10) {
459 value += name[len - (plen + 1 + 1)];
460 len = 10;
461 if (plen > 10)
462 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000463 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000464 switch (plen) {
465 case 10: value += prefix[9];
466 case 9: value += prefix[8];
467 case 8: value += prefix[7];
468 case 7: value += prefix[6];
469 case 6: value += prefix[5];
470 case 5: value += prefix[4];
471 case 4: value += prefix[3];
472 case 3: value += prefix[2];
473 case 2: value += prefix[1];
474 case 1: value += prefix[0];
475 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000476 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000477 len -= plen;
478 if (len > 0) {
479 value += (unsigned long) ':';
480 len--;
481 }
482 switch (len) {
483 case 10: value += name[9];
484 case 9: value += name[8];
485 case 8: value += name[7];
486 case 7: value += name[6];
487 case 6: value += name[5];
488 case 5: value += name[4];
489 case 4: value += name[3];
490 case 3: value += name[2];
491 case 2: value += name[1];
492 case 1: value += name[0];
493 default: break;
494 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000495 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000496}
497
498/**
499 * xmlDictCreate:
500 *
501 * Create a new dictionary
502 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000503 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000504 */
505xmlDictPtr
506xmlDictCreate(void) {
507 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000508
509 if (!xmlDictInitialized)
510 if (!xmlInitializeDict())
511 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000512
513#ifdef DICT_DEBUG_PATTERNS
514 fprintf(stderr, "C");
515#endif
516
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000517 dict = xmlMalloc(sizeof(xmlDict));
518 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000519 dict->ref_counter = 1;
520
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000521 dict->size = MIN_DICT_SIZE;
522 dict->nbElems = 0;
523 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000524 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000525 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000526 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000527 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800528#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800529 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800530#else
531 dict->seed = 0;
532#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000533 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000534 }
535 xmlFree(dict);
536 }
537 return(NULL);
538}
539
540/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000541 * xmlDictCreateSub:
542 * @sub: an existing dictionnary
543 *
544 * Create a new dictionary, inheriting strings from the read-only
545 * dictionnary @sub. On lookup, strings are first searched in the
546 * new dictionnary, then in @sub, and if not found are created in the
547 * new dictionnary.
548 *
549 * Returns the newly created dictionnary, or NULL if an error occured.
550 */
551xmlDictPtr
552xmlDictCreateSub(xmlDictPtr sub) {
553 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000554
Daniel Veillard4773df22004-01-23 13:15:13 +0000555 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000556#ifdef DICT_DEBUG_PATTERNS
557 fprintf(stderr, "R");
558#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800559 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000560 dict->subdict = sub;
561 xmlDictReference(dict->subdict);
562 }
563 return(dict);
564}
565
566/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000567 * xmlDictReference:
568 * @dict: the dictionnary
569 *
570 * Increment the reference counter of a dictionary
571 *
572 * Returns 0 in case of success and -1 in case of error
573 */
574int
575xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000576 if (!xmlDictInitialized)
577 if (!xmlInitializeDict())
578 return(-1);
579
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000580 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000581 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000582 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000583 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000584 return(0);
585}
586
587/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000588 * xmlDictGrow:
589 * @dict: the dictionnary
590 * @size: the new size of the dictionnary
591 *
592 * resize the dictionnary
593 *
594 * Returns 0 in case of success, -1 in case of failure
595 */
596static int
597xmlDictGrow(xmlDictPtr dict, int size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000598 unsigned long key, okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000599 int oldsize, i;
600 xmlDictEntryPtr iter, next;
601 struct _xmlDictEntry *olddict;
602#ifdef DEBUG_GROW
603 unsigned long nbElem = 0;
604#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000605 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000606 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000607
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000608 if (dict == NULL)
609 return(-1);
610 if (size < 8)
611 return(-1);
612 if (size > 8 * 2048)
613 return(-1);
614
Daniel Veillard424785e2008-08-06 09:35:25 +0000615#ifdef DICT_DEBUG_PATTERNS
616 fprintf(stderr, "*");
617#endif
618
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000619 oldsize = dict->size;
620 olddict = dict->dict;
621 if (olddict == NULL)
622 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000623 if (oldsize == MIN_DICT_SIZE)
624 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000625
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000626 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
627 if (dict->dict == NULL) {
628 dict->dict = olddict;
629 return(-1);
630 }
631 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
632 dict->size = size;
633
634 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000635 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000636 the main dict. It is nicer to run through the array twice, first
637 copying all the elements in the main array (less probability of
638 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000639 */
640 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000641 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000642 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000643
644 if (keep_keys)
645 okey = olddict[i].okey;
646 else
647 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
648 key = okey % dict->size;
649
Daniel Veillardffda65f2008-08-07 16:33:49 +0000650 if (dict->dict[key].valid == 0) {
651 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
652 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000653 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000654 } else {
655 xmlDictEntryPtr entry;
656
657 entry = xmlMalloc(sizeof(xmlDictEntry));
658 if (entry != NULL) {
659 entry->name = olddict[i].name;
660 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000661 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000662 entry->next = dict->dict[key].next;
663 entry->valid = 1;
664 dict->dict[key].next = entry;
665 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000666 /*
667 * we don't have much ways to alert from herei
668 * result is loosing an entry and unicity garantee
669 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000670 ret = -1;
671 }
672 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000673#ifdef DEBUG_GROW
674 nbElem++;
675#endif
676 }
677
678 for (i = 0; i < oldsize; i++) {
679 iter = olddict[i].next;
680 while (iter) {
681 next = iter->next;
682
683 /*
684 * put back the entry in the new dict
685 */
686
Daniel Veillardd68f8912008-08-08 10:09:19 +0000687 if (keep_keys)
688 okey = iter->okey;
689 else
690 okey = xmlDictComputeKey(dict, iter->name, iter->len);
691 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000692 if (dict->dict[key].valid == 0) {
693 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
694 dict->dict[key].next = NULL;
695 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000696 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000697 xmlFree(iter);
698 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000699 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000700 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000701 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000702 }
703
704#ifdef DEBUG_GROW
705 nbElem++;
706#endif
707
708 iter = next;
709 }
710 }
711
712 xmlFree(olddict);
713
714#ifdef DEBUG_GROW
715 xmlGenericError(xmlGenericErrorContext,
716 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
717#endif
718
Daniel Veillardffda65f2008-08-07 16:33:49 +0000719 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000720}
721
722/**
723 * xmlDictFree:
724 * @dict: the dictionnary
725 *
726 * Free the hash @dict and its contents. The userdata is
727 * deallocated with @f if provided.
728 */
729void
730xmlDictFree(xmlDictPtr dict) {
731 int i;
732 xmlDictEntryPtr iter;
733 xmlDictEntryPtr next;
734 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000735 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000736
737 if (dict == NULL)
738 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000739
Daniel Veillard14412512005-01-21 23:53:26 +0000740 if (!xmlDictInitialized)
741 if (!xmlInitializeDict())
742 return;
743
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000744 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000745 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000746 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000747 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000748 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000749 return;
750 }
751
Daniel Veillard14412512005-01-21 23:53:26 +0000752 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000753
Daniel Veillard4773df22004-01-23 13:15:13 +0000754 if (dict->subdict != NULL) {
755 xmlDictFree(dict->subdict);
756 }
757
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000758 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000759 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000760 iter = &(dict->dict[i]);
761 if (iter->valid == 0)
762 continue;
763 inside_dict = 1;
764 while (iter) {
765 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000766 if (!inside_dict)
767 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000768 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000769 inside_dict = 0;
770 iter = next;
771 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000772 }
773 xmlFree(dict->dict);
774 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000775 pool = dict->strings;
776 while (pool != NULL) {
777 nextp = pool->next;
778 xmlFree(pool);
779 pool = nextp;
780 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000781 xmlFree(dict);
782}
783
784/**
785 * xmlDictLookup:
786 * @dict: the dictionnary
787 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000788 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000789 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000790 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000791 *
792 * Returns the internal copy of the name or NULL in case of internal error
793 */
794const xmlChar *
795xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000796 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000797 xmlDictEntryPtr entry;
798 xmlDictEntryPtr insert;
799 const xmlChar *ret;
800
Daniel Veillard0fb18932003-09-07 09:14:37 +0000801 if ((dict == NULL) || (name == NULL))
802 return(NULL);
803
804 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000805 len = strlen((const char *) name);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000806
807 /*
808 * Check for duplicate and insertion location.
809 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000810 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard4773df22004-01-23 13:15:13 +0000811 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000812 if (dict->dict[key].valid == 0) {
813 insert = NULL;
814 } else {
815 for (insert = &(dict->dict[key]); insert->next != NULL;
816 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000817#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000818 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000819 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000820 return(insert->name);
821 }
822#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000823 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000824 (!xmlStrncmp(insert->name, name, len)))
825 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000826#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000827 nbi++;
828 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000829#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000830 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000831 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000832 return(insert->name);
833 }
834#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000835 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000836 (!xmlStrncmp(insert->name, name, len)))
837 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000838#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000839 }
840
Daniel Veillard4773df22004-01-23 13:15:13 +0000841 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000842 unsigned long skey;
843
844 /* we cannot always reuse the same okey for the subdict */
845 if (((dict->size == MIN_DICT_SIZE) &&
846 (dict->subdict->size != MIN_DICT_SIZE)) ||
847 ((dict->size != MIN_DICT_SIZE) &&
848 (dict->subdict->size == MIN_DICT_SIZE)))
849 skey = xmlDictComputeKey(dict->subdict, name, len);
850 else
851 skey = okey;
852
853 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000854 if (dict->subdict->dict[key].valid != 0) {
855 xmlDictEntryPtr tmp;
856
857 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
858 tmp = tmp->next) {
859#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000860 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000861 if (!memcmp(tmp->name, name, len))
862 return(tmp->name);
863 }
864#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000865 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000866 (!xmlStrncmp(tmp->name, name, len)))
867 return(tmp->name);
868#endif
869 nbi++;
870 }
871#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000872 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000873 if (!memcmp(tmp->name, name, len))
874 return(tmp->name);
875 }
876#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000877 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000878 (!xmlStrncmp(tmp->name, name, len)))
879 return(tmp->name);
880#endif
881 }
882 key = okey % dict->size;
883 }
884
Daniel Veillard81514ba2003-09-16 23:17:26 +0000885 ret = xmlDictAddString(dict, name, len);
886 if (ret == NULL)
887 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000888 if (insert == NULL) {
889 entry = &(dict->dict[key]);
890 } else {
891 entry = xmlMalloc(sizeof(xmlDictEntry));
892 if (entry == NULL)
893 return(NULL);
894 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000895 entry->name = ret;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000896 entry->len = len;
897 entry->next = NULL;
898 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000899 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000900
901
902 if (insert != NULL)
903 insert->next = entry;
904
905 dict->nbElems++;
906
907 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000908 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
909 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
910 return(NULL);
911 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000912 /* Note that entry may have been freed at this point by xmlDictGrow */
913
914 return(ret);
915}
916
917/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000918 * xmlDictExists:
919 * @dict: the dictionnary
920 * @name: the name of the userdata
921 * @len: the length of the name, if -1 it is recomputed
922 *
923 * Check if the @name exists in the dictionnary @dict.
924 *
925 * Returns the internal copy of the name or NULL if not found.
926 */
927const xmlChar *
928xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
929 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000930 xmlDictEntryPtr insert;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000931
932 if ((dict == NULL) || (name == NULL))
933 return(NULL);
934
935 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000936 len = strlen((const char *) name);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000937
938 /*
939 * Check for duplicate and insertion location.
940 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000941 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000942 key = okey % dict->size;
943 if (dict->dict[key].valid == 0) {
944 insert = NULL;
945 } else {
946 for (insert = &(dict->dict[key]); insert->next != NULL;
947 insert = insert->next) {
948#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000949 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000950 if (!memcmp(insert->name, name, len))
951 return(insert->name);
952 }
953#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000954 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000955 (!xmlStrncmp(insert->name, name, len)))
956 return(insert->name);
957#endif
958 nbi++;
959 }
960#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000961 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000962 if (!memcmp(insert->name, name, len))
963 return(insert->name);
964 }
965#else
Rob Richards117baa02008-08-10 17:07:33 +0000966 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000967 (!xmlStrncmp(insert->name, name, len)))
968 return(insert->name);
969#endif
970 }
971
972 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000973 unsigned long skey;
974
975 /* we cannot always reuse the same okey for the subdict */
976 if (((dict->size == MIN_DICT_SIZE) &&
977 (dict->subdict->size != MIN_DICT_SIZE)) ||
978 ((dict->size != MIN_DICT_SIZE) &&
979 (dict->subdict->size == MIN_DICT_SIZE)))
980 skey = xmlDictComputeKey(dict->subdict, name, len);
981 else
982 skey = okey;
983
984 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000985 if (dict->subdict->dict[key].valid != 0) {
986 xmlDictEntryPtr tmp;
987
988 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
989 tmp = tmp->next) {
990#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000991 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000992 if (!memcmp(tmp->name, name, len))
993 return(tmp->name);
994 }
995#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000996 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000997 (!xmlStrncmp(tmp->name, name, len)))
998 return(tmp->name);
999#endif
1000 nbi++;
1001 }
1002#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +00001003 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001004 if (!memcmp(tmp->name, name, len))
1005 return(tmp->name);
1006 }
1007#else
Daniel Veillardd68f8912008-08-08 10:09:19 +00001008 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001009 (!xmlStrncmp(tmp->name, name, len)))
1010 return(tmp->name);
1011#endif
1012 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001013 }
1014
1015 /* not found */
1016 return(NULL);
1017}
1018
1019/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001020 * xmlDictQLookup:
1021 * @dict: the dictionnary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001022 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001023 * @name: the name
1024 *
1025 * Add the QName @prefix:@name to the hash @dict if not present.
1026 *
1027 * Returns the internal copy of the QName or NULL in case of internal error
1028 */
1029const xmlChar *
1030xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001031 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001032 xmlDictEntryPtr entry;
1033 xmlDictEntryPtr insert;
1034 const xmlChar *ret;
Daniel Veillardffda65f2008-08-07 16:33:49 +00001035 int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001036
1037 if ((dict == NULL) || (name == NULL))
1038 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001039 if (prefix == NULL)
1040 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001041
Daniel Veillardffda65f2008-08-07 16:33:49 +00001042 l = len = strlen((const char *) name);
1043 plen = strlen((const char *) prefix);
1044 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001045
1046 /*
1047 * Check for duplicate and insertion location.
1048 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001049 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001050 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001051 if (dict->dict[key].valid == 0) {
1052 insert = NULL;
1053 } else {
1054 for (insert = &(dict->dict[key]); insert->next != NULL;
1055 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001056 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001057 (xmlStrQEqual(prefix, name, insert->name)))
1058 return(insert->name);
1059 nbi++;
1060 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001061 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001062 (xmlStrQEqual(prefix, name, insert->name)))
1063 return(insert->name);
1064 }
1065
Daniel Veillard4773df22004-01-23 13:15:13 +00001066 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001067 unsigned long skey;
1068
1069 /* we cannot always reuse the same okey for the subdict */
1070 if (((dict->size == MIN_DICT_SIZE) &&
1071 (dict->subdict->size != MIN_DICT_SIZE)) ||
1072 ((dict->size != MIN_DICT_SIZE) &&
1073 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001074 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001075 else
1076 skey = okey;
1077
1078 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001079 if (dict->subdict->dict[key].valid != 0) {
1080 xmlDictEntryPtr tmp;
1081 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1082 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001083 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001084 (xmlStrQEqual(prefix, name, tmp->name)))
1085 return(tmp->name);
1086 nbi++;
1087 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001088 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001089 (xmlStrQEqual(prefix, name, tmp->name)))
1090 return(tmp->name);
1091 }
1092 key = okey % dict->size;
1093 }
1094
Daniel Veillardffda65f2008-08-07 16:33:49 +00001095 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001096 if (ret == NULL)
1097 return(NULL);
1098 if (insert == NULL) {
1099 entry = &(dict->dict[key]);
1100 } else {
1101 entry = xmlMalloc(sizeof(xmlDictEntry));
1102 if (entry == NULL)
1103 return(NULL);
1104 }
1105 entry->name = ret;
1106 entry->len = len;
1107 entry->next = NULL;
1108 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001109 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001110
1111 if (insert != NULL)
1112 insert->next = entry;
1113
1114 dict->nbElems++;
1115
1116 if ((nbi > MAX_HASH_LEN) &&
1117 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1118 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1119 /* Note that entry may have been freed at this point by xmlDictGrow */
1120
1121 return(ret);
1122}
1123
1124/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001125 * xmlDictOwns:
1126 * @dict: the dictionnary
1127 * @str: the string
1128 *
1129 * check if a string is owned by the disctionary
1130 *
1131 * Returns 1 if true, 0 if false and -1 in case of error
1132 * -1 in case of error
1133 */
1134int
1135xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1136 xmlDictStringsPtr pool;
1137
1138 if ((dict == NULL) || (str == NULL))
1139 return(-1);
1140 pool = dict->strings;
1141 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001142 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001143 return(1);
1144 pool = pool->next;
1145 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001146 if (dict->subdict)
1147 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001148 return(0);
1149}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001150
Daniel Veillard81514ba2003-09-16 23:17:26 +00001151/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001152 * xmlDictSize:
1153 * @dict: the dictionnary
1154 *
1155 * Query the number of elements installed in the hash @dict.
1156 *
1157 * Returns the number of elements in the dictionnary or
1158 * -1 in case of error
1159 */
1160int
1161xmlDictSize(xmlDictPtr dict) {
1162 if (dict == NULL)
1163 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001164 if (dict->subdict)
1165 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001166 return(dict->nbElems);
1167}
1168
1169
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001170#define bottom_dict
1171#include "elfgcchack.h"