blob: 3579f64d1db0696376426704d7471eec101edea9 [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
153 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800154int xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000155 if (xmlDictInitialized)
156 return(1);
157
158 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
159 return(0);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800160 xmlRMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000161
Daniel Veillard8973d582012-02-04 19:07:44 +0800162#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800163#ifdef HAVE_RAND_R
164 rand_seed = time(NULL);
165 rand_r(& rand_seed);
166#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800167 srand(time(NULL));
168#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800169#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000170 xmlDictInitialized = 1;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800171 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000172 return(1);
173}
174
Daniel Veillard379ebc12012-05-18 15:41:31 +0800175#ifdef DICT_RANDOMIZATION
176int __xmlRandom(void) {
177 int ret;
178
179 if (xmlDictInitialized == 0)
180 xmlInitializeDict();
181
182 xmlRMutexLock(xmlDictMutex);
183#ifdef HAVE_RAND_R
184 ret = rand_r(& rand_seed);
185#else
186 ret = rand();
187#endif
188 xmlRMutexUnlock(xmlDictMutex);
189 return(ret);
190}
191#endif
192
Daniel Veillard14412512005-01-21 23:53:26 +0000193/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000194 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000195 *
Daniel Veillard379ebc12012-05-18 15:41:31 +0800196 * Free the dictionary mutex. Do not call unless sure the library
197 * is not in use anymore !
Daniel Veillard14412512005-01-21 23:53:26 +0000198 */
199void
200xmlDictCleanup(void) {
201 if (!xmlDictInitialized)
202 return;
203
204 xmlFreeRMutex(xmlDictMutex);
205
206 xmlDictInitialized = 0;
207}
208
209/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000210 * xmlDictAddString:
211 * @dict: the dictionnary
212 * @name: the name of the userdata
213 * @len: the length of the name, if -1 it is recomputed
214 *
215 * Add the string to the array[s]
216 *
217 * Returns the pointer of the local string, or NULL in case of error.
218 */
219static const xmlChar *
220xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
221 xmlDictStringsPtr pool;
222 const xmlChar *ret;
223 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
224
Daniel Veillard424785e2008-08-06 09:35:25 +0000225#ifdef DICT_DEBUG_PATTERNS
226 fprintf(stderr, "-");
227#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000228 pool = dict->strings;
229 while (pool != NULL) {
230 if (pool->end - pool->free > namelen)
231 goto found_pool;
232 if (pool->size > size) size = pool->size;
233 pool = pool->next;
234 }
235 /*
236 * Not found, need to allocate
237 */
238 if (pool == NULL) {
239 if (size == 0) size = 1000;
240 else size *= 4; /* exponential growth */
241 if (size < 4 * namelen)
242 size = 4 * namelen; /* just in case ! */
243 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
244 if (pool == NULL)
245 return(NULL);
246 pool->size = size;
247 pool->nbStrings = 0;
248 pool->free = &pool->array[0];
249 pool->end = &pool->array[size];
250 pool->next = dict->strings;
251 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000252#ifdef DICT_DEBUG_PATTERNS
253 fprintf(stderr, "+");
254#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000255 }
256found_pool:
257 ret = pool->free;
258 memcpy(pool->free, name, namelen);
259 pool->free += namelen;
260 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000261 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000262 return(ret);
263}
264
265/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000266 * xmlDictAddQString:
267 * @dict: the dictionnary
268 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000269 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000270 * @name: the name of the userdata
271 * @len: the length of the name, if -1 it is recomputed
272 *
273 * Add the QName to the array[s]
274 *
275 * Returns the pointer of the local string, or NULL in case of error.
276 */
277static const xmlChar *
Daniel Veillardffda65f2008-08-07 16:33:49 +0000278xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
Daniel Veillarde72c5082003-09-19 12:44:05 +0000279 const xmlChar *name, int namelen)
280{
281 xmlDictStringsPtr pool;
282 const xmlChar *ret;
283 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000284
285 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000286
Daniel Veillard424785e2008-08-06 09:35:25 +0000287#ifdef DICT_DEBUG_PATTERNS
288 fprintf(stderr, "=");
289#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000290 pool = dict->strings;
291 while (pool != NULL) {
Daniel Veillardffda65f2008-08-07 16:33:49 +0000292 if (pool->end - pool->free > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000293 goto found_pool;
294 if (pool->size > size) size = pool->size;
295 pool = pool->next;
296 }
297 /*
298 * Not found, need to allocate
299 */
300 if (pool == NULL) {
301 if (size == 0) size = 1000;
302 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000303 if (size < 4 * (namelen + plen + 1))
304 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000305 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
306 if (pool == NULL)
307 return(NULL);
308 pool->size = size;
309 pool->nbStrings = 0;
310 pool->free = &pool->array[0];
311 pool->end = &pool->array[size];
312 pool->next = dict->strings;
313 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000314#ifdef DICT_DEBUG_PATTERNS
315 fprintf(stderr, "+");
316#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000317 }
318found_pool:
319 ret = pool->free;
320 memcpy(pool->free, prefix, plen);
321 pool->free += plen;
322 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000323 memcpy(pool->free, name, namelen);
324 pool->free += namelen;
325 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000326 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000327 return(ret);
328}
329
Daniel Veillard424785e2008-08-06 09:35:25 +0000330#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000331/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000332 * xmlDictComputeBigKey:
333 *
334 * Calculate a hash key using a good hash function that works well for
335 * larger hash table sizes.
336 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000337 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000338 * http://burtleburtle.net/bob/hash/doobs.html
339 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000340
341static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800342xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000343 uint32_t hash;
344 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000345
Daniel Veillard424785e2008-08-06 09:35:25 +0000346 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000347
Daniel Veillard8973d582012-02-04 19:07:44 +0800348 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000349
Daniel Veillard424785e2008-08-06 09:35:25 +0000350 for (i = 0;i < namelen; i++) {
351 hash += data[i];
352 hash += (hash << 10);
353 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000354 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000355 hash += (hash << 3);
356 hash ^= (hash >> 11);
357 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000358
359 return hash;
360}
361
362/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000363 * xmlDictComputeBigQKey:
364 *
365 * Calculate a hash key for two strings using a good hash function
366 * that works well for larger hash table sizes.
367 *
368 * Hash function by "One-at-a-Time Hash" see
369 * http://burtleburtle.net/bob/hash/doobs.html
370 *
371 * Neither of the two strings must be NULL.
372 */
373static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000374xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800375 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000376{
377 uint32_t hash;
378 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000379
Daniel Veillard8973d582012-02-04 19:07:44 +0800380 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000381
382 for (i = 0;i < plen; i++) {
383 hash += prefix[i];
384 hash += (hash << 10);
385 hash ^= (hash >> 6);
386 }
387 hash += ':';
388 hash += (hash << 10);
389 hash ^= (hash >> 6);
390
391 for (i = 0;i < len; i++) {
392 hash += name[i];
393 hash += (hash << 10);
394 hash ^= (hash >> 6);
395 }
396 hash += (hash << 3);
397 hash ^= (hash >> 11);
398 hash += (hash << 15);
399
400 return hash;
401}
402#endif /* WITH_BIG_KEY */
403
404/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000405 * xmlDictComputeFastKey:
406 *
407 * Calculate a hash key using a fast hash function that works well
408 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000409 */
410static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800411xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
412 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000413
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000414 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000415 value = *name;
416 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000417 if (namelen > 10) {
418 value += name[namelen - 1];
419 namelen = 10;
420 }
421 switch (namelen) {
422 case 10: value += name[9];
423 case 9: value += name[8];
424 case 8: value += name[7];
425 case 7: value += name[6];
426 case 6: value += name[5];
427 case 5: value += name[4];
428 case 4: value += name[3];
429 case 3: value += name[2];
430 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000431 default: break;
432 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000433 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000434}
435
436/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000437 * xmlDictComputeFastQKey:
438 *
439 * Calculate a hash key for two strings using a fast hash function
440 * that works well for low hash table fill.
441 *
442 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000443 */
444static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000445xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800446 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000447{
Daniel Veillard8973d582012-02-04 19:07:44 +0800448 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000449
Daniel Veillarde72c5082003-09-19 12:44:05 +0000450 if (plen == 0)
451 value += 30 * (unsigned long) ':';
452 else
453 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000454
Daniel Veillarde72c5082003-09-19 12:44:05 +0000455 if (len > 10) {
456 value += name[len - (plen + 1 + 1)];
457 len = 10;
458 if (plen > 10)
459 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000460 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000461 switch (plen) {
462 case 10: value += prefix[9];
463 case 9: value += prefix[8];
464 case 8: value += prefix[7];
465 case 7: value += prefix[6];
466 case 6: value += prefix[5];
467 case 5: value += prefix[4];
468 case 4: value += prefix[3];
469 case 3: value += prefix[2];
470 case 2: value += prefix[1];
471 case 1: value += prefix[0];
472 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000473 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000474 len -= plen;
475 if (len > 0) {
476 value += (unsigned long) ':';
477 len--;
478 }
479 switch (len) {
480 case 10: value += name[9];
481 case 9: value += name[8];
482 case 8: value += name[7];
483 case 7: value += name[6];
484 case 6: value += name[5];
485 case 5: value += name[4];
486 case 4: value += name[3];
487 case 3: value += name[2];
488 case 2: value += name[1];
489 case 1: value += name[0];
490 default: break;
491 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000492 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000493}
494
495/**
496 * xmlDictCreate:
497 *
498 * Create a new dictionary
499 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000500 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000501 */
502xmlDictPtr
503xmlDictCreate(void) {
504 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000505
506 if (!xmlDictInitialized)
507 if (!xmlInitializeDict())
508 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000509
510#ifdef DICT_DEBUG_PATTERNS
511 fprintf(stderr, "C");
512#endif
513
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000514 dict = xmlMalloc(sizeof(xmlDict));
515 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000516 dict->ref_counter = 1;
517
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000518 dict->size = MIN_DICT_SIZE;
519 dict->nbElems = 0;
520 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000521 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000522 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000523 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000524 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800525#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800526 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800527#else
528 dict->seed = 0;
529#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000530 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000531 }
532 xmlFree(dict);
533 }
534 return(NULL);
535}
536
537/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000538 * xmlDictCreateSub:
539 * @sub: an existing dictionnary
540 *
541 * Create a new dictionary, inheriting strings from the read-only
542 * dictionnary @sub. On lookup, strings are first searched in the
543 * new dictionnary, then in @sub, and if not found are created in the
544 * new dictionnary.
545 *
546 * Returns the newly created dictionnary, or NULL if an error occured.
547 */
548xmlDictPtr
549xmlDictCreateSub(xmlDictPtr sub) {
550 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000551
Daniel Veillard4773df22004-01-23 13:15:13 +0000552 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000553#ifdef DICT_DEBUG_PATTERNS
554 fprintf(stderr, "R");
555#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800556 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000557 dict->subdict = sub;
558 xmlDictReference(dict->subdict);
559 }
560 return(dict);
561}
562
563/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000564 * xmlDictReference:
565 * @dict: the dictionnary
566 *
567 * Increment the reference counter of a dictionary
568 *
569 * Returns 0 in case of success and -1 in case of error
570 */
571int
572xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000573 if (!xmlDictInitialized)
574 if (!xmlInitializeDict())
575 return(-1);
576
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000577 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000578 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000579 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000580 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000581 return(0);
582}
583
584/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000585 * xmlDictGrow:
586 * @dict: the dictionnary
587 * @size: the new size of the dictionnary
588 *
589 * resize the dictionnary
590 *
591 * Returns 0 in case of success, -1 in case of failure
592 */
593static int
594xmlDictGrow(xmlDictPtr dict, int size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000595 unsigned long key, okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000596 int oldsize, i;
597 xmlDictEntryPtr iter, next;
598 struct _xmlDictEntry *olddict;
599#ifdef DEBUG_GROW
600 unsigned long nbElem = 0;
601#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000602 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000603 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000604
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000605 if (dict == NULL)
606 return(-1);
607 if (size < 8)
608 return(-1);
609 if (size > 8 * 2048)
610 return(-1);
611
Daniel Veillard424785e2008-08-06 09:35:25 +0000612#ifdef DICT_DEBUG_PATTERNS
613 fprintf(stderr, "*");
614#endif
615
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000616 oldsize = dict->size;
617 olddict = dict->dict;
618 if (olddict == NULL)
619 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000620 if (oldsize == MIN_DICT_SIZE)
621 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000622
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000623 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
624 if (dict->dict == NULL) {
625 dict->dict = olddict;
626 return(-1);
627 }
628 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
629 dict->size = size;
630
631 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000632 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000633 the main dict. It is nicer to run through the array twice, first
634 copying all the elements in the main array (less probability of
635 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000636 */
637 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000638 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000639 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000640
641 if (keep_keys)
642 okey = olddict[i].okey;
643 else
644 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
645 key = okey % dict->size;
646
Daniel Veillardffda65f2008-08-07 16:33:49 +0000647 if (dict->dict[key].valid == 0) {
648 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
649 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000650 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000651 } else {
652 xmlDictEntryPtr entry;
653
654 entry = xmlMalloc(sizeof(xmlDictEntry));
655 if (entry != NULL) {
656 entry->name = olddict[i].name;
657 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000658 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000659 entry->next = dict->dict[key].next;
660 entry->valid = 1;
661 dict->dict[key].next = entry;
662 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000663 /*
664 * we don't have much ways to alert from herei
665 * result is loosing an entry and unicity garantee
666 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000667 ret = -1;
668 }
669 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000670#ifdef DEBUG_GROW
671 nbElem++;
672#endif
673 }
674
675 for (i = 0; i < oldsize; i++) {
676 iter = olddict[i].next;
677 while (iter) {
678 next = iter->next;
679
680 /*
681 * put back the entry in the new dict
682 */
683
Daniel Veillardd68f8912008-08-08 10:09:19 +0000684 if (keep_keys)
685 okey = iter->okey;
686 else
687 okey = xmlDictComputeKey(dict, iter->name, iter->len);
688 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000689 if (dict->dict[key].valid == 0) {
690 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
691 dict->dict[key].next = NULL;
692 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000693 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000694 xmlFree(iter);
695 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000696 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000697 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000698 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000699 }
700
701#ifdef DEBUG_GROW
702 nbElem++;
703#endif
704
705 iter = next;
706 }
707 }
708
709 xmlFree(olddict);
710
711#ifdef DEBUG_GROW
712 xmlGenericError(xmlGenericErrorContext,
713 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
714#endif
715
Daniel Veillardffda65f2008-08-07 16:33:49 +0000716 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000717}
718
719/**
720 * xmlDictFree:
721 * @dict: the dictionnary
722 *
723 * Free the hash @dict and its contents. The userdata is
724 * deallocated with @f if provided.
725 */
726void
727xmlDictFree(xmlDictPtr dict) {
728 int i;
729 xmlDictEntryPtr iter;
730 xmlDictEntryPtr next;
731 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000732 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000733
734 if (dict == NULL)
735 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000736
Daniel Veillard14412512005-01-21 23:53:26 +0000737 if (!xmlDictInitialized)
738 if (!xmlInitializeDict())
739 return;
740
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000741 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000742 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000743 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000744 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000745 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000746 return;
747 }
748
Daniel Veillard14412512005-01-21 23:53:26 +0000749 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000750
Daniel Veillard4773df22004-01-23 13:15:13 +0000751 if (dict->subdict != NULL) {
752 xmlDictFree(dict->subdict);
753 }
754
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000755 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000756 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000757 iter = &(dict->dict[i]);
758 if (iter->valid == 0)
759 continue;
760 inside_dict = 1;
761 while (iter) {
762 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000763 if (!inside_dict)
764 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000765 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000766 inside_dict = 0;
767 iter = next;
768 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000769 }
770 xmlFree(dict->dict);
771 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000772 pool = dict->strings;
773 while (pool != NULL) {
774 nextp = pool->next;
775 xmlFree(pool);
776 pool = nextp;
777 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000778 xmlFree(dict);
779}
780
781/**
782 * xmlDictLookup:
783 * @dict: the dictionnary
784 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000785 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000786 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000787 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000788 *
789 * Returns the internal copy of the name or NULL in case of internal error
790 */
791const xmlChar *
792xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000793 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000794 xmlDictEntryPtr entry;
795 xmlDictEntryPtr insert;
796 const xmlChar *ret;
797
Daniel Veillard0fb18932003-09-07 09:14:37 +0000798 if ((dict == NULL) || (name == NULL))
799 return(NULL);
800
801 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000802 len = strlen((const char *) name);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000803
804 /*
805 * Check for duplicate and insertion location.
806 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000807 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard4773df22004-01-23 13:15:13 +0000808 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000809 if (dict->dict[key].valid == 0) {
810 insert = NULL;
811 } else {
812 for (insert = &(dict->dict[key]); insert->next != NULL;
813 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000814#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000815 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000816 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000817 return(insert->name);
818 }
819#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000820 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000821 (!xmlStrncmp(insert->name, name, len)))
822 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000823#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000824 nbi++;
825 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000826#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000827 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000828 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000829 return(insert->name);
830 }
831#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000832 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000833 (!xmlStrncmp(insert->name, name, len)))
834 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000835#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000836 }
837
Daniel Veillard4773df22004-01-23 13:15:13 +0000838 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000839 unsigned long skey;
840
841 /* we cannot always reuse the same okey for the subdict */
842 if (((dict->size == MIN_DICT_SIZE) &&
843 (dict->subdict->size != MIN_DICT_SIZE)) ||
844 ((dict->size != MIN_DICT_SIZE) &&
845 (dict->subdict->size == MIN_DICT_SIZE)))
846 skey = xmlDictComputeKey(dict->subdict, name, len);
847 else
848 skey = okey;
849
850 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000851 if (dict->subdict->dict[key].valid != 0) {
852 xmlDictEntryPtr tmp;
853
854 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
855 tmp = tmp->next) {
856#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000857 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000858 if (!memcmp(tmp->name, name, len))
859 return(tmp->name);
860 }
861#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000862 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000863 (!xmlStrncmp(tmp->name, name, len)))
864 return(tmp->name);
865#endif
866 nbi++;
867 }
868#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000869 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000870 if (!memcmp(tmp->name, name, len))
871 return(tmp->name);
872 }
873#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000874 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000875 (!xmlStrncmp(tmp->name, name, len)))
876 return(tmp->name);
877#endif
878 }
879 key = okey % dict->size;
880 }
881
Daniel Veillard81514ba2003-09-16 23:17:26 +0000882 ret = xmlDictAddString(dict, name, len);
883 if (ret == NULL)
884 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000885 if (insert == NULL) {
886 entry = &(dict->dict[key]);
887 } else {
888 entry = xmlMalloc(sizeof(xmlDictEntry));
889 if (entry == NULL)
890 return(NULL);
891 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000892 entry->name = ret;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000893 entry->len = len;
894 entry->next = NULL;
895 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000896 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000897
898
899 if (insert != NULL)
900 insert->next = entry;
901
902 dict->nbElems++;
903
904 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000905 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
906 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
907 return(NULL);
908 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000909 /* Note that entry may have been freed at this point by xmlDictGrow */
910
911 return(ret);
912}
913
914/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000915 * xmlDictExists:
916 * @dict: the dictionnary
917 * @name: the name of the userdata
918 * @len: the length of the name, if -1 it is recomputed
919 *
920 * Check if the @name exists in the dictionnary @dict.
921 *
922 * Returns the internal copy of the name or NULL if not found.
923 */
924const xmlChar *
925xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
926 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000927 xmlDictEntryPtr insert;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000928
929 if ((dict == NULL) || (name == NULL))
930 return(NULL);
931
932 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000933 len = strlen((const char *) name);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000934
935 /*
936 * Check for duplicate and insertion location.
937 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000938 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000939 key = okey % dict->size;
940 if (dict->dict[key].valid == 0) {
941 insert = NULL;
942 } else {
943 for (insert = &(dict->dict[key]); insert->next != NULL;
944 insert = insert->next) {
945#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000946 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000947 if (!memcmp(insert->name, name, len))
948 return(insert->name);
949 }
950#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000951 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000952 (!xmlStrncmp(insert->name, name, len)))
953 return(insert->name);
954#endif
955 nbi++;
956 }
957#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000958 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000959 if (!memcmp(insert->name, name, len))
960 return(insert->name);
961 }
962#else
Rob Richards117baa02008-08-10 17:07:33 +0000963 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000964 (!xmlStrncmp(insert->name, name, len)))
965 return(insert->name);
966#endif
967 }
968
969 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000970 unsigned long skey;
971
972 /* we cannot always reuse the same okey for the subdict */
973 if (((dict->size == MIN_DICT_SIZE) &&
974 (dict->subdict->size != MIN_DICT_SIZE)) ||
975 ((dict->size != MIN_DICT_SIZE) &&
976 (dict->subdict->size == MIN_DICT_SIZE)))
977 skey = xmlDictComputeKey(dict->subdict, name, len);
978 else
979 skey = okey;
980
981 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000982 if (dict->subdict->dict[key].valid != 0) {
983 xmlDictEntryPtr tmp;
984
985 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
986 tmp = tmp->next) {
987#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000988 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000989 if (!memcmp(tmp->name, name, len))
990 return(tmp->name);
991 }
992#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000993 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000994 (!xmlStrncmp(tmp->name, name, len)))
995 return(tmp->name);
996#endif
997 nbi++;
998 }
999#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +00001000 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001001 if (!memcmp(tmp->name, name, len))
1002 return(tmp->name);
1003 }
1004#else
Daniel Veillardd68f8912008-08-08 10:09:19 +00001005 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001006 (!xmlStrncmp(tmp->name, name, len)))
1007 return(tmp->name);
1008#endif
1009 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001010 }
1011
1012 /* not found */
1013 return(NULL);
1014}
1015
1016/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001017 * xmlDictQLookup:
1018 * @dict: the dictionnary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001019 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001020 * @name: the name
1021 *
1022 * Add the QName @prefix:@name to the hash @dict if not present.
1023 *
1024 * Returns the internal copy of the QName or NULL in case of internal error
1025 */
1026const xmlChar *
1027xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001028 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001029 xmlDictEntryPtr entry;
1030 xmlDictEntryPtr insert;
1031 const xmlChar *ret;
Daniel Veillardffda65f2008-08-07 16:33:49 +00001032 int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001033
1034 if ((dict == NULL) || (name == NULL))
1035 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001036 if (prefix == NULL)
1037 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001038
Daniel Veillardffda65f2008-08-07 16:33:49 +00001039 l = len = strlen((const char *) name);
1040 plen = strlen((const char *) prefix);
1041 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001042
1043 /*
1044 * Check for duplicate and insertion location.
1045 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001046 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001047 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001048 if (dict->dict[key].valid == 0) {
1049 insert = NULL;
1050 } else {
1051 for (insert = &(dict->dict[key]); insert->next != NULL;
1052 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001053 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001054 (xmlStrQEqual(prefix, name, insert->name)))
1055 return(insert->name);
1056 nbi++;
1057 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001058 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001059 (xmlStrQEqual(prefix, name, insert->name)))
1060 return(insert->name);
1061 }
1062
Daniel Veillard4773df22004-01-23 13:15:13 +00001063 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001064 unsigned long skey;
1065
1066 /* we cannot always reuse the same okey for the subdict */
1067 if (((dict->size == MIN_DICT_SIZE) &&
1068 (dict->subdict->size != MIN_DICT_SIZE)) ||
1069 ((dict->size != MIN_DICT_SIZE) &&
1070 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001071 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001072 else
1073 skey = okey;
1074
1075 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001076 if (dict->subdict->dict[key].valid != 0) {
1077 xmlDictEntryPtr tmp;
1078 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1079 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001080 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001081 (xmlStrQEqual(prefix, name, tmp->name)))
1082 return(tmp->name);
1083 nbi++;
1084 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001085 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001086 (xmlStrQEqual(prefix, name, tmp->name)))
1087 return(tmp->name);
1088 }
1089 key = okey % dict->size;
1090 }
1091
Daniel Veillardffda65f2008-08-07 16:33:49 +00001092 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001093 if (ret == NULL)
1094 return(NULL);
1095 if (insert == NULL) {
1096 entry = &(dict->dict[key]);
1097 } else {
1098 entry = xmlMalloc(sizeof(xmlDictEntry));
1099 if (entry == NULL)
1100 return(NULL);
1101 }
1102 entry->name = ret;
1103 entry->len = len;
1104 entry->next = NULL;
1105 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001106 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001107
1108 if (insert != NULL)
1109 insert->next = entry;
1110
1111 dict->nbElems++;
1112
1113 if ((nbi > MAX_HASH_LEN) &&
1114 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1115 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1116 /* Note that entry may have been freed at this point by xmlDictGrow */
1117
1118 return(ret);
1119}
1120
1121/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001122 * xmlDictOwns:
1123 * @dict: the dictionnary
1124 * @str: the string
1125 *
1126 * check if a string is owned by the disctionary
1127 *
1128 * Returns 1 if true, 0 if false and -1 in case of error
1129 * -1 in case of error
1130 */
1131int
1132xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1133 xmlDictStringsPtr pool;
1134
1135 if ((dict == NULL) || (str == NULL))
1136 return(-1);
1137 pool = dict->strings;
1138 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001139 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001140 return(1);
1141 pool = pool->next;
1142 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001143 if (dict->subdict)
1144 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001145 return(0);
1146}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001147
Daniel Veillard81514ba2003-09-16 23:17:26 +00001148/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001149 * xmlDictSize:
1150 * @dict: the dictionnary
1151 *
1152 * Query the number of elements installed in the hash @dict.
1153 *
1154 * Returns the number of elements in the dictionnary or
1155 * -1 in case of error
1156 */
1157int
1158xmlDictSize(xmlDictPtr dict) {
1159 if (dict == NULL)
1160 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001161 if (dict->subdict)
1162 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001163 return(dict->nbElems);
1164}
1165
1166
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001167#define bottom_dict
1168#include "elfgcchack.h"