blob: 0ef3718da282f92d8115e70e875437db244663d7 [file] [log] [blame]
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001/*
2 * dict.c: dictionary of reusable strings, just used to avoid allocation
3 * and freeing operations.
4 *
Daniel Veillard8973d582012-02-04 19:07:44 +08005 * Copyright (C) 2003-2012 Daniel Veillard.
Daniel Veillard2fdbd322003-08-18 12:15:38 +00006 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 * Author: daniel@veillard.com
17 */
18
19#define IN_LIBXML
20#include "libxml.h"
21
Daniel Veillard7c693da2012-07-25 16:32:18 +080022#include <limits.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080023#ifdef HAVE_STDLIB_H
24#include <stdlib.h>
25#endif
26#ifdef HAVE_TIME_H
27#include <time.h>
28#endif
29
30/*
31 * Following http://www.ocert.org/advisories/ocert-2011-003.html
32 * it seems that having hash randomization might be a good idea
33 * when using XML with untrusted data
34 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
35 * which is the default.
36 * Note2: the fast function used for a small dict won't protect very
37 * well but since the attack is based on growing a very big hash
38 * list we will use the BigKey algo as soon as the hash size grows
39 * over MIN_DICT_SIZE so this actually works
40 */
41#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
42#define DICT_RANDOMIZATION
43#endif
44
Daniel Veillard2fdbd322003-08-18 12:15:38 +000045#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000046#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000047#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000048#else
49#ifdef HAVE_INTTYPES_H
50#include <inttypes.h>
akirilov20297912018-06-01 13:43:34 -070051#elif defined(_WIN32)
Rob Richardsb6b2ee12008-05-03 12:34:25 +000052typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000053#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000054#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000055#include <libxml/tree.h>
56#include <libxml/dict.h>
57#include <libxml/xmlmemory.h>
58#include <libxml/xmlerror.h>
59#include <libxml/globals.h>
60
Daniel Veillard424785e2008-08-06 09:35:25 +000061/* #define DEBUG_GROW */
62/* #define DICT_DEBUG_PATTERNS */
63
Daniel Veillarde9100a52008-04-22 08:28:50 +000064#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000065#define MIN_DICT_SIZE 128
66#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000067#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000068
Daniel Veillard424785e2008-08-06 09:35:25 +000069#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080070#define xmlDictComputeKey(dict, name, len) \
71 (((dict)->size == MIN_DICT_SIZE) ? \
72 xmlDictComputeFastKey(name, len, (dict)->seed) : \
73 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000074
Daniel Veillard8973d582012-02-04 19:07:44 +080075#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
76 (((prefix) == NULL) ? \
77 (xmlDictComputeKey(dict, name, len)) : \
78 (((dict)->size == MIN_DICT_SIZE) ? \
79 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
80 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000081
Daniel Veillard424785e2008-08-06 09:35:25 +000082#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080083#define xmlDictComputeKey(dict, name, len) \
84 xmlDictComputeFastKey(name, len, (dict)->seed)
85#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
86 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000087#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000088
89/*
Xin Lia136fc22016-07-26 14:22:54 -070090 * An entry in the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +000091 */
92typedef struct _xmlDictEntry xmlDictEntry;
93typedef xmlDictEntry *xmlDictEntryPtr;
94struct _xmlDictEntry {
95 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000096 const xmlChar *name;
Daniel Veillard7c693da2012-07-25 16:32:18 +080097 unsigned int len;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000098 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000099 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000100};
101
Daniel Veillard81514ba2003-09-16 23:17:26 +0000102typedef struct _xmlDictStrings xmlDictStrings;
103typedef xmlDictStrings *xmlDictStringsPtr;
104struct _xmlDictStrings {
105 xmlDictStringsPtr next;
106 xmlChar *free;
107 xmlChar *end;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800108 size_t size;
109 size_t nbStrings;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000110 xmlChar array[1];
111};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000112/*
Xin Lia136fc22016-07-26 14:22:54 -0700113 * The entire dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000114 */
115struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000116 int ref_counter;
117
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000118 struct _xmlDictEntry *dict;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800119 size_t size;
120 unsigned int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000121 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000122
123 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800124 /* used for randomization */
125 int seed;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800126 /* used to impose a limit on size */
127 size_t limit;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000128};
129
130/*
Daniel Veillard14412512005-01-21 23:53:26 +0000131 * A mutex for modifying the reference counter for shared
132 * dictionaries.
133 */
134static xmlRMutexPtr xmlDictMutex = NULL;
135
136/*
137 * Whether the dictionary mutex was initialized.
138 */
139static int xmlDictInitialized = 0;
140
Daniel Veillard379ebc12012-05-18 15:41:31 +0800141#ifdef DICT_RANDOMIZATION
142#ifdef HAVE_RAND_R
143/*
144 * Internal data for random function, protected by xmlDictMutex
145 */
Wouter Van Rooye7715a52012-09-14 14:39:42 +0800146static unsigned int rand_seed = 0;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800147#endif
148#endif
149
Daniel Veillard14412512005-01-21 23:53:26 +0000150/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000151 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000152 *
153 * Do the dictionary mutex initialization.
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800154 * this function is deprecated
Daniel Veillardee8f1d42012-05-21 11:16:12 +0800155 *
156 * Returns 0 if initialization was already done, and 1 if that
157 * call led to the initialization
Daniel Veillard14412512005-01-21 23:53:26 +0000158 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800159int xmlInitializeDict(void) {
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800160 return(0);
161}
162
163/**
164 * __xmlInitializeDict:
165 *
166 * This function is not public
167 * Do the dictionary mutex initialization.
168 * this function is not thread safe, initialization should
169 * normally be done once at setup when called from xmlOnceInit()
170 * we may also land in this code if thread support is not compiled in
171 *
172 * Returns 0 if initialization was already done, and 1 if that
173 * call led to the initialization
174 */
175int __xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000176 if (xmlDictInitialized)
177 return(1);
178
179 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
180 return(0);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800181 xmlRMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000182
Daniel Veillard8973d582012-02-04 19:07:44 +0800183#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800184#ifdef HAVE_RAND_R
185 rand_seed = time(NULL);
186 rand_r(& rand_seed);
187#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800188 srand(time(NULL));
189#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800190#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000191 xmlDictInitialized = 1;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800192 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000193 return(1);
194}
195
Daniel Veillard379ebc12012-05-18 15:41:31 +0800196#ifdef DICT_RANDOMIZATION
197int __xmlRandom(void) {
198 int ret;
199
200 if (xmlDictInitialized == 0)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800201 __xmlInitializeDict();
Daniel Veillard379ebc12012-05-18 15:41:31 +0800202
203 xmlRMutexLock(xmlDictMutex);
204#ifdef HAVE_RAND_R
205 ret = rand_r(& rand_seed);
206#else
207 ret = rand();
208#endif
209 xmlRMutexUnlock(xmlDictMutex);
210 return(ret);
211}
212#endif
213
Daniel Veillard14412512005-01-21 23:53:26 +0000214/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000215 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000216 *
Daniel Veillard379ebc12012-05-18 15:41:31 +0800217 * Free the dictionary mutex. Do not call unless sure the library
218 * is not in use anymore !
Daniel Veillard14412512005-01-21 23:53:26 +0000219 */
220void
221xmlDictCleanup(void) {
222 if (!xmlDictInitialized)
223 return;
224
225 xmlFreeRMutex(xmlDictMutex);
226
227 xmlDictInitialized = 0;
228}
229
230/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000231 * xmlDictAddString:
Xin Lia136fc22016-07-26 14:22:54 -0700232 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +0000233 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800234 * @len: the length of the name
Daniel Veillard81514ba2003-09-16 23:17:26 +0000235 *
236 * Add the string to the array[s]
237 *
238 * Returns the pointer of the local string, or NULL in case of error.
239 */
240static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800241xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Daniel Veillard81514ba2003-09-16 23:17:26 +0000242 xmlDictStringsPtr pool;
243 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800244 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
245 size_t limit = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000246
Daniel Veillard424785e2008-08-06 09:35:25 +0000247#ifdef DICT_DEBUG_PATTERNS
248 fprintf(stderr, "-");
249#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000250 pool = dict->strings;
251 while (pool != NULL) {
akirilov20297912018-06-01 13:43:34 -0700252 if ((size_t)(pool->end - pool->free) > namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000253 goto found_pool;
254 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800255 limit += pool->size;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000256 pool = pool->next;
257 }
258 /*
259 * Not found, need to allocate
260 */
261 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800262 if ((dict->limit > 0) && (limit > dict->limit)) {
263 return(NULL);
264 }
265
Daniel Veillard81514ba2003-09-16 23:17:26 +0000266 if (size == 0) size = 1000;
267 else size *= 4; /* exponential growth */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800268 if (size < 4 * namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000269 size = 4 * namelen; /* just in case ! */
270 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 Veillard81514ba2003-09-16 23:17:26 +0000282 }
283found_pool:
284 ret = pool->free;
285 memcpy(pool->free, name, namelen);
286 pool->free += namelen;
287 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000288 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000289 return(ret);
290}
291
292/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000293 * xmlDictAddQString:
Xin Lia136fc22016-07-26 14:22:54 -0700294 * @dict: the dictionary
Daniel Veillarde72c5082003-09-19 12:44:05 +0000295 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000296 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000297 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800298 * @len: the length of the name
Daniel Veillarde72c5082003-09-19 12:44:05 +0000299 *
300 * Add the QName to the array[s]
301 *
302 * Returns the pointer of the local string, or NULL in case of error.
303 */
304static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800305xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
306 const xmlChar *name, unsigned int namelen)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000307{
308 xmlDictStringsPtr pool;
309 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800310 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
311 size_t limit = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000312
313 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000314
Daniel Veillard424785e2008-08-06 09:35:25 +0000315#ifdef DICT_DEBUG_PATTERNS
316 fprintf(stderr, "=");
317#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000318 pool = dict->strings;
319 while (pool != NULL) {
akirilov20297912018-06-01 13:43:34 -0700320 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000321 goto found_pool;
322 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800323 limit += pool->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000324 pool = pool->next;
325 }
326 /*
327 * Not found, need to allocate
328 */
329 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800330 if ((dict->limit > 0) && (limit > dict->limit)) {
331 return(NULL);
332 }
333
Daniel Veillarde72c5082003-09-19 12:44:05 +0000334 if (size == 0) size = 1000;
335 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000336 if (size < 4 * (namelen + plen + 1))
337 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000338 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
339 if (pool == NULL)
340 return(NULL);
341 pool->size = size;
342 pool->nbStrings = 0;
343 pool->free = &pool->array[0];
344 pool->end = &pool->array[size];
345 pool->next = dict->strings;
346 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000347#ifdef DICT_DEBUG_PATTERNS
348 fprintf(stderr, "+");
349#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000350 }
351found_pool:
352 ret = pool->free;
353 memcpy(pool->free, prefix, plen);
354 pool->free += plen;
355 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000356 memcpy(pool->free, name, namelen);
357 pool->free += namelen;
358 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000359 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000360 return(ret);
361}
362
Daniel Veillard424785e2008-08-06 09:35:25 +0000363#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000364/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000365 * xmlDictComputeBigKey:
366 *
367 * Calculate a hash key using a good hash function that works well for
368 * larger hash table sizes.
369 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000370 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000371 * http://burtleburtle.net/bob/hash/doobs.html
372 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000373
374static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800375xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000376 uint32_t hash;
377 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000378
Daniel Veillard424785e2008-08-06 09:35:25 +0000379 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000380
Daniel Veillard8973d582012-02-04 19:07:44 +0800381 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000382
Daniel Veillard424785e2008-08-06 09:35:25 +0000383 for (i = 0;i < namelen; i++) {
384 hash += data[i];
385 hash += (hash << 10);
386 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000387 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000388 hash += (hash << 3);
389 hash ^= (hash >> 11);
390 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000391
392 return hash;
393}
394
395/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000396 * xmlDictComputeBigQKey:
397 *
398 * Calculate a hash key for two strings using a good hash function
399 * that works well for larger hash table sizes.
400 *
401 * Hash function by "One-at-a-Time Hash" see
402 * http://burtleburtle.net/bob/hash/doobs.html
403 *
404 * Neither of the two strings must be NULL.
405 */
406static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000407xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800408 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000409{
410 uint32_t hash;
411 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000412
Daniel Veillard8973d582012-02-04 19:07:44 +0800413 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000414
415 for (i = 0;i < plen; i++) {
416 hash += prefix[i];
417 hash += (hash << 10);
418 hash ^= (hash >> 6);
419 }
420 hash += ':';
421 hash += (hash << 10);
422 hash ^= (hash >> 6);
423
424 for (i = 0;i < len; i++) {
425 hash += name[i];
426 hash += (hash << 10);
427 hash ^= (hash >> 6);
428 }
429 hash += (hash << 3);
430 hash ^= (hash >> 11);
431 hash += (hash << 15);
432
433 return hash;
434}
435#endif /* WITH_BIG_KEY */
436
437/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000438 * xmlDictComputeFastKey:
439 *
440 * Calculate a hash key using a fast hash function that works well
441 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000442 */
443static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800444xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
445 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000446
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000447 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000448 value = *name;
449 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000450 if (namelen > 10) {
451 value += name[namelen - 1];
452 namelen = 10;
453 }
454 switch (namelen) {
455 case 10: value += name[9];
akirilov20297912018-06-01 13:43:34 -0700456 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000457 case 9: value += name[8];
akirilov20297912018-06-01 13:43:34 -0700458 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000459 case 8: value += name[7];
akirilov20297912018-06-01 13:43:34 -0700460 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000461 case 7: value += name[6];
akirilov20297912018-06-01 13:43:34 -0700462 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000463 case 6: value += name[5];
akirilov20297912018-06-01 13:43:34 -0700464 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000465 case 5: value += name[4];
akirilov20297912018-06-01 13:43:34 -0700466 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000467 case 4: value += name[3];
akirilov20297912018-06-01 13:43:34 -0700468 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000469 case 3: value += name[2];
akirilov20297912018-06-01 13:43:34 -0700470 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000471 case 2: value += name[1];
akirilov20297912018-06-01 13:43:34 -0700472 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000473 default: break;
474 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000475 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000476}
477
478/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000479 * xmlDictComputeFastQKey:
480 *
481 * Calculate a hash key for two strings using a fast hash function
482 * that works well for low hash table fill.
483 *
484 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000485 */
486static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000487xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800488 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000489{
Daniel Veillard8973d582012-02-04 19:07:44 +0800490 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000491
Daniel Veillarde72c5082003-09-19 12:44:05 +0000492 if (plen == 0)
493 value += 30 * (unsigned long) ':';
494 else
495 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000496
Daniel Veillarde72c5082003-09-19 12:44:05 +0000497 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800498 int offset = len - (plen + 1 + 1);
499 if (offset < 0)
500 offset = len - (10 + 1);
501 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000502 len = 10;
503 if (plen > 10)
504 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000505 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000506 switch (plen) {
507 case 10: value += prefix[9];
akirilov20297912018-06-01 13:43:34 -0700508 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000509 case 9: value += prefix[8];
akirilov20297912018-06-01 13:43:34 -0700510 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000511 case 8: value += prefix[7];
akirilov20297912018-06-01 13:43:34 -0700512 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000513 case 7: value += prefix[6];
akirilov20297912018-06-01 13:43:34 -0700514 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000515 case 6: value += prefix[5];
akirilov20297912018-06-01 13:43:34 -0700516 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000517 case 5: value += prefix[4];
akirilov20297912018-06-01 13:43:34 -0700518 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000519 case 4: value += prefix[3];
akirilov20297912018-06-01 13:43:34 -0700520 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000521 case 3: value += prefix[2];
akirilov20297912018-06-01 13:43:34 -0700522 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000523 case 2: value += prefix[1];
akirilov20297912018-06-01 13:43:34 -0700524 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000525 case 1: value += prefix[0];
akirilov20297912018-06-01 13:43:34 -0700526 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000527 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000528 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000529 len -= plen;
530 if (len > 0) {
531 value += (unsigned long) ':';
532 len--;
533 }
534 switch (len) {
535 case 10: value += name[9];
akirilov20297912018-06-01 13:43:34 -0700536 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000537 case 9: value += name[8];
akirilov20297912018-06-01 13:43:34 -0700538 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000539 case 8: value += name[7];
akirilov20297912018-06-01 13:43:34 -0700540 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000541 case 7: value += name[6];
akirilov20297912018-06-01 13:43:34 -0700542 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000543 case 6: value += name[5];
akirilov20297912018-06-01 13:43:34 -0700544 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000545 case 5: value += name[4];
akirilov20297912018-06-01 13:43:34 -0700546 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000547 case 4: value += name[3];
akirilov20297912018-06-01 13:43:34 -0700548 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000549 case 3: value += name[2];
akirilov20297912018-06-01 13:43:34 -0700550 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000551 case 2: value += name[1];
akirilov20297912018-06-01 13:43:34 -0700552 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000553 case 1: value += name[0];
akirilov20297912018-06-01 13:43:34 -0700554 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000555 default: break;
556 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000557 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000558}
559
560/**
561 * xmlDictCreate:
562 *
563 * Create a new dictionary
564 *
akirilov20297912018-06-01 13:43:34 -0700565 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000566 */
567xmlDictPtr
568xmlDictCreate(void) {
569 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000570
571 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800572 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000573 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000574
575#ifdef DICT_DEBUG_PATTERNS
576 fprintf(stderr, "C");
577#endif
578
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000579 dict = xmlMalloc(sizeof(xmlDict));
580 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000581 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800582 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000583
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000584 dict->size = MIN_DICT_SIZE;
585 dict->nbElems = 0;
586 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000587 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000588 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000589 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000590 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800591#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800592 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800593#else
594 dict->seed = 0;
595#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000596 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000597 }
598 xmlFree(dict);
599 }
600 return(NULL);
601}
602
603/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000604 * xmlDictCreateSub:
Xin Lia136fc22016-07-26 14:22:54 -0700605 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000606 *
607 * Create a new dictionary, inheriting strings from the read-only
Xin Lia136fc22016-07-26 14:22:54 -0700608 * dictionary @sub. On lookup, strings are first searched in the
609 * new dictionary, then in @sub, and if not found are created in the
610 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000611 *
akirilov20297912018-06-01 13:43:34 -0700612 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000613 */
614xmlDictPtr
615xmlDictCreateSub(xmlDictPtr sub) {
616 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000617
Daniel Veillard4773df22004-01-23 13:15:13 +0000618 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000619#ifdef DICT_DEBUG_PATTERNS
620 fprintf(stderr, "R");
621#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800622 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000623 dict->subdict = sub;
624 xmlDictReference(dict->subdict);
625 }
626 return(dict);
627}
628
629/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000630 * xmlDictReference:
Xin Lia136fc22016-07-26 14:22:54 -0700631 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000632 *
633 * Increment the reference counter of a dictionary
634 *
635 * Returns 0 in case of success and -1 in case of error
636 */
637int
638xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000639 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800640 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000641 return(-1);
642
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000643 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000644 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000645 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000646 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000647 return(0);
648}
649
650/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000651 * xmlDictGrow:
Xin Lia136fc22016-07-26 14:22:54 -0700652 * @dict: the dictionary
653 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000654 *
Xin Lia136fc22016-07-26 14:22:54 -0700655 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000656 *
657 * Returns 0 in case of success, -1 in case of failure
658 */
659static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800660xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000661 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800662 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000663 xmlDictEntryPtr iter, next;
664 struct _xmlDictEntry *olddict;
665#ifdef DEBUG_GROW
666 unsigned long nbElem = 0;
667#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000668 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000669 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000670
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000671 if (dict == NULL)
672 return(-1);
673 if (size < 8)
674 return(-1);
675 if (size > 8 * 2048)
676 return(-1);
677
Daniel Veillard424785e2008-08-06 09:35:25 +0000678#ifdef DICT_DEBUG_PATTERNS
679 fprintf(stderr, "*");
680#endif
681
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000682 oldsize = dict->size;
683 olddict = dict->dict;
684 if (olddict == NULL)
685 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000686 if (oldsize == MIN_DICT_SIZE)
687 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000688
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000689 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
690 if (dict->dict == NULL) {
691 dict->dict = olddict;
692 return(-1);
693 }
694 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
695 dict->size = size;
696
697 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000698 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000699 the main dict. It is nicer to run through the array twice, first
700 copying all the elements in the main array (less probability of
701 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000702 */
703 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000704 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000705 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000706
707 if (keep_keys)
708 okey = olddict[i].okey;
709 else
710 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
711 key = okey % dict->size;
712
Daniel Veillardffda65f2008-08-07 16:33:49 +0000713 if (dict->dict[key].valid == 0) {
714 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
715 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000716 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000717 } else {
718 xmlDictEntryPtr entry;
719
720 entry = xmlMalloc(sizeof(xmlDictEntry));
721 if (entry != NULL) {
722 entry->name = olddict[i].name;
723 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000724 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000725 entry->next = dict->dict[key].next;
726 entry->valid = 1;
727 dict->dict[key].next = entry;
728 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000729 /*
730 * we don't have much ways to alert from herei
akirilov20297912018-06-01 13:43:34 -0700731 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000732 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000733 ret = -1;
734 }
735 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000736#ifdef DEBUG_GROW
737 nbElem++;
738#endif
739 }
740
741 for (i = 0; i < oldsize; i++) {
742 iter = olddict[i].next;
743 while (iter) {
744 next = iter->next;
745
746 /*
747 * put back the entry in the new dict
748 */
749
Daniel Veillardd68f8912008-08-08 10:09:19 +0000750 if (keep_keys)
751 okey = iter->okey;
752 else
753 okey = xmlDictComputeKey(dict, iter->name, iter->len);
754 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000755 if (dict->dict[key].valid == 0) {
756 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
757 dict->dict[key].next = NULL;
758 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000759 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000760 xmlFree(iter);
761 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000762 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000763 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000764 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000765 }
766
767#ifdef DEBUG_GROW
768 nbElem++;
769#endif
770
771 iter = next;
772 }
773 }
774
775 xmlFree(olddict);
776
777#ifdef DEBUG_GROW
778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800779 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000780#endif
781
Daniel Veillardffda65f2008-08-07 16:33:49 +0000782 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000783}
784
785/**
786 * xmlDictFree:
Xin Lia136fc22016-07-26 14:22:54 -0700787 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000788 *
789 * Free the hash @dict and its contents. The userdata is
790 * deallocated with @f if provided.
791 */
792void
793xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800794 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000795 xmlDictEntryPtr iter;
796 xmlDictEntryPtr next;
797 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000798 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000799
800 if (dict == NULL)
801 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000802
Daniel Veillard14412512005-01-21 23:53:26 +0000803 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800804 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000805 return;
806
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000807 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000808 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000809 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000810 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000811 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000812 return;
813 }
814
Daniel Veillard14412512005-01-21 23:53:26 +0000815 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000816
Daniel Veillard4773df22004-01-23 13:15:13 +0000817 if (dict->subdict != NULL) {
818 xmlDictFree(dict->subdict);
819 }
820
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000821 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000822 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000823 iter = &(dict->dict[i]);
824 if (iter->valid == 0)
825 continue;
826 inside_dict = 1;
827 while (iter) {
828 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000829 if (!inside_dict)
830 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000831 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000832 inside_dict = 0;
833 iter = next;
834 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000835 }
836 xmlFree(dict->dict);
837 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000838 pool = dict->strings;
839 while (pool != NULL) {
840 nextp = pool->next;
841 xmlFree(pool);
842 pool = nextp;
843 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000844 xmlFree(dict);
845}
846
847/**
848 * xmlDictLookup:
Xin Lia136fc22016-07-26 14:22:54 -0700849 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000850 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000851 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000852 *
Xin Lia136fc22016-07-26 14:22:54 -0700853 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000854 *
855 * Returns the internal copy of the name or NULL in case of internal error
856 */
857const xmlChar *
858xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000859 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000860 xmlDictEntryPtr entry;
861 xmlDictEntryPtr insert;
862 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800863 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000864
Daniel Veillard0fb18932003-09-07 09:14:37 +0000865 if ((dict == NULL) || (name == NULL))
866 return(NULL);
867
868 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800869 l = strlen((const char *) name);
870 else
871 l = len;
872
873 if (((dict->limit > 0) && (l >= dict->limit)) ||
874 (l > INT_MAX / 2))
875 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000876
877 /*
878 * Check for duplicate and insertion location.
879 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800880 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000881 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000882 if (dict->dict[key].valid == 0) {
883 insert = NULL;
884 } else {
885 for (insert = &(dict->dict[key]); insert->next != NULL;
886 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000887#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800888 if ((insert->okey == okey) && (insert->len == l)) {
889 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000890 return(insert->name);
891 }
892#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800893 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800894 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000895 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000896#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000897 nbi++;
898 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000899#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800900 if ((insert->okey == okey) && (insert->len == l)) {
901 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000902 return(insert->name);
903 }
904#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800905 if ((insert->okey == okey) && (insert->len == l) &&
906 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000907 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000908#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000909 }
910
Daniel Veillard4773df22004-01-23 13:15:13 +0000911 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000912 unsigned long skey;
913
914 /* we cannot always reuse the same okey for the subdict */
915 if (((dict->size == MIN_DICT_SIZE) &&
916 (dict->subdict->size != MIN_DICT_SIZE)) ||
917 ((dict->size != MIN_DICT_SIZE) &&
918 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800919 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000920 else
921 skey = okey;
922
923 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000924 if (dict->subdict->dict[key].valid != 0) {
925 xmlDictEntryPtr tmp;
926
927 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
928 tmp = tmp->next) {
929#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800930 if ((tmp->okey == skey) && (tmp->len == l)) {
931 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000932 return(tmp->name);
933 }
934#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800935 if ((tmp->okey == skey) && (tmp->len == l) &&
936 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000937 return(tmp->name);
938#endif
939 nbi++;
940 }
941#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800942 if ((tmp->okey == skey) && (tmp->len == l)) {
943 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000944 return(tmp->name);
945 }
946#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800947 if ((tmp->okey == skey) && (tmp->len == l) &&
948 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000949 return(tmp->name);
950#endif
951 }
952 key = okey % dict->size;
953 }
954
Daniel Veillard7c693da2012-07-25 16:32:18 +0800955 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000956 if (ret == NULL)
957 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000958 if (insert == NULL) {
959 entry = &(dict->dict[key]);
960 } else {
961 entry = xmlMalloc(sizeof(xmlDictEntry));
962 if (entry == NULL)
963 return(NULL);
964 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000965 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800966 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000967 entry->next = NULL;
968 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000969 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000970
971
Daniel Veillard7c693da2012-07-25 16:32:18 +0800972 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000973 insert->next = entry;
974
975 dict->nbElems++;
976
977 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000978 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
979 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
980 return(NULL);
981 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000982 /* Note that entry may have been freed at this point by xmlDictGrow */
983
984 return(ret);
985}
986
987/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000988 * xmlDictExists:
Xin Lia136fc22016-07-26 14:22:54 -0700989 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000990 * @name: the name of the userdata
991 * @len: the length of the name, if -1 it is recomputed
992 *
Xin Lia136fc22016-07-26 14:22:54 -0700993 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000994 *
995 * Returns the internal copy of the name or NULL if not found.
996 */
997const xmlChar *
998xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
999 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001000 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001001 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001002
1003 if ((dict == NULL) || (name == NULL))
1004 return(NULL);
1005
1006 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +08001007 l = strlen((const char *) name);
1008 else
1009 l = len;
1010 if (((dict->limit > 0) && (l >= dict->limit)) ||
1011 (l > INT_MAX / 2))
1012 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001013
1014 /*
1015 * Check for duplicate and insertion location.
1016 */
Daniel Veillard7c693da2012-07-25 16:32:18 +08001017 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001018 key = okey % dict->size;
1019 if (dict->dict[key].valid == 0) {
1020 insert = NULL;
1021 } else {
1022 for (insert = &(dict->dict[key]); insert->next != NULL;
1023 insert = insert->next) {
1024#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001025 if ((insert->okey == okey) && (insert->len == l)) {
1026 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001027 return(insert->name);
1028 }
1029#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001030 if ((insert->okey == okey) && (insert->len == l) &&
1031 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001032 return(insert->name);
1033#endif
1034 nbi++;
1035 }
1036#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001037 if ((insert->okey == okey) && (insert->len == l)) {
1038 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001039 return(insert->name);
1040 }
1041#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001042 if ((insert->okey == okey) && (insert->len == l) &&
1043 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001044 return(insert->name);
1045#endif
1046 }
1047
1048 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001049 unsigned long skey;
1050
1051 /* we cannot always reuse the same okey for the subdict */
1052 if (((dict->size == MIN_DICT_SIZE) &&
1053 (dict->subdict->size != MIN_DICT_SIZE)) ||
1054 ((dict->size != MIN_DICT_SIZE) &&
1055 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001056 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001057 else
1058 skey = okey;
1059
1060 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001061 if (dict->subdict->dict[key].valid != 0) {
1062 xmlDictEntryPtr tmp;
1063
1064 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1065 tmp = tmp->next) {
1066#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001067 if ((tmp->okey == skey) && (tmp->len == l)) {
1068 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001069 return(tmp->name);
1070 }
1071#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001072 if ((tmp->okey == skey) && (tmp->len == l) &&
1073 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001074 return(tmp->name);
1075#endif
1076 nbi++;
1077 }
1078#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001079 if ((tmp->okey == skey) && (tmp->len == l)) {
1080 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001081 return(tmp->name);
1082 }
1083#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001084 if ((tmp->okey == skey) && (tmp->len == l) &&
1085 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001086 return(tmp->name);
1087#endif
1088 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001089 }
1090
1091 /* not found */
1092 return(NULL);
1093}
1094
1095/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001096 * xmlDictQLookup:
Xin Lia136fc22016-07-26 14:22:54 -07001097 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001098 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001099 * @name: the name
1100 *
1101 * Add the QName @prefix:@name to the hash @dict if not present.
1102 *
1103 * Returns the internal copy of the QName or NULL in case of internal error
1104 */
1105const xmlChar *
1106xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001107 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001108 xmlDictEntryPtr entry;
1109 xmlDictEntryPtr insert;
1110 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001111 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001112
1113 if ((dict == NULL) || (name == NULL))
1114 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001115 if (prefix == NULL)
1116 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001117
Daniel Veillardffda65f2008-08-07 16:33:49 +00001118 l = len = strlen((const char *) name);
1119 plen = strlen((const char *) prefix);
1120 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001121
1122 /*
1123 * Check for duplicate and insertion location.
1124 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001125 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001126 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001127 if (dict->dict[key].valid == 0) {
1128 insert = NULL;
1129 } else {
1130 for (insert = &(dict->dict[key]); insert->next != NULL;
1131 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001132 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001133 (xmlStrQEqual(prefix, name, insert->name)))
1134 return(insert->name);
1135 nbi++;
1136 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001137 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001138 (xmlStrQEqual(prefix, name, insert->name)))
1139 return(insert->name);
1140 }
1141
Daniel Veillard4773df22004-01-23 13:15:13 +00001142 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001143 unsigned long skey;
1144
1145 /* we cannot always reuse the same okey for the subdict */
1146 if (((dict->size == MIN_DICT_SIZE) &&
1147 (dict->subdict->size != MIN_DICT_SIZE)) ||
1148 ((dict->size != MIN_DICT_SIZE) &&
1149 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001150 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001151 else
1152 skey = okey;
1153
1154 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001155 if (dict->subdict->dict[key].valid != 0) {
1156 xmlDictEntryPtr tmp;
1157 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1158 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001159 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001160 (xmlStrQEqual(prefix, name, tmp->name)))
1161 return(tmp->name);
1162 nbi++;
1163 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001164 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001165 (xmlStrQEqual(prefix, name, tmp->name)))
1166 return(tmp->name);
1167 }
1168 key = okey % dict->size;
1169 }
1170
Daniel Veillardffda65f2008-08-07 16:33:49 +00001171 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001172 if (ret == NULL)
1173 return(NULL);
1174 if (insert == NULL) {
1175 entry = &(dict->dict[key]);
1176 } else {
1177 entry = xmlMalloc(sizeof(xmlDictEntry));
1178 if (entry == NULL)
1179 return(NULL);
1180 }
1181 entry->name = ret;
1182 entry->len = len;
1183 entry->next = NULL;
1184 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001185 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001186
Daniel Veillard7c693da2012-07-25 16:32:18 +08001187 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001188 insert->next = entry;
1189
1190 dict->nbElems++;
1191
1192 if ((nbi > MAX_HASH_LEN) &&
1193 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1194 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1195 /* Note that entry may have been freed at this point by xmlDictGrow */
1196
1197 return(ret);
1198}
1199
1200/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001201 * xmlDictOwns:
Xin Lia136fc22016-07-26 14:22:54 -07001202 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001203 * @str: the string
1204 *
1205 * check if a string is owned by the disctionary
1206 *
1207 * Returns 1 if true, 0 if false and -1 in case of error
1208 * -1 in case of error
1209 */
1210int
1211xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1212 xmlDictStringsPtr pool;
1213
1214 if ((dict == NULL) || (str == NULL))
1215 return(-1);
1216 pool = dict->strings;
1217 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001218 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001219 return(1);
1220 pool = pool->next;
1221 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001222 if (dict->subdict)
1223 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001224 return(0);
1225}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001226
Daniel Veillard81514ba2003-09-16 23:17:26 +00001227/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001228 * xmlDictSize:
Xin Lia136fc22016-07-26 14:22:54 -07001229 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001230 *
1231 * Query the number of elements installed in the hash @dict.
1232 *
Xin Lia136fc22016-07-26 14:22:54 -07001233 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001234 * -1 in case of error
1235 */
1236int
1237xmlDictSize(xmlDictPtr dict) {
1238 if (dict == NULL)
1239 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001240 if (dict->subdict)
1241 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001242 return(dict->nbElems);
1243}
1244
Daniel Veillard7c693da2012-07-25 16:32:18 +08001245/**
1246 * xmlDictSetLimit:
Xin Lia136fc22016-07-26 14:22:54 -07001247 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001248 * @limit: the limit in bytes
1249 *
1250 * Set a size limit for the dictionary
1251 * Added in 2.9.0
1252 *
1253 * Returns the previous limit of the dictionary or 0
1254 */
1255size_t
1256xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1257 size_t ret;
1258
1259 if (dict == NULL)
1260 return(0);
1261 ret = dict->limit;
1262 dict->limit = limit;
1263 return(ret);
1264}
1265
1266/**
1267 * xmlDictGetUsage:
Xin Lia136fc22016-07-26 14:22:54 -07001268 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001269 *
1270 * Get how much memory is used by a dictionary for strings
1271 * Added in 2.9.0
1272 *
1273 * Returns the amount of strings allocated
1274 */
1275size_t
1276xmlDictGetUsage(xmlDictPtr dict) {
1277 xmlDictStringsPtr pool;
1278 size_t limit = 0;
1279
1280 if (dict == NULL)
1281 return(0);
1282 pool = dict->strings;
1283 while (pool != NULL) {
1284 limit += pool->size;
1285 pool = pool->next;
1286 }
1287 return(limit);
1288}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001289
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001290#define bottom_dict
1291#include "elfgcchack.h"