blob: 8901ec29eee351065fbf93ab13d63fefd4783cbd [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"
27
Daniel Veillard8973d582012-02-04 19:07:44 +080028/*
29 * Following http://www.ocert.org/advisories/ocert-2011-003.html
30 * it seems that having hash randomization might be a good idea
31 * when using XML with untrusted data
32 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
33 * which is the default.
34 * Note2: the fast function used for a small dict won't protect very
35 * well but since the attack is based on growing a very big hash
36 * list we will use the BigKey algo as soon as the hash size grows
37 * over MIN_DICT_SIZE so this actually works
38 */
Nick Wellnhofer72119af2022-03-02 01:14:08 +010039#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
Daniel Veillard8973d582012-02-04 19:07:44 +080040#define DICT_RANDOMIZATION
41#endif
42
Daniel Veillard2fdbd322003-08-18 12:15:38 +000043#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000044#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000045#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000046#else
47#ifdef HAVE_INTTYPES_H
48#include <inttypes.h>
Nick Wellnhofere3890542017-10-09 00:20:01 +020049#elif defined(_WIN32)
Rob Richardsb6b2ee12008-05-03 12:34:25 +000050typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000051#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000052#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000053#include <libxml/tree.h>
54#include <libxml/dict.h>
55#include <libxml/xmlmemory.h>
56#include <libxml/xmlerror.h>
57#include <libxml/globals.h>
58
Daniel Veillard424785e2008-08-06 09:35:25 +000059/* #define DEBUG_GROW */
60/* #define DICT_DEBUG_PATTERNS */
61
Daniel Veillarde9100a52008-04-22 08:28:50 +000062#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000063#define MIN_DICT_SIZE 128
64#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000065#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000066
Daniel Veillard424785e2008-08-06 09:35:25 +000067#ifdef WITH_BIG_KEY
Daniel Veillard8973d582012-02-04 19:07:44 +080068#define xmlDictComputeKey(dict, name, len) \
69 (((dict)->size == MIN_DICT_SIZE) ? \
70 xmlDictComputeFastKey(name, len, (dict)->seed) : \
71 xmlDictComputeBigKey(name, len, (dict)->seed))
Daniel Veillarde9100a52008-04-22 08:28:50 +000072
Daniel Veillard8973d582012-02-04 19:07:44 +080073#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
74 (((prefix) == NULL) ? \
75 (xmlDictComputeKey(dict, name, len)) : \
76 (((dict)->size == MIN_DICT_SIZE) ? \
77 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
78 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000079
Daniel Veillard424785e2008-08-06 09:35:25 +000080#else /* !WITH_BIG_KEY */
Daniel Veillard8973d582012-02-04 19:07:44 +080081#define xmlDictComputeKey(dict, name, len) \
82 xmlDictComputeFastKey(name, len, (dict)->seed)
83#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
84 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
Daniel Veillard424785e2008-08-06 09:35:25 +000085#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000086
87/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +020088 * An entry in the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +000089 */
90typedef struct _xmlDictEntry xmlDictEntry;
91typedef xmlDictEntry *xmlDictEntryPtr;
92struct _xmlDictEntry {
93 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000094 const xmlChar *name;
Daniel Veillard7c693da2012-07-25 16:32:18 +080095 unsigned int len;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000096 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000097 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000098};
99
Daniel Veillard81514ba2003-09-16 23:17:26 +0000100typedef struct _xmlDictStrings xmlDictStrings;
101typedef xmlDictStrings *xmlDictStringsPtr;
102struct _xmlDictStrings {
103 xmlDictStringsPtr next;
104 xmlChar *free;
105 xmlChar *end;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800106 size_t size;
107 size_t nbStrings;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000108 xmlChar array[1];
109};
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000110/*
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200111 * The entire dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000112 */
113struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000114 int ref_counter;
115
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000116 struct _xmlDictEntry *dict;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800117 size_t size;
118 unsigned int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000119 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +0000120
121 struct _xmlDict *subdict;
Daniel Veillard8973d582012-02-04 19:07:44 +0800122 /* used for randomization */
123 int seed;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800124 /* used to impose a limit on size */
125 size_t limit;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000126};
127
128/*
Daniel Veillard14412512005-01-21 23:53:26 +0000129 * A mutex for modifying the reference counter for shared
130 * dictionaries.
131 */
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100132static xmlMutexPtr xmlDictMutex = NULL;
Daniel Veillard14412512005-01-21 23:53:26 +0000133
134/*
135 * Whether the dictionary mutex was initialized.
136 */
137static int xmlDictInitialized = 0;
138
Daniel Veillard379ebc12012-05-18 15:41:31 +0800139#ifdef DICT_RANDOMIZATION
140#ifdef HAVE_RAND_R
141/*
142 * Internal data for random function, protected by xmlDictMutex
143 */
Wouter Van Rooye7715a52012-09-14 14:39:42 +0800144static unsigned int rand_seed = 0;
Daniel Veillard379ebc12012-05-18 15:41:31 +0800145#endif
146#endif
147
Daniel Veillard14412512005-01-21 23:53:26 +0000148/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000149 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000150 *
Nick Wellnhofered053c52022-11-25 12:27:14 +0100151 * DEPRECATED: Alias for xmlInitParser.
Daniel Veillard14412512005-01-21 23:53:26 +0000152 */
Daniel Veillard379ebc12012-05-18 15:41:31 +0800153int xmlInitializeDict(void) {
Nick Wellnhofered053c52022-11-25 12:27:14 +0100154 xmlInitParser();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800155 return(0);
156}
157
158/**
159 * __xmlInitializeDict:
160 *
161 * This function is not public
162 * Do the dictionary mutex initialization.
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800163 *
164 * Returns 0 if initialization was already done, and 1 if that
165 * call led to the initialization
166 */
167int __xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000168 if (xmlDictInitialized)
169 return(1);
170
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100171 if ((xmlDictMutex = xmlNewMutex()) == NULL)
Daniel Veillard14412512005-01-21 23:53:26 +0000172 return(0);
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100173 xmlMutexLock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000174
Daniel Veillard8973d582012-02-04 19:07:44 +0800175#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800176#ifdef HAVE_RAND_R
177 rand_seed = time(NULL);
178 rand_r(& rand_seed);
179#else
Daniel Veillard8973d582012-02-04 19:07:44 +0800180 srand(time(NULL));
181#endif
Daniel Veillard379ebc12012-05-18 15:41:31 +0800182#endif
Daniel Veillard14412512005-01-21 23:53:26 +0000183 xmlDictInitialized = 1;
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100184 xmlMutexUnlock(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000185 return(1);
186}
187
Daniel Veillard379ebc12012-05-18 15:41:31 +0800188#ifdef DICT_RANDOMIZATION
189int __xmlRandom(void) {
190 int ret;
191
192 if (xmlDictInitialized == 0)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800193 __xmlInitializeDict();
Daniel Veillard379ebc12012-05-18 15:41:31 +0800194
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100195 xmlMutexLock(xmlDictMutex);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800196#ifdef HAVE_RAND_R
197 ret = rand_r(& rand_seed);
198#else
199 ret = rand();
200#endif
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100201 xmlMutexUnlock(xmlDictMutex);
Daniel Veillard379ebc12012-05-18 15:41:31 +0800202 return(ret);
203}
204#endif
205
Daniel Veillard14412512005-01-21 23:53:26 +0000206/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000207 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000208 *
Nick Wellnhofered053c52022-11-25 12:27:14 +0100209 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
Nick Wellnhofer40483d02022-03-06 13:55:48 +0100210 * to free global state but see the warnings there. xmlCleanupParser
211 * should be only called once at program exit. In most cases, you don't
212 * have call cleanup functions at all.
Daniel Veillard14412512005-01-21 23:53:26 +0000213 */
214void
215xmlDictCleanup(void) {
Nick Wellnhofered053c52022-11-25 12:27:14 +0100216}
217
218/**
219 * xmlCleanupDictInternal:
220 *
221 * Free the dictionary mutex.
222 */
223void
224xmlCleanupDictInternal(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000225 if (!xmlDictInitialized)
226 return;
227
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100228 xmlFreeMutex(xmlDictMutex);
Daniel Veillard14412512005-01-21 23:53:26 +0000229
230 xmlDictInitialized = 0;
231}
232
233/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000234 * xmlDictAddString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200235 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +0000236 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800237 * @len: the length of the name
Daniel Veillard81514ba2003-09-16 23:17:26 +0000238 *
239 * Add the string to the array[s]
240 *
241 * Returns the pointer of the local string, or NULL in case of error.
242 */
243static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800244xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
Daniel Veillard81514ba2003-09-16 23:17:26 +0000245 xmlDictStringsPtr pool;
246 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800247 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
248 size_t limit = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000249
Daniel Veillard424785e2008-08-06 09:35:25 +0000250#ifdef DICT_DEBUG_PATTERNS
251 fprintf(stderr, "-");
252#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000253 pool = dict->strings;
254 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200255 if ((size_t)(pool->end - pool->free) > namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000256 goto found_pool;
257 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800258 limit += pool->size;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000259 pool = pool->next;
260 }
261 /*
262 * Not found, need to allocate
263 */
264 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800265 if ((dict->limit > 0) && (limit > dict->limit)) {
266 return(NULL);
267 }
268
Daniel Veillard81514ba2003-09-16 23:17:26 +0000269 if (size == 0) size = 1000;
270 else size *= 4; /* exponential growth */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800271 if (size < 4 * namelen)
Daniel Veillard81514ba2003-09-16 23:17:26 +0000272 size = 4 * namelen; /* just in case ! */
273 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
274 if (pool == NULL)
275 return(NULL);
276 pool->size = size;
277 pool->nbStrings = 0;
278 pool->free = &pool->array[0];
279 pool->end = &pool->array[size];
280 pool->next = dict->strings;
281 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000282#ifdef DICT_DEBUG_PATTERNS
283 fprintf(stderr, "+");
284#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000285 }
286found_pool:
287 ret = pool->free;
288 memcpy(pool->free, name, namelen);
289 pool->free += namelen;
290 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000291 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000292 return(ret);
293}
294
295/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000296 * xmlDictAddQString:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200297 * @dict: the dictionary
Daniel Veillarde72c5082003-09-19 12:44:05 +0000298 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000299 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000300 * @name: the name of the userdata
Daniel Veillard7c693da2012-07-25 16:32:18 +0800301 * @len: the length of the name
Daniel Veillarde72c5082003-09-19 12:44:05 +0000302 *
303 * Add the QName to the array[s]
304 *
305 * Returns the pointer of the local string, or NULL in case of error.
306 */
307static const xmlChar *
Daniel Veillard7c693da2012-07-25 16:32:18 +0800308xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
309 const xmlChar *name, unsigned int namelen)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000310{
311 xmlDictStringsPtr pool;
312 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800313 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
314 size_t limit = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000315
316 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000317
Daniel Veillard424785e2008-08-06 09:35:25 +0000318#ifdef DICT_DEBUG_PATTERNS
319 fprintf(stderr, "=");
320#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000321 pool = dict->strings;
322 while (pool != NULL) {
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200323 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000324 goto found_pool;
325 if (pool->size > size) size = pool->size;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800326 limit += pool->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000327 pool = pool->next;
328 }
329 /*
330 * Not found, need to allocate
331 */
332 if (pool == NULL) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800333 if ((dict->limit > 0) && (limit > dict->limit)) {
334 return(NULL);
335 }
336
Daniel Veillarde72c5082003-09-19 12:44:05 +0000337 if (size == 0) size = 1000;
338 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000339 if (size < 4 * (namelen + plen + 1))
340 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000341 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
342 if (pool == NULL)
343 return(NULL);
344 pool->size = size;
345 pool->nbStrings = 0;
346 pool->free = &pool->array[0];
347 pool->end = &pool->array[size];
348 pool->next = dict->strings;
349 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000350#ifdef DICT_DEBUG_PATTERNS
351 fprintf(stderr, "+");
352#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000353 }
354found_pool:
355 ret = pool->free;
356 memcpy(pool->free, prefix, plen);
357 pool->free += plen;
358 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000359 memcpy(pool->free, name, namelen);
360 pool->free += namelen;
361 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000362 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000363 return(ret);
364}
365
Daniel Veillard424785e2008-08-06 09:35:25 +0000366#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000367/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000368 * xmlDictComputeBigKey:
369 *
370 * Calculate a hash key using a good hash function that works well for
371 * larger hash table sizes.
372 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000373 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000374 * http://burtleburtle.net/bob/hash/doobs.html
375 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000376
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200377#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200378ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200379#endif
Daniel Veillarde9100a52008-04-22 08:28:50 +0000380static uint32_t
Daniel Veillard8973d582012-02-04 19:07:44 +0800381xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000382 uint32_t hash;
383 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000384
Daniel Veillard424785e2008-08-06 09:35:25 +0000385 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000386
Daniel Veillard8973d582012-02-04 19:07:44 +0800387 hash = seed;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000388
Daniel Veillard424785e2008-08-06 09:35:25 +0000389 for (i = 0;i < namelen; i++) {
390 hash += data[i];
391 hash += (hash << 10);
392 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000393 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000394 hash += (hash << 3);
395 hash ^= (hash >> 11);
396 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000397
398 return hash;
399}
400
401/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000402 * xmlDictComputeBigQKey:
403 *
404 * Calculate a hash key for two strings using a good hash function
405 * that works well for larger hash table sizes.
406 *
407 * Hash function by "One-at-a-Time Hash" see
408 * http://burtleburtle.net/bob/hash/doobs.html
409 *
410 * Neither of the two strings must be NULL.
411 */
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200412#ifdef __clang__
Nick Wellnhofer44e7a0d2019-05-16 21:17:28 +0200413ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
Nick Wellnhoferb88ae6d2019-10-14 15:38:28 +0200414#endif
Daniel Veillard424785e2008-08-06 09:35:25 +0000415static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000416xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800417 const xmlChar *name, int len, int seed)
Daniel Veillard424785e2008-08-06 09:35:25 +0000418{
419 uint32_t hash;
420 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000421
Daniel Veillard8973d582012-02-04 19:07:44 +0800422 hash = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000423
424 for (i = 0;i < plen; i++) {
425 hash += prefix[i];
426 hash += (hash << 10);
427 hash ^= (hash >> 6);
428 }
429 hash += ':';
430 hash += (hash << 10);
431 hash ^= (hash >> 6);
432
433 for (i = 0;i < len; i++) {
434 hash += name[i];
435 hash += (hash << 10);
436 hash ^= (hash >> 6);
437 }
438 hash += (hash << 3);
439 hash ^= (hash >> 11);
440 hash += (hash << 15);
441
442 return hash;
443}
444#endif /* WITH_BIG_KEY */
445
446/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000447 * xmlDictComputeFastKey:
448 *
449 * Calculate a hash key using a fast hash function that works well
450 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000451 */
452static unsigned long
Daniel Veillard8973d582012-02-04 19:07:44 +0800453xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
454 unsigned long value = seed;
Daniel Veillard424785e2008-08-06 09:35:25 +0000455
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000456 if (name == NULL) return(0);
Ranier Vilela3c8a3e92019-11-07 12:59:10 +0000457 value += *name;
Daniel Veillard4773df22004-01-23 13:15:13 +0000458 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000459 if (namelen > 10) {
460 value += name[namelen - 1];
461 namelen = 10;
462 }
463 switch (namelen) {
464 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200465 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000466 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200467 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000468 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200469 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000470 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200471 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000472 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200473 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000474 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200475 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000476 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200477 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000478 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200479 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000480 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200481 /* Falls through. */
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000482 default: break;
483 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000484 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000485}
486
487/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000488 * xmlDictComputeFastQKey:
489 *
490 * Calculate a hash key for two strings using a fast hash function
491 * that works well for low hash table fill.
492 *
493 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000494 */
495static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000496xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
Daniel Veillard8973d582012-02-04 19:07:44 +0800497 const xmlChar *name, int len, int seed)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000498{
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200499 unsigned long value = seed;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000500
Daniel Veillarde72c5082003-09-19 12:44:05 +0000501 if (plen == 0)
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200502 value += 30 * ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000503 else
504 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000505
Daniel Veillarde72c5082003-09-19 12:44:05 +0000506 if (len > 10) {
David Drysdale6360a312015-11-20 10:47:12 +0800507 int offset = len - (plen + 1 + 1);
508 if (offset < 0)
509 offset = len - (10 + 1);
510 value += name[offset];
Daniel Veillarde72c5082003-09-19 12:44:05 +0000511 len = 10;
512 if (plen > 10)
513 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000514 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000515 switch (plen) {
516 case 10: value += prefix[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200517 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000518 case 9: value += prefix[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200519 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000520 case 8: value += prefix[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200521 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000522 case 7: value += prefix[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200523 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000524 case 6: value += prefix[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200525 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000526 case 5: value += prefix[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200527 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000528 case 4: value += prefix[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200529 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000530 case 3: value += prefix[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200531 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000532 case 2: value += prefix[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200533 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000534 case 1: value += prefix[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200535 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000536 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000537 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000538 len -= plen;
539 if (len > 0) {
Nick Wellnhoferad338ca2022-09-01 01:18:30 +0200540 value += ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000541 len--;
542 }
543 switch (len) {
544 case 10: value += name[9];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200545 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000546 case 9: value += name[8];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200547 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000548 case 8: value += name[7];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200549 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000550 case 7: value += name[6];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200551 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000552 case 6: value += name[5];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200553 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000554 case 5: value += name[4];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200555 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000556 case 4: value += name[3];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200557 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000558 case 3: value += name[2];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200559 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000560 case 2: value += name[1];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200561 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000562 case 1: value += name[0];
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +0200563 /* Falls through. */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000564 default: break;
565 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000566 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000567}
568
569/**
570 * xmlDictCreate:
571 *
572 * Create a new dictionary
573 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200574 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000575 */
576xmlDictPtr
577xmlDictCreate(void) {
578 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000579
580 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800581 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000582 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000583
584#ifdef DICT_DEBUG_PATTERNS
585 fprintf(stderr, "C");
586#endif
587
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000588 dict = xmlMalloc(sizeof(xmlDict));
589 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000590 dict->ref_counter = 1;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800591 dict->limit = 0;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000592
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000593 dict->size = MIN_DICT_SIZE;
594 dict->nbElems = 0;
595 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000596 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000597 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000598 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000599 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800600#ifdef DICT_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800601 dict->seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800602#else
603 dict->seed = 0;
604#endif
Daniel Veillardb242b082008-02-08 09:56:31 +0000605 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000606 }
607 xmlFree(dict);
608 }
609 return(NULL);
610}
611
612/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000613 * xmlDictCreateSub:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200614 * @sub: an existing dictionary
Daniel Veillard4773df22004-01-23 13:15:13 +0000615 *
616 * Create a new dictionary, inheriting strings from the read-only
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200617 * dictionary @sub. On lookup, strings are first searched in the
618 * new dictionary, then in @sub, and if not found are created in the
619 * new dictionary.
Daniel Veillard4773df22004-01-23 13:15:13 +0000620 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200621 * Returns the newly created dictionary, or NULL if an error occurred.
Daniel Veillard4773df22004-01-23 13:15:13 +0000622 */
623xmlDictPtr
624xmlDictCreateSub(xmlDictPtr sub) {
625 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000626
Daniel Veillard4773df22004-01-23 13:15:13 +0000627 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000628#ifdef DICT_DEBUG_PATTERNS
629 fprintf(stderr, "R");
630#endif
Daniel Veillard8973d582012-02-04 19:07:44 +0800631 dict->seed = sub->seed;
Daniel Veillard4773df22004-01-23 13:15:13 +0000632 dict->subdict = sub;
633 xmlDictReference(dict->subdict);
634 }
635 return(dict);
636}
637
638/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000639 * xmlDictReference:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200640 * @dict: the dictionary
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000641 *
642 * Increment the reference counter of a dictionary
643 *
644 * Returns 0 in case of success and -1 in case of error
645 */
646int
647xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000648 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800649 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000650 return(-1);
651
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000652 if (dict == NULL) return -1;
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100653 xmlMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000654 dict->ref_counter++;
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100655 xmlMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000656 return(0);
657}
658
659/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000660 * xmlDictGrow:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200661 * @dict: the dictionary
662 * @size: the new size of the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000663 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200664 * resize the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000665 *
666 * Returns 0 in case of success, -1 in case of failure
667 */
668static int
Daniel Veillard7c693da2012-07-25 16:32:18 +0800669xmlDictGrow(xmlDictPtr dict, size_t size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000670 unsigned long key, okey;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800671 size_t oldsize, i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000672 xmlDictEntryPtr iter, next;
673 struct _xmlDictEntry *olddict;
674#ifdef DEBUG_GROW
675 unsigned long nbElem = 0;
676#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000677 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000678 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000679
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000680 if (dict == NULL)
681 return(-1);
682 if (size < 8)
683 return(-1);
684 if (size > 8 * 2048)
685 return(-1);
686
Daniel Veillard424785e2008-08-06 09:35:25 +0000687#ifdef DICT_DEBUG_PATTERNS
688 fprintf(stderr, "*");
689#endif
690
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000691 oldsize = dict->size;
692 olddict = dict->dict;
693 if (olddict == NULL)
694 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000695 if (oldsize == MIN_DICT_SIZE)
696 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000697
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000698 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
699 if (dict->dict == NULL) {
700 dict->dict = olddict;
701 return(-1);
702 }
703 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
704 dict->size = size;
705
706 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000707 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000708 the main dict. It is nicer to run through the array twice, first
709 copying all the elements in the main array (less probability of
710 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000711 */
712 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000713 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000714 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000715
716 if (keep_keys)
717 okey = olddict[i].okey;
718 else
719 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
720 key = okey % dict->size;
721
Daniel Veillardffda65f2008-08-07 16:33:49 +0000722 if (dict->dict[key].valid == 0) {
723 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
724 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000725 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000726 } else {
727 xmlDictEntryPtr entry;
728
729 entry = xmlMalloc(sizeof(xmlDictEntry));
730 if (entry != NULL) {
731 entry->name = olddict[i].name;
732 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000733 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000734 entry->next = dict->dict[key].next;
735 entry->valid = 1;
736 dict->dict[key].next = entry;
737 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000738 /*
Jared Yanovich2a350ee2019-09-30 17:04:54 +0200739 * we don't have much ways to alert from here
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200740 * result is losing an entry and unicity guarantee
Daniel Veillardd68f8912008-08-08 10:09:19 +0000741 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000742 ret = -1;
743 }
744 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000745#ifdef DEBUG_GROW
746 nbElem++;
747#endif
748 }
749
750 for (i = 0; i < oldsize; i++) {
751 iter = olddict[i].next;
752 while (iter) {
753 next = iter->next;
754
755 /*
756 * put back the entry in the new dict
757 */
758
Daniel Veillardd68f8912008-08-08 10:09:19 +0000759 if (keep_keys)
760 okey = iter->okey;
761 else
762 okey = xmlDictComputeKey(dict, iter->name, iter->len);
763 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000764 if (dict->dict[key].valid == 0) {
765 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
766 dict->dict[key].next = NULL;
767 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000768 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000769 xmlFree(iter);
770 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000771 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000772 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000773 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000774 }
775
776#ifdef DEBUG_GROW
777 nbElem++;
778#endif
779
780 iter = next;
781 }
782 }
783
784 xmlFree(olddict);
785
786#ifdef DEBUG_GROW
787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard7c693da2012-07-25 16:32:18 +0800788 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000789#endif
790
Daniel Veillardffda65f2008-08-07 16:33:49 +0000791 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000792}
793
794/**
795 * xmlDictFree:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200796 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000797 *
798 * Free the hash @dict and its contents. The userdata is
799 * deallocated with @f if provided.
800 */
801void
802xmlDictFree(xmlDictPtr dict) {
Daniel Veillard7c693da2012-07-25 16:32:18 +0800803 size_t i;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000804 xmlDictEntryPtr iter;
805 xmlDictEntryPtr next;
806 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000807 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000808
809 if (dict == NULL)
810 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000811
Daniel Veillard14412512005-01-21 23:53:26 +0000812 if (!xmlDictInitialized)
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800813 if (!__xmlInitializeDict())
Daniel Veillard14412512005-01-21 23:53:26 +0000814 return;
815
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000816 /* decrement the counter, it may be shared by a parser and docs */
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100817 xmlMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000818 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000819 if (dict->ref_counter > 0) {
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100820 xmlMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000821 return;
822 }
823
Nick Wellnhofer3241c472022-03-06 14:58:04 +0100824 xmlMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000825
Daniel Veillard4773df22004-01-23 13:15:13 +0000826 if (dict->subdict != NULL) {
827 xmlDictFree(dict->subdict);
828 }
829
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000830 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000831 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000832 iter = &(dict->dict[i]);
833 if (iter->valid == 0)
834 continue;
835 inside_dict = 1;
836 while (iter) {
837 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000838 if (!inside_dict)
839 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000840 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000841 inside_dict = 0;
842 iter = next;
843 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000844 }
845 xmlFree(dict->dict);
846 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000847 pool = dict->strings;
848 while (pool != NULL) {
849 nextp = pool->next;
850 xmlFree(pool);
851 pool = nextp;
852 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000853 xmlFree(dict);
854}
855
856/**
857 * xmlDictLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200858 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000859 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000860 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000861 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200862 * Add the @name to the dictionary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000863 *
864 * Returns the internal copy of the name or NULL in case of internal error
865 */
866const xmlChar *
867xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000868 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000869 xmlDictEntryPtr entry;
870 xmlDictEntryPtr insert;
871 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800872 unsigned int l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000873
Daniel Veillard0fb18932003-09-07 09:14:37 +0000874 if ((dict == NULL) || (name == NULL))
875 return(NULL);
876
877 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +0800878 l = strlen((const char *) name);
879 else
880 l = len;
881
882 if (((dict->limit > 0) && (l >= dict->limit)) ||
883 (l > INT_MAX / 2))
884 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000885
886 /*
887 * Check for duplicate and insertion location.
888 */
Daniel Veillard7c693da2012-07-25 16:32:18 +0800889 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000890 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000891 if (dict->dict[key].valid == 0) {
892 insert = NULL;
893 } else {
894 for (insert = &(dict->dict[key]); insert->next != NULL;
895 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000896#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800897 if ((insert->okey == okey) && (insert->len == l)) {
898 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000899 return(insert->name);
900 }
901#else
Patrick Ganstererfd4f6fd2012-08-13 17:54:20 +0800902 if ((insert->okey == okey) && (insert->len == l) &&
Daniel Veillard7c693da2012-07-25 16:32:18 +0800903 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000904 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000905#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000906 nbi++;
907 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000908#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800909 if ((insert->okey == okey) && (insert->len == l)) {
910 if (!memcmp(insert->name, name, l))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000911 return(insert->name);
912 }
913#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800914 if ((insert->okey == okey) && (insert->len == l) &&
915 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000916 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000917#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000918 }
919
Daniel Veillard4773df22004-01-23 13:15:13 +0000920 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000921 unsigned long skey;
922
923 /* we cannot always reuse the same okey for the subdict */
924 if (((dict->size == MIN_DICT_SIZE) &&
925 (dict->subdict->size != MIN_DICT_SIZE)) ||
926 ((dict->size != MIN_DICT_SIZE) &&
927 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +0800928 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +0000929 else
930 skey = okey;
931
932 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000933 if (dict->subdict->dict[key].valid != 0) {
934 xmlDictEntryPtr tmp;
935
936 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
937 tmp = tmp->next) {
938#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800939 if ((tmp->okey == skey) && (tmp->len == l)) {
940 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000941 return(tmp->name);
942 }
943#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800944 if ((tmp->okey == skey) && (tmp->len == l) &&
945 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000946 return(tmp->name);
947#endif
948 nbi++;
949 }
950#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +0800951 if ((tmp->okey == skey) && (tmp->len == l)) {
952 if (!memcmp(tmp->name, name, l))
Daniel Veillard4773df22004-01-23 13:15:13 +0000953 return(tmp->name);
954 }
955#else
Daniel Veillard7c693da2012-07-25 16:32:18 +0800956 if ((tmp->okey == skey) && (tmp->len == l) &&
957 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard4773df22004-01-23 13:15:13 +0000958 return(tmp->name);
959#endif
960 }
961 key = okey % dict->size;
962 }
963
Daniel Veillard7c693da2012-07-25 16:32:18 +0800964 ret = xmlDictAddString(dict, name, l);
Daniel Veillard81514ba2003-09-16 23:17:26 +0000965 if (ret == NULL)
966 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000967 if (insert == NULL) {
968 entry = &(dict->dict[key]);
969 } else {
970 entry = xmlMalloc(sizeof(xmlDictEntry));
971 if (entry == NULL)
972 return(NULL);
973 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000974 entry->name = ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +0800975 entry->len = l;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000976 entry->next = NULL;
977 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000978 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000979
980
Daniel Veillard7c693da2012-07-25 16:32:18 +0800981 if (insert != NULL)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000982 insert->next = entry;
983
984 dict->nbElems++;
985
986 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000987 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
988 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
989 return(NULL);
990 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000991 /* Note that entry may have been freed at this point by xmlDictGrow */
992
993 return(ret);
994}
995
996/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000997 * xmlDictExists:
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200998 * @dict: the dictionary
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000999 * @name: the name of the userdata
1000 * @len: the length of the name, if -1 it is recomputed
1001 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001002 * Check if the @name exists in the dictionary @dict.
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001003 *
1004 * Returns the internal copy of the name or NULL if not found.
1005 */
1006const xmlChar *
1007xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
Nick Wellnhoferb6f12982022-10-24 20:47:10 +02001008 unsigned long key, okey;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001009 xmlDictEntryPtr insert;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001010 unsigned int l;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001011
1012 if ((dict == NULL) || (name == NULL))
1013 return(NULL);
1014
1015 if (len < 0)
Daniel Veillard7c693da2012-07-25 16:32:18 +08001016 l = strlen((const char *) name);
1017 else
1018 l = len;
1019 if (((dict->limit > 0) && (l >= dict->limit)) ||
1020 (l > INT_MAX / 2))
1021 return(NULL);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001022
1023 /*
1024 * Check for duplicate and insertion location.
1025 */
Daniel Veillard7c693da2012-07-25 16:32:18 +08001026 okey = xmlDictComputeKey(dict, name, l);
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001027 key = okey % dict->size;
1028 if (dict->dict[key].valid == 0) {
1029 insert = NULL;
1030 } else {
1031 for (insert = &(dict->dict[key]); insert->next != NULL;
1032 insert = insert->next) {
1033#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001034 if ((insert->okey == okey) && (insert->len == l)) {
1035 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001036 return(insert->name);
1037 }
1038#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001039 if ((insert->okey == okey) && (insert->len == l) &&
1040 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001041 return(insert->name);
1042#endif
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001043 }
1044#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001045 if ((insert->okey == okey) && (insert->len == l)) {
1046 if (!memcmp(insert->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001047 return(insert->name);
1048 }
1049#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001050 if ((insert->okey == okey) && (insert->len == l) &&
1051 (!xmlStrncmp(insert->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001052 return(insert->name);
1053#endif
1054 }
1055
1056 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001057 unsigned long skey;
1058
1059 /* we cannot always reuse the same okey for the subdict */
1060 if (((dict->size == MIN_DICT_SIZE) &&
1061 (dict->subdict->size != MIN_DICT_SIZE)) ||
1062 ((dict->size != MIN_DICT_SIZE) &&
1063 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillard7c693da2012-07-25 16:32:18 +08001064 skey = xmlDictComputeKey(dict->subdict, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001065 else
1066 skey = okey;
1067
1068 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001069 if (dict->subdict->dict[key].valid != 0) {
1070 xmlDictEntryPtr tmp;
1071
1072 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1073 tmp = tmp->next) {
1074#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001075 if ((tmp->okey == skey) && (tmp->len == l)) {
1076 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001077 return(tmp->name);
1078 }
1079#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001080 if ((tmp->okey == skey) && (tmp->len == l) &&
1081 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001082 return(tmp->name);
1083#endif
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001084 }
1085#ifdef __GNUC__
Daniel Veillard7c693da2012-07-25 16:32:18 +08001086 if ((tmp->okey == skey) && (tmp->len == l)) {
1087 if (!memcmp(tmp->name, name, l))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001088 return(tmp->name);
1089 }
1090#else
Daniel Veillard7c693da2012-07-25 16:32:18 +08001091 if ((tmp->okey == skey) && (tmp->len == l) &&
1092 (!xmlStrncmp(tmp->name, name, l)))
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001093 return(tmp->name);
1094#endif
1095 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +00001096 }
1097
1098 /* not found */
1099 return(NULL);
1100}
1101
1102/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00001103 * xmlDictQLookup:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001104 * @dict: the dictionary
Daniel Veillardd68f8912008-08-08 10:09:19 +00001105 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +00001106 * @name: the name
1107 *
1108 * Add the QName @prefix:@name to the hash @dict if not present.
1109 *
1110 * Returns the internal copy of the QName or NULL in case of internal error
1111 */
1112const xmlChar *
1113xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +00001114 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001115 xmlDictEntryPtr entry;
1116 xmlDictEntryPtr insert;
1117 const xmlChar *ret;
Daniel Veillard7c693da2012-07-25 16:32:18 +08001118 unsigned int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001119
1120 if ((dict == NULL) || (name == NULL))
1121 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +00001122 if (prefix == NULL)
1123 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +00001124
Daniel Veillardffda65f2008-08-07 16:33:49 +00001125 l = len = strlen((const char *) name);
1126 plen = strlen((const char *) prefix);
1127 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001128
1129 /*
1130 * Check for duplicate and insertion location.
1131 */
Daniel Veillardffda65f2008-08-07 16:33:49 +00001132 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +00001133 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001134 if (dict->dict[key].valid == 0) {
1135 insert = NULL;
1136 } else {
1137 for (insert = &(dict->dict[key]); insert->next != NULL;
1138 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001139 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001140 (xmlStrQEqual(prefix, name, insert->name)))
1141 return(insert->name);
1142 nbi++;
1143 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001144 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +00001145 (xmlStrQEqual(prefix, name, insert->name)))
1146 return(insert->name);
1147 }
1148
Daniel Veillard4773df22004-01-23 13:15:13 +00001149 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +00001150 unsigned long skey;
1151
1152 /* we cannot always reuse the same okey for the subdict */
1153 if (((dict->size == MIN_DICT_SIZE) &&
1154 (dict->subdict->size != MIN_DICT_SIZE)) ||
1155 ((dict->size != MIN_DICT_SIZE) &&
1156 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001157 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001158 else
1159 skey = okey;
1160
1161 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001162 if (dict->subdict->dict[key].valid != 0) {
1163 xmlDictEntryPtr tmp;
1164 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1165 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001166 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001167 (xmlStrQEqual(prefix, name, tmp->name)))
1168 return(tmp->name);
1169 nbi++;
1170 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001171 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001172 (xmlStrQEqual(prefix, name, tmp->name)))
1173 return(tmp->name);
1174 }
1175 key = okey % dict->size;
1176 }
1177
Daniel Veillardffda65f2008-08-07 16:33:49 +00001178 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001179 if (ret == NULL)
1180 return(NULL);
1181 if (insert == NULL) {
1182 entry = &(dict->dict[key]);
1183 } else {
1184 entry = xmlMalloc(sizeof(xmlDictEntry));
1185 if (entry == NULL)
1186 return(NULL);
1187 }
1188 entry->name = ret;
1189 entry->len = len;
1190 entry->next = NULL;
1191 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001192 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001193
Daniel Veillard7c693da2012-07-25 16:32:18 +08001194 if (insert != NULL)
Daniel Veillarde72c5082003-09-19 12:44:05 +00001195 insert->next = entry;
1196
1197 dict->nbElems++;
1198
1199 if ((nbi > MAX_HASH_LEN) &&
1200 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1201 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1202 /* Note that entry may have been freed at this point by xmlDictGrow */
1203
1204 return(ret);
1205}
1206
1207/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001208 * xmlDictOwns:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001209 * @dict: the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001210 * @str: the string
1211 *
Jared Yanovich2a350ee2019-09-30 17:04:54 +02001212 * check if a string is owned by the dictionary
Daniel Veillard81514ba2003-09-16 23:17:26 +00001213 *
1214 * Returns 1 if true, 0 if false and -1 in case of error
1215 * -1 in case of error
1216 */
1217int
1218xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1219 xmlDictStringsPtr pool;
1220
1221 if ((dict == NULL) || (str == NULL))
1222 return(-1);
1223 pool = dict->strings;
1224 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001225 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001226 return(1);
1227 pool = pool->next;
1228 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001229 if (dict->subdict)
1230 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001231 return(0);
1232}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001233
Daniel Veillard81514ba2003-09-16 23:17:26 +00001234/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001235 * xmlDictSize:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001236 * @dict: the dictionary
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001237 *
1238 * Query the number of elements installed in the hash @dict.
1239 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001240 * Returns the number of elements in the dictionary or
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001241 * -1 in case of error
1242 */
1243int
1244xmlDictSize(xmlDictPtr dict) {
1245 if (dict == NULL)
1246 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001247 if (dict->subdict)
1248 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001249 return(dict->nbElems);
1250}
1251
Daniel Veillard7c693da2012-07-25 16:32:18 +08001252/**
1253 * xmlDictSetLimit:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001254 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001255 * @limit: the limit in bytes
1256 *
1257 * Set a size limit for the dictionary
1258 * Added in 2.9.0
1259 *
1260 * Returns the previous limit of the dictionary or 0
1261 */
1262size_t
1263xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1264 size_t ret;
1265
1266 if (dict == NULL)
1267 return(0);
1268 ret = dict->limit;
1269 dict->limit = limit;
1270 return(ret);
1271}
1272
1273/**
1274 * xmlDictGetUsage:
Jan Pokornýbb654fe2016-04-13 16:56:07 +02001275 * @dict: the dictionary
Daniel Veillard7c693da2012-07-25 16:32:18 +08001276 *
1277 * Get how much memory is used by a dictionary for strings
1278 * Added in 2.9.0
1279 *
1280 * Returns the amount of strings allocated
1281 */
1282size_t
1283xmlDictGetUsage(xmlDictPtr dict) {
1284 xmlDictStringsPtr pool;
1285 size_t limit = 0;
1286
1287 if (dict == NULL)
1288 return(0);
1289 pool = dict->strings;
1290 while (pool != NULL) {
1291 limit += pool->size;
1292 pool = pool->next;
1293 }
1294 return(limit);
1295}
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001296