blob: ae4966bcac4f4097209cc0db350af29238050f86 [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
138/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000139 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000140 *
141 * Do the dictionary mutex initialization.
142 * this function is not thread safe, initialization should
143 * preferably be done once at startup
144 */
William M. Brack4e1c2db2005-02-11 10:58:55 +0000145static int xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000146 if (xmlDictInitialized)
147 return(1);
148
149 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
150 return(0);
151
Daniel Veillard8973d582012-02-04 19:07:44 +0800152#ifdef DICT_RANDOMIZATION
153 srand(time(NULL));
154#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000155 xmlDictInitialized = 1;
156 return(1);
157}
158
159/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000160 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000161 *
162 * Free the dictionary mutex.
163 */
164void
165xmlDictCleanup(void) {
166 if (!xmlDictInitialized)
167 return;
168
169 xmlFreeRMutex(xmlDictMutex);
170
171 xmlDictInitialized = 0;
172}
173
174/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000175 * xmlDictAddString:
176 * @dict: the dictionnary
177 * @name: the name of the userdata
178 * @len: the length of the name, if -1 it is recomputed
179 *
180 * Add the string to the array[s]
181 *
182 * Returns the pointer of the local string, or NULL in case of error.
183 */
184static const xmlChar *
185xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
186 xmlDictStringsPtr pool;
187 const xmlChar *ret;
188 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
189
Daniel Veillard424785e2008-08-06 09:35:25 +0000190#ifdef DICT_DEBUG_PATTERNS
191 fprintf(stderr, "-");
192#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000193 pool = dict->strings;
194 while (pool != NULL) {
195 if (pool->end - pool->free > namelen)
196 goto found_pool;
197 if (pool->size > size) size = pool->size;
198 pool = pool->next;
199 }
200 /*
201 * Not found, need to allocate
202 */
203 if (pool == NULL) {
204 if (size == 0) size = 1000;
205 else size *= 4; /* exponential growth */
206 if (size < 4 * namelen)
207 size = 4 * namelen; /* just in case ! */
208 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
209 if (pool == NULL)
210 return(NULL);
211 pool->size = size;
212 pool->nbStrings = 0;
213 pool->free = &pool->array[0];
214 pool->end = &pool->array[size];
215 pool->next = dict->strings;
216 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000217#ifdef DICT_DEBUG_PATTERNS
218 fprintf(stderr, "+");
219#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000220 }
221found_pool:
222 ret = pool->free;
223 memcpy(pool->free, name, namelen);
224 pool->free += namelen;
225 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000226 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000227 return(ret);
228}
229
230/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000231 * xmlDictAddQString:
232 * @dict: the dictionnary
233 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000234 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000235 * @name: the name of the userdata
236 * @len: the length of the name, if -1 it is recomputed
237 *
238 * Add the QName to the array[s]
239 *
240 * Returns the pointer of the local string, or NULL in case of error.
241 */
242static const xmlChar *
Daniel Veillardffda65f2008-08-07 16:33:49 +0000243xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
Daniel Veillarde72c5082003-09-19 12:44:05 +0000244 const xmlChar *name, int namelen)
245{
246 xmlDictStringsPtr pool;
247 const xmlChar *ret;
248 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000249
250 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000251
Daniel Veillard424785e2008-08-06 09:35:25 +0000252#ifdef DICT_DEBUG_PATTERNS
253 fprintf(stderr, "=");
254#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000255 pool = dict->strings;
256 while (pool != NULL) {
Daniel Veillardffda65f2008-08-07 16:33:49 +0000257 if (pool->end - pool->free > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000258 goto found_pool;
259 if (pool->size > size) size = pool->size;
260 pool = pool->next;
261 }
262 /*
263 * Not found, need to allocate
264 */
265 if (pool == NULL) {
266 if (size == 0) size = 1000;
267 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000268 if (size < 4 * (namelen + plen + 1))
269 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000270 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
271 if (pool == NULL)
272 return(NULL);
273 pool->size = size;
274 pool->nbStrings = 0;
275 pool->free = &pool->array[0];
276 pool->end = &pool->array[size];
277 pool->next = dict->strings;
278 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000279#ifdef DICT_DEBUG_PATTERNS
280 fprintf(stderr, "+");
281#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000282 }
283found_pool:
284 ret = pool->free;
285 memcpy(pool->free, prefix, plen);
286 pool->free += plen;
287 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000288 memcpy(pool->free, name, namelen);
289 pool->free += namelen;
290 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000291 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000292 return(ret);
293}
294
Daniel Veillard424785e2008-08-06 09:35:25 +0000295#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000296/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000297 * xmlDictComputeBigKey:
298 *
299 * Calculate a hash key using a good hash function that works well for
300 * larger hash table sizes.
301 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000302 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000303 * http://burtleburtle.net/bob/hash/doobs.html
304 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000305
306static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800307xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000308 uint32_t hash;
309 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000310
Daniel Veillard424785e2008-08-06 09:35:25 +0000311 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000312
Daniel Veillard8973d582012-02-04 19:07:44 +0800313 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000314
Daniel Veillard424785e2008-08-06 09:35:25 +0000315 for (i = 0;i < namelen; i++) {
316 hash += data[i];
317 hash += (hash << 10);
318 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000319 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000320 hash += (hash << 3);
321 hash ^= (hash >> 11);
322 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000323
324 return hash;
325}
326
327/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000328 * xmlDictComputeBigQKey:
329 *
330 * Calculate a hash key for two strings using a good hash function
331 * that works well for larger hash table sizes.
332 *
333 * Hash function by "One-at-a-Time Hash" see
334 * http://burtleburtle.net/bob/hash/doobs.html
335 *
336 * Neither of the two strings must be NULL.
337 */
338static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000339xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800340 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000341{
342 uint32_t hash;
343 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000344
Daniel Veillard8973d582012-02-04 19:07:44 +0800345 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000346
347 for (i = 0;i < plen; i++) {
348 hash += prefix[i];
349 hash += (hash << 10);
350 hash ^= (hash >> 6);
351 }
352 hash += ':';
353 hash += (hash << 10);
354 hash ^= (hash >> 6);
355
356 for (i = 0;i < len; i++) {
357 hash += name[i];
358 hash += (hash << 10);
359 hash ^= (hash >> 6);
360 }
361 hash += (hash << 3);
362 hash ^= (hash >> 11);
363 hash += (hash << 15);
364
365 return hash;
366}
367#endif /* WITH_BIG_KEY */
368
369/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000370 * xmlDictComputeFastKey:
371 *
372 * Calculate a hash key using a fast hash function that works well
373 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000374 */
375static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800376xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
377 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000378
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000379 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000380 value = *name;
381 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000382 if (namelen > 10) {
383 value += name[namelen - 1];
384 namelen = 10;
385 }
386 switch (namelen) {
387 case 10: value += name[9];
388 case 9: value += name[8];
389 case 8: value += name[7];
390 case 7: value += name[6];
391 case 6: value += name[5];
392 case 5: value += name[4];
393 case 4: value += name[3];
394 case 3: value += name[2];
395 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000396 default: break;
397 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000398 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000399}
400
401/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000402 * xmlDictComputeFastQKey:
403 *
404 * Calculate a hash key for two strings using a fast hash function
405 * that works well for low hash table fill.
406 *
407 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000408 */
409static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000410xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800411 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000412{
Daniel Veillard8973d582012-02-04 19:07:44 +0800413 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000414
Daniel Veillarde72c5082003-09-19 12:44:05 +0000415 if (plen == 0)
416 value += 30 * (unsigned long) ':';
417 else
418 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000419
Daniel Veillarde72c5082003-09-19 12:44:05 +0000420 if (len > 10) {
421 value += name[len - (plen + 1 + 1)];
422 len = 10;
423 if (plen > 10)
424 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000425 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000426 switch (plen) {
427 case 10: value += prefix[9];
428 case 9: value += prefix[8];
429 case 8: value += prefix[7];
430 case 7: value += prefix[6];
431 case 6: value += prefix[5];
432 case 5: value += prefix[4];
433 case 4: value += prefix[3];
434 case 3: value += prefix[2];
435 case 2: value += prefix[1];
436 case 1: value += prefix[0];
437 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000438 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000439 len -= plen;
440 if (len > 0) {
441 value += (unsigned long) ':';
442 len--;
443 }
444 switch (len) {
445 case 10: value += name[9];
446 case 9: value += name[8];
447 case 8: value += name[7];
448 case 7: value += name[6];
449 case 6: value += name[5];
450 case 5: value += name[4];
451 case 4: value += name[3];
452 case 3: value += name[2];
453 case 2: value += name[1];
454 case 1: value += name[0];
455 default: break;
456 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000457 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000458}
459
460/**
461 * xmlDictCreate:
462 *
463 * Create a new dictionary
464 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000465 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000466 */
467xmlDictPtr
468xmlDictCreate(void) {
469 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000470
471 if (!xmlDictInitialized)
472 if (!xmlInitializeDict())
473 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000474
475#ifdef DICT_DEBUG_PATTERNS
476 fprintf(stderr, "C");
477#endif
478
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000479 dict = xmlMalloc(sizeof(xmlDict));
480 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000481 dict->ref_counter = 1;
482
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000483 dict->size = MIN_DICT_SIZE;
484 dict->nbElems = 0;
485 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000486 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000487 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000488 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000489 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800490#ifdef DICT_RANDOMIZATION
491 dict->seed = rand();
492#else
493 dict->seed = 0;
494#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000495 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000496 }
497 xmlFree(dict);
498 }
499 return(NULL);
500}
501
502/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000503 * xmlDictCreateSub:
504 * @sub: an existing dictionnary
505 *
506 * Create a new dictionary, inheriting strings from the read-only
507 * dictionnary @sub. On lookup, strings are first searched in the
508 * new dictionnary, then in @sub, and if not found are created in the
509 * new dictionnary.
510 *
511 * Returns the newly created dictionnary, or NULL if an error occured.
512 */
513xmlDictPtr
514xmlDictCreateSub(xmlDictPtr sub) {
515 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000516
Daniel Veillard4773df22004-01-23 13:15:13 +0000517 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000518#ifdef DICT_DEBUG_PATTERNS
519 fprintf(stderr, "R");
520#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800521 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000522 dict->subdict = sub;
523 xmlDictReference(dict->subdict);
524 }
525 return(dict);
526}
527
528/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000529 * xmlDictReference:
530 * @dict: the dictionnary
531 *
532 * Increment the reference counter of a dictionary
533 *
534 * Returns 0 in case of success and -1 in case of error
535 */
536int
537xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000538 if (!xmlDictInitialized)
539 if (!xmlInitializeDict())
540 return(-1);
541
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000542 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000543 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000544 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000545 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000546 return(0);
547}
548
549/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000550 * xmlDictGrow:
551 * @dict: the dictionnary
552 * @size: the new size of the dictionnary
553 *
554 * resize the dictionnary
555 *
556 * Returns 0 in case of success, -1 in case of failure
557 */
558static int
559xmlDictGrow(xmlDictPtr dict, int size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000560 unsigned long key, okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000561 int oldsize, i;
562 xmlDictEntryPtr iter, next;
563 struct _xmlDictEntry *olddict;
564#ifdef DEBUG_GROW
565 unsigned long nbElem = 0;
566#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000567 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000568 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000569
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000570 if (dict == NULL)
571 return(-1);
572 if (size < 8)
573 return(-1);
574 if (size > 8 * 2048)
575 return(-1);
576
Daniel Veillard424785e2008-08-06 09:35:25 +0000577#ifdef DICT_DEBUG_PATTERNS
578 fprintf(stderr, "*");
579#endif
580
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000581 oldsize = dict->size;
582 olddict = dict->dict;
583 if (olddict == NULL)
584 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000585 if (oldsize == MIN_DICT_SIZE)
586 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000587
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000588 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
589 if (dict->dict == NULL) {
590 dict->dict = olddict;
591 return(-1);
592 }
593 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
594 dict->size = size;
595
596 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000597 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000598 the main dict. It is nicer to run through the array twice, first
599 copying all the elements in the main array (less probability of
600 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000601 */
602 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000603 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000604 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000605
606 if (keep_keys)
607 okey = olddict[i].okey;
608 else
609 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
610 key = okey % dict->size;
611
Daniel Veillardffda65f2008-08-07 16:33:49 +0000612 if (dict->dict[key].valid == 0) {
613 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
614 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000615 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000616 } else {
617 xmlDictEntryPtr entry;
618
619 entry = xmlMalloc(sizeof(xmlDictEntry));
620 if (entry != NULL) {
621 entry->name = olddict[i].name;
622 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000623 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000624 entry->next = dict->dict[key].next;
625 entry->valid = 1;
626 dict->dict[key].next = entry;
627 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000628 /*
629 * we don't have much ways to alert from herei
630 * result is loosing an entry and unicity garantee
631 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000632 ret = -1;
633 }
634 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000635#ifdef DEBUG_GROW
636 nbElem++;
637#endif
638 }
639
640 for (i = 0; i < oldsize; i++) {
641 iter = olddict[i].next;
642 while (iter) {
643 next = iter->next;
644
645 /*
646 * put back the entry in the new dict
647 */
648
Daniel Veillardd68f8912008-08-08 10:09:19 +0000649 if (keep_keys)
650 okey = iter->okey;
651 else
652 okey = xmlDictComputeKey(dict, iter->name, iter->len);
653 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000654 if (dict->dict[key].valid == 0) {
655 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
656 dict->dict[key].next = NULL;
657 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000658 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000659 xmlFree(iter);
660 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000661 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000662 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000663 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000664 }
665
666#ifdef DEBUG_GROW
667 nbElem++;
668#endif
669
670 iter = next;
671 }
672 }
673
674 xmlFree(olddict);
675
676#ifdef DEBUG_GROW
677 xmlGenericError(xmlGenericErrorContext,
678 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
679#endif
680
Daniel Veillardffda65f2008-08-07 16:33:49 +0000681 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000682}
683
684/**
685 * xmlDictFree:
686 * @dict: the dictionnary
687 *
688 * Free the hash @dict and its contents. The userdata is
689 * deallocated with @f if provided.
690 */
691void
692xmlDictFree(xmlDictPtr dict) {
693 int i;
694 xmlDictEntryPtr iter;
695 xmlDictEntryPtr next;
696 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000697 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000698
699 if (dict == NULL)
700 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000701
Daniel Veillard14412512005-01-21 23:53:26 +0000702 if (!xmlDictInitialized)
703 if (!xmlInitializeDict())
704 return;
705
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000706 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000707 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000708 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000709 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000710 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000711 return;
712 }
713
Daniel Veillard14412512005-01-21 23:53:26 +0000714 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000715
Daniel Veillard4773df22004-01-23 13:15:13 +0000716 if (dict->subdict != NULL) {
717 xmlDictFree(dict->subdict);
718 }
719
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000720 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000721 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000722 iter = &(dict->dict[i]);
723 if (iter->valid == 0)
724 continue;
725 inside_dict = 1;
726 while (iter) {
727 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000728 if (!inside_dict)
729 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000730 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000731 inside_dict = 0;
732 iter = next;
733 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000734 }
735 xmlFree(dict->dict);
736 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000737 pool = dict->strings;
738 while (pool != NULL) {
739 nextp = pool->next;
740 xmlFree(pool);
741 pool = nextp;
742 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000743 xmlFree(dict);
744}
745
746/**
747 * xmlDictLookup:
748 * @dict: the dictionnary
749 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000750 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000751 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000752 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000753 *
754 * Returns the internal copy of the name or NULL in case of internal error
755 */
756const xmlChar *
757xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000758 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000759 xmlDictEntryPtr entry;
760 xmlDictEntryPtr insert;
761 const xmlChar *ret;
762
Daniel Veillard0fb18932003-09-07 09:14:37 +0000763 if ((dict == NULL) || (name == NULL))
764 return(NULL);
765
766 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000767 len = strlen((const char *) name);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000768
769 /*
770 * Check for duplicate and insertion location.
771 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000772 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard4773df22004-01-23 13:15:13 +0000773 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000774 if (dict->dict[key].valid == 0) {
775 insert = NULL;
776 } else {
777 for (insert = &(dict->dict[key]); insert->next != NULL;
778 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000779#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000780 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000781 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000782 return(insert->name);
783 }
784#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000785 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000786 (!xmlStrncmp(insert->name, name, len)))
787 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000788#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000789 nbi++;
790 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000791#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000792 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000793 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000794 return(insert->name);
795 }
796#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000797 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000798 (!xmlStrncmp(insert->name, name, len)))
799 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000800#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000801 }
802
Daniel Veillard4773df22004-01-23 13:15:13 +0000803 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000804 unsigned long skey;
805
806 /* we cannot always reuse the same okey for the subdict */
807 if (((dict->size == MIN_DICT_SIZE) &&
808 (dict->subdict->size != MIN_DICT_SIZE)) ||
809 ((dict->size != MIN_DICT_SIZE) &&
810 (dict->subdict->size == MIN_DICT_SIZE)))
811 skey = xmlDictComputeKey(dict->subdict, name, len);
812 else
813 skey = okey;
814
815 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000816 if (dict->subdict->dict[key].valid != 0) {
817 xmlDictEntryPtr tmp;
818
819 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
820 tmp = tmp->next) {
821#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000822 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000823 if (!memcmp(tmp->name, name, len))
824 return(tmp->name);
825 }
826#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000827 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000828 (!xmlStrncmp(tmp->name, name, len)))
829 return(tmp->name);
830#endif
831 nbi++;
832 }
833#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000834 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000835 if (!memcmp(tmp->name, name, len))
836 return(tmp->name);
837 }
838#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000839 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000840 (!xmlStrncmp(tmp->name, name, len)))
841 return(tmp->name);
842#endif
843 }
844 key = okey % dict->size;
845 }
846
Daniel Veillard81514ba2003-09-16 23:17:26 +0000847 ret = xmlDictAddString(dict, name, len);
848 if (ret == NULL)
849 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000850 if (insert == NULL) {
851 entry = &(dict->dict[key]);
852 } else {
853 entry = xmlMalloc(sizeof(xmlDictEntry));
854 if (entry == NULL)
855 return(NULL);
856 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000857 entry->name = ret;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000858 entry->len = len;
859 entry->next = NULL;
860 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000861 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000862
863
864 if (insert != NULL)
865 insert->next = entry;
866
867 dict->nbElems++;
868
869 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000870 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
871 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
872 return(NULL);
873 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000874 /* Note that entry may have been freed at this point by xmlDictGrow */
875
876 return(ret);
877}
878
879/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000880 * xmlDictExists:
881 * @dict: the dictionnary
882 * @name: the name of the userdata
883 * @len: the length of the name, if -1 it is recomputed
884 *
885 * Check if the @name exists in the dictionnary @dict.
886 *
887 * Returns the internal copy of the name or NULL if not found.
888 */
889const xmlChar *
890xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
891 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000892 xmlDictEntryPtr insert;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000893
894 if ((dict == NULL) || (name == NULL))
895 return(NULL);
896
897 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000898 len = strlen((const char *) name);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000899
900 /*
901 * Check for duplicate and insertion location.
902 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000903 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000904 key = okey % dict->size;
905 if (dict->dict[key].valid == 0) {
906 insert = NULL;
907 } else {
908 for (insert = &(dict->dict[key]); insert->next != NULL;
909 insert = insert->next) {
910#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000911 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000912 if (!memcmp(insert->name, name, len))
913 return(insert->name);
914 }
915#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000916 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000917 (!xmlStrncmp(insert->name, name, len)))
918 return(insert->name);
919#endif
920 nbi++;
921 }
922#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000923 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000924 if (!memcmp(insert->name, name, len))
925 return(insert->name);
926 }
927#else
Rob Richards117baa02008-08-10 17:07:33 +0000928 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000929 (!xmlStrncmp(insert->name, name, len)))
930 return(insert->name);
931#endif
932 }
933
934 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000935 unsigned long skey;
936
937 /* we cannot always reuse the same okey for the subdict */
938 if (((dict->size == MIN_DICT_SIZE) &&
939 (dict->subdict->size != MIN_DICT_SIZE)) ||
940 ((dict->size != MIN_DICT_SIZE) &&
941 (dict->subdict->size == MIN_DICT_SIZE)))
942 skey = xmlDictComputeKey(dict->subdict, name, len);
943 else
944 skey = okey;
945
946 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000947 if (dict->subdict->dict[key].valid != 0) {
948 xmlDictEntryPtr tmp;
949
950 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
951 tmp = tmp->next) {
952#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000953 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000954 if (!memcmp(tmp->name, name, len))
955 return(tmp->name);
956 }
957#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000958 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000959 (!xmlStrncmp(tmp->name, name, len)))
960 return(tmp->name);
961#endif
962 nbi++;
963 }
964#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000965 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000966 if (!memcmp(tmp->name, name, len))
967 return(tmp->name);
968 }
969#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000970 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000971 (!xmlStrncmp(tmp->name, name, len)))
972 return(tmp->name);
973#endif
974 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000975 }
976
977 /* not found */
978 return(NULL);
979}
980
981/**
Daniel Veillarde72c5082003-09-19 12:44:05 +0000982 * xmlDictQLookup:
983 * @dict: the dictionnary
Daniel Veillardd68f8912008-08-08 10:09:19 +0000984 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +0000985 * @name: the name
986 *
987 * Add the QName @prefix:@name to the hash @dict if not present.
988 *
989 * Returns the internal copy of the QName or NULL in case of internal error
990 */
991const xmlChar *
992xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000993 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000994 xmlDictEntryPtr entry;
995 xmlDictEntryPtr insert;
996 const xmlChar *ret;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000997 int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000998
999 if ((dict == NULL) || (name == NULL))
1000 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001001 if (prefix == NULL)
1002 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001003
Daniel Veillardffda65f2008-08-07 16:33:49 +00001004 l = len = strlen((const char *) name);
1005 plen = strlen((const char *) prefix);
1006 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001007
1008 /*
1009 * Check for duplicate and insertion location.
1010 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001011 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001012 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001013 if (dict->dict[key].valid == 0) {
1014 insert = NULL;
1015 } else {
1016 for (insert = &(dict->dict[key]); insert->next != NULL;
1017 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001018 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001019 (xmlStrQEqual(prefix, name, insert->name)))
1020 return(insert->name);
1021 nbi++;
1022 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001023 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001024 (xmlStrQEqual(prefix, name, insert->name)))
1025 return(insert->name);
1026 }
1027
Daniel Veillard4773df22004-01-23 13:15:13 +00001028 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001029 unsigned long skey;
1030
1031 /* we cannot always reuse the same okey for the subdict */
1032 if (((dict->size == MIN_DICT_SIZE) &&
1033 (dict->subdict->size != MIN_DICT_SIZE)) ||
1034 ((dict->size != MIN_DICT_SIZE) &&
1035 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001036 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001037 else
1038 skey = okey;
1039
1040 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001041 if (dict->subdict->dict[key].valid != 0) {
1042 xmlDictEntryPtr tmp;
1043 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1044 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001045 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001046 (xmlStrQEqual(prefix, name, tmp->name)))
1047 return(tmp->name);
1048 nbi++;
1049 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001050 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001051 (xmlStrQEqual(prefix, name, tmp->name)))
1052 return(tmp->name);
1053 }
1054 key = okey % dict->size;
1055 }
1056
Daniel Veillardffda65f2008-08-07 16:33:49 +00001057 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001058 if (ret == NULL)
1059 return(NULL);
1060 if (insert == NULL) {
1061 entry = &(dict->dict[key]);
1062 } else {
1063 entry = xmlMalloc(sizeof(xmlDictEntry));
1064 if (entry == NULL)
1065 return(NULL);
1066 }
1067 entry->name = ret;
1068 entry->len = len;
1069 entry->next = NULL;
1070 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001071 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001072
1073 if (insert != NULL)
1074 insert->next = entry;
1075
1076 dict->nbElems++;
1077
1078 if ((nbi > MAX_HASH_LEN) &&
1079 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1080 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1081 /* Note that entry may have been freed at this point by xmlDictGrow */
1082
1083 return(ret);
1084}
1085
1086/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001087 * xmlDictOwns:
1088 * @dict: the dictionnary
1089 * @str: the string
1090 *
1091 * check if a string is owned by the disctionary
1092 *
1093 * Returns 1 if true, 0 if false and -1 in case of error
1094 * -1 in case of error
1095 */
1096int
1097xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1098 xmlDictStringsPtr pool;
1099
1100 if ((dict == NULL) || (str == NULL))
1101 return(-1);
1102 pool = dict->strings;
1103 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001104 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001105 return(1);
1106 pool = pool->next;
1107 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001108 if (dict->subdict)
1109 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001110 return(0);
1111}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001112
Daniel Veillard81514ba2003-09-16 23:17:26 +00001113/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001114 * xmlDictSize:
1115 * @dict: the dictionnary
1116 *
1117 * Query the number of elements installed in the hash @dict.
1118 *
1119 * Returns the number of elements in the dictionnary or
1120 * -1 in case of error
1121 */
1122int
1123xmlDictSize(xmlDictPtr dict) {
1124 if (dict == NULL)
1125 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001126 if (dict->subdict)
1127 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001128 return(dict->nbElems);
1129}
1130
1131
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001132#define bottom_dict
1133#include "elfgcchack.h"