pocjenkixx 0.30.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pocjenkixx might be problematic. Click here for more details.
- package/LICENSE +19 -0
- package/Makefile +18 -0
- package/README.md +52 -0
- package/binding.gyp +81 -0
- package/index.d.ts +273 -0
- package/index.js +45 -0
- package/lib/bindings.js +1 -0
- package/lib/document.js +122 -0
- package/lib/element.js +82 -0
- package/lib/sax_parser.js +38 -0
- package/package.json +70 -0
- package/src/html_document.cc +7 -0
- package/src/html_document.h +18 -0
- package/src/libxmljs.cc +252 -0
- package/src/libxmljs.h +53 -0
- package/src/xml_attribute.cc +173 -0
- package/src/xml_attribute.h +40 -0
- package/src/xml_comment.cc +117 -0
- package/src/xml_comment.h +30 -0
- package/src/xml_document.cc +810 -0
- package/src/xml_document.h +67 -0
- package/src/xml_element.cc +565 -0
- package/src/xml_element.h +61 -0
- package/src/xml_namespace.cc +158 -0
- package/src/xml_namespace.h +39 -0
- package/src/xml_node.cc +761 -0
- package/src/xml_node.h +73 -0
- package/src/xml_pi.cc +161 -0
- package/src/xml_pi.h +34 -0
- package/src/xml_sax_parser.cc +424 -0
- package/src/xml_sax_parser.h +73 -0
- package/src/xml_syntax_error.cc +66 -0
- package/src/xml_syntax_error.h +25 -0
- package/src/xml_text.cc +320 -0
- package/src/xml_text.h +48 -0
- package/src/xml_textwriter.cc +315 -0
- package/src/xml_textwriter.h +62 -0
- package/src/xml_xpath_context.cc +70 -0
- package/src/xml_xpath_context.h +23 -0
- package/vendor/libxml/Copyright +23 -0
- package/vendor/libxml/DOCBparser.c +305 -0
- package/vendor/libxml/HTMLparser.c +7287 -0
- package/vendor/libxml/HTMLtree.c +1200 -0
- package/vendor/libxml/Makefile +2983 -0
- package/vendor/libxml/SAX.c +180 -0
- package/vendor/libxml/SAX2.c +3036 -0
- package/vendor/libxml/buf.c +1351 -0
- package/vendor/libxml/buf.h +72 -0
- package/vendor/libxml/c14n.c +2234 -0
- package/vendor/libxml/catalog.c +3828 -0
- package/vendor/libxml/chvalid.c +336 -0
- package/vendor/libxml/config.h +294 -0
- package/vendor/libxml/config.h.gch +0 -0
- package/vendor/libxml/debugXML.c +3423 -0
- package/vendor/libxml/dict.c +1298 -0
- package/vendor/libxml/elfgcchack.h +17818 -0
- package/vendor/libxml/enc.h +32 -0
- package/vendor/libxml/encoding.c +3975 -0
- package/vendor/libxml/entities.c +1163 -0
- package/vendor/libxml/error.c +998 -0
- package/vendor/libxml/globals.c +1126 -0
- package/vendor/libxml/hash.c +1146 -0
- package/vendor/libxml/include/libxml/DOCBparser.h +96 -0
- package/vendor/libxml/include/libxml/HTMLparser.h +306 -0
- package/vendor/libxml/include/libxml/HTMLtree.h +147 -0
- package/vendor/libxml/include/libxml/Makefile +725 -0
- package/vendor/libxml/include/libxml/Makefile.am +54 -0
- package/vendor/libxml/include/libxml/Makefile.in +725 -0
- package/vendor/libxml/include/libxml/SAX.h +173 -0
- package/vendor/libxml/include/libxml/SAX2.h +178 -0
- package/vendor/libxml/include/libxml/c14n.h +128 -0
- package/vendor/libxml/include/libxml/catalog.h +182 -0
- package/vendor/libxml/include/libxml/chvalid.h +230 -0
- package/vendor/libxml/include/libxml/debugXML.h +217 -0
- package/vendor/libxml/include/libxml/dict.h +79 -0
- package/vendor/libxml/include/libxml/encoding.h +245 -0
- package/vendor/libxml/include/libxml/entities.h +151 -0
- package/vendor/libxml/include/libxml/globals.h +508 -0
- package/vendor/libxml/include/libxml/hash.h +236 -0
- package/vendor/libxml/include/libxml/list.h +137 -0
- package/vendor/libxml/include/libxml/nanoftp.h +163 -0
- package/vendor/libxml/include/libxml/nanohttp.h +81 -0
- package/vendor/libxml/include/libxml/parser.h +1243 -0
- package/vendor/libxml/include/libxml/parserInternals.h +644 -0
- package/vendor/libxml/include/libxml/pattern.h +100 -0
- package/vendor/libxml/include/libxml/relaxng.h +217 -0
- package/vendor/libxml/include/libxml/schemasInternals.h +958 -0
- package/vendor/libxml/include/libxml/schematron.h +142 -0
- package/vendor/libxml/include/libxml/threads.h +89 -0
- package/vendor/libxml/include/libxml/tree.h +1311 -0
- package/vendor/libxml/include/libxml/uri.h +94 -0
- package/vendor/libxml/include/libxml/valid.h +458 -0
- package/vendor/libxml/include/libxml/xinclude.h +129 -0
- package/vendor/libxml/include/libxml/xlink.h +189 -0
- package/vendor/libxml/include/libxml/xmlIO.h +368 -0
- package/vendor/libxml/include/libxml/xmlautomata.h +146 -0
- package/vendor/libxml/include/libxml/xmlerror.h +945 -0
- package/vendor/libxml/include/libxml/xmlexports.h +77 -0
- package/vendor/libxml/include/libxml/xmlmemory.h +224 -0
- package/vendor/libxml/include/libxml/xmlmodule.h +57 -0
- package/vendor/libxml/include/libxml/xmlreader.h +428 -0
- package/vendor/libxml/include/libxml/xmlregexp.h +222 -0
- package/vendor/libxml/include/libxml/xmlsave.h +88 -0
- package/vendor/libxml/include/libxml/xmlschemas.h +246 -0
- package/vendor/libxml/include/libxml/xmlschemastypes.h +151 -0
- package/vendor/libxml/include/libxml/xmlstring.h +140 -0
- package/vendor/libxml/include/libxml/xmlunicode.h +202 -0
- package/vendor/libxml/include/libxml/xmlversion.h +484 -0
- package/vendor/libxml/include/libxml/xmlwin32version.h +239 -0
- package/vendor/libxml/include/libxml/xmlwriter.h +488 -0
- package/vendor/libxml/include/libxml/xpath.h +564 -0
- package/vendor/libxml/include/libxml/xpathInternals.h +632 -0
- package/vendor/libxml/include/libxml/xpointer.h +114 -0
- package/vendor/libxml/include/win32config.h +122 -0
- package/vendor/libxml/include/wsockcompat.h +54 -0
- package/vendor/libxml/legacy.c +1343 -0
- package/vendor/libxml/libxml.h +134 -0
- package/vendor/libxml/list.c +779 -0
- package/vendor/libxml/nanoftp.c +2118 -0
- package/vendor/libxml/nanohttp.c +1899 -0
- package/vendor/libxml/parser.c +15553 -0
- package/vendor/libxml/parserInternals.c +2164 -0
- package/vendor/libxml/pattern.c +2621 -0
- package/vendor/libxml/relaxng.c +11101 -0
- package/vendor/libxml/rngparser.c +1595 -0
- package/vendor/libxml/runsuite.c +1157 -0
- package/vendor/libxml/save.h +36 -0
- package/vendor/libxml/schematron.c +1787 -0
- package/vendor/libxml/threads.c +1049 -0
- package/vendor/libxml/timsort.h +601 -0
- package/vendor/libxml/tree.c +10183 -0
- package/vendor/libxml/trio.c +6895 -0
- package/vendor/libxml/trio.h +230 -0
- package/vendor/libxml/triodef.h +228 -0
- package/vendor/libxml/trionan.c +914 -0
- package/vendor/libxml/trionan.h +84 -0
- package/vendor/libxml/triop.h +150 -0
- package/vendor/libxml/triostr.c +2112 -0
- package/vendor/libxml/triostr.h +144 -0
- package/vendor/libxml/uri.c +2561 -0
- package/vendor/libxml/valid.c +7138 -0
- package/vendor/libxml/xinclude.c +2657 -0
- package/vendor/libxml/xlink.c +183 -0
- package/vendor/libxml/xmlIO.c +4135 -0
- package/vendor/libxml/xmlcatalog.c +624 -0
- package/vendor/libxml/xmllint.c +3796 -0
- package/vendor/libxml/xmlmemory.c +1163 -0
- package/vendor/libxml/xmlmodule.c +468 -0
- package/vendor/libxml/xmlreader.c +6033 -0
- package/vendor/libxml/xmlregexp.c +8271 -0
- package/vendor/libxml/xmlsave.c +2735 -0
- package/vendor/libxml/xmlschemas.c +29173 -0
- package/vendor/libxml/xmlschemastypes.c +6276 -0
- package/vendor/libxml/xmlstring.c +1050 -0
- package/vendor/libxml/xmlunicode.c +3179 -0
- package/vendor/libxml/xmlwriter.c +4738 -0
- package/vendor/libxml/xpath.c +14734 -0
- package/vendor/libxml/xpointer.c +2969 -0
- package/vendor/libxml/xzlib.c +815 -0
- package/vendor/libxml/xzlib.h +19 -0
@@ -0,0 +1,1298 @@
|
|
1
|
+
/*
|
2
|
+
* dict.c: dictionary of reusable strings, just used to avoid allocation
|
3
|
+
* and freeing operations.
|
4
|
+
*
|
5
|
+
* Copyright (C) 2003-2012 Daniel Veillard.
|
6
|
+
*
|
7
|
+
* Permission to use, copy, modify, and distribute this software for any
|
8
|
+
* purpose with or without fee is hereby granted, provided that the above
|
9
|
+
* copyright notice and this permission notice appear in all copies.
|
10
|
+
*
|
11
|
+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
12
|
+
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
13
|
+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
14
|
+
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
15
|
+
*
|
16
|
+
* Author: daniel@veillard.com
|
17
|
+
*/
|
18
|
+
|
19
|
+
#define IN_LIBXML
|
20
|
+
#include "libxml.h"
|
21
|
+
|
22
|
+
#include <limits.h>
|
23
|
+
#ifdef HAVE_STDLIB_H
|
24
|
+
#include <stdlib.h>
|
25
|
+
#endif
|
26
|
+
#ifdef HAVE_TIME_H
|
27
|
+
#include <time.h>
|
28
|
+
#endif
|
29
|
+
|
30
|
+
/*
|
31
|
+
* Following http://www.ocert.org/advisories/ocert-2011-003.html
|
32
|
+
* it seems that having hash randomization might be a good idea
|
33
|
+
* when using XML with untrusted data
|
34
|
+
* Note1: that it works correctly only if compiled with WITH_BIG_KEY
|
35
|
+
* which is the default.
|
36
|
+
* Note2: the fast function used for a small dict won't protect very
|
37
|
+
* well but since the attack is based on growing a very big hash
|
38
|
+
* list we will use the BigKey algo as soon as the hash size grows
|
39
|
+
* over MIN_DICT_SIZE so this actually works
|
40
|
+
*/
|
41
|
+
#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) && \
|
42
|
+
!defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
|
43
|
+
#define DICT_RANDOMIZATION
|
44
|
+
#endif
|
45
|
+
|
46
|
+
#include <string.h>
|
47
|
+
#ifdef HAVE_STDINT_H
|
48
|
+
#include <stdint.h>
|
49
|
+
#else
|
50
|
+
#ifdef HAVE_INTTYPES_H
|
51
|
+
#include <inttypes.h>
|
52
|
+
#elif defined(_WIN32)
|
53
|
+
typedef unsigned __int32 uint32_t;
|
54
|
+
#endif
|
55
|
+
#endif
|
56
|
+
#include <libxml/tree.h>
|
57
|
+
#include <libxml/dict.h>
|
58
|
+
#include <libxml/xmlmemory.h>
|
59
|
+
#include <libxml/xmlerror.h>
|
60
|
+
#include <libxml/globals.h>
|
61
|
+
|
62
|
+
/* #define DEBUG_GROW */
|
63
|
+
/* #define DICT_DEBUG_PATTERNS */
|
64
|
+
|
65
|
+
#define MAX_HASH_LEN 3
|
66
|
+
#define MIN_DICT_SIZE 128
|
67
|
+
#define MAX_DICT_HASH 8 * 2048
|
68
|
+
#define WITH_BIG_KEY
|
69
|
+
|
70
|
+
#ifdef WITH_BIG_KEY
|
71
|
+
#define xmlDictComputeKey(dict, name, len) \
|
72
|
+
(((dict)->size == MIN_DICT_SIZE) ? \
|
73
|
+
xmlDictComputeFastKey(name, len, (dict)->seed) : \
|
74
|
+
xmlDictComputeBigKey(name, len, (dict)->seed))
|
75
|
+
|
76
|
+
#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
|
77
|
+
(((prefix) == NULL) ? \
|
78
|
+
(xmlDictComputeKey(dict, name, len)) : \
|
79
|
+
(((dict)->size == MIN_DICT_SIZE) ? \
|
80
|
+
xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
|
81
|
+
xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
|
82
|
+
|
83
|
+
#else /* !WITH_BIG_KEY */
|
84
|
+
#define xmlDictComputeKey(dict, name, len) \
|
85
|
+
xmlDictComputeFastKey(name, len, (dict)->seed)
|
86
|
+
#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
|
87
|
+
xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
|
88
|
+
#endif /* WITH_BIG_KEY */
|
89
|
+
|
90
|
+
/*
|
91
|
+
* An entry in the dictionary
|
92
|
+
*/
|
93
|
+
typedef struct _xmlDictEntry xmlDictEntry;
|
94
|
+
typedef xmlDictEntry *xmlDictEntryPtr;
|
95
|
+
struct _xmlDictEntry {
|
96
|
+
struct _xmlDictEntry *next;
|
97
|
+
const xmlChar *name;
|
98
|
+
unsigned int len;
|
99
|
+
int valid;
|
100
|
+
unsigned long okey;
|
101
|
+
};
|
102
|
+
|
103
|
+
typedef struct _xmlDictStrings xmlDictStrings;
|
104
|
+
typedef xmlDictStrings *xmlDictStringsPtr;
|
105
|
+
struct _xmlDictStrings {
|
106
|
+
xmlDictStringsPtr next;
|
107
|
+
xmlChar *free;
|
108
|
+
xmlChar *end;
|
109
|
+
size_t size;
|
110
|
+
size_t nbStrings;
|
111
|
+
xmlChar array[1];
|
112
|
+
};
|
113
|
+
/*
|
114
|
+
* The entire dictionary
|
115
|
+
*/
|
116
|
+
struct _xmlDict {
|
117
|
+
int ref_counter;
|
118
|
+
|
119
|
+
struct _xmlDictEntry *dict;
|
120
|
+
size_t size;
|
121
|
+
unsigned int nbElems;
|
122
|
+
xmlDictStringsPtr strings;
|
123
|
+
|
124
|
+
struct _xmlDict *subdict;
|
125
|
+
/* used for randomization */
|
126
|
+
int seed;
|
127
|
+
/* used to impose a limit on size */
|
128
|
+
size_t limit;
|
129
|
+
};
|
130
|
+
|
131
|
+
/*
|
132
|
+
* A mutex for modifying the reference counter for shared
|
133
|
+
* dictionaries.
|
134
|
+
*/
|
135
|
+
static xmlRMutexPtr xmlDictMutex = NULL;
|
136
|
+
|
137
|
+
/*
|
138
|
+
* Whether the dictionary mutex was initialized.
|
139
|
+
*/
|
140
|
+
static int xmlDictInitialized = 0;
|
141
|
+
|
142
|
+
#ifdef DICT_RANDOMIZATION
|
143
|
+
#ifdef HAVE_RAND_R
|
144
|
+
/*
|
145
|
+
* Internal data for random function, protected by xmlDictMutex
|
146
|
+
*/
|
147
|
+
static unsigned int rand_seed = 0;
|
148
|
+
#endif
|
149
|
+
#endif
|
150
|
+
|
151
|
+
/**
|
152
|
+
* xmlInitializeDict:
|
153
|
+
*
|
154
|
+
* Do the dictionary mutex initialization.
|
155
|
+
* this function is deprecated
|
156
|
+
*
|
157
|
+
* Returns 0 if initialization was already done, and 1 if that
|
158
|
+
* call led to the initialization
|
159
|
+
*/
|
160
|
+
int xmlInitializeDict(void) {
|
161
|
+
return(0);
|
162
|
+
}
|
163
|
+
|
164
|
+
/**
|
165
|
+
* __xmlInitializeDict:
|
166
|
+
*
|
167
|
+
* This function is not public
|
168
|
+
* Do the dictionary mutex initialization.
|
169
|
+
* this function is not thread safe, initialization should
|
170
|
+
* normally be done once at setup when called from xmlOnceInit()
|
171
|
+
* we may also land in this code if thread support is not compiled in
|
172
|
+
*
|
173
|
+
* Returns 0 if initialization was already done, and 1 if that
|
174
|
+
* call led to the initialization
|
175
|
+
*/
|
176
|
+
int __xmlInitializeDict(void) {
|
177
|
+
if (xmlDictInitialized)
|
178
|
+
return(1);
|
179
|
+
|
180
|
+
if ((xmlDictMutex = xmlNewRMutex()) == NULL)
|
181
|
+
return(0);
|
182
|
+
xmlRMutexLock(xmlDictMutex);
|
183
|
+
|
184
|
+
#ifdef DICT_RANDOMIZATION
|
185
|
+
#ifdef HAVE_RAND_R
|
186
|
+
rand_seed = time(NULL);
|
187
|
+
rand_r(& rand_seed);
|
188
|
+
#else
|
189
|
+
srand(time(NULL));
|
190
|
+
#endif
|
191
|
+
#endif
|
192
|
+
xmlDictInitialized = 1;
|
193
|
+
xmlRMutexUnlock(xmlDictMutex);
|
194
|
+
return(1);
|
195
|
+
}
|
196
|
+
|
197
|
+
#ifdef DICT_RANDOMIZATION
|
198
|
+
int __xmlRandom(void) {
|
199
|
+
int ret;
|
200
|
+
|
201
|
+
if (xmlDictInitialized == 0)
|
202
|
+
__xmlInitializeDict();
|
203
|
+
|
204
|
+
xmlRMutexLock(xmlDictMutex);
|
205
|
+
#ifdef HAVE_RAND_R
|
206
|
+
ret = rand_r(& rand_seed);
|
207
|
+
#else
|
208
|
+
ret = rand();
|
209
|
+
#endif
|
210
|
+
xmlRMutexUnlock(xmlDictMutex);
|
211
|
+
return(ret);
|
212
|
+
}
|
213
|
+
#endif
|
214
|
+
|
215
|
+
/**
|
216
|
+
* xmlDictCleanup:
|
217
|
+
*
|
218
|
+
* Free the dictionary mutex. Do not call unless sure the library
|
219
|
+
* is not in use anymore !
|
220
|
+
*/
|
221
|
+
void
|
222
|
+
xmlDictCleanup(void) {
|
223
|
+
if (!xmlDictInitialized)
|
224
|
+
return;
|
225
|
+
|
226
|
+
xmlFreeRMutex(xmlDictMutex);
|
227
|
+
|
228
|
+
xmlDictInitialized = 0;
|
229
|
+
}
|
230
|
+
|
231
|
+
/*
|
232
|
+
* xmlDictAddString:
|
233
|
+
* @dict: the dictionary
|
234
|
+
* @name: the name of the userdata
|
235
|
+
* @len: the length of the name
|
236
|
+
*
|
237
|
+
* Add the string to the array[s]
|
238
|
+
*
|
239
|
+
* Returns the pointer of the local string, or NULL in case of error.
|
240
|
+
*/
|
241
|
+
static const xmlChar *
|
242
|
+
xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
|
243
|
+
xmlDictStringsPtr pool;
|
244
|
+
const xmlChar *ret;
|
245
|
+
size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
|
246
|
+
size_t limit = 0;
|
247
|
+
|
248
|
+
#ifdef DICT_DEBUG_PATTERNS
|
249
|
+
fprintf(stderr, "-");
|
250
|
+
#endif
|
251
|
+
pool = dict->strings;
|
252
|
+
while (pool != NULL) {
|
253
|
+
if ((size_t)(pool->end - pool->free) > namelen)
|
254
|
+
goto found_pool;
|
255
|
+
if (pool->size > size) size = pool->size;
|
256
|
+
limit += pool->size;
|
257
|
+
pool = pool->next;
|
258
|
+
}
|
259
|
+
/*
|
260
|
+
* Not found, need to allocate
|
261
|
+
*/
|
262
|
+
if (pool == NULL) {
|
263
|
+
if ((dict->limit > 0) && (limit > dict->limit)) {
|
264
|
+
return(NULL);
|
265
|
+
}
|
266
|
+
|
267
|
+
if (size == 0) size = 1000;
|
268
|
+
else size *= 4; /* exponential growth */
|
269
|
+
if (size < 4 * namelen)
|
270
|
+
size = 4 * namelen; /* just in case ! */
|
271
|
+
pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
|
272
|
+
if (pool == NULL)
|
273
|
+
return(NULL);
|
274
|
+
pool->size = size;
|
275
|
+
pool->nbStrings = 0;
|
276
|
+
pool->free = &pool->array[0];
|
277
|
+
pool->end = &pool->array[size];
|
278
|
+
pool->next = dict->strings;
|
279
|
+
dict->strings = pool;
|
280
|
+
#ifdef DICT_DEBUG_PATTERNS
|
281
|
+
fprintf(stderr, "+");
|
282
|
+
#endif
|
283
|
+
}
|
284
|
+
found_pool:
|
285
|
+
ret = pool->free;
|
286
|
+
memcpy(pool->free, name, namelen);
|
287
|
+
pool->free += namelen;
|
288
|
+
*(pool->free++) = 0;
|
289
|
+
pool->nbStrings++;
|
290
|
+
return(ret);
|
291
|
+
}
|
292
|
+
|
293
|
+
/*
|
294
|
+
* xmlDictAddQString:
|
295
|
+
* @dict: the dictionary
|
296
|
+
* @prefix: the prefix of the userdata
|
297
|
+
* @plen: the prefix length
|
298
|
+
* @name: the name of the userdata
|
299
|
+
* @len: the length of the name
|
300
|
+
*
|
301
|
+
* Add the QName to the array[s]
|
302
|
+
*
|
303
|
+
* Returns the pointer of the local string, or NULL in case of error.
|
304
|
+
*/
|
305
|
+
static const xmlChar *
|
306
|
+
xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
|
307
|
+
const xmlChar *name, unsigned int namelen)
|
308
|
+
{
|
309
|
+
xmlDictStringsPtr pool;
|
310
|
+
const xmlChar *ret;
|
311
|
+
size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
|
312
|
+
size_t limit = 0;
|
313
|
+
|
314
|
+
if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
|
315
|
+
|
316
|
+
#ifdef DICT_DEBUG_PATTERNS
|
317
|
+
fprintf(stderr, "=");
|
318
|
+
#endif
|
319
|
+
pool = dict->strings;
|
320
|
+
while (pool != NULL) {
|
321
|
+
if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
|
322
|
+
goto found_pool;
|
323
|
+
if (pool->size > size) size = pool->size;
|
324
|
+
limit += pool->size;
|
325
|
+
pool = pool->next;
|
326
|
+
}
|
327
|
+
/*
|
328
|
+
* Not found, need to allocate
|
329
|
+
*/
|
330
|
+
if (pool == NULL) {
|
331
|
+
if ((dict->limit > 0) && (limit > dict->limit)) {
|
332
|
+
return(NULL);
|
333
|
+
}
|
334
|
+
|
335
|
+
if (size == 0) size = 1000;
|
336
|
+
else size *= 4; /* exponential growth */
|
337
|
+
if (size < 4 * (namelen + plen + 1))
|
338
|
+
size = 4 * (namelen + plen + 1); /* just in case ! */
|
339
|
+
pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
|
340
|
+
if (pool == NULL)
|
341
|
+
return(NULL);
|
342
|
+
pool->size = size;
|
343
|
+
pool->nbStrings = 0;
|
344
|
+
pool->free = &pool->array[0];
|
345
|
+
pool->end = &pool->array[size];
|
346
|
+
pool->next = dict->strings;
|
347
|
+
dict->strings = pool;
|
348
|
+
#ifdef DICT_DEBUG_PATTERNS
|
349
|
+
fprintf(stderr, "+");
|
350
|
+
#endif
|
351
|
+
}
|
352
|
+
found_pool:
|
353
|
+
ret = pool->free;
|
354
|
+
memcpy(pool->free, prefix, plen);
|
355
|
+
pool->free += plen;
|
356
|
+
*(pool->free++) = ':';
|
357
|
+
memcpy(pool->free, name, namelen);
|
358
|
+
pool->free += namelen;
|
359
|
+
*(pool->free++) = 0;
|
360
|
+
pool->nbStrings++;
|
361
|
+
return(ret);
|
362
|
+
}
|
363
|
+
|
364
|
+
#ifdef WITH_BIG_KEY
|
365
|
+
/*
|
366
|
+
* xmlDictComputeBigKey:
|
367
|
+
*
|
368
|
+
* Calculate a hash key using a good hash function that works well for
|
369
|
+
* larger hash table sizes.
|
370
|
+
*
|
371
|
+
* Hash function by "One-at-a-Time Hash" see
|
372
|
+
* http://burtleburtle.net/bob/hash/doobs.html
|
373
|
+
*/
|
374
|
+
|
375
|
+
#ifdef __clang__
|
376
|
+
ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
|
377
|
+
#endif
|
378
|
+
static uint32_t
|
379
|
+
xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
|
380
|
+
uint32_t hash;
|
381
|
+
int i;
|
382
|
+
|
383
|
+
if (namelen <= 0 || data == NULL) return(0);
|
384
|
+
|
385
|
+
hash = seed;
|
386
|
+
|
387
|
+
for (i = 0;i < namelen; i++) {
|
388
|
+
hash += data[i];
|
389
|
+
hash += (hash << 10);
|
390
|
+
hash ^= (hash >> 6);
|
391
|
+
}
|
392
|
+
hash += (hash << 3);
|
393
|
+
hash ^= (hash >> 11);
|
394
|
+
hash += (hash << 15);
|
395
|
+
|
396
|
+
return hash;
|
397
|
+
}
|
398
|
+
|
399
|
+
/*
|
400
|
+
* xmlDictComputeBigQKey:
|
401
|
+
*
|
402
|
+
* Calculate a hash key for two strings using a good hash function
|
403
|
+
* that works well for larger hash table sizes.
|
404
|
+
*
|
405
|
+
* Hash function by "One-at-a-Time Hash" see
|
406
|
+
* http://burtleburtle.net/bob/hash/doobs.html
|
407
|
+
*
|
408
|
+
* Neither of the two strings must be NULL.
|
409
|
+
*/
|
410
|
+
#ifdef __clang__
|
411
|
+
ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
|
412
|
+
#endif
|
413
|
+
static unsigned long
|
414
|
+
xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
|
415
|
+
const xmlChar *name, int len, int seed)
|
416
|
+
{
|
417
|
+
uint32_t hash;
|
418
|
+
int i;
|
419
|
+
|
420
|
+
hash = seed;
|
421
|
+
|
422
|
+
for (i = 0;i < plen; i++) {
|
423
|
+
hash += prefix[i];
|
424
|
+
hash += (hash << 10);
|
425
|
+
hash ^= (hash >> 6);
|
426
|
+
}
|
427
|
+
hash += ':';
|
428
|
+
hash += (hash << 10);
|
429
|
+
hash ^= (hash >> 6);
|
430
|
+
|
431
|
+
for (i = 0;i < len; i++) {
|
432
|
+
hash += name[i];
|
433
|
+
hash += (hash << 10);
|
434
|
+
hash ^= (hash >> 6);
|
435
|
+
}
|
436
|
+
hash += (hash << 3);
|
437
|
+
hash ^= (hash >> 11);
|
438
|
+
hash += (hash << 15);
|
439
|
+
|
440
|
+
return hash;
|
441
|
+
}
|
442
|
+
#endif /* WITH_BIG_KEY */
|
443
|
+
|
444
|
+
/*
|
445
|
+
* xmlDictComputeFastKey:
|
446
|
+
*
|
447
|
+
* Calculate a hash key using a fast hash function that works well
|
448
|
+
* for low hash table fill.
|
449
|
+
*/
|
450
|
+
static unsigned long
|
451
|
+
xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
|
452
|
+
unsigned long value = seed;
|
453
|
+
|
454
|
+
if (name == NULL) return(0);
|
455
|
+
value += *name;
|
456
|
+
value <<= 5;
|
457
|
+
if (namelen > 10) {
|
458
|
+
value += name[namelen - 1];
|
459
|
+
namelen = 10;
|
460
|
+
}
|
461
|
+
switch (namelen) {
|
462
|
+
case 10: value += name[9];
|
463
|
+
/* Falls through. */
|
464
|
+
case 9: value += name[8];
|
465
|
+
/* Falls through. */
|
466
|
+
case 8: value += name[7];
|
467
|
+
/* Falls through. */
|
468
|
+
case 7: value += name[6];
|
469
|
+
/* Falls through. */
|
470
|
+
case 6: value += name[5];
|
471
|
+
/* Falls through. */
|
472
|
+
case 5: value += name[4];
|
473
|
+
/* Falls through. */
|
474
|
+
case 4: value += name[3];
|
475
|
+
/* Falls through. */
|
476
|
+
case 3: value += name[2];
|
477
|
+
/* Falls through. */
|
478
|
+
case 2: value += name[1];
|
479
|
+
/* Falls through. */
|
480
|
+
default: break;
|
481
|
+
}
|
482
|
+
return(value);
|
483
|
+
}
|
484
|
+
|
485
|
+
/*
|
486
|
+
* xmlDictComputeFastQKey:
|
487
|
+
*
|
488
|
+
* Calculate a hash key for two strings using a fast hash function
|
489
|
+
* that works well for low hash table fill.
|
490
|
+
*
|
491
|
+
* Neither of the two strings must be NULL.
|
492
|
+
*/
|
493
|
+
static unsigned long
|
494
|
+
xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
|
495
|
+
const xmlChar *name, int len, int seed)
|
496
|
+
{
|
497
|
+
unsigned long value = (unsigned long) seed;
|
498
|
+
|
499
|
+
if (plen == 0)
|
500
|
+
value += 30 * (unsigned long) ':';
|
501
|
+
else
|
502
|
+
value += 30 * (*prefix);
|
503
|
+
|
504
|
+
if (len > 10) {
|
505
|
+
int offset = len - (plen + 1 + 1);
|
506
|
+
if (offset < 0)
|
507
|
+
offset = len - (10 + 1);
|
508
|
+
value += name[offset];
|
509
|
+
len = 10;
|
510
|
+
if (plen > 10)
|
511
|
+
plen = 10;
|
512
|
+
}
|
513
|
+
switch (plen) {
|
514
|
+
case 10: value += prefix[9];
|
515
|
+
/* Falls through. */
|
516
|
+
case 9: value += prefix[8];
|
517
|
+
/* Falls through. */
|
518
|
+
case 8: value += prefix[7];
|
519
|
+
/* Falls through. */
|
520
|
+
case 7: value += prefix[6];
|
521
|
+
/* Falls through. */
|
522
|
+
case 6: value += prefix[5];
|
523
|
+
/* Falls through. */
|
524
|
+
case 5: value += prefix[4];
|
525
|
+
/* Falls through. */
|
526
|
+
case 4: value += prefix[3];
|
527
|
+
/* Falls through. */
|
528
|
+
case 3: value += prefix[2];
|
529
|
+
/* Falls through. */
|
530
|
+
case 2: value += prefix[1];
|
531
|
+
/* Falls through. */
|
532
|
+
case 1: value += prefix[0];
|
533
|
+
/* Falls through. */
|
534
|
+
default: break;
|
535
|
+
}
|
536
|
+
len -= plen;
|
537
|
+
if (len > 0) {
|
538
|
+
value += (unsigned long) ':';
|
539
|
+
len--;
|
540
|
+
}
|
541
|
+
switch (len) {
|
542
|
+
case 10: value += name[9];
|
543
|
+
/* Falls through. */
|
544
|
+
case 9: value += name[8];
|
545
|
+
/* Falls through. */
|
546
|
+
case 8: value += name[7];
|
547
|
+
/* Falls through. */
|
548
|
+
case 7: value += name[6];
|
549
|
+
/* Falls through. */
|
550
|
+
case 6: value += name[5];
|
551
|
+
/* Falls through. */
|
552
|
+
case 5: value += name[4];
|
553
|
+
/* Falls through. */
|
554
|
+
case 4: value += name[3];
|
555
|
+
/* Falls through. */
|
556
|
+
case 3: value += name[2];
|
557
|
+
/* Falls through. */
|
558
|
+
case 2: value += name[1];
|
559
|
+
/* Falls through. */
|
560
|
+
case 1: value += name[0];
|
561
|
+
/* Falls through. */
|
562
|
+
default: break;
|
563
|
+
}
|
564
|
+
return(value);
|
565
|
+
}
|
566
|
+
|
567
|
+
/**
|
568
|
+
* xmlDictCreate:
|
569
|
+
*
|
570
|
+
* Create a new dictionary
|
571
|
+
*
|
572
|
+
* Returns the newly created dictionary, or NULL if an error occurred.
|
573
|
+
*/
|
574
|
+
xmlDictPtr
|
575
|
+
xmlDictCreate(void) {
|
576
|
+
xmlDictPtr dict;
|
577
|
+
|
578
|
+
if (!xmlDictInitialized)
|
579
|
+
if (!__xmlInitializeDict())
|
580
|
+
return(NULL);
|
581
|
+
|
582
|
+
#ifdef DICT_DEBUG_PATTERNS
|
583
|
+
fprintf(stderr, "C");
|
584
|
+
#endif
|
585
|
+
|
586
|
+
dict = xmlMalloc(sizeof(xmlDict));
|
587
|
+
if (dict) {
|
588
|
+
dict->ref_counter = 1;
|
589
|
+
dict->limit = 0;
|
590
|
+
|
591
|
+
dict->size = MIN_DICT_SIZE;
|
592
|
+
dict->nbElems = 0;
|
593
|
+
dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
|
594
|
+
dict->strings = NULL;
|
595
|
+
dict->subdict = NULL;
|
596
|
+
if (dict->dict) {
|
597
|
+
memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
|
598
|
+
#ifdef DICT_RANDOMIZATION
|
599
|
+
dict->seed = __xmlRandom();
|
600
|
+
#else
|
601
|
+
dict->seed = 0;
|
602
|
+
#endif
|
603
|
+
return(dict);
|
604
|
+
}
|
605
|
+
xmlFree(dict);
|
606
|
+
}
|
607
|
+
return(NULL);
|
608
|
+
}
|
609
|
+
|
610
|
+
/**
|
611
|
+
* xmlDictCreateSub:
|
612
|
+
* @sub: an existing dictionary
|
613
|
+
*
|
614
|
+
* Create a new dictionary, inheriting strings from the read-only
|
615
|
+
* dictionary @sub. On lookup, strings are first searched in the
|
616
|
+
* new dictionary, then in @sub, and if not found are created in the
|
617
|
+
* new dictionary.
|
618
|
+
*
|
619
|
+
* Returns the newly created dictionary, or NULL if an error occurred.
|
620
|
+
*/
|
621
|
+
xmlDictPtr
|
622
|
+
xmlDictCreateSub(xmlDictPtr sub) {
|
623
|
+
xmlDictPtr dict = xmlDictCreate();
|
624
|
+
|
625
|
+
if ((dict != NULL) && (sub != NULL)) {
|
626
|
+
#ifdef DICT_DEBUG_PATTERNS
|
627
|
+
fprintf(stderr, "R");
|
628
|
+
#endif
|
629
|
+
dict->seed = sub->seed;
|
630
|
+
dict->subdict = sub;
|
631
|
+
xmlDictReference(dict->subdict);
|
632
|
+
}
|
633
|
+
return(dict);
|
634
|
+
}
|
635
|
+
|
636
|
+
/**
|
637
|
+
* xmlDictReference:
|
638
|
+
* @dict: the dictionary
|
639
|
+
*
|
640
|
+
* Increment the reference counter of a dictionary
|
641
|
+
*
|
642
|
+
* Returns 0 in case of success and -1 in case of error
|
643
|
+
*/
|
644
|
+
int
|
645
|
+
xmlDictReference(xmlDictPtr dict) {
|
646
|
+
if (!xmlDictInitialized)
|
647
|
+
if (!__xmlInitializeDict())
|
648
|
+
return(-1);
|
649
|
+
|
650
|
+
if (dict == NULL) return -1;
|
651
|
+
xmlRMutexLock(xmlDictMutex);
|
652
|
+
dict->ref_counter++;
|
653
|
+
xmlRMutexUnlock(xmlDictMutex);
|
654
|
+
return(0);
|
655
|
+
}
|
656
|
+
|
657
|
+
/**
|
658
|
+
* xmlDictGrow:
|
659
|
+
* @dict: the dictionary
|
660
|
+
* @size: the new size of the dictionary
|
661
|
+
*
|
662
|
+
* resize the dictionary
|
663
|
+
*
|
664
|
+
* Returns 0 in case of success, -1 in case of failure
|
665
|
+
*/
|
666
|
+
static int
|
667
|
+
xmlDictGrow(xmlDictPtr dict, size_t size) {
|
668
|
+
unsigned long key, okey;
|
669
|
+
size_t oldsize, i;
|
670
|
+
xmlDictEntryPtr iter, next;
|
671
|
+
struct _xmlDictEntry *olddict;
|
672
|
+
#ifdef DEBUG_GROW
|
673
|
+
unsigned long nbElem = 0;
|
674
|
+
#endif
|
675
|
+
int ret = 0;
|
676
|
+
int keep_keys = 1;
|
677
|
+
|
678
|
+
if (dict == NULL)
|
679
|
+
return(-1);
|
680
|
+
if (size < 8)
|
681
|
+
return(-1);
|
682
|
+
if (size > 8 * 2048)
|
683
|
+
return(-1);
|
684
|
+
|
685
|
+
#ifdef DICT_DEBUG_PATTERNS
|
686
|
+
fprintf(stderr, "*");
|
687
|
+
#endif
|
688
|
+
|
689
|
+
oldsize = dict->size;
|
690
|
+
olddict = dict->dict;
|
691
|
+
if (olddict == NULL)
|
692
|
+
return(-1);
|
693
|
+
if (oldsize == MIN_DICT_SIZE)
|
694
|
+
keep_keys = 0;
|
695
|
+
|
696
|
+
dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
|
697
|
+
if (dict->dict == NULL) {
|
698
|
+
dict->dict = olddict;
|
699
|
+
return(-1);
|
700
|
+
}
|
701
|
+
memset(dict->dict, 0, size * sizeof(xmlDictEntry));
|
702
|
+
dict->size = size;
|
703
|
+
|
704
|
+
/* If the two loops are merged, there would be situations where
|
705
|
+
a new entry needs to allocated and data copied into it from
|
706
|
+
the main dict. It is nicer to run through the array twice, first
|
707
|
+
copying all the elements in the main array (less probability of
|
708
|
+
allocate) and then the rest, so we only free in the second loop.
|
709
|
+
*/
|
710
|
+
for (i = 0; i < oldsize; i++) {
|
711
|
+
if (olddict[i].valid == 0)
|
712
|
+
continue;
|
713
|
+
|
714
|
+
if (keep_keys)
|
715
|
+
okey = olddict[i].okey;
|
716
|
+
else
|
717
|
+
okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
|
718
|
+
key = okey % dict->size;
|
719
|
+
|
720
|
+
if (dict->dict[key].valid == 0) {
|
721
|
+
memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
|
722
|
+
dict->dict[key].next = NULL;
|
723
|
+
dict->dict[key].okey = okey;
|
724
|
+
} else {
|
725
|
+
xmlDictEntryPtr entry;
|
726
|
+
|
727
|
+
entry = xmlMalloc(sizeof(xmlDictEntry));
|
728
|
+
if (entry != NULL) {
|
729
|
+
entry->name = olddict[i].name;
|
730
|
+
entry->len = olddict[i].len;
|
731
|
+
entry->okey = okey;
|
732
|
+
entry->next = dict->dict[key].next;
|
733
|
+
entry->valid = 1;
|
734
|
+
dict->dict[key].next = entry;
|
735
|
+
} else {
|
736
|
+
/*
|
737
|
+
* we don't have much ways to alert from here
|
738
|
+
* result is losing an entry and unicity guarantee
|
739
|
+
*/
|
740
|
+
ret = -1;
|
741
|
+
}
|
742
|
+
}
|
743
|
+
#ifdef DEBUG_GROW
|
744
|
+
nbElem++;
|
745
|
+
#endif
|
746
|
+
}
|
747
|
+
|
748
|
+
for (i = 0; i < oldsize; i++) {
|
749
|
+
iter = olddict[i].next;
|
750
|
+
while (iter) {
|
751
|
+
next = iter->next;
|
752
|
+
|
753
|
+
/*
|
754
|
+
* put back the entry in the new dict
|
755
|
+
*/
|
756
|
+
|
757
|
+
if (keep_keys)
|
758
|
+
okey = iter->okey;
|
759
|
+
else
|
760
|
+
okey = xmlDictComputeKey(dict, iter->name, iter->len);
|
761
|
+
key = okey % dict->size;
|
762
|
+
if (dict->dict[key].valid == 0) {
|
763
|
+
memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
|
764
|
+
dict->dict[key].next = NULL;
|
765
|
+
dict->dict[key].valid = 1;
|
766
|
+
dict->dict[key].okey = okey;
|
767
|
+
xmlFree(iter);
|
768
|
+
} else {
|
769
|
+
iter->next = dict->dict[key].next;
|
770
|
+
iter->okey = okey;
|
771
|
+
dict->dict[key].next = iter;
|
772
|
+
}
|
773
|
+
|
774
|
+
#ifdef DEBUG_GROW
|
775
|
+
nbElem++;
|
776
|
+
#endif
|
777
|
+
|
778
|
+
iter = next;
|
779
|
+
}
|
780
|
+
}
|
781
|
+
|
782
|
+
xmlFree(olddict);
|
783
|
+
|
784
|
+
#ifdef DEBUG_GROW
|
785
|
+
xmlGenericError(xmlGenericErrorContext,
|
786
|
+
"xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
|
787
|
+
#endif
|
788
|
+
|
789
|
+
return(ret);
|
790
|
+
}
|
791
|
+
|
792
|
+
/**
|
793
|
+
* xmlDictFree:
|
794
|
+
* @dict: the dictionary
|
795
|
+
*
|
796
|
+
* Free the hash @dict and its contents. The userdata is
|
797
|
+
* deallocated with @f if provided.
|
798
|
+
*/
|
799
|
+
void
|
800
|
+
xmlDictFree(xmlDictPtr dict) {
|
801
|
+
size_t i;
|
802
|
+
xmlDictEntryPtr iter;
|
803
|
+
xmlDictEntryPtr next;
|
804
|
+
int inside_dict = 0;
|
805
|
+
xmlDictStringsPtr pool, nextp;
|
806
|
+
|
807
|
+
if (dict == NULL)
|
808
|
+
return;
|
809
|
+
|
810
|
+
if (!xmlDictInitialized)
|
811
|
+
if (!__xmlInitializeDict())
|
812
|
+
return;
|
813
|
+
|
814
|
+
/* decrement the counter, it may be shared by a parser and docs */
|
815
|
+
xmlRMutexLock(xmlDictMutex);
|
816
|
+
dict->ref_counter--;
|
817
|
+
if (dict->ref_counter > 0) {
|
818
|
+
xmlRMutexUnlock(xmlDictMutex);
|
819
|
+
return;
|
820
|
+
}
|
821
|
+
|
822
|
+
xmlRMutexUnlock(xmlDictMutex);
|
823
|
+
|
824
|
+
if (dict->subdict != NULL) {
|
825
|
+
xmlDictFree(dict->subdict);
|
826
|
+
}
|
827
|
+
|
828
|
+
if (dict->dict) {
|
829
|
+
for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
|
830
|
+
iter = &(dict->dict[i]);
|
831
|
+
if (iter->valid == 0)
|
832
|
+
continue;
|
833
|
+
inside_dict = 1;
|
834
|
+
while (iter) {
|
835
|
+
next = iter->next;
|
836
|
+
if (!inside_dict)
|
837
|
+
xmlFree(iter);
|
838
|
+
dict->nbElems--;
|
839
|
+
inside_dict = 0;
|
840
|
+
iter = next;
|
841
|
+
}
|
842
|
+
}
|
843
|
+
xmlFree(dict->dict);
|
844
|
+
}
|
845
|
+
pool = dict->strings;
|
846
|
+
while (pool != NULL) {
|
847
|
+
nextp = pool->next;
|
848
|
+
xmlFree(pool);
|
849
|
+
pool = nextp;
|
850
|
+
}
|
851
|
+
xmlFree(dict);
|
852
|
+
}
|
853
|
+
|
854
|
+
/**
|
855
|
+
* xmlDictLookup:
|
856
|
+
* @dict: the dictionary
|
857
|
+
* @name: the name of the userdata
|
858
|
+
* @len: the length of the name, if -1 it is recomputed
|
859
|
+
*
|
860
|
+
* Add the @name to the dictionary @dict if not present.
|
861
|
+
*
|
862
|
+
* Returns the internal copy of the name or NULL in case of internal error
|
863
|
+
*/
|
864
|
+
const xmlChar *
|
865
|
+
xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
|
866
|
+
unsigned long key, okey, nbi = 0;
|
867
|
+
xmlDictEntryPtr entry;
|
868
|
+
xmlDictEntryPtr insert;
|
869
|
+
const xmlChar *ret;
|
870
|
+
unsigned int l;
|
871
|
+
|
872
|
+
if ((dict == NULL) || (name == NULL))
|
873
|
+
return(NULL);
|
874
|
+
|
875
|
+
if (len < 0)
|
876
|
+
l = strlen((const char *) name);
|
877
|
+
else
|
878
|
+
l = len;
|
879
|
+
|
880
|
+
if (((dict->limit > 0) && (l >= dict->limit)) ||
|
881
|
+
(l > INT_MAX / 2))
|
882
|
+
return(NULL);
|
883
|
+
|
884
|
+
/*
|
885
|
+
* Check for duplicate and insertion location.
|
886
|
+
*/
|
887
|
+
okey = xmlDictComputeKey(dict, name, l);
|
888
|
+
key = okey % dict->size;
|
889
|
+
if (dict->dict[key].valid == 0) {
|
890
|
+
insert = NULL;
|
891
|
+
} else {
|
892
|
+
for (insert = &(dict->dict[key]); insert->next != NULL;
|
893
|
+
insert = insert->next) {
|
894
|
+
#ifdef __GNUC__
|
895
|
+
if ((insert->okey == okey) && (insert->len == l)) {
|
896
|
+
if (!memcmp(insert->name, name, l))
|
897
|
+
return(insert->name);
|
898
|
+
}
|
899
|
+
#else
|
900
|
+
if ((insert->okey == okey) && (insert->len == l) &&
|
901
|
+
(!xmlStrncmp(insert->name, name, l)))
|
902
|
+
return(insert->name);
|
903
|
+
#endif
|
904
|
+
nbi++;
|
905
|
+
}
|
906
|
+
#ifdef __GNUC__
|
907
|
+
if ((insert->okey == okey) && (insert->len == l)) {
|
908
|
+
if (!memcmp(insert->name, name, l))
|
909
|
+
return(insert->name);
|
910
|
+
}
|
911
|
+
#else
|
912
|
+
if ((insert->okey == okey) && (insert->len == l) &&
|
913
|
+
(!xmlStrncmp(insert->name, name, l)))
|
914
|
+
return(insert->name);
|
915
|
+
#endif
|
916
|
+
}
|
917
|
+
|
918
|
+
if (dict->subdict) {
|
919
|
+
unsigned long skey;
|
920
|
+
|
921
|
+
/* we cannot always reuse the same okey for the subdict */
|
922
|
+
if (((dict->size == MIN_DICT_SIZE) &&
|
923
|
+
(dict->subdict->size != MIN_DICT_SIZE)) ||
|
924
|
+
((dict->size != MIN_DICT_SIZE) &&
|
925
|
+
(dict->subdict->size == MIN_DICT_SIZE)))
|
926
|
+
skey = xmlDictComputeKey(dict->subdict, name, l);
|
927
|
+
else
|
928
|
+
skey = okey;
|
929
|
+
|
930
|
+
key = skey % dict->subdict->size;
|
931
|
+
if (dict->subdict->dict[key].valid != 0) {
|
932
|
+
xmlDictEntryPtr tmp;
|
933
|
+
|
934
|
+
for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
|
935
|
+
tmp = tmp->next) {
|
936
|
+
#ifdef __GNUC__
|
937
|
+
if ((tmp->okey == skey) && (tmp->len == l)) {
|
938
|
+
if (!memcmp(tmp->name, name, l))
|
939
|
+
return(tmp->name);
|
940
|
+
}
|
941
|
+
#else
|
942
|
+
if ((tmp->okey == skey) && (tmp->len == l) &&
|
943
|
+
(!xmlStrncmp(tmp->name, name, l)))
|
944
|
+
return(tmp->name);
|
945
|
+
#endif
|
946
|
+
nbi++;
|
947
|
+
}
|
948
|
+
#ifdef __GNUC__
|
949
|
+
if ((tmp->okey == skey) && (tmp->len == l)) {
|
950
|
+
if (!memcmp(tmp->name, name, l))
|
951
|
+
return(tmp->name);
|
952
|
+
}
|
953
|
+
#else
|
954
|
+
if ((tmp->okey == skey) && (tmp->len == l) &&
|
955
|
+
(!xmlStrncmp(tmp->name, name, l)))
|
956
|
+
return(tmp->name);
|
957
|
+
#endif
|
958
|
+
}
|
959
|
+
key = okey % dict->size;
|
960
|
+
}
|
961
|
+
|
962
|
+
ret = xmlDictAddString(dict, name, l);
|
963
|
+
if (ret == NULL)
|
964
|
+
return(NULL);
|
965
|
+
if (insert == NULL) {
|
966
|
+
entry = &(dict->dict[key]);
|
967
|
+
} else {
|
968
|
+
entry = xmlMalloc(sizeof(xmlDictEntry));
|
969
|
+
if (entry == NULL)
|
970
|
+
return(NULL);
|
971
|
+
}
|
972
|
+
entry->name = ret;
|
973
|
+
entry->len = l;
|
974
|
+
entry->next = NULL;
|
975
|
+
entry->valid = 1;
|
976
|
+
entry->okey = okey;
|
977
|
+
|
978
|
+
|
979
|
+
if (insert != NULL)
|
980
|
+
insert->next = entry;
|
981
|
+
|
982
|
+
dict->nbElems++;
|
983
|
+
|
984
|
+
if ((nbi > MAX_HASH_LEN) &&
|
985
|
+
(dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
|
986
|
+
if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
|
987
|
+
return(NULL);
|
988
|
+
}
|
989
|
+
/* Note that entry may have been freed at this point by xmlDictGrow */
|
990
|
+
|
991
|
+
return(ret);
|
992
|
+
}
|
993
|
+
|
994
|
+
/**
|
995
|
+
* xmlDictExists:
|
996
|
+
* @dict: the dictionary
|
997
|
+
* @name: the name of the userdata
|
998
|
+
* @len: the length of the name, if -1 it is recomputed
|
999
|
+
*
|
1000
|
+
* Check if the @name exists in the dictionary @dict.
|
1001
|
+
*
|
1002
|
+
* Returns the internal copy of the name or NULL if not found.
|
1003
|
+
*/
|
1004
|
+
const xmlChar *
|
1005
|
+
xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
|
1006
|
+
unsigned long key, okey, nbi = 0;
|
1007
|
+
xmlDictEntryPtr insert;
|
1008
|
+
unsigned int l;
|
1009
|
+
|
1010
|
+
if ((dict == NULL) || (name == NULL))
|
1011
|
+
return(NULL);
|
1012
|
+
|
1013
|
+
if (len < 0)
|
1014
|
+
l = strlen((const char *) name);
|
1015
|
+
else
|
1016
|
+
l = len;
|
1017
|
+
if (((dict->limit > 0) && (l >= dict->limit)) ||
|
1018
|
+
(l > INT_MAX / 2))
|
1019
|
+
return(NULL);
|
1020
|
+
|
1021
|
+
/*
|
1022
|
+
* Check for duplicate and insertion location.
|
1023
|
+
*/
|
1024
|
+
okey = xmlDictComputeKey(dict, name, l);
|
1025
|
+
key = okey % dict->size;
|
1026
|
+
if (dict->dict[key].valid == 0) {
|
1027
|
+
insert = NULL;
|
1028
|
+
} else {
|
1029
|
+
for (insert = &(dict->dict[key]); insert->next != NULL;
|
1030
|
+
insert = insert->next) {
|
1031
|
+
#ifdef __GNUC__
|
1032
|
+
if ((insert->okey == okey) && (insert->len == l)) {
|
1033
|
+
if (!memcmp(insert->name, name, l))
|
1034
|
+
return(insert->name);
|
1035
|
+
}
|
1036
|
+
#else
|
1037
|
+
if ((insert->okey == okey) && (insert->len == l) &&
|
1038
|
+
(!xmlStrncmp(insert->name, name, l)))
|
1039
|
+
return(insert->name);
|
1040
|
+
#endif
|
1041
|
+
nbi++;
|
1042
|
+
}
|
1043
|
+
#ifdef __GNUC__
|
1044
|
+
if ((insert->okey == okey) && (insert->len == l)) {
|
1045
|
+
if (!memcmp(insert->name, name, l))
|
1046
|
+
return(insert->name);
|
1047
|
+
}
|
1048
|
+
#else
|
1049
|
+
if ((insert->okey == okey) && (insert->len == l) &&
|
1050
|
+
(!xmlStrncmp(insert->name, name, l)))
|
1051
|
+
return(insert->name);
|
1052
|
+
#endif
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
if (dict->subdict) {
|
1056
|
+
unsigned long skey;
|
1057
|
+
|
1058
|
+
/* we cannot always reuse the same okey for the subdict */
|
1059
|
+
if (((dict->size == MIN_DICT_SIZE) &&
|
1060
|
+
(dict->subdict->size != MIN_DICT_SIZE)) ||
|
1061
|
+
((dict->size != MIN_DICT_SIZE) &&
|
1062
|
+
(dict->subdict->size == MIN_DICT_SIZE)))
|
1063
|
+
skey = xmlDictComputeKey(dict->subdict, name, l);
|
1064
|
+
else
|
1065
|
+
skey = okey;
|
1066
|
+
|
1067
|
+
key = skey % dict->subdict->size;
|
1068
|
+
if (dict->subdict->dict[key].valid != 0) {
|
1069
|
+
xmlDictEntryPtr tmp;
|
1070
|
+
|
1071
|
+
for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
|
1072
|
+
tmp = tmp->next) {
|
1073
|
+
#ifdef __GNUC__
|
1074
|
+
if ((tmp->okey == skey) && (tmp->len == l)) {
|
1075
|
+
if (!memcmp(tmp->name, name, l))
|
1076
|
+
return(tmp->name);
|
1077
|
+
}
|
1078
|
+
#else
|
1079
|
+
if ((tmp->okey == skey) && (tmp->len == l) &&
|
1080
|
+
(!xmlStrncmp(tmp->name, name, l)))
|
1081
|
+
return(tmp->name);
|
1082
|
+
#endif
|
1083
|
+
nbi++;
|
1084
|
+
}
|
1085
|
+
#ifdef __GNUC__
|
1086
|
+
if ((tmp->okey == skey) && (tmp->len == l)) {
|
1087
|
+
if (!memcmp(tmp->name, name, l))
|
1088
|
+
return(tmp->name);
|
1089
|
+
}
|
1090
|
+
#else
|
1091
|
+
if ((tmp->okey == skey) && (tmp->len == l) &&
|
1092
|
+
(!xmlStrncmp(tmp->name, name, l)))
|
1093
|
+
return(tmp->name);
|
1094
|
+
#endif
|
1095
|
+
}
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
/* not found */
|
1099
|
+
return(NULL);
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
/**
|
1103
|
+
* xmlDictQLookup:
|
1104
|
+
* @dict: the dictionary
|
1105
|
+
* @prefix: the prefix
|
1106
|
+
* @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
|
+
*/
|
1112
|
+
const xmlChar *
|
1113
|
+
xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
|
1114
|
+
unsigned long okey, key, nbi = 0;
|
1115
|
+
xmlDictEntryPtr entry;
|
1116
|
+
xmlDictEntryPtr insert;
|
1117
|
+
const xmlChar *ret;
|
1118
|
+
unsigned int len, plen, l;
|
1119
|
+
|
1120
|
+
if ((dict == NULL) || (name == NULL))
|
1121
|
+
return(NULL);
|
1122
|
+
if (prefix == NULL)
|
1123
|
+
return(xmlDictLookup(dict, name, -1));
|
1124
|
+
|
1125
|
+
l = len = strlen((const char *) name);
|
1126
|
+
plen = strlen((const char *) prefix);
|
1127
|
+
len += 1 + plen;
|
1128
|
+
|
1129
|
+
/*
|
1130
|
+
* Check for duplicate and insertion location.
|
1131
|
+
*/
|
1132
|
+
okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
|
1133
|
+
key = okey % dict->size;
|
1134
|
+
if (dict->dict[key].valid == 0) {
|
1135
|
+
insert = NULL;
|
1136
|
+
} else {
|
1137
|
+
for (insert = &(dict->dict[key]); insert->next != NULL;
|
1138
|
+
insert = insert->next) {
|
1139
|
+
if ((insert->okey == okey) && (insert->len == len) &&
|
1140
|
+
(xmlStrQEqual(prefix, name, insert->name)))
|
1141
|
+
return(insert->name);
|
1142
|
+
nbi++;
|
1143
|
+
}
|
1144
|
+
if ((insert->okey == okey) && (insert->len == len) &&
|
1145
|
+
(xmlStrQEqual(prefix, name, insert->name)))
|
1146
|
+
return(insert->name);
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
if (dict->subdict) {
|
1150
|
+
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)))
|
1157
|
+
skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
|
1158
|
+
else
|
1159
|
+
skey = okey;
|
1160
|
+
|
1161
|
+
key = skey % dict->subdict->size;
|
1162
|
+
if (dict->subdict->dict[key].valid != 0) {
|
1163
|
+
xmlDictEntryPtr tmp;
|
1164
|
+
for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
|
1165
|
+
tmp = tmp->next) {
|
1166
|
+
if ((tmp->okey == skey) && (tmp->len == len) &&
|
1167
|
+
(xmlStrQEqual(prefix, name, tmp->name)))
|
1168
|
+
return(tmp->name);
|
1169
|
+
nbi++;
|
1170
|
+
}
|
1171
|
+
if ((tmp->okey == skey) && (tmp->len == len) &&
|
1172
|
+
(xmlStrQEqual(prefix, name, tmp->name)))
|
1173
|
+
return(tmp->name);
|
1174
|
+
}
|
1175
|
+
key = okey % dict->size;
|
1176
|
+
}
|
1177
|
+
|
1178
|
+
ret = xmlDictAddQString(dict, prefix, plen, name, l);
|
1179
|
+
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;
|
1192
|
+
entry->okey = okey;
|
1193
|
+
|
1194
|
+
if (insert != NULL)
|
1195
|
+
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
|
+
/**
|
1208
|
+
* xmlDictOwns:
|
1209
|
+
* @dict: the dictionary
|
1210
|
+
* @str: the string
|
1211
|
+
*
|
1212
|
+
* check if a string is owned by the dictionary
|
1213
|
+
*
|
1214
|
+
* Returns 1 if true, 0 if false and -1 in case of error
|
1215
|
+
* -1 in case of error
|
1216
|
+
*/
|
1217
|
+
int
|
1218
|
+
xmlDictOwns(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) {
|
1225
|
+
if ((str >= &pool->array[0]) && (str <= pool->free))
|
1226
|
+
return(1);
|
1227
|
+
pool = pool->next;
|
1228
|
+
}
|
1229
|
+
if (dict->subdict)
|
1230
|
+
return(xmlDictOwns(dict->subdict, str));
|
1231
|
+
return(0);
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
/**
|
1235
|
+
* xmlDictSize:
|
1236
|
+
* @dict: the dictionary
|
1237
|
+
*
|
1238
|
+
* Query the number of elements installed in the hash @dict.
|
1239
|
+
*
|
1240
|
+
* Returns the number of elements in the dictionary or
|
1241
|
+
* -1 in case of error
|
1242
|
+
*/
|
1243
|
+
int
|
1244
|
+
xmlDictSize(xmlDictPtr dict) {
|
1245
|
+
if (dict == NULL)
|
1246
|
+
return(-1);
|
1247
|
+
if (dict->subdict)
|
1248
|
+
return(dict->nbElems + dict->subdict->nbElems);
|
1249
|
+
return(dict->nbElems);
|
1250
|
+
}
|
1251
|
+
|
1252
|
+
/**
|
1253
|
+
* xmlDictSetLimit:
|
1254
|
+
* @dict: the dictionary
|
1255
|
+
* @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
|
+
*/
|
1262
|
+
size_t
|
1263
|
+
xmlDictSetLimit(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:
|
1275
|
+
* @dict: the dictionary
|
1276
|
+
*
|
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
|
+
*/
|
1282
|
+
size_t
|
1283
|
+
xmlDictGetUsage(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
|
+
}
|
1296
|
+
|
1297
|
+
#define bottom_dict
|
1298
|
+
#include "elfgcchack.h"
|