blob: 5e3951103077c33ba29a007d91849d500cffbf6a [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
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013 * 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#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 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070041#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
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700375#ifdef __clang__
376ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
377#endif
Daniel Veillarde9100a52008-04-22 08:28:50 +0000378static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800379xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000380 uint32_t hash;
381 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000382
Daniel Veillard424785e2008-08-06 09:35:25 +0000383 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000384
Daniel Veillard8973d582012-02-04 19:07:44 +0800385 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000386
Daniel Veillard424785e2008-08-06 09:35:25 +0000387 for (i = 0;i < namelen; i++) {
388 hash += data[i];
389 hash += (hash << 10);
390 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000391 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000392 hash += (hash << 3);
393 hash ^= (hash >> 11);
394 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000395
396 return hash;
397}
398
399/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000400 * xmlDictComputeBigQKey:
401 *
402 * Calculate a hash key for two strings using a good hash function
403 * that works well for larger hash table sizes.
404 *
405 * Hash function by "One-at-a-Time Hash" see
406 * http://burtleburtle.net/bob/hash/doobs.html
407 *
408 * Neither of the two strings must be NULL.
409 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700410#ifdef __clang__
411ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
412#endif
Daniel Veillard424785e2008-08-06 09:35:25 +0000413static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000414xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800415 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000416{
417 uint32_t hash;
418 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000419
Daniel Veillard8973d582012-02-04 19:07:44 +0800420 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000421
422 for (i = 0;i < plen; i++) {
423 hash += prefix[i];
424 hash += (hash << 10);
425 hash ^= (hash >> 6);
426 }
427 hash += ':';
428 hash += (hash << 10);
429 hash ^= (hash >> 6);
430
431 for (i = 0;i < len; i++) {
432 hash += name[i];
433 hash += (hash << 10);
434 hash ^= (hash >> 6);
435 }
436 hash += (hash << 3);
437 hash ^= (hash >> 11);
438 hash += (hash << 15);
439
440 return hash;
441}
442#endif /* WITH_BIG_KEY */
443
444/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000445 * xmlDictComputeFastKey:
446 *
447 * Calculate a hash key using a fast hash function that works well
448 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000449 */
450static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800451xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
452 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000453
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000454 if (name == NULL) return(0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700455 value += *name;
Daniel Veillard4773df22004-01-23 13:15:13 +0000456 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000457 if (namelen > 10) {
458 value += name[namelen - 1];
459 namelen = 10;
460 }
461 switch (namelen) {
462 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200463 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000464 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200465 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000466 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200467 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000468 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200469 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000470 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200471 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000472 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200473 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000474 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200475 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000476 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200477 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000478 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200479 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000480 default: break;
481 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000482 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000483}
484
485/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000486 * xmlDictComputeFastQKey:
487 *
488 * Calculate a hash key for two strings using a fast hash function
489 * that works well for low hash table fill.
490 *
491 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000492 */
493static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000494xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800495 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000496{
Daniel Veillard8973d582012-02-04 19:07:44 +0800497 unsigned long value = (unsigned long) seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000498
Daniel Veillarde72c5082003-09-19 12:44:05 +0000499 if (plen == 0)
500 value += 30 * (unsigned long) ':';
501 else
502 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000503
Daniel Veillarde72c5082003-09-19 12:44:05 +0000504 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800505 int offset = len - (plen + 1 + 1);
506 if (offset < 0)
507 offset = len - (10 + 1);
508 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000509 len = 10;
510 if (plen > 10)
511 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000512 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000513 switch (plen) {
514 case 10: value += prefix[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200515 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000516 case 9: value += prefix[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200517 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000518 case 8: value += prefix[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200519 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000520 case 7: value += prefix[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200521 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000522 case 6: value += prefix[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200523 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000524 case 5: value += prefix[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200525 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000526 case 4: value += prefix[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200527 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000528 case 3: value += prefix[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200529 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000530 case 2: value += prefix[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200531 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000532 case 1: value += prefix[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200533 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000534 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000535 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000536 len -= plen;
537 if (len > 0) {
538 value += (unsigned long) ':';
539 len--;
540 }
541 switch (len) {
542 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200543 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000544 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200545 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000546 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200547 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000548 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200549 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000550 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200551 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000552 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200553 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000554 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200555 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000556 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200557 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000558 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200559 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000560 case 1: value += name[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200561 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000562 default: break;
563 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000564 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000565}
566
567/**
568 * xmlDictCreate:
569 *
570 * Create a new dictionary
571 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200572 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000573 */
574xmlDictPtr
575xmlDictCreate(void) {
576 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000577
578 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800579 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000580 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000581
582#ifdef DICT_DEBUG_PATTERNS
583 fprintf(stderr, "C");
584#endif
585
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000586 dict = xmlMalloc(sizeof(xmlDict));
587 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000588 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800589 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000590
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000591 dict->size = MIN_DICT_SIZE;
592 dict->nbElems = 0;
593 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000594 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000595 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000596 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000597 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800598#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800599 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800600#else
601 dict->seed = 0;
602#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000603 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000604 }
605 xmlFree(dict);
606 }
607 return(NULL);
608}
609
610/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000611 * xmlDictCreateSub:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200612 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000613 *
614 * Create a new dictionary, inheriting strings from the read-only
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200615 * dictionary @sub. On lookup, strings are first searched in the
616 * new dictionary, then in @sub, and if not found are created in the
617 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000618 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200619 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000620 */
621xmlDictPtr
622xmlDictCreateSub(xmlDictPtr sub) {
623 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000624
Daniel Veillard4773df22004-01-23 13:15:13 +0000625 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000626#ifdef DICT_DEBUG_PATTERNS
627 fprintf(stderr, "R");
628#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800629 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000630 dict->subdict = sub;
631 xmlDictReference(dict->subdict);
632 }
633 return(dict);
634}
635
636/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000637 * xmlDictReference:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200638 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000639 *
640 * Increment the reference counter of a dictionary
641 *
642 * Returns 0 in case of success and -1 in case of error
643 */
644int
645xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000646 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800647 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000648 return(-1);
649
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000650 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000651 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000652 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000653 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000654 return(0);
655}
656
657/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000658 * xmlDictGrow:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200659 * @dict: the dictionary
660 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000661 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200662 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000663 *
664 * Returns 0 in case of success, -1 in case of failure
665 */
666static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800667xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000668 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800669 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000670 xmlDictEntryPtr iter, next;
671 struct _xmlDictEntry *olddict;
672#ifdef DEBUG_GROW
673 unsigned long nbElem = 0;
674#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000675 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000676 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000677
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000678 if (dict == NULL)
679 return(-1);
680 if (size < 8)
681 return(-1);
682 if (size > 8 * 2048)
683 return(-1);
684
Daniel Veillard424785e2008-08-06 09:35:25 +0000685#ifdef DICT_DEBUG_PATTERNS
686 fprintf(stderr, "*");
687#endif
688
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000689 oldsize = dict->size;
690 olddict = dict->dict;
691 if (olddict == NULL)
692 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000693 if (oldsize == MIN_DICT_SIZE)
694 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000695
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000696 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
697 if (dict->dict == NULL) {
698 dict->dict = olddict;
699 return(-1);
700 }
701 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
702 dict->size = size;
703
704 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000705 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000706 the main dict. It is nicer to run through the array twice, first
707 copying all the elements in the main array (less probability of
708 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000709 */
710 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000711 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000712 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000713
714 if (keep_keys)
715 okey = olddict[i].okey;
716 else
717 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
718 key = okey % dict->size;
719
Daniel Veillardffda65f2008-08-07 16:33:49 +0000720 if (dict->dict[key].valid == 0) {
721 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
722 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000723 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000724 } else {
725 xmlDictEntryPtr entry;
726
727 entry = xmlMalloc(sizeof(xmlDictEntry));
728 if (entry != NULL) {
729 entry->name = olddict[i].name;
730 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000731 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000732 entry->next = dict->dict[key].next;
733 entry->valid = 1;
734 dict->dict[key].next = entry;
735 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000736 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700737 * we don't have much ways to alert from here
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200738 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000739 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000740 ret = -1;
741 }
742 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000743#ifdef DEBUG_GROW
744 nbElem++;
745#endif
746 }
747
748 for (i = 0; i < oldsize; i++) {
749 iter = olddict[i].next;
750 while (iter) {
751 next = iter->next;
752
753 /*
754 * put back the entry in the new dict
755 */
756
Daniel Veillardd68f8912008-08-08 10:09:19 +0000757 if (keep_keys)
758 okey = iter->okey;
759 else
760 okey = xmlDictComputeKey(dict, iter->name, iter->len);
761 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000762 if (dict->dict[key].valid == 0) {
763 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
764 dict->dict[key].next = NULL;
765 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000766 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000767 xmlFree(iter);
768 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000769 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000770 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000771 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000772 }
773
774#ifdef DEBUG_GROW
775 nbElem++;
776#endif
777
778 iter = next;
779 }
780 }
781
782 xmlFree(olddict);
783
784#ifdef DEBUG_GROW
785 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800786 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000787#endif
788
Daniel Veillardffda65f2008-08-07 16:33:49 +0000789 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000790}
791
792/**
793 * xmlDictFree:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200794 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000795 *
796 * Free the hash @dict and its contents. The userdata is
797 * deallocated with @f if provided.
798 */
799void
800xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800801 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000802 xmlDictEntryPtr iter;
803 xmlDictEntryPtr next;
804 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000805 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000806
807 if (dict == NULL)
808 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000809
Daniel Veillard14412512005-01-21 23:53:26 +0000810 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800811 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000812 return;
813
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000814 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000815 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000816 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000817 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000818 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000819 return;
820 }
821
Daniel Veillard14412512005-01-21 23:53:26 +0000822 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000823
Daniel Veillard4773df22004-01-23 13:15:13 +0000824 if (dict->subdict != NULL) {
825 xmlDictFree(dict->subdict);
826 }
827
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000828 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000829 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000830 iter = &(dict->dict[i]);
831 if (iter->valid == 0)
832 continue;
833 inside_dict = 1;
834 while (iter) {
835 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000836 if (!inside_dict)
837 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000838 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000839 inside_dict = 0;
840 iter = next;
841 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000842 }
843 xmlFree(dict->dict);
844 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000845 pool = dict->strings;
846 while (pool != NULL) {
847 nextp = pool->next;
848 xmlFree(pool);
849 pool = nextp;
850 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000851 xmlFree(dict);
852}
853
854/**
855 * xmlDictLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200856 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000857 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000858 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000859 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200860 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000861 *
862 * Returns the internal copy of the name or NULL in case of internal error
863 */
864const xmlChar *
865xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000866 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000867 xmlDictEntryPtr entry;
868 xmlDictEntryPtr insert;
869 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800870 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000871
Daniel Veillard0fb18932003-09-07 09:14:37 +0000872 if ((dict == NULL) || (name == NULL))
873 return(NULL);
874
875 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800876 l = strlen((const char *) name);
877 else
878 l = len;
879
880 if (((dict->limit > 0) && (l >= dict->limit)) ||
881 (l > INT_MAX / 2))
882 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000883
884 /*
885 * Check for duplicate and insertion location.
886 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800887 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000888 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000889 if (dict->dict[key].valid == 0) {
890 insert = NULL;
891 } else {
892 for (insert = &(dict->dict[key]); insert->next != NULL;
893 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000894#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800895 if ((insert->okey == okey) && (insert->len == l)) {
896 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000897 return(insert->name);
898 }
899#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800900 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800901 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000902 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000903#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000904 nbi++;
905 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000906#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800907 if ((insert->okey == okey) && (insert->len == l)) {
908 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000909 return(insert->name);
910 }
911#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800912 if ((insert->okey == okey) && (insert->len == l) &&
913 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000914 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000915#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000916 }
917
Daniel Veillard4773df22004-01-23 13:15:13 +0000918 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000919 unsigned long skey;
920
921 /* we cannot always reuse the same okey for the subdict */
922 if (((dict->size == MIN_DICT_SIZE) &&
923 (dict->subdict->size != MIN_DICT_SIZE)) ||
924 ((dict->size != MIN_DICT_SIZE) &&
925 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800926 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000927 else
928 skey = okey;
929
930 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000931 if (dict->subdict->dict[key].valid != 0) {
932 xmlDictEntryPtr tmp;
933
934 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
935 tmp = tmp->next) {
936#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800937 if ((tmp->okey == skey) && (tmp->len == l)) {
938 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000939 return(tmp->name);
940 }
941#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800942 if ((tmp->okey == skey) && (tmp->len == l) &&
943 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000944 return(tmp->name);
945#endif
946 nbi++;
947 }
948#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800949 if ((tmp->okey == skey) && (tmp->len == l)) {
950 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000951 return(tmp->name);
952 }
953#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800954 if ((tmp->okey == skey) && (tmp->len == l) &&
955 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000956 return(tmp->name);
957#endif
958 }
959 key = okey % dict->size;
960 }
961
Daniel Veillard7c693da2012-07-25 16:32:18 +0800962 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000963 if (ret == NULL)
964 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000965 if (insert == NULL) {
966 entry = &(dict->dict[key]);
967 } else {
968 entry = xmlMalloc(sizeof(xmlDictEntry));
969 if (entry == NULL)
970 return(NULL);
971 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000972 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800973 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000974 entry->next = NULL;
975 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000976 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000977
978
Daniel Veillard7c693da2012-07-25 16:32:18 +0800979 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000980 insert->next = entry;
981
982 dict->nbElems++;
983
984 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000985 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
986 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
987 return(NULL);
988 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000989 /* Note that entry may have been freed at this point by xmlDictGrow */
990
991 return(ret);
992}
993
994/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000995 * xmlDictExists:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200996 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000997 * @name: the name of the userdata
998 * @len: the length of the name, if -1 it is recomputed
999 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001000 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001001 *
1002 * Returns the internal copy of the name or NULL if not found.
1003 */
1004const xmlChar *
1005xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
1006 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001007 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001008 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001009
1010 if ((dict == NULL) || (name == NULL))
1011 return(NULL);
1012
1013 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +08001014 l = strlen((const char *) name);
1015 else
1016 l = len;
1017 if (((dict->limit > 0) && (l >= dict->limit)) ||
1018 (l > INT_MAX / 2))
1019 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001020
1021 /*
1022 * Check for duplicate and insertion location.
1023 */
Daniel Veillard7c693da2012-07-25 16:32:18 +08001024 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001025 key = okey % dict->size;
1026 if (dict->dict[key].valid == 0) {
1027 insert = NULL;
1028 } else {
1029 for (insert = &(dict->dict[key]); insert->next != NULL;
1030 insert = insert->next) {
1031#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001032 if ((insert->okey == okey) && (insert->len == l)) {
1033 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001034 return(insert->name);
1035 }
1036#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001037 if ((insert->okey == okey) && (insert->len == l) &&
1038 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001039 return(insert->name);
1040#endif
1041 nbi++;
1042 }
1043#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001044 if ((insert->okey == okey) && (insert->len == l)) {
1045 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001046 return(insert->name);
1047 }
1048#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001049 if ((insert->okey == okey) && (insert->len == l) &&
1050 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001051 return(insert->name);
1052#endif
1053 }
1054
1055 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001056 unsigned long skey;
1057
1058 /* we cannot always reuse the same okey for the subdict */
1059 if (((dict->size == MIN_DICT_SIZE) &&
1060 (dict->subdict->size != MIN_DICT_SIZE)) ||
1061 ((dict->size != MIN_DICT_SIZE) &&
1062 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001063 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001064 else
1065 skey = okey;
1066
1067 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001068 if (dict->subdict->dict[key].valid != 0) {
1069 xmlDictEntryPtr tmp;
1070
1071 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1072 tmp = tmp->next) {
1073#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001074 if ((tmp->okey == skey) && (tmp->len == l)) {
1075 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001076 return(tmp->name);
1077 }
1078#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001079 if ((tmp->okey == skey) && (tmp->len == l) &&
1080 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001081 return(tmp->name);
1082#endif
1083 nbi++;
1084 }
1085#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001086 if ((tmp->okey == skey) && (tmp->len == l)) {
1087 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001088 return(tmp->name);
1089 }
1090#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001091 if ((tmp->okey == skey) && (tmp->len == l) &&
1092 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001093 return(tmp->name);
1094#endif
1095 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001096 }
1097
1098 /* not found */
1099 return(NULL);
1100}
1101
1102/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001103 * xmlDictQLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001104 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001105 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001106 * @name: the name
1107 *
1108 * Add the QName @prefix:@name to the hash @dict if not present.
1109 *
1110 * Returns the internal copy of the QName or NULL in case of internal error
1111 */
1112const xmlChar *
1113xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001114 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001115 xmlDictEntryPtr entry;
1116 xmlDictEntryPtr insert;
1117 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001118 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001119
1120 if ((dict == NULL) || (name == NULL))
1121 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001122 if (prefix == NULL)
1123 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001124
Daniel Veillardffda65f2008-08-07 16:33:49 +00001125 l = len = strlen((const char *) name);
1126 plen = strlen((const char *) prefix);
1127 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001128
1129 /*
1130 * Check for duplicate and insertion location.
1131 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001132 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001133 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001134 if (dict->dict[key].valid == 0) {
1135 insert = NULL;
1136 } else {
1137 for (insert = &(dict->dict[key]); insert->next != NULL;
1138 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001139 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001140 (xmlStrQEqual(prefix, name, insert->name)))
1141 return(insert->name);
1142 nbi++;
1143 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001144 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001145 (xmlStrQEqual(prefix, name, insert->name)))
1146 return(insert->name);
1147 }
1148
Daniel Veillard4773df22004-01-23 13:15:13 +00001149 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001150 unsigned long skey;
1151
1152 /* we cannot always reuse the same okey for the subdict */
1153 if (((dict->size == MIN_DICT_SIZE) &&
1154 (dict->subdict->size != MIN_DICT_SIZE)) ||
1155 ((dict->size != MIN_DICT_SIZE) &&
1156 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001157 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001158 else
1159 skey = okey;
1160
1161 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001162 if (dict->subdict->dict[key].valid != 0) {
1163 xmlDictEntryPtr tmp;
1164 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1165 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001166 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001167 (xmlStrQEqual(prefix, name, tmp->name)))
1168 return(tmp->name);
1169 nbi++;
1170 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001171 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001172 (xmlStrQEqual(prefix, name, tmp->name)))
1173 return(tmp->name);
1174 }
1175 key = okey % dict->size;
1176 }
1177
Daniel Veillardffda65f2008-08-07 16:33:49 +00001178 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001179 if (ret == NULL)
1180 return(NULL);
1181 if (insert == NULL) {
1182 entry = &(dict->dict[key]);
1183 } else {
1184 entry = xmlMalloc(sizeof(xmlDictEntry));
1185 if (entry == NULL)
1186 return(NULL);
1187 }
1188 entry->name = ret;
1189 entry->len = len;
1190 entry->next = NULL;
1191 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001192 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001193
Daniel Veillard7c693da2012-07-25 16:32:18 +08001194 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001195 insert->next = entry;
1196
1197 dict->nbElems++;
1198
1199 if ((nbi > MAX_HASH_LEN) &&
1200 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1201 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1202 /* Note that entry may have been freed at this point by xmlDictGrow */
1203
1204 return(ret);
1205}
1206
1207/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001208 * xmlDictOwns:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001209 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001210 * @str: the string
1211 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001212 * check if a string is owned by the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001213 *
1214 * Returns 1 if true, 0 if false and -1 in case of error
1215 * -1 in case of error
1216 */
1217int
1218xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1219 xmlDictStringsPtr pool;
1220
1221 if ((dict == NULL) || (str == NULL))
1222 return(-1);
1223 pool = dict->strings;
1224 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001225 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001226 return(1);
1227 pool = pool->next;
1228 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001229 if (dict->subdict)
1230 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001231 return(0);
1232}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001233
Daniel Veillard81514ba2003-09-16 23:17:26 +00001234/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001235 * xmlDictSize:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001236 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001237 *
1238 * Query the number of elements installed in the hash @dict.
1239 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001240 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001241 * -1 in case of error
1242 */
1243int
1244xmlDictSize(xmlDictPtr dict) {
1245 if (dict == NULL)
1246 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001247 if (dict->subdict)
1248 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001249 return(dict->nbElems);
1250}
1251
Daniel Veillard7c693da2012-07-25 16:32:18 +08001252/**
1253 * xmlDictSetLimit:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001254 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001255 * @limit: the limit in bytes
1256 *
1257 * Set a size limit for the dictionary
1258 * Added in 2.9.0
1259 *
1260 * Returns the previous limit of the dictionary or 0
1261 */
1262size_t
1263xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1264 size_t ret;
1265
1266 if (dict == NULL)
1267 return(0);
1268 ret = dict->limit;
1269 dict->limit = limit;
1270 return(ret);
1271}
1272
1273/**
1274 * xmlDictGetUsage:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001275 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001276 *
1277 * Get how much memory is used by a dictionary for strings
1278 * Added in 2.9.0
1279 *
1280 * Returns the amount of strings allocated
1281 */
1282size_t
1283xmlDictGetUsage(xmlDictPtr dict) {
1284 xmlDictStringsPtr pool;
1285 size_t limit = 0;
1286
1287 if (dict == NULL)
1288 return(0);
1289 pool = dict->strings;
1290 while (pool != NULL) {
1291 limit += pool->size;
1292 pool = pool->next;
1293 }
1294 return(limit);
1295}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001296