blob: 67b2a2eaa1d9fcb28fefed60c7b04667a260364b [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
Nick Wellnhofer7f3f3f12023-05-03 03:20:14 +020065#define MAX_DICT_HASH 100000000
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 Wellnhofer8c2e5082023-03-12 14:45:14 +0100357ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200358#endif
Daniel Veillarde9100a52008-04-22 08:28:50 +0000359static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800360xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000361 uint32_t hash;
362 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000363
Daniel Veillard424785e2008-08-06 09:35:25 +0000364 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000365
Daniel Veillard8973d582012-02-04 19:07:44 +0800366 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000367
Daniel Veillard424785e2008-08-06 09:35:25 +0000368 for (i = 0;i < namelen; i++) {
369 hash += data[i];
370 hash += (hash << 10);
371 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000372 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000373 hash += (hash << 3);
374 hash ^= (hash >> 11);
375 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000376
377 return hash;
378}
379
380/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000381 * xmlDictComputeBigQKey:
382 *
383 * Calculate a hash key for two strings using a good hash function
384 * that works well for larger hash table sizes.
385 *
386 * Hash function by "One-at-a-Time Hash" see
387 * http://burtleburtle.net/bob/hash/doobs.html
388 *
389 * Neither of the two strings must be NULL.
390 */
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200391#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200392ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhofer8c2e5082023-03-12 14:45:14 +0100393ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200394#endif
Daniel Veillard424785e2008-08-06 09:35:25 +0000395static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000396xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800397 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000398{
399 uint32_t hash;
400 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000401
Daniel Veillard8973d582012-02-04 19:07:44 +0800402 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000403
404 for (i = 0;i < plen; i++) {
405 hash += prefix[i];
406 hash += (hash << 10);
407 hash ^= (hash >> 6);
408 }
409 hash += ':';
410 hash += (hash << 10);
411 hash ^= (hash >> 6);
412
413 for (i = 0;i < len; i++) {
414 hash += name[i];
415 hash += (hash << 10);
416 hash ^= (hash >> 6);
417 }
418 hash += (hash << 3);
419 hash ^= (hash >> 11);
420 hash += (hash << 15);
421
422 return hash;
423}
424#endif /* WITH_BIG_KEY */
425
426/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000427 * xmlDictComputeFastKey:
428 *
429 * Calculate a hash key using a fast hash function that works well
430 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000431 */
432static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800433xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
434 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000435
Nick Wellnhofer547edbf2023-04-07 11:49:27 +0200436 if ((name == NULL) || (namelen <= 0))
437 return(value);
Ranier Vilela3c8a3e92019-11-07 12:59:10 +0000438 value += *name;
Daniel Veillard4773df22004-01-23 13:15:13 +0000439 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000440 if (namelen > 10) {
441 value += name[namelen - 1];
442 namelen = 10;
443 }
444 switch (namelen) {
445 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200446 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000447 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200448 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000449 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200450 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000451 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200452 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000453 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200454 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000455 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200456 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000457 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200458 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000459 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200460 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000461 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200462 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000463 default: break;
464 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000465 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000466}
467
468/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000469 * xmlDictComputeFastQKey:
470 *
471 * Calculate a hash key for two strings using a fast hash function
472 * that works well for low hash table fill.
473 *
474 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000475 */
476static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000477xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800478 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000479{
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200480 unsigned long value = seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000481
Daniel Veillarde72c5082003-09-19 12:44:05 +0000482 if (plen == 0)
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200483 value += 30 * ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000484 else
485 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000486
Daniel Veillarde72c5082003-09-19 12:44:05 +0000487 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800488 int offset = len - (plen + 1 + 1);
489 if (offset < 0)
490 offset = len - (10 + 1);
491 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000492 len = 10;
493 if (plen > 10)
494 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000495 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000496 switch (plen) {
497 case 10: value += prefix[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200498 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000499 case 9: value += prefix[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200500 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000501 case 8: value += prefix[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200502 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000503 case 7: value += prefix[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200504 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000505 case 6: value += prefix[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200506 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000507 case 5: value += prefix[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200508 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000509 case 4: value += prefix[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200510 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000511 case 3: value += prefix[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200512 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000513 case 2: value += prefix[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200514 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000515 case 1: value += prefix[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200516 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000517 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000518 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000519 len -= plen;
520 if (len > 0) {
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200521 value += ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000522 len--;
523 }
524 switch (len) {
525 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200526 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000527 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200528 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000529 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200530 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000531 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200532 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000533 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200534 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000535 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200536 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000537 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200538 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000539 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200540 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000541 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200542 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000543 case 1: value += name[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200544 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000545 default: break;
546 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000547 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000548}
549
550/**
551 * xmlDictCreate:
552 *
553 * Create a new dictionary
554 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200555 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000556 */
557xmlDictPtr
558xmlDictCreate(void) {
559 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000560
Nick Wellnhofer9ef80ff2022-11-25 12:33:25 +0100561 xmlInitParser();
Daniel Veillard424785e2008-08-06 09:35:25 +0000562
563#ifdef DICT_DEBUG_PATTERNS
564 fprintf(stderr, "C");
565#endif
566
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000567 dict = xmlMalloc(sizeof(xmlDict));
568 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000569 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800570 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000571
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000572 dict->size = MIN_DICT_SIZE;
573 dict->nbElems = 0;
574 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000575 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000576 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000577 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000578 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800579#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800580 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800581#else
582 dict->seed = 0;
583#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000584 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000585 }
586 xmlFree(dict);
587 }
588 return(NULL);
589}
590
591/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000592 * xmlDictCreateSub:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200593 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000594 *
595 * Create a new dictionary, inheriting strings from the read-only
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200596 * dictionary @sub. On lookup, strings are first searched in the
597 * new dictionary, then in @sub, and if not found are created in the
598 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000599 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200600 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000601 */
602xmlDictPtr
603xmlDictCreateSub(xmlDictPtr sub) {
604 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000605
Daniel Veillard4773df22004-01-23 13:15:13 +0000606 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000607#ifdef DICT_DEBUG_PATTERNS
608 fprintf(stderr, "R");
609#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800610 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000611 dict->subdict = sub;
612 xmlDictReference(dict->subdict);
613 }
614 return(dict);
615}
616
617/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000618 * xmlDictReference:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200619 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000620 *
621 * Increment the reference counter of a dictionary
622 *
623 * Returns 0 in case of success and -1 in case of error
624 */
625int
626xmlDictReference(xmlDictPtr dict) {
627 if (dict == NULL) return -1;
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100628 xmlMutexLock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000629 dict->ref_counter++;
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100630 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000631 return(0);
632}
633
634/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000635 * xmlDictGrow:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200636 * @dict: the dictionary
637 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000638 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200639 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000640 *
641 * Returns 0 in case of success, -1 in case of failure
642 */
643static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800644xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000645 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800646 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000647 xmlDictEntryPtr iter, next;
648 struct _xmlDictEntry *olddict;
649#ifdef DEBUG_GROW
650 unsigned long nbElem = 0;
651#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000652 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000653 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000654
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000655 if (dict == NULL)
656 return(-1);
657 if (size < 8)
658 return(-1);
Nick Wellnhofer7f3f3f12023-05-03 03:20:14 +0200659 if (size > MAX_DICT_HASH)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000660 return(-1);
661
Daniel Veillard424785e2008-08-06 09:35:25 +0000662#ifdef DICT_DEBUG_PATTERNS
663 fprintf(stderr, "*");
664#endif
665
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000666 oldsize = dict->size;
667 olddict = dict->dict;
668 if (olddict == NULL)
669 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000670 if (oldsize == MIN_DICT_SIZE)
671 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000672
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000673 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
674 if (dict->dict == NULL) {
675 dict->dict = olddict;
676 return(-1);
677 }
678 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
679 dict->size = size;
680
681 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000682 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000683 the main dict. It is nicer to run through the array twice, first
684 copying all the elements in the main array (less probability of
685 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000686 */
687 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000688 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000689 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000690
691 if (keep_keys)
692 okey = olddict[i].okey;
693 else
694 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
695 key = okey % dict->size;
696
Daniel Veillardffda65f2008-08-07 16:33:49 +0000697 if (dict->dict[key].valid == 0) {
698 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
699 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000700 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000701 } else {
702 xmlDictEntryPtr entry;
703
704 entry = xmlMalloc(sizeof(xmlDictEntry));
705 if (entry != NULL) {
706 entry->name = olddict[i].name;
707 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000708 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000709 entry->next = dict->dict[key].next;
710 entry->valid = 1;
711 dict->dict[key].next = entry;
712 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000713 /*
Jared Yanovich2a350ee2019-09-30 17:04:54 +0200714 * we don't have much ways to alert from here
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200715 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000716 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000717 ret = -1;
718 }
719 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000720#ifdef DEBUG_GROW
721 nbElem++;
722#endif
723 }
724
725 for (i = 0; i < oldsize; i++) {
726 iter = olddict[i].next;
727 while (iter) {
728 next = iter->next;
729
730 /*
731 * put back the entry in the new dict
732 */
733
Daniel Veillardd68f8912008-08-08 10:09:19 +0000734 if (keep_keys)
735 okey = iter->okey;
736 else
737 okey = xmlDictComputeKey(dict, iter->name, iter->len);
738 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000739 if (dict->dict[key].valid == 0) {
740 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
741 dict->dict[key].next = NULL;
742 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000743 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000744 xmlFree(iter);
745 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000746 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000747 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000748 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000749 }
750
751#ifdef DEBUG_GROW
752 nbElem++;
753#endif
754
755 iter = next;
756 }
757 }
758
759 xmlFree(olddict);
760
761#ifdef DEBUG_GROW
762 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800763 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000764#endif
765
Daniel Veillardffda65f2008-08-07 16:33:49 +0000766 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000767}
768
769/**
770 * xmlDictFree:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200771 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000772 *
773 * Free the hash @dict and its contents. The userdata is
774 * deallocated with @f if provided.
775 */
776void
777xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800778 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000779 xmlDictEntryPtr iter;
780 xmlDictEntryPtr next;
781 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000782 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000783
784 if (dict == NULL)
785 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000786
787 /* decrement the counter, it may be shared by a parser and docs */
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100788 xmlMutexLock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000789 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000790 if (dict->ref_counter > 0) {
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100791 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000792 return;
793 }
794
Nick Wellnhofer65d381f2022-11-24 20:54:18 +0100795 xmlMutexUnlock(&xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000796
Daniel Veillard4773df22004-01-23 13:15:13 +0000797 if (dict->subdict != NULL) {
798 xmlDictFree(dict->subdict);
799 }
800
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000801 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000802 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000803 iter = &(dict->dict[i]);
804 if (iter->valid == 0)
805 continue;
806 inside_dict = 1;
807 while (iter) {
808 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000809 if (!inside_dict)
810 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000811 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000812 inside_dict = 0;
813 iter = next;
814 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000815 }
816 xmlFree(dict->dict);
817 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000818 pool = dict->strings;
819 while (pool != NULL) {
820 nextp = pool->next;
821 xmlFree(pool);
822 pool = nextp;
823 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000824 xmlFree(dict);
825}
826
827/**
828 * xmlDictLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200829 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000830 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000831 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000832 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200833 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000834 *
835 * Returns the internal copy of the name or NULL in case of internal error
836 */
837const xmlChar *
838xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000839 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000840 xmlDictEntryPtr entry;
841 xmlDictEntryPtr insert;
842 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800843 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000844
Daniel Veillard0fb18932003-09-07 09:14:37 +0000845 if ((dict == NULL) || (name == NULL))
846 return(NULL);
847
848 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800849 l = strlen((const char *) name);
850 else
851 l = len;
852
853 if (((dict->limit > 0) && (l >= dict->limit)) ||
854 (l > INT_MAX / 2))
855 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000856
857 /*
858 * Check for duplicate and insertion location.
859 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800860 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000861 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000862 if (dict->dict[key].valid == 0) {
863 insert = NULL;
864 } else {
865 for (insert = &(dict->dict[key]); insert->next != NULL;
866 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000867#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800868 if ((insert->okey == okey) && (insert->len == l)) {
869 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000870 return(insert->name);
871 }
872#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800873 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800874 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000875 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000876#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000877 nbi++;
878 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000879#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800880 if ((insert->okey == okey) && (insert->len == l)) {
881 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000882 return(insert->name);
883 }
884#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800885 if ((insert->okey == okey) && (insert->len == l) &&
886 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000887 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000888#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000889 }
890
Daniel Veillard4773df22004-01-23 13:15:13 +0000891 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000892 unsigned long skey;
893
894 /* we cannot always reuse the same okey for the subdict */
895 if (((dict->size == MIN_DICT_SIZE) &&
896 (dict->subdict->size != MIN_DICT_SIZE)) ||
897 ((dict->size != MIN_DICT_SIZE) &&
898 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800899 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000900 else
901 skey = okey;
902
903 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000904 if (dict->subdict->dict[key].valid != 0) {
905 xmlDictEntryPtr tmp;
906
907 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
908 tmp = tmp->next) {
909#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800910 if ((tmp->okey == skey) && (tmp->len == l)) {
911 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000912 return(tmp->name);
913 }
914#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800915 if ((tmp->okey == skey) && (tmp->len == l) &&
916 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000917 return(tmp->name);
918#endif
919 nbi++;
920 }
921#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800922 if ((tmp->okey == skey) && (tmp->len == l)) {
923 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000924 return(tmp->name);
925 }
926#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800927 if ((tmp->okey == skey) && (tmp->len == l) &&
928 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000929 return(tmp->name);
930#endif
931 }
932 key = okey % dict->size;
933 }
934
Daniel Veillard7c693da2012-07-25 16:32:18 +0800935 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000936 if (ret == NULL)
937 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000938 if (insert == NULL) {
939 entry = &(dict->dict[key]);
940 } else {
941 entry = xmlMalloc(sizeof(xmlDictEntry));
942 if (entry == NULL)
943 return(NULL);
944 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000945 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800946 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000947 entry->next = NULL;
948 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000949 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000950
951
Daniel Veillard7c693da2012-07-25 16:32:18 +0800952 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000953 insert->next = entry;
954
955 dict->nbElems++;
956
957 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000958 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
959 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
960 return(NULL);
961 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000962 /* Note that entry may have been freed at this point by xmlDictGrow */
963
964 return(ret);
965}
966
967/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000968 * xmlDictExists:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200969 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000970 * @name: the name of the userdata
971 * @len: the length of the name, if -1 it is recomputed
972 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200973 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000974 *
975 * Returns the internal copy of the name or NULL if not found.
976 */
977const xmlChar *
978xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
Nick Wellnhoferb6f12982022-10-24 20:47:10 +0200979 unsigned long key, okey;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000980 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800981 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000982
983 if ((dict == NULL) || (name == NULL))
984 return(NULL);
985
986 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800987 l = strlen((const char *) name);
988 else
989 l = len;
990 if (((dict->limit > 0) && (l >= dict->limit)) ||
991 (l > INT_MAX / 2))
992 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000993
994 /*
995 * Check for duplicate and insertion location.
996 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800997 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000998 key = okey % dict->size;
999 if (dict->dict[key].valid == 0) {
1000 insert = NULL;
1001 } else {
1002 for (insert = &(dict->dict[key]); insert->next != NULL;
1003 insert = insert->next) {
1004#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001005 if ((insert->okey == okey) && (insert->len == l)) {
1006 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001007 return(insert->name);
1008 }
1009#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001010 if ((insert->okey == okey) && (insert->len == l) &&
1011 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001012 return(insert->name);
1013#endif
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001014 }
1015#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001016 if ((insert->okey == okey) && (insert->len == l)) {
1017 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001018 return(insert->name);
1019 }
1020#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001021 if ((insert->okey == okey) && (insert->len == l) &&
1022 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001023 return(insert->name);
1024#endif
1025 }
1026
1027 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001028 unsigned long skey;
1029
1030 /* we cannot always reuse the same okey for the subdict */
1031 if (((dict->size == MIN_DICT_SIZE) &&
1032 (dict->subdict->size != MIN_DICT_SIZE)) ||
1033 ((dict->size != MIN_DICT_SIZE) &&
1034 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001035 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001036 else
1037 skey = okey;
1038
1039 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001040 if (dict->subdict->dict[key].valid != 0) {
1041 xmlDictEntryPtr tmp;
1042
1043 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1044 tmp = tmp->next) {
1045#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001046 if ((tmp->okey == skey) && (tmp->len == l)) {
1047 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001048 return(tmp->name);
1049 }
1050#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001051 if ((tmp->okey == skey) && (tmp->len == l) &&
1052 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001053 return(tmp->name);
1054#endif
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001055 }
1056#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001057 if ((tmp->okey == skey) && (tmp->len == l)) {
1058 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001059 return(tmp->name);
1060 }
1061#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001062 if ((tmp->okey == skey) && (tmp->len == l) &&
1063 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001064 return(tmp->name);
1065#endif
1066 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001067 }
1068
1069 /* not found */
1070 return(NULL);
1071}
1072
1073/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001074 * xmlDictQLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001075 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001076 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001077 * @name: the name
1078 *
1079 * Add the QName @prefix:@name to the hash @dict if not present.
1080 *
1081 * Returns the internal copy of the QName or NULL in case of internal error
1082 */
1083const xmlChar *
1084xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001085 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001086 xmlDictEntryPtr entry;
1087 xmlDictEntryPtr insert;
1088 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001089 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001090
1091 if ((dict == NULL) || (name == NULL))
1092 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001093 if (prefix == NULL)
1094 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001095
Daniel Veillardffda65f2008-08-07 16:33:49 +00001096 l = len = strlen((const char *) name);
1097 plen = strlen((const char *) prefix);
1098 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001099
1100 /*
1101 * Check for duplicate and insertion location.
1102 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001103 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001104 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001105 if (dict->dict[key].valid == 0) {
1106 insert = NULL;
1107 } else {
1108 for (insert = &(dict->dict[key]); insert->next != NULL;
1109 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001110 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001111 (xmlStrQEqual(prefix, name, insert->name)))
1112 return(insert->name);
1113 nbi++;
1114 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001115 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001116 (xmlStrQEqual(prefix, name, insert->name)))
1117 return(insert->name);
1118 }
1119
Daniel Veillard4773df22004-01-23 13:15:13 +00001120 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001121 unsigned long skey;
1122
1123 /* we cannot always reuse the same okey for the subdict */
1124 if (((dict->size == MIN_DICT_SIZE) &&
1125 (dict->subdict->size != MIN_DICT_SIZE)) ||
1126 ((dict->size != MIN_DICT_SIZE) &&
1127 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001128 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001129 else
1130 skey = okey;
1131
1132 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001133 if (dict->subdict->dict[key].valid != 0) {
1134 xmlDictEntryPtr tmp;
1135 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1136 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001137 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001138 (xmlStrQEqual(prefix, name, tmp->name)))
1139 return(tmp->name);
1140 nbi++;
1141 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001142 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001143 (xmlStrQEqual(prefix, name, tmp->name)))
1144 return(tmp->name);
1145 }
1146 key = okey % dict->size;
1147 }
1148
Daniel Veillardffda65f2008-08-07 16:33:49 +00001149 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001150 if (ret == NULL)
1151 return(NULL);
1152 if (insert == NULL) {
1153 entry = &(dict->dict[key]);
1154 } else {
1155 entry = xmlMalloc(sizeof(xmlDictEntry));
1156 if (entry == NULL)
1157 return(NULL);
1158 }
1159 entry->name = ret;
1160 entry->len = len;
1161 entry->next = NULL;
1162 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001163 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001164
Daniel Veillard7c693da2012-07-25 16:32:18 +08001165 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001166 insert->next = entry;
1167
1168 dict->nbElems++;
1169
1170 if ((nbi > MAX_HASH_LEN) &&
1171 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1172 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1173 /* Note that entry may have been freed at this point by xmlDictGrow */
1174
1175 return(ret);
1176}
1177
1178/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001179 * xmlDictOwns:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001180 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001181 * @str: the string
1182 *
Jared Yanovich2a350ee2019-09-30 17:04:54 +02001183 * check if a string is owned by the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001184 *
1185 * Returns 1 if true, 0 if false and -1 in case of error
1186 * -1 in case of error
1187 */
1188int
1189xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1190 xmlDictStringsPtr pool;
1191
1192 if ((dict == NULL) || (str == NULL))
1193 return(-1);
1194 pool = dict->strings;
1195 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001196 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001197 return(1);
1198 pool = pool->next;
1199 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001200 if (dict->subdict)
1201 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001202 return(0);
1203}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001204
Daniel Veillard81514ba2003-09-16 23:17:26 +00001205/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001206 * xmlDictSize:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001207 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001208 *
1209 * Query the number of elements installed in the hash @dict.
1210 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001211 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001212 * -1 in case of error
1213 */
1214int
1215xmlDictSize(xmlDictPtr dict) {
1216 if (dict == NULL)
1217 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001218 if (dict->subdict)
1219 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001220 return(dict->nbElems);
1221}
1222
Daniel Veillard7c693da2012-07-25 16:32:18 +08001223/**
1224 * xmlDictSetLimit:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001225 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001226 * @limit: the limit in bytes
1227 *
1228 * Set a size limit for the dictionary
1229 * Added in 2.9.0
1230 *
1231 * Returns the previous limit of the dictionary or 0
1232 */
1233size_t
1234xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1235 size_t ret;
1236
1237 if (dict == NULL)
1238 return(0);
1239 ret = dict->limit;
1240 dict->limit = limit;
1241 return(ret);
1242}
1243
1244/**
1245 * xmlDictGetUsage:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001246 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001247 *
1248 * Get how much memory is used by a dictionary for strings
1249 * Added in 2.9.0
1250 *
1251 * Returns the amount of strings allocated
1252 */
1253size_t
1254xmlDictGetUsage(xmlDictPtr dict) {
1255 xmlDictStringsPtr pool;
1256 size_t limit = 0;
1257
1258 if (dict == NULL)
1259 return(0);
1260 pool = dict->strings;
1261 while (pool != NULL) {
1262 limit += pool->size;
1263 pool = pool->next;
1264 }
1265 return(limit);
1266}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001267