blob: fb0773b61821e1c4513c70a590732eb1c57a8159 [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 */
Nick Wellnhoferfa3166c2019-04-12 12:03:04 +020041#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) && \
42 !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
Daniel Veillard8973d582012-02-04 19:07:44 +080043#define DICT_RANDOMIZATION
44#endif
45
Daniel Veillard2fdbd322003-08-18 12:15:38 +000046#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000047#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000048#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000049#else
50#ifdef HAVE_INTTYPES_H
51#include <inttypes.h>
Nick Wellnhofere3890542017-10-09 00:20:01 +020052#elif defined(_WIN32)
Rob Richardsb6b2ee12008-05-03 12:34:25 +000053typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000054#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000055#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000056#include <libxml/tree.h>
57#include <libxml/dict.h>
58#include <libxml/xmlmemory.h>
59#include <libxml/xmlerror.h>
60#include <libxml/globals.h>
61
Daniel Veillard424785e2008-08-06 09:35:25 +000062/* #define DEBUG_GROW */
63/* #define DICT_DEBUG_PATTERNS */
64
Daniel Veillarde9100a52008-04-22 08:28:50 +000065#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000066#define MIN_DICT_SIZE 128
67#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000068#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000069
Daniel Veillard424785e2008-08-06 09:35:25 +000070#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080071#define xmlDictComputeKey(dict, name, len) \
72 (((dict)->size == MIN_DICT_SIZE) ? \
73 xmlDictComputeFastKey(name, len, (dict)->seed) : \
74 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000075
Daniel Veillard8973d582012-02-04 19:07:44 +080076#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
77 (((prefix) == NULL) ? \
78 (xmlDictComputeKey(dict, name, len)) : \
79 (((dict)->size == MIN_DICT_SIZE) ? \
80 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
81 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000082
Daniel Veillard424785e2008-08-06 09:35:25 +000083#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080084#define xmlDictComputeKey(dict, name, len) \
85 xmlDictComputeFastKey(name, len, (dict)->seed)
86#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
87 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000088#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000089
90/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +020091 * An entry in the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +000092 */
93typedef struct _xmlDictEntry xmlDictEntry;
94typedef xmlDictEntry *xmlDictEntryPtr;
95struct _xmlDictEntry {
96 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000097 const xmlChar *name;
Daniel Veillard7c693da2012-07-25 16:32:18 +080098 unsigned int len;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000099 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000100 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000101};
102
Daniel Veillard81514ba2003-09-16 23:17:26 +0000103typedef struct _xmlDictStrings xmlDictStrings;
104typedef xmlDictStrings *xmlDictStringsPtr;
105struct _xmlDictStrings {
106 xmlDictStringsPtr next;
107 xmlChar *free;
108 xmlChar *end;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800109 size_t size;
110 size_t nbStrings;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000111 xmlChar array[1];
112};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000113/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200114 * The entire dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000115 */
116struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000117 int ref_counter;
118
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000119 struct _xmlDictEntry *dict;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800120 size_t size;
121 unsigned int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000122 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000123
124 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800125 /* used for randomization */
126 int seed;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800127 /* used to impose a limit on size */
128 size_t limit;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000129};
130
131/*
Daniel Veillard14412512005-01-21 23:53:26 +0000132 * A mutex for modifying the reference counter for shared
133 * dictionaries.
134 */
135static xmlRMutexPtr xmlDictMutex = NULL;
136
137/*
138 * Whether the dictionary mutex was initialized.
139 */
140static int xmlDictInitialized = 0;
141
Daniel Veillard379ebc12012-05-18 15:41:31 +0800142#ifdef DICT_RANDOMIZATION
143#ifdef HAVE_RAND_R
144/*
145 * Internal data for random function, protected by xmlDictMutex
146 */
Wouter Van Rooye7715a52012-09-14 14:39:42 +0800147static unsigned int rand_seed = 0;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800148#endif
149#endif
150
Daniel Veillard14412512005-01-21 23:53:26 +0000151/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000152 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000153 *
154 * Do the dictionary mutex initialization.
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800155 * this function is deprecated
Daniel Veillardee8f1d42012-05-21 11:16:12 +0800156 *
157 * Returns 0 if initialization was already done, and 1 if that
158 * call led to the initialization
Daniel Veillard14412512005-01-21 23:53:26 +0000159 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800160int xmlInitializeDict(void) {
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800161 return(0);
162}
163
164/**
165 * __xmlInitializeDict:
166 *
167 * This function is not public
168 * Do the dictionary mutex initialization.
169 * this function is not thread safe, initialization should
170 * normally be done once at setup when called from xmlOnceInit()
171 * we may also land in this code if thread support is not compiled in
172 *
173 * Returns 0 if initialization was already done, and 1 if that
174 * call led to the initialization
175 */
176int __xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000177 if (xmlDictInitialized)
178 return(1);
179
180 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
181 return(0);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800182 xmlRMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000183
Daniel Veillard8973d582012-02-04 19:07:44 +0800184#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800185#ifdef HAVE_RAND_R
186 rand_seed = time(NULL);
187 rand_r(& rand_seed);
188#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800189 srand(time(NULL));
190#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800191#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000192 xmlDictInitialized = 1;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800193 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000194 return(1);
195}
196
Daniel Veillard379ebc12012-05-18 15:41:31 +0800197#ifdef DICT_RANDOMIZATION
198int __xmlRandom(void) {
199 int ret;
200
201 if (xmlDictInitialized == 0)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800202 __xmlInitializeDict();
Daniel Veillard379ebc12012-05-18 15:41:31 +0800203
204 xmlRMutexLock(xmlDictMutex);
205#ifdef HAVE_RAND_R
206 ret = rand_r(& rand_seed);
207#else
208 ret = rand();
209#endif
210 xmlRMutexUnlock(xmlDictMutex);
211 return(ret);
212}
213#endif
214
Daniel Veillard14412512005-01-21 23:53:26 +0000215/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000216 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000217 *
Daniel Veillard379ebc12012-05-18 15:41:31 +0800218 * Free the dictionary mutex. Do not call unless sure the library
219 * is not in use anymore !
Daniel Veillard14412512005-01-21 23:53:26 +0000220 */
221void
222xmlDictCleanup(void) {
223 if (!xmlDictInitialized)
224 return;
225
226 xmlFreeRMutex(xmlDictMutex);
227
228 xmlDictInitialized = 0;
229}
230
231/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000232 * xmlDictAddString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200233 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +0000234 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800235 * @len: the length of the name
Daniel Veillard81514ba2003-09-16 23:17:26 +0000236 *
237 * Add the string to the array[s]
238 *
239 * Returns the pointer of the local string, or NULL in case of error.
240 */
241static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800242xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Daniel Veillard81514ba2003-09-16 23:17:26 +0000243 xmlDictStringsPtr pool;
244 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800245 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
246 size_t limit = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000247
Daniel Veillard424785e2008-08-06 09:35:25 +0000248#ifdef DICT_DEBUG_PATTERNS
249 fprintf(stderr, "-");
250#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000251 pool = dict->strings;
252 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200253 if ((size_t)(pool->end - pool->free) > namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000254 goto found_pool;
255 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800256 limit += pool->size;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000257 pool = pool->next;
258 }
259 /*
260 * Not found, need to allocate
261 */
262 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800263 if ((dict->limit > 0) && (limit > dict->limit)) {
264 return(NULL);
265 }
266
Daniel Veillard81514ba2003-09-16 23:17:26 +0000267 if (size == 0) size = 1000;
268 else size *= 4; /* exponential growth */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800269 if (size < 4 * namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000270 size = 4 * namelen; /* just in case ! */
271 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
272 if (pool == NULL)
273 return(NULL);
274 pool->size = size;
275 pool->nbStrings = 0;
276 pool->free = &pool->array[0];
277 pool->end = &pool->array[size];
278 pool->next = dict->strings;
279 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000280#ifdef DICT_DEBUG_PATTERNS
281 fprintf(stderr, "+");
282#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000283 }
284found_pool:
285 ret = pool->free;
286 memcpy(pool->free, name, namelen);
287 pool->free += namelen;
288 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000289 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000290 return(ret);
291}
292
293/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000294 * xmlDictAddQString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200295 * @dict: the dictionary
Daniel Veillarde72c5082003-09-19 12:44:05 +0000296 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000297 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000298 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800299 * @len: the length of the name
Daniel Veillarde72c5082003-09-19 12:44:05 +0000300 *
301 * Add the QName to the array[s]
302 *
303 * Returns the pointer of the local string, or NULL in case of error.
304 */
305static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800306xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
307 const xmlChar *name, unsigned int namelen)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000308{
309 xmlDictStringsPtr pool;
310 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800311 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
312 size_t limit = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000313
314 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000315
Daniel Veillard424785e2008-08-06 09:35:25 +0000316#ifdef DICT_DEBUG_PATTERNS
317 fprintf(stderr, "=");
318#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000319 pool = dict->strings;
320 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200321 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000322 goto found_pool;
323 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800324 limit += pool->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000325 pool = pool->next;
326 }
327 /*
328 * Not found, need to allocate
329 */
330 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800331 if ((dict->limit > 0) && (limit > dict->limit)) {
332 return(NULL);
333 }
334
Daniel Veillarde72c5082003-09-19 12:44:05 +0000335 if (size == 0) size = 1000;
336 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000337 if (size < 4 * (namelen + plen + 1))
338 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000339 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
340 if (pool == NULL)
341 return(NULL);
342 pool->size = size;
343 pool->nbStrings = 0;
344 pool->free = &pool->array[0];
345 pool->end = &pool->array[size];
346 pool->next = dict->strings;
347 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000348#ifdef DICT_DEBUG_PATTERNS
349 fprintf(stderr, "+");
350#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000351 }
352found_pool:
353 ret = pool->free;
354 memcpy(pool->free, prefix, plen);
355 pool->free += plen;
356 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000357 memcpy(pool->free, name, namelen);
358 pool->free += namelen;
359 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000360 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000361 return(ret);
362}
363
Daniel Veillard424785e2008-08-06 09:35:25 +0000364#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000365/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000366 * xmlDictComputeBigKey:
367 *
368 * Calculate a hash key using a good hash function that works well for
369 * larger hash table sizes.
370 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000371 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000372 * http://burtleburtle.net/bob/hash/doobs.html
373 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000374
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200375ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Daniel Veillarde9100a52008-04-22 08:28:50 +0000376static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800377xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000378 uint32_t hash;
379 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000380
Daniel Veillard424785e2008-08-06 09:35:25 +0000381 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000382
Daniel Veillard8973d582012-02-04 19:07:44 +0800383 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000384
Daniel Veillard424785e2008-08-06 09:35:25 +0000385 for (i = 0;i < namelen; i++) {
386 hash += data[i];
387 hash += (hash << 10);
388 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000389 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000390 hash += (hash << 3);
391 hash ^= (hash >> 11);
392 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000393
394 return hash;
395}
396
397/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000398 * xmlDictComputeBigQKey:
399 *
400 * Calculate a hash key for two strings using a good hash function
401 * that works well for larger hash table sizes.
402 *
403 * Hash function by "One-at-a-Time Hash" see
404 * http://burtleburtle.net/bob/hash/doobs.html
405 *
406 * Neither of the two strings must be NULL.
407 */
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200408ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Daniel Veillard424785e2008-08-06 09:35:25 +0000409static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000410xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800411 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000412{
413 uint32_t hash;
414 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000415
Daniel Veillard8973d582012-02-04 19:07:44 +0800416 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000417
418 for (i = 0;i < plen; i++) {
419 hash += prefix[i];
420 hash += (hash << 10);
421 hash ^= (hash >> 6);
422 }
423 hash += ':';
424 hash += (hash << 10);
425 hash ^= (hash >> 6);
426
427 for (i = 0;i < len; i++) {
428 hash += name[i];
429 hash += (hash << 10);
430 hash ^= (hash >> 6);
431 }
432 hash += (hash << 3);
433 hash ^= (hash >> 11);
434 hash += (hash << 15);
435
436 return hash;
437}
438#endif /* WITH_BIG_KEY */
439
440/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000441 * xmlDictComputeFastKey:
442 *
443 * Calculate a hash key using a fast hash function that works well
444 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000445 */
446static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800447xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
448 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000449
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000450 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000451 value = *name;
452 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000453 if (namelen > 10) {
454 value += name[namelen - 1];
455 namelen = 10;
456 }
457 switch (namelen) {
458 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200459 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000460 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200461 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000462 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200463 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000464 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200465 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000466 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200467 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000468 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200469 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000470 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200471 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000472 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200473 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000474 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200475 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000476 default: break;
477 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000478 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000479}
480
481/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000482 * xmlDictComputeFastQKey:
483 *
484 * Calculate a hash key for two strings using a fast hash function
485 * that works well for low hash table fill.
486 *
487 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000488 */
489static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000490xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800491 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000492{
Daniel Veillard8973d582012-02-04 19:07:44 +0800493 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000494
Daniel Veillarde72c5082003-09-19 12:44:05 +0000495 if (plen == 0)
496 value += 30 * (unsigned long) ':';
497 else
498 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000499
Daniel Veillarde72c5082003-09-19 12:44:05 +0000500 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800501 int offset = len - (plen + 1 + 1);
502 if (offset < 0)
503 offset = len - (10 + 1);
504 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000505 len = 10;
506 if (plen > 10)
507 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000508 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000509 switch (plen) {
510 case 10: value += prefix[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200511 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000512 case 9: value += prefix[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200513 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000514 case 8: value += prefix[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200515 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000516 case 7: value += prefix[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200517 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000518 case 6: value += prefix[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200519 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000520 case 5: value += prefix[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200521 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000522 case 4: value += prefix[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200523 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000524 case 3: value += prefix[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200525 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000526 case 2: value += prefix[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200527 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000528 case 1: value += prefix[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200529 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000530 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000531 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000532 len -= plen;
533 if (len > 0) {
534 value += (unsigned long) ':';
535 len--;
536 }
537 switch (len) {
538 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200539 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000540 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200541 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000542 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200543 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000544 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200545 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000546 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200547 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000548 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200549 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000550 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200551 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000552 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200553 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000554 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200555 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000556 case 1: value += name[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200557 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000558 default: break;
559 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000560 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000561}
562
563/**
564 * xmlDictCreate:
565 *
566 * Create a new dictionary
567 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200568 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000569 */
570xmlDictPtr
571xmlDictCreate(void) {
572 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000573
574 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800575 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000576 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000577
578#ifdef DICT_DEBUG_PATTERNS
579 fprintf(stderr, "C");
580#endif
581
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000582 dict = xmlMalloc(sizeof(xmlDict));
583 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000584 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800585 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000586
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000587 dict->size = MIN_DICT_SIZE;
588 dict->nbElems = 0;
589 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000590 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000591 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000592 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000593 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800594#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800595 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800596#else
597 dict->seed = 0;
598#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000599 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000600 }
601 xmlFree(dict);
602 }
603 return(NULL);
604}
605
606/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000607 * xmlDictCreateSub:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200608 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000609 *
610 * Create a new dictionary, inheriting strings from the read-only
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200611 * dictionary @sub. On lookup, strings are first searched in the
612 * new dictionary, then in @sub, and if not found are created in the
613 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000614 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200615 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000616 */
617xmlDictPtr
618xmlDictCreateSub(xmlDictPtr sub) {
619 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000620
Daniel Veillard4773df22004-01-23 13:15:13 +0000621 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000622#ifdef DICT_DEBUG_PATTERNS
623 fprintf(stderr, "R");
624#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800625 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000626 dict->subdict = sub;
627 xmlDictReference(dict->subdict);
628 }
629 return(dict);
630}
631
632/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000633 * xmlDictReference:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200634 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000635 *
636 * Increment the reference counter of a dictionary
637 *
638 * Returns 0 in case of success and -1 in case of error
639 */
640int
641xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000642 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800643 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000644 return(-1);
645
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000646 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000647 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000648 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000649 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000650 return(0);
651}
652
653/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000654 * xmlDictGrow:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200655 * @dict: the dictionary
656 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000657 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200658 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000659 *
660 * Returns 0 in case of success, -1 in case of failure
661 */
662static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800663xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000664 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800665 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000666 xmlDictEntryPtr iter, next;
667 struct _xmlDictEntry *olddict;
668#ifdef DEBUG_GROW
669 unsigned long nbElem = 0;
670#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000671 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000672 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000673
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000674 if (dict == NULL)
675 return(-1);
676 if (size < 8)
677 return(-1);
678 if (size > 8 * 2048)
679 return(-1);
680
Daniel Veillard424785e2008-08-06 09:35:25 +0000681#ifdef DICT_DEBUG_PATTERNS
682 fprintf(stderr, "*");
683#endif
684
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000685 oldsize = dict->size;
686 olddict = dict->dict;
687 if (olddict == NULL)
688 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000689 if (oldsize == MIN_DICT_SIZE)
690 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000691
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000692 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
693 if (dict->dict == NULL) {
694 dict->dict = olddict;
695 return(-1);
696 }
697 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
698 dict->size = size;
699
700 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000701 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000702 the main dict. It is nicer to run through the array twice, first
703 copying all the elements in the main array (less probability of
704 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000705 */
706 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000707 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000708 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000709
710 if (keep_keys)
711 okey = olddict[i].okey;
712 else
713 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
714 key = okey % dict->size;
715
Daniel Veillardffda65f2008-08-07 16:33:49 +0000716 if (dict->dict[key].valid == 0) {
717 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
718 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000719 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000720 } else {
721 xmlDictEntryPtr entry;
722
723 entry = xmlMalloc(sizeof(xmlDictEntry));
724 if (entry != NULL) {
725 entry->name = olddict[i].name;
726 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000727 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000728 entry->next = dict->dict[key].next;
729 entry->valid = 1;
730 dict->dict[key].next = entry;
731 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000732 /*
Jared Yanovich2a350ee2019-09-30 17:04:54 +0200733 * we don't have much ways to alert from here
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200734 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000735 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000736 ret = -1;
737 }
738 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000739#ifdef DEBUG_GROW
740 nbElem++;
741#endif
742 }
743
744 for (i = 0; i < oldsize; i++) {
745 iter = olddict[i].next;
746 while (iter) {
747 next = iter->next;
748
749 /*
750 * put back the entry in the new dict
751 */
752
Daniel Veillardd68f8912008-08-08 10:09:19 +0000753 if (keep_keys)
754 okey = iter->okey;
755 else
756 okey = xmlDictComputeKey(dict, iter->name, iter->len);
757 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000758 if (dict->dict[key].valid == 0) {
759 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
760 dict->dict[key].next = NULL;
761 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000762 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000763 xmlFree(iter);
764 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000765 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000766 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000767 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000768 }
769
770#ifdef DEBUG_GROW
771 nbElem++;
772#endif
773
774 iter = next;
775 }
776 }
777
778 xmlFree(olddict);
779
780#ifdef DEBUG_GROW
781 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800782 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000783#endif
784
Daniel Veillardffda65f2008-08-07 16:33:49 +0000785 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000786}
787
788/**
789 * xmlDictFree:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200790 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000791 *
792 * Free the hash @dict and its contents. The userdata is
793 * deallocated with @f if provided.
794 */
795void
796xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800797 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000798 xmlDictEntryPtr iter;
799 xmlDictEntryPtr next;
800 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000801 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000802
803 if (dict == NULL)
804 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000805
Daniel Veillard14412512005-01-21 23:53:26 +0000806 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800807 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000808 return;
809
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000810 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000811 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000812 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000813 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000814 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000815 return;
816 }
817
Daniel Veillard14412512005-01-21 23:53:26 +0000818 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000819
Daniel Veillard4773df22004-01-23 13:15:13 +0000820 if (dict->subdict != NULL) {
821 xmlDictFree(dict->subdict);
822 }
823
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000824 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000825 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000826 iter = &(dict->dict[i]);
827 if (iter->valid == 0)
828 continue;
829 inside_dict = 1;
830 while (iter) {
831 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000832 if (!inside_dict)
833 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000834 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000835 inside_dict = 0;
836 iter = next;
837 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000838 }
839 xmlFree(dict->dict);
840 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000841 pool = dict->strings;
842 while (pool != NULL) {
843 nextp = pool->next;
844 xmlFree(pool);
845 pool = nextp;
846 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000847 xmlFree(dict);
848}
849
850/**
851 * xmlDictLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200852 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000853 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000854 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000855 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200856 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000857 *
858 * Returns the internal copy of the name or NULL in case of internal error
859 */
860const xmlChar *
861xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000862 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000863 xmlDictEntryPtr entry;
864 xmlDictEntryPtr insert;
865 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800866 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000867
Daniel Veillard0fb18932003-09-07 09:14:37 +0000868 if ((dict == NULL) || (name == NULL))
869 return(NULL);
870
871 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800872 l = strlen((const char *) name);
873 else
874 l = len;
875
876 if (((dict->limit > 0) && (l >= dict->limit)) ||
877 (l > INT_MAX / 2))
878 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000879
880 /*
881 * Check for duplicate and insertion location.
882 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800883 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000884 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000885 if (dict->dict[key].valid == 0) {
886 insert = NULL;
887 } else {
888 for (insert = &(dict->dict[key]); insert->next != NULL;
889 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000890#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800891 if ((insert->okey == okey) && (insert->len == l)) {
892 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000893 return(insert->name);
894 }
895#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800896 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800897 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000898 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000899#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000900 nbi++;
901 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000902#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800903 if ((insert->okey == okey) && (insert->len == l)) {
904 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000905 return(insert->name);
906 }
907#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800908 if ((insert->okey == okey) && (insert->len == l) &&
909 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000910 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000911#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000912 }
913
Daniel Veillard4773df22004-01-23 13:15:13 +0000914 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000915 unsigned long skey;
916
917 /* we cannot always reuse the same okey for the subdict */
918 if (((dict->size == MIN_DICT_SIZE) &&
919 (dict->subdict->size != MIN_DICT_SIZE)) ||
920 ((dict->size != MIN_DICT_SIZE) &&
921 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800922 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000923 else
924 skey = okey;
925
926 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000927 if (dict->subdict->dict[key].valid != 0) {
928 xmlDictEntryPtr tmp;
929
930 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
931 tmp = tmp->next) {
932#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800933 if ((tmp->okey == skey) && (tmp->len == l)) {
934 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000935 return(tmp->name);
936 }
937#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800938 if ((tmp->okey == skey) && (tmp->len == l) &&
939 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000940 return(tmp->name);
941#endif
942 nbi++;
943 }
944#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800945 if ((tmp->okey == skey) && (tmp->len == l)) {
946 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000947 return(tmp->name);
948 }
949#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800950 if ((tmp->okey == skey) && (tmp->len == l) &&
951 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000952 return(tmp->name);
953#endif
954 }
955 key = okey % dict->size;
956 }
957
Daniel Veillard7c693da2012-07-25 16:32:18 +0800958 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000959 if (ret == NULL)
960 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000961 if (insert == NULL) {
962 entry = &(dict->dict[key]);
963 } else {
964 entry = xmlMalloc(sizeof(xmlDictEntry));
965 if (entry == NULL)
966 return(NULL);
967 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000968 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800969 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000970 entry->next = NULL;
971 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000972 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000973
974
Daniel Veillard7c693da2012-07-25 16:32:18 +0800975 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000976 insert->next = entry;
977
978 dict->nbElems++;
979
980 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000981 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
982 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
983 return(NULL);
984 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000985 /* Note that entry may have been freed at this point by xmlDictGrow */
986
987 return(ret);
988}
989
990/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000991 * xmlDictExists:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200992 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000993 * @name: the name of the userdata
994 * @len: the length of the name, if -1 it is recomputed
995 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200996 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000997 *
998 * Returns the internal copy of the name or NULL if not found.
999 */
1000const xmlChar *
1001xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
1002 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001003 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001004 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001005
1006 if ((dict == NULL) || (name == NULL))
1007 return(NULL);
1008
1009 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +08001010 l = strlen((const char *) name);
1011 else
1012 l = len;
1013 if (((dict->limit > 0) && (l >= dict->limit)) ||
1014 (l > INT_MAX / 2))
1015 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001016
1017 /*
1018 * Check for duplicate and insertion location.
1019 */
Daniel Veillard7c693da2012-07-25 16:32:18 +08001020 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001021 key = okey % dict->size;
1022 if (dict->dict[key].valid == 0) {
1023 insert = NULL;
1024 } else {
1025 for (insert = &(dict->dict[key]); insert->next != NULL;
1026 insert = insert->next) {
1027#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001028 if ((insert->okey == okey) && (insert->len == l)) {
1029 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001030 return(insert->name);
1031 }
1032#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001033 if ((insert->okey == okey) && (insert->len == l) &&
1034 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001035 return(insert->name);
1036#endif
1037 nbi++;
1038 }
1039#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001040 if ((insert->okey == okey) && (insert->len == l)) {
1041 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001042 return(insert->name);
1043 }
1044#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001045 if ((insert->okey == okey) && (insert->len == l) &&
1046 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001047 return(insert->name);
1048#endif
1049 }
1050
1051 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001052 unsigned long skey;
1053
1054 /* we cannot always reuse the same okey for the subdict */
1055 if (((dict->size == MIN_DICT_SIZE) &&
1056 (dict->subdict->size != MIN_DICT_SIZE)) ||
1057 ((dict->size != MIN_DICT_SIZE) &&
1058 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001059 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001060 else
1061 skey = okey;
1062
1063 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001064 if (dict->subdict->dict[key].valid != 0) {
1065 xmlDictEntryPtr tmp;
1066
1067 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1068 tmp = tmp->next) {
1069#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001070 if ((tmp->okey == skey) && (tmp->len == l)) {
1071 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001072 return(tmp->name);
1073 }
1074#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001075 if ((tmp->okey == skey) && (tmp->len == l) &&
1076 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001077 return(tmp->name);
1078#endif
1079 nbi++;
1080 }
1081#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001082 if ((tmp->okey == skey) && (tmp->len == l)) {
1083 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001084 return(tmp->name);
1085 }
1086#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001087 if ((tmp->okey == skey) && (tmp->len == l) &&
1088 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001089 return(tmp->name);
1090#endif
1091 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001092 }
1093
1094 /* not found */
1095 return(NULL);
1096}
1097
1098/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001099 * xmlDictQLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001100 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001101 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001102 * @name: the name
1103 *
1104 * Add the QName @prefix:@name to the hash @dict if not present.
1105 *
1106 * Returns the internal copy of the QName or NULL in case of internal error
1107 */
1108const xmlChar *
1109xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001110 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001111 xmlDictEntryPtr entry;
1112 xmlDictEntryPtr insert;
1113 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001114 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001115
1116 if ((dict == NULL) || (name == NULL))
1117 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001118 if (prefix == NULL)
1119 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001120
Daniel Veillardffda65f2008-08-07 16:33:49 +00001121 l = len = strlen((const char *) name);
1122 plen = strlen((const char *) prefix);
1123 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001124
1125 /*
1126 * Check for duplicate and insertion location.
1127 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001128 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001129 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001130 if (dict->dict[key].valid == 0) {
1131 insert = NULL;
1132 } else {
1133 for (insert = &(dict->dict[key]); insert->next != NULL;
1134 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001135 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001136 (xmlStrQEqual(prefix, name, insert->name)))
1137 return(insert->name);
1138 nbi++;
1139 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001140 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001141 (xmlStrQEqual(prefix, name, insert->name)))
1142 return(insert->name);
1143 }
1144
Daniel Veillard4773df22004-01-23 13:15:13 +00001145 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001146 unsigned long skey;
1147
1148 /* we cannot always reuse the same okey for the subdict */
1149 if (((dict->size == MIN_DICT_SIZE) &&
1150 (dict->subdict->size != MIN_DICT_SIZE)) ||
1151 ((dict->size != MIN_DICT_SIZE) &&
1152 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001153 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001154 else
1155 skey = okey;
1156
1157 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001158 if (dict->subdict->dict[key].valid != 0) {
1159 xmlDictEntryPtr tmp;
1160 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1161 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001162 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001163 (xmlStrQEqual(prefix, name, tmp->name)))
1164 return(tmp->name);
1165 nbi++;
1166 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001167 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001168 (xmlStrQEqual(prefix, name, tmp->name)))
1169 return(tmp->name);
1170 }
1171 key = okey % dict->size;
1172 }
1173
Daniel Veillardffda65f2008-08-07 16:33:49 +00001174 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001175 if (ret == NULL)
1176 return(NULL);
1177 if (insert == NULL) {
1178 entry = &(dict->dict[key]);
1179 } else {
1180 entry = xmlMalloc(sizeof(xmlDictEntry));
1181 if (entry == NULL)
1182 return(NULL);
1183 }
1184 entry->name = ret;
1185 entry->len = len;
1186 entry->next = NULL;
1187 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001188 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001189
Daniel Veillard7c693da2012-07-25 16:32:18 +08001190 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001191 insert->next = entry;
1192
1193 dict->nbElems++;
1194
1195 if ((nbi > MAX_HASH_LEN) &&
1196 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1197 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1198 /* Note that entry may have been freed at this point by xmlDictGrow */
1199
1200 return(ret);
1201}
1202
1203/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001204 * xmlDictOwns:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001205 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001206 * @str: the string
1207 *
Jared Yanovich2a350ee2019-09-30 17:04:54 +02001208 * check if a string is owned by the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001209 *
1210 * Returns 1 if true, 0 if false and -1 in case of error
1211 * -1 in case of error
1212 */
1213int
1214xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1215 xmlDictStringsPtr pool;
1216
1217 if ((dict == NULL) || (str == NULL))
1218 return(-1);
1219 pool = dict->strings;
1220 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001221 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001222 return(1);
1223 pool = pool->next;
1224 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001225 if (dict->subdict)
1226 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001227 return(0);
1228}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001229
Daniel Veillard81514ba2003-09-16 23:17:26 +00001230/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001231 * xmlDictSize:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001232 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001233 *
1234 * Query the number of elements installed in the hash @dict.
1235 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001236 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001237 * -1 in case of error
1238 */
1239int
1240xmlDictSize(xmlDictPtr dict) {
1241 if (dict == NULL)
1242 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001243 if (dict->subdict)
1244 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001245 return(dict->nbElems);
1246}
1247
Daniel Veillard7c693da2012-07-25 16:32:18 +08001248/**
1249 * xmlDictSetLimit:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001250 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001251 * @limit: the limit in bytes
1252 *
1253 * Set a size limit for the dictionary
1254 * Added in 2.9.0
1255 *
1256 * Returns the previous limit of the dictionary or 0
1257 */
1258size_t
1259xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1260 size_t ret;
1261
1262 if (dict == NULL)
1263 return(0);
1264 ret = dict->limit;
1265 dict->limit = limit;
1266 return(ret);
1267}
1268
1269/**
1270 * xmlDictGetUsage:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001271 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001272 *
1273 * Get how much memory is used by a dictionary for strings
1274 * Added in 2.9.0
1275 *
1276 * Returns the amount of strings allocated
1277 */
1278size_t
1279xmlDictGetUsage(xmlDictPtr dict) {
1280 xmlDictStringsPtr pool;
1281 size_t limit = 0;
1282
1283 if (dict == NULL)
1284 return(0);
1285 pool = dict->strings;
1286 while (pool != NULL) {
1287 limit += pool->size;
1288 pool = pool->next;
1289 }
1290 return(limit);
1291}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001292
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001293#define bottom_dict
1294#include "elfgcchack.h"