blob: 0e4c87b90ffa34aea676cebfc0f150a599a73716 [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
Nick Wellnhofer20c60882020-03-08 17:19:42 +010013 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
Daniel Veillard2fdbd322003-08-18 12:15:38 +000014 * 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#include <stdlib.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080024#include <time.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080025
26/*
27 * Following http://www.ocert.org/advisories/ocert-2011-003.html
28 * it seems that having hash randomization might be a good idea
29 * when using XML with untrusted data
30 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
31 * which is the default.
32 * Note2: the fast function used for a small dict won't protect very
33 * well but since the attack is based on growing a very big hash
34 * list we will use the BigKey algo as soon as the hash size grows
35 * over MIN_DICT_SIZE so this actually works
36 */
Nick Wellnhofer72119af2022-03-02 01:14:08 +010037#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
Daniel Veillard8973d582012-02-04 19:07:44 +080038#define DICT_RANDOMIZATION
39#endif
40
Daniel Veillard2fdbd322003-08-18 12:15:38 +000041#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000042#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000043#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000044#else
45#ifdef HAVE_INTTYPES_H
46#include <inttypes.h>
Nick Wellnhofere3890542017-10-09 00:20:01 +020047#elif defined(_WIN32)
Rob Richardsb6b2ee12008-05-03 12:34:25 +000048typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000049#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000050#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000051#include <libxml/tree.h>
52#include <libxml/dict.h>
53#include <libxml/xmlmemory.h>
54#include <libxml/xmlerror.h>
55#include <libxml/globals.h>
56
Daniel Veillard424785e2008-08-06 09:35:25 +000057/* #define DEBUG_GROW */
58/* #define DICT_DEBUG_PATTERNS */
59
Daniel Veillarde9100a52008-04-22 08:28:50 +000060#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000061#define MIN_DICT_SIZE 128
62#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000063#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000064
Daniel Veillard424785e2008-08-06 09:35:25 +000065#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080066#define xmlDictComputeKey(dict, name, len) \
67 (((dict)->size == MIN_DICT_SIZE) ? \
68 xmlDictComputeFastKey(name, len, (dict)->seed) : \
69 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000070
Daniel Veillard8973d582012-02-04 19:07:44 +080071#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
72 (((prefix) == NULL) ? \
73 (xmlDictComputeKey(dict, name, len)) : \
74 (((dict)->size == MIN_DICT_SIZE) ? \
75 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
76 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000077
Daniel Veillard424785e2008-08-06 09:35:25 +000078#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080079#define xmlDictComputeKey(dict, name, len) \
80 xmlDictComputeFastKey(name, len, (dict)->seed)
81#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
82 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000083#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000084
85/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +020086 * An entry in the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +000087 */
88typedef struct _xmlDictEntry xmlDictEntry;
89typedef xmlDictEntry *xmlDictEntryPtr;
90struct _xmlDictEntry {
91 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000092 const xmlChar *name;
Daniel Veillard7c693da2012-07-25 16:32:18 +080093 unsigned int len;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000094 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000095 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000096};
97
Daniel Veillard81514ba2003-09-16 23:17:26 +000098typedef struct _xmlDictStrings xmlDictStrings;
99typedef xmlDictStrings *xmlDictStringsPtr;
100struct _xmlDictStrings {
101 xmlDictStringsPtr next;
102 xmlChar *free;
103 xmlChar *end;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800104 size_t size;
105 size_t nbStrings;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000106 xmlChar array[1];
107};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000108/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200109 * The entire dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000110 */
111struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000112 int ref_counter;
113
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000114 struct _xmlDictEntry *dict;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800115 size_t size;
116 unsigned int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000117 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000118
119 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800120 /* used for randomization */
121 int seed;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800122 /* used to impose a limit on size */
123 size_t limit;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000124};
125
126/*
Daniel Veillard14412512005-01-21 23:53:26 +0000127 * A mutex for modifying the reference counter for shared
128 * dictionaries.
129 */
130static xmlRMutexPtr xmlDictMutex = NULL;
131
132/*
133 * Whether the dictionary mutex was initialized.
134 */
135static int xmlDictInitialized = 0;
136
Daniel Veillard379ebc12012-05-18 15:41:31 +0800137#ifdef DICT_RANDOMIZATION
138#ifdef HAVE_RAND_R
139/*
140 * Internal data for random function, protected by xmlDictMutex
141 */
Wouter Van Rooye7715a52012-09-14 14:39:42 +0800142static unsigned int rand_seed = 0;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800143#endif
144#endif
145
Daniel Veillard14412512005-01-21 23:53:26 +0000146/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000147 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000148 *
Nick Wellnhofer40483d02022-03-06 13:55:48 +0100149 * DEPRECATED: This function will be made private. Call xmlInitParser to
150 * initialize the library.
151 *
Daniel Veillard14412512005-01-21 23:53:26 +0000152 * Do the dictionary mutex initialization.
Daniel Veillardee8f1d42012-05-21 11:16:12 +0800153 *
154 * Returns 0 if initialization was already done, and 1 if that
155 * call led to the initialization
Daniel Veillard14412512005-01-21 23:53:26 +0000156 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800157int xmlInitializeDict(void) {
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800158 return(0);
159}
160
161/**
162 * __xmlInitializeDict:
163 *
164 * This function is not public
165 * Do the dictionary mutex initialization.
166 * this function is not thread safe, initialization should
167 * normally be done once at setup when called from xmlOnceInit()
168 * we may also land in this code if thread support is not compiled in
169 *
170 * Returns 0 if initialization was already done, and 1 if that
171 * call led to the initialization
172 */
173int __xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000174 if (xmlDictInitialized)
175 return(1);
176
177 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
178 return(0);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800179 xmlRMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000180
Daniel Veillard8973d582012-02-04 19:07:44 +0800181#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800182#ifdef HAVE_RAND_R
183 rand_seed = time(NULL);
184 rand_r(& rand_seed);
185#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800186 srand(time(NULL));
187#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800188#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000189 xmlDictInitialized = 1;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800190 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000191 return(1);
192}
193
Daniel Veillard379ebc12012-05-18 15:41:31 +0800194#ifdef DICT_RANDOMIZATION
195int __xmlRandom(void) {
196 int ret;
197
198 if (xmlDictInitialized == 0)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800199 __xmlInitializeDict();
Daniel Veillard379ebc12012-05-18 15:41:31 +0800200
201 xmlRMutexLock(xmlDictMutex);
202#ifdef HAVE_RAND_R
203 ret = rand_r(& rand_seed);
204#else
205 ret = rand();
206#endif
207 xmlRMutexUnlock(xmlDictMutex);
208 return(ret);
209}
210#endif
211
Daniel Veillard14412512005-01-21 23:53:26 +0000212/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000213 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000214 *
Nick Wellnhofer40483d02022-03-06 13:55:48 +0100215 * DEPRECATED: This function will be made private. Call xmlCleanupParser
216 * to free global state but see the warnings there. xmlCleanupParser
217 * should be only called once at program exit. In most cases, you don't
218 * have call cleanup functions at all.
219 *
Daniel Veillard379ebc12012-05-18 15:41:31 +0800220 * Free the dictionary mutex. Do not call unless sure the library
221 * is not in use anymore !
Daniel Veillard14412512005-01-21 23:53:26 +0000222 */
223void
224xmlDictCleanup(void) {
225 if (!xmlDictInitialized)
226 return;
227
228 xmlFreeRMutex(xmlDictMutex);
229
230 xmlDictInitialized = 0;
231}
232
233/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000234 * xmlDictAddString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200235 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +0000236 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800237 * @len: the length of the name
Daniel Veillard81514ba2003-09-16 23:17:26 +0000238 *
239 * Add the string to the array[s]
240 *
241 * Returns the pointer of the local string, or NULL in case of error.
242 */
243static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800244xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Daniel Veillard81514ba2003-09-16 23:17:26 +0000245 xmlDictStringsPtr pool;
246 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800247 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
248 size_t limit = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000249
Daniel Veillard424785e2008-08-06 09:35:25 +0000250#ifdef DICT_DEBUG_PATTERNS
251 fprintf(stderr, "-");
252#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000253 pool = dict->strings;
254 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200255 if ((size_t)(pool->end - pool->free) > namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000256 goto found_pool;
257 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800258 limit += pool->size;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000259 pool = pool->next;
260 }
261 /*
262 * Not found, need to allocate
263 */
264 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800265 if ((dict->limit > 0) && (limit > dict->limit)) {
266 return(NULL);
267 }
268
Daniel Veillard81514ba2003-09-16 23:17:26 +0000269 if (size == 0) size = 1000;
270 else size *= 4; /* exponential growth */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800271 if (size < 4 * namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000272 size = 4 * namelen; /* just in case ! */
273 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
274 if (pool == NULL)
275 return(NULL);
276 pool->size = size;
277 pool->nbStrings = 0;
278 pool->free = &pool->array[0];
279 pool->end = &pool->array[size];
280 pool->next = dict->strings;
281 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000282#ifdef DICT_DEBUG_PATTERNS
283 fprintf(stderr, "+");
284#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000285 }
286found_pool:
287 ret = pool->free;
288 memcpy(pool->free, name, namelen);
289 pool->free += namelen;
290 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000291 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000292 return(ret);
293}
294
295/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000296 * xmlDictAddQString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200297 * @dict: the dictionary
Daniel Veillarde72c5082003-09-19 12:44:05 +0000298 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000299 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000300 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800301 * @len: the length of the name
Daniel Veillarde72c5082003-09-19 12:44:05 +0000302 *
303 * Add the QName to the array[s]
304 *
305 * Returns the pointer of the local string, or NULL in case of error.
306 */
307static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800308xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
309 const xmlChar *name, unsigned int namelen)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000310{
311 xmlDictStringsPtr pool;
312 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800313 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
314 size_t limit = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000315
316 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000317
Daniel Veillard424785e2008-08-06 09:35:25 +0000318#ifdef DICT_DEBUG_PATTERNS
319 fprintf(stderr, "=");
320#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000321 pool = dict->strings;
322 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200323 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000324 goto found_pool;
325 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800326 limit += pool->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000327 pool = pool->next;
328 }
329 /*
330 * Not found, need to allocate
331 */
332 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800333 if ((dict->limit > 0) && (limit > dict->limit)) {
334 return(NULL);
335 }
336
Daniel Veillarde72c5082003-09-19 12:44:05 +0000337 if (size == 0) size = 1000;
338 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000339 if (size < 4 * (namelen + plen + 1))
340 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000341 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
342 if (pool == NULL)
343 return(NULL);
344 pool->size = size;
345 pool->nbStrings = 0;
346 pool->free = &pool->array[0];
347 pool->end = &pool->array[size];
348 pool->next = dict->strings;
349 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000350#ifdef DICT_DEBUG_PATTERNS
351 fprintf(stderr, "+");
352#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000353 }
354found_pool:
355 ret = pool->free;
356 memcpy(pool->free, prefix, plen);
357 pool->free += plen;
358 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000359 memcpy(pool->free, name, namelen);
360 pool->free += namelen;
361 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000362 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000363 return(ret);
364}
365
Daniel Veillard424785e2008-08-06 09:35:25 +0000366#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000367/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000368 * xmlDictComputeBigKey:
369 *
370 * Calculate a hash key using a good hash function that works well for
371 * larger hash table sizes.
372 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000373 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000374 * http://burtleburtle.net/bob/hash/doobs.html
375 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000376
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200377#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200378ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200379#endif
Daniel Veillarde9100a52008-04-22 08:28:50 +0000380static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800381xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000382 uint32_t hash;
383 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000384
Daniel Veillard424785e2008-08-06 09:35:25 +0000385 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000386
Daniel Veillard8973d582012-02-04 19:07:44 +0800387 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000388
Daniel Veillard424785e2008-08-06 09:35:25 +0000389 for (i = 0;i < namelen; i++) {
390 hash += data[i];
391 hash += (hash << 10);
392 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000393 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000394 hash += (hash << 3);
395 hash ^= (hash >> 11);
396 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000397
398 return hash;
399}
400
401/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000402 * xmlDictComputeBigQKey:
403 *
404 * Calculate a hash key for two strings using a good hash function
405 * that works well for larger hash table sizes.
406 *
407 * Hash function by "One-at-a-Time Hash" see
408 * http://burtleburtle.net/bob/hash/doobs.html
409 *
410 * Neither of the two strings must be NULL.
411 */
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200412#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200413ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200414#endif
Daniel Veillard424785e2008-08-06 09:35:25 +0000415static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000416xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800417 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000418{
419 uint32_t hash;
420 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000421
Daniel Veillard8973d582012-02-04 19:07:44 +0800422 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000423
424 for (i = 0;i < plen; i++) {
425 hash += prefix[i];
426 hash += (hash << 10);
427 hash ^= (hash >> 6);
428 }
429 hash += ':';
430 hash += (hash << 10);
431 hash ^= (hash >> 6);
432
433 for (i = 0;i < len; i++) {
434 hash += name[i];
435 hash += (hash << 10);
436 hash ^= (hash >> 6);
437 }
438 hash += (hash << 3);
439 hash ^= (hash >> 11);
440 hash += (hash << 15);
441
442 return hash;
443}
444#endif /* WITH_BIG_KEY */
445
446/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000447 * xmlDictComputeFastKey:
448 *
449 * Calculate a hash key using a fast hash function that works well
450 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000451 */
452static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800453xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
454 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000455
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000456 if (name == NULL) return(0);
Ranier Vilela3c8a3e92019-11-07 12:59:10 +0000457 value += *name;
Daniel Veillard4773df22004-01-23 13:15:13 +0000458 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000459 if (namelen > 10) {
460 value += name[namelen - 1];
461 namelen = 10;
462 }
463 switch (namelen) {
464 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200465 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000466 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200467 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000468 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200469 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000470 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200471 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000472 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200473 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000474 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200475 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000476 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200477 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000478 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200479 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000480 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200481 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000482 default: break;
483 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000484 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000485}
486
487/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000488 * xmlDictComputeFastQKey:
489 *
490 * Calculate a hash key for two strings using a fast hash function
491 * that works well for low hash table fill.
492 *
493 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000494 */
495static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000496xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800497 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000498{
Daniel Veillard8973d582012-02-04 19:07:44 +0800499 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000500
Daniel Veillarde72c5082003-09-19 12:44:05 +0000501 if (plen == 0)
502 value += 30 * (unsigned long) ':';
503 else
504 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000505
Daniel Veillarde72c5082003-09-19 12:44:05 +0000506 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800507 int offset = len - (plen + 1 + 1);
508 if (offset < 0)
509 offset = len - (10 + 1);
510 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000511 len = 10;
512 if (plen > 10)
513 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000514 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000515 switch (plen) {
516 case 10: value += prefix[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200517 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000518 case 9: value += prefix[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200519 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000520 case 8: value += prefix[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200521 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000522 case 7: value += prefix[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200523 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000524 case 6: value += prefix[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200525 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000526 case 5: value += prefix[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200527 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000528 case 4: value += prefix[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200529 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000530 case 3: value += prefix[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200531 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000532 case 2: value += prefix[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200533 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000534 case 1: value += prefix[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200535 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000536 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000537 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000538 len -= plen;
539 if (len > 0) {
540 value += (unsigned long) ':';
541 len--;
542 }
543 switch (len) {
544 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200545 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000546 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200547 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000548 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200549 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000550 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200551 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000552 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200553 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000554 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200555 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000556 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200557 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000558 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200559 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000560 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200561 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000562 case 1: value += name[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200563 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000564 default: break;
565 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000566 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000567}
568
569/**
570 * xmlDictCreate:
571 *
572 * Create a new dictionary
573 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200574 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000575 */
576xmlDictPtr
577xmlDictCreate(void) {
578 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000579
580 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800581 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000582 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000583
584#ifdef DICT_DEBUG_PATTERNS
585 fprintf(stderr, "C");
586#endif
587
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000588 dict = xmlMalloc(sizeof(xmlDict));
589 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000590 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800591 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000592
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000593 dict->size = MIN_DICT_SIZE;
594 dict->nbElems = 0;
595 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000596 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000597 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000598 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000599 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800600#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800601 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800602#else
603 dict->seed = 0;
604#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000605 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000606 }
607 xmlFree(dict);
608 }
609 return(NULL);
610}
611
612/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000613 * xmlDictCreateSub:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200614 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000615 *
616 * Create a new dictionary, inheriting strings from the read-only
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200617 * dictionary @sub. On lookup, strings are first searched in the
618 * new dictionary, then in @sub, and if not found are created in the
619 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000620 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200621 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000622 */
623xmlDictPtr
624xmlDictCreateSub(xmlDictPtr sub) {
625 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000626
Daniel Veillard4773df22004-01-23 13:15:13 +0000627 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000628#ifdef DICT_DEBUG_PATTERNS
629 fprintf(stderr, "R");
630#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800631 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000632 dict->subdict = sub;
633 xmlDictReference(dict->subdict);
634 }
635 return(dict);
636}
637
638/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000639 * xmlDictReference:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200640 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000641 *
642 * Increment the reference counter of a dictionary
643 *
644 * Returns 0 in case of success and -1 in case of error
645 */
646int
647xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000648 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800649 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000650 return(-1);
651
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000652 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000653 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000654 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000655 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000656 return(0);
657}
658
659/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000660 * xmlDictGrow:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200661 * @dict: the dictionary
662 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000663 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200664 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000665 *
666 * Returns 0 in case of success, -1 in case of failure
667 */
668static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800669xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000670 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800671 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000672 xmlDictEntryPtr iter, next;
673 struct _xmlDictEntry *olddict;
674#ifdef DEBUG_GROW
675 unsigned long nbElem = 0;
676#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000677 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000678 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000679
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000680 if (dict == NULL)
681 return(-1);
682 if (size < 8)
683 return(-1);
684 if (size > 8 * 2048)
685 return(-1);
686
Daniel Veillard424785e2008-08-06 09:35:25 +0000687#ifdef DICT_DEBUG_PATTERNS
688 fprintf(stderr, "*");
689#endif
690
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000691 oldsize = dict->size;
692 olddict = dict->dict;
693 if (olddict == NULL)
694 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000695 if (oldsize == MIN_DICT_SIZE)
696 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000697
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000698 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
699 if (dict->dict == NULL) {
700 dict->dict = olddict;
701 return(-1);
702 }
703 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
704 dict->size = size;
705
706 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000707 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000708 the main dict. It is nicer to run through the array twice, first
709 copying all the elements in the main array (less probability of
710 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000711 */
712 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000713 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000714 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000715
716 if (keep_keys)
717 okey = olddict[i].okey;
718 else
719 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
720 key = okey % dict->size;
721
Daniel Veillardffda65f2008-08-07 16:33:49 +0000722 if (dict->dict[key].valid == 0) {
723 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
724 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000725 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000726 } else {
727 xmlDictEntryPtr entry;
728
729 entry = xmlMalloc(sizeof(xmlDictEntry));
730 if (entry != NULL) {
731 entry->name = olddict[i].name;
732 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000733 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000734 entry->next = dict->dict[key].next;
735 entry->valid = 1;
736 dict->dict[key].next = entry;
737 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000738 /*
Jared Yanovich2a350ee2019-09-30 17:04:54 +0200739 * we don't have much ways to alert from here
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200740 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000741 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000742 ret = -1;
743 }
744 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000745#ifdef DEBUG_GROW
746 nbElem++;
747#endif
748 }
749
750 for (i = 0; i < oldsize; i++) {
751 iter = olddict[i].next;
752 while (iter) {
753 next = iter->next;
754
755 /*
756 * put back the entry in the new dict
757 */
758
Daniel Veillardd68f8912008-08-08 10:09:19 +0000759 if (keep_keys)
760 okey = iter->okey;
761 else
762 okey = xmlDictComputeKey(dict, iter->name, iter->len);
763 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000764 if (dict->dict[key].valid == 0) {
765 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
766 dict->dict[key].next = NULL;
767 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000768 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000769 xmlFree(iter);
770 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000771 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000772 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000773 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000774 }
775
776#ifdef DEBUG_GROW
777 nbElem++;
778#endif
779
780 iter = next;
781 }
782 }
783
784 xmlFree(olddict);
785
786#ifdef DEBUG_GROW
787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800788 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000789#endif
790
Daniel Veillardffda65f2008-08-07 16:33:49 +0000791 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000792}
793
794/**
795 * xmlDictFree:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200796 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000797 *
798 * Free the hash @dict and its contents. The userdata is
799 * deallocated with @f if provided.
800 */
801void
802xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800803 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000804 xmlDictEntryPtr iter;
805 xmlDictEntryPtr next;
806 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000807 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000808
809 if (dict == NULL)
810 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000811
Daniel Veillard14412512005-01-21 23:53:26 +0000812 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800813 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000814 return;
815
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000816 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000817 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000818 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000819 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000820 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000821 return;
822 }
823
Daniel Veillard14412512005-01-21 23:53:26 +0000824 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000825
Daniel Veillard4773df22004-01-23 13:15:13 +0000826 if (dict->subdict != NULL) {
827 xmlDictFree(dict->subdict);
828 }
829
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000830 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000831 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000832 iter = &(dict->dict[i]);
833 if (iter->valid == 0)
834 continue;
835 inside_dict = 1;
836 while (iter) {
837 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000838 if (!inside_dict)
839 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000840 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000841 inside_dict = 0;
842 iter = next;
843 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000844 }
845 xmlFree(dict->dict);
846 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000847 pool = dict->strings;
848 while (pool != NULL) {
849 nextp = pool->next;
850 xmlFree(pool);
851 pool = nextp;
852 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000853 xmlFree(dict);
854}
855
856/**
857 * xmlDictLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200858 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000859 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000860 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000861 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200862 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000863 *
864 * Returns the internal copy of the name or NULL in case of internal error
865 */
866const xmlChar *
867xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000868 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000869 xmlDictEntryPtr entry;
870 xmlDictEntryPtr insert;
871 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800872 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000873
Daniel Veillard0fb18932003-09-07 09:14:37 +0000874 if ((dict == NULL) || (name == NULL))
875 return(NULL);
876
877 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800878 l = strlen((const char *) name);
879 else
880 l = len;
881
882 if (((dict->limit > 0) && (l >= dict->limit)) ||
883 (l > INT_MAX / 2))
884 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000885
886 /*
887 * Check for duplicate and insertion location.
888 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800889 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000890 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000891 if (dict->dict[key].valid == 0) {
892 insert = NULL;
893 } else {
894 for (insert = &(dict->dict[key]); insert->next != NULL;
895 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000896#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800897 if ((insert->okey == okey) && (insert->len == l)) {
898 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000899 return(insert->name);
900 }
901#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800902 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800903 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000904 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000905#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000906 nbi++;
907 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000908#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800909 if ((insert->okey == okey) && (insert->len == l)) {
910 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000911 return(insert->name);
912 }
913#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800914 if ((insert->okey == okey) && (insert->len == l) &&
915 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000916 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000917#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000918 }
919
Daniel Veillard4773df22004-01-23 13:15:13 +0000920 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000921 unsigned long skey;
922
923 /* we cannot always reuse the same okey for the subdict */
924 if (((dict->size == MIN_DICT_SIZE) &&
925 (dict->subdict->size != MIN_DICT_SIZE)) ||
926 ((dict->size != MIN_DICT_SIZE) &&
927 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800928 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000929 else
930 skey = okey;
931
932 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000933 if (dict->subdict->dict[key].valid != 0) {
934 xmlDictEntryPtr tmp;
935
936 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
937 tmp = tmp->next) {
938#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800939 if ((tmp->okey == skey) && (tmp->len == l)) {
940 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000941 return(tmp->name);
942 }
943#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800944 if ((tmp->okey == skey) && (tmp->len == l) &&
945 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000946 return(tmp->name);
947#endif
948 nbi++;
949 }
950#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800951 if ((tmp->okey == skey) && (tmp->len == l)) {
952 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000953 return(tmp->name);
954 }
955#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800956 if ((tmp->okey == skey) && (tmp->len == l) &&
957 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000958 return(tmp->name);
959#endif
960 }
961 key = okey % dict->size;
962 }
963
Daniel Veillard7c693da2012-07-25 16:32:18 +0800964 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000965 if (ret == NULL)
966 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000967 if (insert == NULL) {
968 entry = &(dict->dict[key]);
969 } else {
970 entry = xmlMalloc(sizeof(xmlDictEntry));
971 if (entry == NULL)
972 return(NULL);
973 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000974 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800975 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000976 entry->next = NULL;
977 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000978 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000979
980
Daniel Veillard7c693da2012-07-25 16:32:18 +0800981 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000982 insert->next = entry;
983
984 dict->nbElems++;
985
986 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000987 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
988 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
989 return(NULL);
990 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000991 /* Note that entry may have been freed at this point by xmlDictGrow */
992
993 return(ret);
994}
995
996/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000997 * xmlDictExists:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200998 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000999 * @name: the name of the userdata
1000 * @len: the length of the name, if -1 it is recomputed
1001 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001002 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001003 *
1004 * Returns the internal copy of the name or NULL if not found.
1005 */
1006const xmlChar *
1007xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
1008 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001009 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001010 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001011
1012 if ((dict == NULL) || (name == NULL))
1013 return(NULL);
1014
1015 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +08001016 l = strlen((const char *) name);
1017 else
1018 l = len;
1019 if (((dict->limit > 0) && (l >= dict->limit)) ||
1020 (l > INT_MAX / 2))
1021 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001022
1023 /*
1024 * Check for duplicate and insertion location.
1025 */
Daniel Veillard7c693da2012-07-25 16:32:18 +08001026 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001027 key = okey % dict->size;
1028 if (dict->dict[key].valid == 0) {
1029 insert = NULL;
1030 } else {
1031 for (insert = &(dict->dict[key]); insert->next != NULL;
1032 insert = insert->next) {
1033#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001034 if ((insert->okey == okey) && (insert->len == l)) {
1035 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001036 return(insert->name);
1037 }
1038#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001039 if ((insert->okey == okey) && (insert->len == l) &&
1040 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001041 return(insert->name);
1042#endif
1043 nbi++;
1044 }
1045#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001046 if ((insert->okey == okey) && (insert->len == l)) {
1047 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001048 return(insert->name);
1049 }
1050#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001051 if ((insert->okey == okey) && (insert->len == l) &&
1052 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001053 return(insert->name);
1054#endif
1055 }
1056
1057 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001058 unsigned long skey;
1059
1060 /* we cannot always reuse the same okey for the subdict */
1061 if (((dict->size == MIN_DICT_SIZE) &&
1062 (dict->subdict->size != MIN_DICT_SIZE)) ||
1063 ((dict->size != MIN_DICT_SIZE) &&
1064 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001065 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001066 else
1067 skey = okey;
1068
1069 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001070 if (dict->subdict->dict[key].valid != 0) {
1071 xmlDictEntryPtr tmp;
1072
1073 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1074 tmp = tmp->next) {
1075#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001076 if ((tmp->okey == skey) && (tmp->len == l)) {
1077 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001078 return(tmp->name);
1079 }
1080#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001081 if ((tmp->okey == skey) && (tmp->len == l) &&
1082 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001083 return(tmp->name);
1084#endif
1085 nbi++;
1086 }
1087#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001088 if ((tmp->okey == skey) && (tmp->len == l)) {
1089 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001090 return(tmp->name);
1091 }
1092#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001093 if ((tmp->okey == skey) && (tmp->len == l) &&
1094 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001095 return(tmp->name);
1096#endif
1097 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001098 }
1099
1100 /* not found */
1101 return(NULL);
1102}
1103
1104/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001105 * xmlDictQLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001106 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001107 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001108 * @name: the name
1109 *
1110 * Add the QName @prefix:@name to the hash @dict if not present.
1111 *
1112 * Returns the internal copy of the QName or NULL in case of internal error
1113 */
1114const xmlChar *
1115xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001116 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001117 xmlDictEntryPtr entry;
1118 xmlDictEntryPtr insert;
1119 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001120 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001121
1122 if ((dict == NULL) || (name == NULL))
1123 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001124 if (prefix == NULL)
1125 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001126
Daniel Veillardffda65f2008-08-07 16:33:49 +00001127 l = len = strlen((const char *) name);
1128 plen = strlen((const char *) prefix);
1129 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001130
1131 /*
1132 * Check for duplicate and insertion location.
1133 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001134 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001135 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001136 if (dict->dict[key].valid == 0) {
1137 insert = NULL;
1138 } else {
1139 for (insert = &(dict->dict[key]); insert->next != NULL;
1140 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001141 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001142 (xmlStrQEqual(prefix, name, insert->name)))
1143 return(insert->name);
1144 nbi++;
1145 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001146 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001147 (xmlStrQEqual(prefix, name, insert->name)))
1148 return(insert->name);
1149 }
1150
Daniel Veillard4773df22004-01-23 13:15:13 +00001151 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001152 unsigned long skey;
1153
1154 /* we cannot always reuse the same okey for the subdict */
1155 if (((dict->size == MIN_DICT_SIZE) &&
1156 (dict->subdict->size != MIN_DICT_SIZE)) ||
1157 ((dict->size != MIN_DICT_SIZE) &&
1158 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001159 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001160 else
1161 skey = okey;
1162
1163 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001164 if (dict->subdict->dict[key].valid != 0) {
1165 xmlDictEntryPtr tmp;
1166 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1167 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001168 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001169 (xmlStrQEqual(prefix, name, tmp->name)))
1170 return(tmp->name);
1171 nbi++;
1172 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001173 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001174 (xmlStrQEqual(prefix, name, tmp->name)))
1175 return(tmp->name);
1176 }
1177 key = okey % dict->size;
1178 }
1179
Daniel Veillardffda65f2008-08-07 16:33:49 +00001180 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001181 if (ret == NULL)
1182 return(NULL);
1183 if (insert == NULL) {
1184 entry = &(dict->dict[key]);
1185 } else {
1186 entry = xmlMalloc(sizeof(xmlDictEntry));
1187 if (entry == NULL)
1188 return(NULL);
1189 }
1190 entry->name = ret;
1191 entry->len = len;
1192 entry->next = NULL;
1193 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001194 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001195
Daniel Veillard7c693da2012-07-25 16:32:18 +08001196 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001197 insert->next = entry;
1198
1199 dict->nbElems++;
1200
1201 if ((nbi > MAX_HASH_LEN) &&
1202 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1203 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1204 /* Note that entry may have been freed at this point by xmlDictGrow */
1205
1206 return(ret);
1207}
1208
1209/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001210 * xmlDictOwns:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001211 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001212 * @str: the string
1213 *
Jared Yanovich2a350ee2019-09-30 17:04:54 +02001214 * check if a string is owned by the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001215 *
1216 * Returns 1 if true, 0 if false and -1 in case of error
1217 * -1 in case of error
1218 */
1219int
1220xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1221 xmlDictStringsPtr pool;
1222
1223 if ((dict == NULL) || (str == NULL))
1224 return(-1);
1225 pool = dict->strings;
1226 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001227 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001228 return(1);
1229 pool = pool->next;
1230 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001231 if (dict->subdict)
1232 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001233 return(0);
1234}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001235
Daniel Veillard81514ba2003-09-16 23:17:26 +00001236/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001237 * xmlDictSize:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001238 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001239 *
1240 * Query the number of elements installed in the hash @dict.
1241 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001242 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001243 * -1 in case of error
1244 */
1245int
1246xmlDictSize(xmlDictPtr dict) {
1247 if (dict == NULL)
1248 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001249 if (dict->subdict)
1250 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001251 return(dict->nbElems);
1252}
1253
Daniel Veillard7c693da2012-07-25 16:32:18 +08001254/**
1255 * xmlDictSetLimit:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001256 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001257 * @limit: the limit in bytes
1258 *
1259 * Set a size limit for the dictionary
1260 * Added in 2.9.0
1261 *
1262 * Returns the previous limit of the dictionary or 0
1263 */
1264size_t
1265xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1266 size_t ret;
1267
1268 if (dict == NULL)
1269 return(0);
1270 ret = dict->limit;
1271 dict->limit = limit;
1272 return(ret);
1273}
1274
1275/**
1276 * xmlDictGetUsage:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001277 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001278 *
1279 * Get how much memory is used by a dictionary for strings
1280 * Added in 2.9.0
1281 *
1282 * Returns the amount of strings allocated
1283 */
1284size_t
1285xmlDictGetUsage(xmlDictPtr dict) {
1286 xmlDictStringsPtr pool;
1287 size_t limit = 0;
1288
1289 if (dict == NULL)
1290 return(0);
1291 pool = dict->strings;
1292 while (pool != NULL) {
1293 limit += pool->size;
1294 pool = pool->next;
1295 }
1296 return(limit);
1297}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001298