blob: 1335387243469b7e8510beefed6444b5f46900d5 [file] [log] [blame]
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001/*
2 * dict.c: dictionary of reusable strings, just used to avoid allocation
3 * and freeing operations.
4 *
Daniel Veillard8973d582012-02-04 19:07:44 +08005 * Copyright (C) 2003-2012 Daniel Veillard.
Daniel Veillard2fdbd322003-08-18 12:15:38 +00006 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
Nick Wellnhofer20c60882020-03-08 17:19:42 +010013 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
Daniel Veillard2fdbd322003-08-18 12:15:38 +000014 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 * Author: daniel@veillard.com
17 */
18
19#define IN_LIBXML
20#include "libxml.h"
21
Daniel Veillard7c693da2012-07-25 16:32:18 +080022#include <limits.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080023#include <stdlib.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080024#include <time.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080025
Nick Wellnhofer0f568c02022-08-26 01:22:33 +020026#include "private/dict.h"
Nick Wellnhofer65d381f2022-11-24 20:54:18 +010027#include "private/threads.h"
Nick Wellnhofer0f568c02022-08-26 01:22:33 +020028
Daniel Veillard8973d582012-02-04 19:07:44 +080029/*
30 * Following http://www.ocert.org/advisories/ocert-2011-003.html
31 * it seems that having hash randomization might be a good idea
32 * when using XML with untrusted data
33 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
34 * which is the default.
35 * Note2: the fast function used for a small dict won't protect very
36 * well but since the attack is based on growing a very big hash
37 * list we will use the BigKey algo as soon as the hash size grows
38 * over MIN_DICT_SIZE so this actually works
39 */
Nick Wellnhofer72119af2022-03-02 01:14:08 +010040#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
Daniel Veillard8973d582012-02-04 19:07:44 +080041#define DICT_RANDOMIZATION
42#endif
43
Daniel Veillard2fdbd322003-08-18 12:15:38 +000044#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000045#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000046#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000047#else
48#ifdef HAVE_INTTYPES_H
49#include <inttypes.h>
Nick Wellnhofere3890542017-10-09 00:20:01 +020050#elif defined(_WIN32)
Rob Richardsb6b2ee12008-05-03 12:34:25 +000051typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000052#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000053#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000054#include <libxml/tree.h>
55#include <libxml/dict.h>
56#include <libxml/xmlmemory.h>
57#include <libxml/xmlerror.h>
58#include <libxml/globals.h>
59
Daniel Veillard424785e2008-08-06 09:35:25 +000060/* #define DEBUG_GROW */
61/* #define DICT_DEBUG_PATTERNS */
62
Daniel Veillarde9100a52008-04-22 08:28:50 +000063#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000064#define MIN_DICT_SIZE 128
65#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000066#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000067
Daniel Veillard424785e2008-08-06 09:35:25 +000068#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080069#define xmlDictComputeKey(dict, name, len) \
70 (((dict)->size == MIN_DICT_SIZE) ? \
71 xmlDictComputeFastKey(name, len, (dict)->seed) : \
72 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000073
Daniel Veillard8973d582012-02-04 19:07:44 +080074#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
75 (((prefix) == NULL) ? \
76 (xmlDictComputeKey(dict, name, len)) : \
77 (((dict)->size == MIN_DICT_SIZE) ? \
78 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
79 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000080
Daniel Veillard424785e2008-08-06 09:35:25 +000081#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080082#define xmlDictComputeKey(dict, name, len) \
83 xmlDictComputeFastKey(name, len, (dict)->seed)
84#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
85 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000086#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000087
88/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +020089 * An entry in the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +000090 */
91typedef struct _xmlDictEntry xmlDictEntry;
92typedef xmlDictEntry *xmlDictEntryPtr;
93struct _xmlDictEntry {
94 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000095 const xmlChar *name;
Daniel Veillard7c693da2012-07-25 16:32:18 +080096 unsigned int len;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000097 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000098 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000099};
100
Daniel Veillard81514ba2003-09-16 23:17:26 +0000101typedef struct _xmlDictStrings xmlDictStrings;
102typedef xmlDictStrings *xmlDictStringsPtr;
103struct _xmlDictStrings {
104 xmlDictStringsPtr next;
105 xmlChar *free;
106 xmlChar *end;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800107 size_t size;
108 size_t nbStrings;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000109 xmlChar array[1];
110};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000111/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200112 * The entire dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000113 */
114struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000115 int ref_counter;
116
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000117 struct _xmlDictEntry *dict;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800118 size_t size;
119 unsigned int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000120 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000121
122 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800123 /* used for randomization */
124 int seed;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800125 /* used to impose a limit on size */
126 size_t limit;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000127};
128
129/*
Daniel Veillard14412512005-01-21 23:53:26 +0000130 * A mutex for modifying the reference counter for shared
131 * dictionaries.
132 */
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100133static xmlMutex xmlDictMutex;
Daniel Veillard14412512005-01-21 23:53:26 +0000134
Daniel Veillard379ebc12012-05-18 15:41:31 +0800135#ifdef DICT_RANDOMIZATION
136#ifdef HAVE_RAND_R
137/*
138 * Internal data for random function, protected by xmlDictMutex
139 */
Wouter Van Rooye7715a52012-09-14 14:39:42 +0800140static unsigned int rand_seed = 0;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800141#endif
142#endif
143
Daniel Veillard14412512005-01-21 23:53:26 +0000144/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000145 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000146 *
Nick Wellnhofered053c52022-11-25 12:27:14 +0100147 * DEPRECATED: Alias for xmlInitParser.
Daniel Veillard14412512005-01-21 23:53:26 +0000148 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800149int xmlInitializeDict(void) {
Nick Wellnhofered053c52022-11-25 12:27:14 +0100150 xmlInitParser();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800151 return(0);
152}
153
154/**
155 * __xmlInitializeDict:
156 *
157 * This function is not public
158 * Do the dictionary mutex initialization.
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800159 */
160int __xmlInitializeDict(void) {
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100161 xmlInitMutex(&xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000162
Daniel Veillard8973d582012-02-04 19:07:44 +0800163#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800164#ifdef HAVE_RAND_R
165 rand_seed = time(NULL);
166 rand_r(& rand_seed);
167#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800168 srand(time(NULL));
169#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800170#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000171 return(1);
172}
173
Daniel Veillard379ebc12012-05-18 15:41:31 +0800174#ifdef DICT_RANDOMIZATION
175int __xmlRandom(void) {
176 int ret;
177
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100178 xmlMutexLock(&xmlDictMutex);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800179#ifdef HAVE_RAND_R
180 ret = rand_r(& rand_seed);
181#else
182 ret = rand();
183#endif
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100184 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800185 return(ret);
186}
187#endif
188
Daniel Veillard14412512005-01-21 23:53:26 +0000189/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000190 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000191 *
Nick Wellnhofered053c52022-11-25 12:27:14 +0100192 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
Nick Wellnhofer40483d02022-03-06 13:55:48 +0100193 * to free global state but see the warnings there. xmlCleanupParser
194 * should be only called once at program exit. In most cases, you don't
195 * have call cleanup functions at all.
Daniel Veillard14412512005-01-21 23:53:26 +0000196 */
197void
198xmlDictCleanup(void) {
Nick Wellnhofered053c52022-11-25 12:27:14 +0100199}
200
201/**
202 * xmlCleanupDictInternal:
203 *
204 * Free the dictionary mutex.
205 */
206void
207xmlCleanupDictInternal(void) {
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100208 xmlCleanupMutex(&xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000209}
210
211/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000212 * xmlDictAddString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200213 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +0000214 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800215 * @len: the length of the name
Daniel Veillard81514ba2003-09-16 23:17:26 +0000216 *
217 * Add the string to the array[s]
218 *
219 * Returns the pointer of the local string, or NULL in case of error.
220 */
221static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800222xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Daniel Veillard81514ba2003-09-16 23:17:26 +0000223 xmlDictStringsPtr pool;
224 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800225 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
226 size_t limit = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000227
Daniel Veillard424785e2008-08-06 09:35:25 +0000228#ifdef DICT_DEBUG_PATTERNS
229 fprintf(stderr, "-");
230#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000231 pool = dict->strings;
232 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200233 if ((size_t)(pool->end - pool->free) > namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000234 goto found_pool;
235 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800236 limit += pool->size;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000237 pool = pool->next;
238 }
239 /*
240 * Not found, need to allocate
241 */
242 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800243 if ((dict->limit > 0) && (limit > dict->limit)) {
244 return(NULL);
245 }
246
Daniel Veillard81514ba2003-09-16 23:17:26 +0000247 if (size == 0) size = 1000;
248 else size *= 4; /* exponential growth */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800249 if (size < 4 * namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000250 size = 4 * namelen; /* just in case ! */
251 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
252 if (pool == NULL)
253 return(NULL);
254 pool->size = size;
255 pool->nbStrings = 0;
256 pool->free = &pool->array[0];
257 pool->end = &pool->array[size];
258 pool->next = dict->strings;
259 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000260#ifdef DICT_DEBUG_PATTERNS
261 fprintf(stderr, "+");
262#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000263 }
264found_pool:
265 ret = pool->free;
266 memcpy(pool->free, name, namelen);
267 pool->free += namelen;
268 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000269 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000270 return(ret);
271}
272
273/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000274 * xmlDictAddQString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200275 * @dict: the dictionary
Daniel Veillarde72c5082003-09-19 12:44:05 +0000276 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000277 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000278 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800279 * @len: the length of the name
Daniel Veillarde72c5082003-09-19 12:44:05 +0000280 *
281 * Add the QName to the array[s]
282 *
283 * Returns the pointer of the local string, or NULL in case of error.
284 */
285static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800286xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
287 const xmlChar *name, unsigned int namelen)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000288{
289 xmlDictStringsPtr pool;
290 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800291 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
292 size_t limit = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000293
294 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000295
Daniel Veillard424785e2008-08-06 09:35:25 +0000296#ifdef DICT_DEBUG_PATTERNS
297 fprintf(stderr, "=");
298#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000299 pool = dict->strings;
300 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200301 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000302 goto found_pool;
303 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800304 limit += pool->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000305 pool = pool->next;
306 }
307 /*
308 * Not found, need to allocate
309 */
310 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800311 if ((dict->limit > 0) && (limit > dict->limit)) {
312 return(NULL);
313 }
314
Daniel Veillarde72c5082003-09-19 12:44:05 +0000315 if (size == 0) size = 1000;
316 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000317 if (size < 4 * (namelen + plen + 1))
318 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000319 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
320 if (pool == NULL)
321 return(NULL);
322 pool->size = size;
323 pool->nbStrings = 0;
324 pool->free = &pool->array[0];
325 pool->end = &pool->array[size];
326 pool->next = dict->strings;
327 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000328#ifdef DICT_DEBUG_PATTERNS
329 fprintf(stderr, "+");
330#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000331 }
332found_pool:
333 ret = pool->free;
334 memcpy(pool->free, prefix, plen);
335 pool->free += plen;
336 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000337 memcpy(pool->free, name, namelen);
338 pool->free += namelen;
339 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000340 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000341 return(ret);
342}
343
Daniel Veillard424785e2008-08-06 09:35:25 +0000344#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000345/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000346 * xmlDictComputeBigKey:
347 *
348 * Calculate a hash key using a good hash function that works well for
349 * larger hash table sizes.
350 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000351 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000352 * http://burtleburtle.net/bob/hash/doobs.html
353 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000354
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200355#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200356ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200357#endif
Daniel Veillarde9100a52008-04-22 08:28:50 +0000358static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800359xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000360 uint32_t hash;
361 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000362
Daniel Veillard424785e2008-08-06 09:35:25 +0000363 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000364
Daniel Veillard8973d582012-02-04 19:07:44 +0800365 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000366
Daniel Veillard424785e2008-08-06 09:35:25 +0000367 for (i = 0;i < namelen; i++) {
368 hash += data[i];
369 hash += (hash << 10);
370 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000371 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000372 hash += (hash << 3);
373 hash ^= (hash >> 11);
374 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000375
376 return hash;
377}
378
379/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000380 * xmlDictComputeBigQKey:
381 *
382 * Calculate a hash key for two strings using a good hash function
383 * that works well for larger hash table sizes.
384 *
385 * Hash function by "One-at-a-Time Hash" see
386 * http://burtleburtle.net/bob/hash/doobs.html
387 *
388 * Neither of the two strings must be NULL.
389 */
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200390#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200391ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200392#endif
Daniel Veillard424785e2008-08-06 09:35:25 +0000393static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000394xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800395 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000396{
397 uint32_t hash;
398 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000399
Daniel Veillard8973d582012-02-04 19:07:44 +0800400 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000401
402 for (i = 0;i < plen; i++) {
403 hash += prefix[i];
404 hash += (hash << 10);
405 hash ^= (hash >> 6);
406 }
407 hash += ':';
408 hash += (hash << 10);
409 hash ^= (hash >> 6);
410
411 for (i = 0;i < len; i++) {
412 hash += name[i];
413 hash += (hash << 10);
414 hash ^= (hash >> 6);
415 }
416 hash += (hash << 3);
417 hash ^= (hash >> 11);
418 hash += (hash << 15);
419
420 return hash;
421}
422#endif /* WITH_BIG_KEY */
423
424/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000425 * xmlDictComputeFastKey:
426 *
427 * Calculate a hash key using a fast hash function that works well
428 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000429 */
430static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800431xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
432 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000433
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000434 if (name == NULL) return(0);
Ranier Vilela3c8a3e92019-11-07 12:59:10 +0000435 value += *name;
Daniel Veillard4773df22004-01-23 13:15:13 +0000436 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000437 if (namelen > 10) {
438 value += name[namelen - 1];
439 namelen = 10;
440 }
441 switch (namelen) {
442 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200443 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000444 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200445 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000446 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200447 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000448 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200449 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000450 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200451 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000452 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200453 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000454 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200455 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000456 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200457 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000458 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200459 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000460 default: break;
461 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000462 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000463}
464
465/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000466 * xmlDictComputeFastQKey:
467 *
468 * Calculate a hash key for two strings using a fast hash function
469 * that works well for low hash table fill.
470 *
471 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000472 */
473static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000474xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800475 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000476{
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200477 unsigned long value = seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000478
Daniel Veillarde72c5082003-09-19 12:44:05 +0000479 if (plen == 0)
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200480 value += 30 * ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000481 else
482 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000483
Daniel Veillarde72c5082003-09-19 12:44:05 +0000484 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800485 int offset = len - (plen + 1 + 1);
486 if (offset < 0)
487 offset = len - (10 + 1);
488 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000489 len = 10;
490 if (plen > 10)
491 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000492 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000493 switch (plen) {
494 case 10: value += prefix[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200495 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000496 case 9: value += prefix[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200497 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000498 case 8: value += prefix[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200499 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000500 case 7: value += prefix[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200501 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000502 case 6: value += prefix[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200503 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000504 case 5: value += prefix[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200505 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000506 case 4: value += prefix[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200507 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000508 case 3: value += prefix[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200509 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000510 case 2: value += prefix[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200511 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000512 case 1: value += prefix[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200513 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000514 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000515 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000516 len -= plen;
517 if (len > 0) {
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200518 value += ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000519 len--;
520 }
521 switch (len) {
522 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200523 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000524 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200525 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000526 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200527 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000528 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200529 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000530 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200531 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000532 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200533 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000534 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200535 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000536 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200537 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000538 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200539 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000540 case 1: value += name[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200541 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000542 default: break;
543 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000544 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000545}
546
547/**
548 * xmlDictCreate:
549 *
550 * Create a new dictionary
551 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200552 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000553 */
554xmlDictPtr
555xmlDictCreate(void) {
556 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000557
Nick Wellnhofer9ef80ff2022-11-25 12:33:25 +0100558 xmlInitParser();
Daniel Veillard424785e2008-08-06 09:35:25 +0000559
560#ifdef DICT_DEBUG_PATTERNS
561 fprintf(stderr, "C");
562#endif
563
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000564 dict = xmlMalloc(sizeof(xmlDict));
565 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000566 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800567 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000568
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000569 dict->size = MIN_DICT_SIZE;
570 dict->nbElems = 0;
571 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000572 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000573 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000574 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000575 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800576#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800577 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800578#else
579 dict->seed = 0;
580#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000581 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000582 }
583 xmlFree(dict);
584 }
585 return(NULL);
586}
587
588/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000589 * xmlDictCreateSub:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200590 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000591 *
592 * Create a new dictionary, inheriting strings from the read-only
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200593 * dictionary @sub. On lookup, strings are first searched in the
594 * new dictionary, then in @sub, and if not found are created in the
595 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000596 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200597 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000598 */
599xmlDictPtr
600xmlDictCreateSub(xmlDictPtr sub) {
601 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000602
Daniel Veillard4773df22004-01-23 13:15:13 +0000603 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000604#ifdef DICT_DEBUG_PATTERNS
605 fprintf(stderr, "R");
606#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800607 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000608 dict->subdict = sub;
609 xmlDictReference(dict->subdict);
610 }
611 return(dict);
612}
613
614/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000615 * xmlDictReference:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200616 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000617 *
618 * Increment the reference counter of a dictionary
619 *
620 * Returns 0 in case of success and -1 in case of error
621 */
622int
623xmlDictReference(xmlDictPtr dict) {
624 if (dict == NULL) return -1;
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100625 xmlMutexLock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000626 dict->ref_counter++;
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100627 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000628 return(0);
629}
630
631/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000632 * xmlDictGrow:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200633 * @dict: the dictionary
634 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000635 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200636 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000637 *
638 * Returns 0 in case of success, -1 in case of failure
639 */
640static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800641xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000642 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800643 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000644 xmlDictEntryPtr iter, next;
645 struct _xmlDictEntry *olddict;
646#ifdef DEBUG_GROW
647 unsigned long nbElem = 0;
648#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000649 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000650 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000651
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000652 if (dict == NULL)
653 return(-1);
654 if (size < 8)
655 return(-1);
656 if (size > 8 * 2048)
657 return(-1);
658
Daniel Veillard424785e2008-08-06 09:35:25 +0000659#ifdef DICT_DEBUG_PATTERNS
660 fprintf(stderr, "*");
661#endif
662
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000663 oldsize = dict->size;
664 olddict = dict->dict;
665 if (olddict == NULL)
666 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000667 if (oldsize == MIN_DICT_SIZE)
668 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000669
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000670 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
671 if (dict->dict == NULL) {
672 dict->dict = olddict;
673 return(-1);
674 }
675 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
676 dict->size = size;
677
678 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000679 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000680 the main dict. It is nicer to run through the array twice, first
681 copying all the elements in the main array (less probability of
682 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000683 */
684 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000685 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000686 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000687
688 if (keep_keys)
689 okey = olddict[i].okey;
690 else
691 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
692 key = okey % dict->size;
693
Daniel Veillardffda65f2008-08-07 16:33:49 +0000694 if (dict->dict[key].valid == 0) {
695 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
696 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000697 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000698 } else {
699 xmlDictEntryPtr entry;
700
701 entry = xmlMalloc(sizeof(xmlDictEntry));
702 if (entry != NULL) {
703 entry->name = olddict[i].name;
704 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000705 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000706 entry->next = dict->dict[key].next;
707 entry->valid = 1;
708 dict->dict[key].next = entry;
709 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000710 /*
Jared Yanovich2a350ee2019-09-30 17:04:54 +0200711 * we don't have much ways to alert from here
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200712 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000713 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000714 ret = -1;
715 }
716 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000717#ifdef DEBUG_GROW
718 nbElem++;
719#endif
720 }
721
722 for (i = 0; i < oldsize; i++) {
723 iter = olddict[i].next;
724 while (iter) {
725 next = iter->next;
726
727 /*
728 * put back the entry in the new dict
729 */
730
Daniel Veillardd68f8912008-08-08 10:09:19 +0000731 if (keep_keys)
732 okey = iter->okey;
733 else
734 okey = xmlDictComputeKey(dict, iter->name, iter->len);
735 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000736 if (dict->dict[key].valid == 0) {
737 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
738 dict->dict[key].next = NULL;
739 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000740 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000741 xmlFree(iter);
742 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000743 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000744 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000745 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000746 }
747
748#ifdef DEBUG_GROW
749 nbElem++;
750#endif
751
752 iter = next;
753 }
754 }
755
756 xmlFree(olddict);
757
758#ifdef DEBUG_GROW
759 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800760 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000761#endif
762
Daniel Veillardffda65f2008-08-07 16:33:49 +0000763 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000764}
765
766/**
767 * xmlDictFree:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200768 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000769 *
770 * Free the hash @dict and its contents. The userdata is
771 * deallocated with @f if provided.
772 */
773void
774xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800775 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000776 xmlDictEntryPtr iter;
777 xmlDictEntryPtr next;
778 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000779 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000780
781 if (dict == NULL)
782 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000783
784 /* decrement the counter, it may be shared by a parser and docs */
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100785 xmlMutexLock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000786 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000787 if (dict->ref_counter > 0) {
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100788 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000789 return;
790 }
791
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100792 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000793
Daniel Veillard4773df22004-01-23 13:15:13 +0000794 if (dict->subdict != NULL) {
795 xmlDictFree(dict->subdict);
796 }
797
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000798 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000799 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000800 iter = &(dict->dict[i]);
801 if (iter->valid == 0)
802 continue;
803 inside_dict = 1;
804 while (iter) {
805 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000806 if (!inside_dict)
807 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000808 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000809 inside_dict = 0;
810 iter = next;
811 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000812 }
813 xmlFree(dict->dict);
814 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000815 pool = dict->strings;
816 while (pool != NULL) {
817 nextp = pool->next;
818 xmlFree(pool);
819 pool = nextp;
820 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000821 xmlFree(dict);
822}
823
824/**
825 * xmlDictLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200826 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000827 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000828 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000829 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200830 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000831 *
832 * Returns the internal copy of the name or NULL in case of internal error
833 */
834const xmlChar *
835xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000836 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000837 xmlDictEntryPtr entry;
838 xmlDictEntryPtr insert;
839 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800840 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000841
Daniel Veillard0fb18932003-09-07 09:14:37 +0000842 if ((dict == NULL) || (name == NULL))
843 return(NULL);
844
845 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800846 l = strlen((const char *) name);
847 else
848 l = len;
849
850 if (((dict->limit > 0) && (l >= dict->limit)) ||
851 (l > INT_MAX / 2))
852 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000853
854 /*
855 * Check for duplicate and insertion location.
856 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800857 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000858 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000859 if (dict->dict[key].valid == 0) {
860 insert = NULL;
861 } else {
862 for (insert = &(dict->dict[key]); insert->next != NULL;
863 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000864#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800865 if ((insert->okey == okey) && (insert->len == l)) {
866 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000867 return(insert->name);
868 }
869#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800870 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800871 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000872 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000873#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000874 nbi++;
875 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000876#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800877 if ((insert->okey == okey) && (insert->len == l)) {
878 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000879 return(insert->name);
880 }
881#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800882 if ((insert->okey == okey) && (insert->len == l) &&
883 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000884 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000885#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000886 }
887
Daniel Veillard4773df22004-01-23 13:15:13 +0000888 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000889 unsigned long skey;
890
891 /* we cannot always reuse the same okey for the subdict */
892 if (((dict->size == MIN_DICT_SIZE) &&
893 (dict->subdict->size != MIN_DICT_SIZE)) ||
894 ((dict->size != MIN_DICT_SIZE) &&
895 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800896 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000897 else
898 skey = okey;
899
900 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000901 if (dict->subdict->dict[key].valid != 0) {
902 xmlDictEntryPtr tmp;
903
904 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
905 tmp = tmp->next) {
906#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800907 if ((tmp->okey == skey) && (tmp->len == l)) {
908 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000909 return(tmp->name);
910 }
911#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800912 if ((tmp->okey == skey) && (tmp->len == l) &&
913 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000914 return(tmp->name);
915#endif
916 nbi++;
917 }
918#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800919 if ((tmp->okey == skey) && (tmp->len == l)) {
920 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000921 return(tmp->name);
922 }
923#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800924 if ((tmp->okey == skey) && (tmp->len == l) &&
925 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000926 return(tmp->name);
927#endif
928 }
929 key = okey % dict->size;
930 }
931
Daniel Veillard7c693da2012-07-25 16:32:18 +0800932 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000933 if (ret == NULL)
934 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000935 if (insert == NULL) {
936 entry = &(dict->dict[key]);
937 } else {
938 entry = xmlMalloc(sizeof(xmlDictEntry));
939 if (entry == NULL)
940 return(NULL);
941 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000942 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800943 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000944 entry->next = NULL;
945 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000946 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000947
948
Daniel Veillard7c693da2012-07-25 16:32:18 +0800949 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000950 insert->next = entry;
951
952 dict->nbElems++;
953
954 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000955 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
956 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
957 return(NULL);
958 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000959 /* Note that entry may have been freed at this point by xmlDictGrow */
960
961 return(ret);
962}
963
964/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000965 * xmlDictExists:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200966 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000967 * @name: the name of the userdata
968 * @len: the length of the name, if -1 it is recomputed
969 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200970 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000971 *
972 * Returns the internal copy of the name or NULL if not found.
973 */
974const xmlChar *
975xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
Nick Wellnhoferb6f12982022-10-24 20:47:10 +0200976 unsigned long key, okey;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000977 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800978 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000979
980 if ((dict == NULL) || (name == NULL))
981 return(NULL);
982
983 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800984 l = strlen((const char *) name);
985 else
986 l = len;
987 if (((dict->limit > 0) && (l >= dict->limit)) ||
988 (l > INT_MAX / 2))
989 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000990
991 /*
992 * Check for duplicate and insertion location.
993 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800994 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000995 key = okey % dict->size;
996 if (dict->dict[key].valid == 0) {
997 insert = NULL;
998 } else {
999 for (insert = &(dict->dict[key]); insert->next != NULL;
1000 insert = insert->next) {
1001#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001002 if ((insert->okey == okey) && (insert->len == l)) {
1003 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001004 return(insert->name);
1005 }
1006#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001007 if ((insert->okey == okey) && (insert->len == l) &&
1008 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001009 return(insert->name);
1010#endif
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001011 }
1012#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001013 if ((insert->okey == okey) && (insert->len == l)) {
1014 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001015 return(insert->name);
1016 }
1017#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001018 if ((insert->okey == okey) && (insert->len == l) &&
1019 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001020 return(insert->name);
1021#endif
1022 }
1023
1024 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001025 unsigned long skey;
1026
1027 /* we cannot always reuse the same okey for the subdict */
1028 if (((dict->size == MIN_DICT_SIZE) &&
1029 (dict->subdict->size != MIN_DICT_SIZE)) ||
1030 ((dict->size != MIN_DICT_SIZE) &&
1031 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001032 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001033 else
1034 skey = okey;
1035
1036 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001037 if (dict->subdict->dict[key].valid != 0) {
1038 xmlDictEntryPtr tmp;
1039
1040 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1041 tmp = tmp->next) {
1042#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001043 if ((tmp->okey == skey) && (tmp->len == l)) {
1044 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001045 return(tmp->name);
1046 }
1047#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001048 if ((tmp->okey == skey) && (tmp->len == l) &&
1049 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001050 return(tmp->name);
1051#endif
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001052 }
1053#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001054 if ((tmp->okey == skey) && (tmp->len == l)) {
1055 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001056 return(tmp->name);
1057 }
1058#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001059 if ((tmp->okey == skey) && (tmp->len == l) &&
1060 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001061 return(tmp->name);
1062#endif
1063 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001064 }
1065
1066 /* not found */
1067 return(NULL);
1068}
1069
1070/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001071 * xmlDictQLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001072 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001073 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001074 * @name: the name
1075 *
1076 * Add the QName @prefix:@name to the hash @dict if not present.
1077 *
1078 * Returns the internal copy of the QName or NULL in case of internal error
1079 */
1080const xmlChar *
1081xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001082 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001083 xmlDictEntryPtr entry;
1084 xmlDictEntryPtr insert;
1085 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001086 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001087
1088 if ((dict == NULL) || (name == NULL))
1089 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001090 if (prefix == NULL)
1091 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001092
Daniel Veillardffda65f2008-08-07 16:33:49 +00001093 l = len = strlen((const char *) name);
1094 plen = strlen((const char *) prefix);
1095 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001096
1097 /*
1098 * Check for duplicate and insertion location.
1099 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001100 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001101 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001102 if (dict->dict[key].valid == 0) {
1103 insert = NULL;
1104 } else {
1105 for (insert = &(dict->dict[key]); insert->next != NULL;
1106 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001107 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001108 (xmlStrQEqual(prefix, name, insert->name)))
1109 return(insert->name);
1110 nbi++;
1111 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001112 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001113 (xmlStrQEqual(prefix, name, insert->name)))
1114 return(insert->name);
1115 }
1116
Daniel Veillard4773df22004-01-23 13:15:13 +00001117 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001118 unsigned long skey;
1119
1120 /* we cannot always reuse the same okey for the subdict */
1121 if (((dict->size == MIN_DICT_SIZE) &&
1122 (dict->subdict->size != MIN_DICT_SIZE)) ||
1123 ((dict->size != MIN_DICT_SIZE) &&
1124 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001125 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001126 else
1127 skey = okey;
1128
1129 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001130 if (dict->subdict->dict[key].valid != 0) {
1131 xmlDictEntryPtr tmp;
1132 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1133 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001134 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001135 (xmlStrQEqual(prefix, name, tmp->name)))
1136 return(tmp->name);
1137 nbi++;
1138 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001139 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001140 (xmlStrQEqual(prefix, name, tmp->name)))
1141 return(tmp->name);
1142 }
1143 key = okey % dict->size;
1144 }
1145
Daniel Veillardffda65f2008-08-07 16:33:49 +00001146 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001147 if (ret == NULL)
1148 return(NULL);
1149 if (insert == NULL) {
1150 entry = &(dict->dict[key]);
1151 } else {
1152 entry = xmlMalloc(sizeof(xmlDictEntry));
1153 if (entry == NULL)
1154 return(NULL);
1155 }
1156 entry->name = ret;
1157 entry->len = len;
1158 entry->next = NULL;
1159 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001160 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001161
Daniel Veillard7c693da2012-07-25 16:32:18 +08001162 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001163 insert->next = entry;
1164
1165 dict->nbElems++;
1166
1167 if ((nbi > MAX_HASH_LEN) &&
1168 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1169 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1170 /* Note that entry may have been freed at this point by xmlDictGrow */
1171
1172 return(ret);
1173}
1174
1175/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001176 * xmlDictOwns:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001177 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001178 * @str: the string
1179 *
Jared Yanovich2a350ee2019-09-30 17:04:54 +02001180 * check if a string is owned by the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001181 *
1182 * Returns 1 if true, 0 if false and -1 in case of error
1183 * -1 in case of error
1184 */
1185int
1186xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1187 xmlDictStringsPtr pool;
1188
1189 if ((dict == NULL) || (str == NULL))
1190 return(-1);
1191 pool = dict->strings;
1192 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001193 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001194 return(1);
1195 pool = pool->next;
1196 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001197 if (dict->subdict)
1198 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001199 return(0);
1200}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001201
Daniel Veillard81514ba2003-09-16 23:17:26 +00001202/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001203 * xmlDictSize:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001204 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001205 *
1206 * Query the number of elements installed in the hash @dict.
1207 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001208 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001209 * -1 in case of error
1210 */
1211int
1212xmlDictSize(xmlDictPtr dict) {
1213 if (dict == NULL)
1214 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001215 if (dict->subdict)
1216 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001217 return(dict->nbElems);
1218}
1219
Daniel Veillard7c693da2012-07-25 16:32:18 +08001220/**
1221 * xmlDictSetLimit:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001222 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001223 * @limit: the limit in bytes
1224 *
1225 * Set a size limit for the dictionary
1226 * Added in 2.9.0
1227 *
1228 * Returns the previous limit of the dictionary or 0
1229 */
1230size_t
1231xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1232 size_t ret;
1233
1234 if (dict == NULL)
1235 return(0);
1236 ret = dict->limit;
1237 dict->limit = limit;
1238 return(ret);
1239}
1240
1241/**
1242 * xmlDictGetUsage:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001243 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001244 *
1245 * Get how much memory is used by a dictionary for strings
1246 * Added in 2.9.0
1247 *
1248 * Returns the amount of strings allocated
1249 */
1250size_t
1251xmlDictGetUsage(xmlDictPtr dict) {
1252 xmlDictStringsPtr pool;
1253 size_t limit = 0;
1254
1255 if (dict == NULL)
1256 return(0);
1257 pool = dict->strings;
1258 while (pool != NULL) {
1259 limit += pool->size;
1260 pool = pool->next;
1261 }
1262 return(limit);
1263}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001264