xref: /aosp_15_r20/external/cronet/third_party/libxml/src/testdict.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
2*6777b538SAndroid Build Coastguard Worker #include <string.h>
3*6777b538SAndroid Build Coastguard Worker #include <libxml/parser.h>
4*6777b538SAndroid Build Coastguard Worker #include <libxml/dict.h>
5*6777b538SAndroid Build Coastguard Worker 
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker /**** dictionary tests ****/
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #ifdef __clang__
10*6777b538SAndroid Build Coastguard Worker   #if __clang_major__ >= 12
11*6777b538SAndroid Build Coastguard Worker     #define ATTRIBUTE_NO_SANITIZE_INTEGER \
12*6777b538SAndroid Build Coastguard Worker       __attribute__ ((no_sanitize("unsigned-integer-overflow"))) \
13*6777b538SAndroid Build Coastguard Worker       __attribute__ ((no_sanitize("unsigned-shift-base")))
14*6777b538SAndroid Build Coastguard Worker   #else
15*6777b538SAndroid Build Coastguard Worker     #define ATTRIBUTE_NO_SANITIZE_INTEGER \
16*6777b538SAndroid Build Coastguard Worker       __attribute__ ((no_sanitize("unsigned-integer-overflow")))
17*6777b538SAndroid Build Coastguard Worker   #endif
18*6777b538SAndroid Build Coastguard Worker #else
19*6777b538SAndroid Build Coastguard Worker   #define ATTRIBUTE_NO_SANITIZE_INTEGER
20*6777b538SAndroid Build Coastguard Worker #endif
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker /* #define WITH_PRINT */
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker static const char *seeds1[] = {
25*6777b538SAndroid Build Coastguard Worker    "a", "b", "c",
26*6777b538SAndroid Build Coastguard Worker    "d", "e", "f",
27*6777b538SAndroid Build Coastguard Worker    "g", "h", "i",
28*6777b538SAndroid Build Coastguard Worker    "j", "k", "l",
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker    NULL
31*6777b538SAndroid Build Coastguard Worker };
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker static const char *seeds2[] = {
34*6777b538SAndroid Build Coastguard Worker    "m", "n", "o",
35*6777b538SAndroid Build Coastguard Worker    "p", "q", "r",
36*6777b538SAndroid Build Coastguard Worker    "s", "t", "u",
37*6777b538SAndroid Build Coastguard Worker    "v", "w", "x",
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker    NULL
40*6777b538SAndroid Build Coastguard Worker };
41*6777b538SAndroid Build Coastguard Worker 
42*6777b538SAndroid Build Coastguard Worker #define NB_STRINGS_MAX 100000
43*6777b538SAndroid Build Coastguard Worker #define NB_STRINGS_NS  10000
44*6777b538SAndroid Build Coastguard Worker #define NB_STRINGS_PREFIX (NB_STRINGS_NS / 20)
45*6777b538SAndroid Build Coastguard Worker #define NB_STRINGS_MIN 10
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker static xmlChar **strings1;
48*6777b538SAndroid Build Coastguard Worker static xmlChar **strings2;
49*6777b538SAndroid Build Coastguard Worker static const xmlChar **test1;
50*6777b538SAndroid Build Coastguard Worker static const xmlChar **test2;
51*6777b538SAndroid Build Coastguard Worker static int nbErrors = 0;
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker static void
fill_string_pool(xmlChar ** strings,const char ** seeds)54*6777b538SAndroid Build Coastguard Worker fill_string_pool(xmlChar **strings, const char **seeds) {
55*6777b538SAndroid Build Coastguard Worker     int i, j, k;
56*6777b538SAndroid Build Coastguard Worker     int start_ns = NB_STRINGS_MAX - NB_STRINGS_NS;
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker     /*
59*6777b538SAndroid Build Coastguard Worker      * That's a bit nasty but the output is fine and it doesn't take hours
60*6777b538SAndroid Build Coastguard Worker      * there is a small but sufficient number of duplicates, and we have
61*6777b538SAndroid Build Coastguard Worker      * ":xxx" and full QNames in the last NB_STRINGS_NS values
62*6777b538SAndroid Build Coastguard Worker      */
63*6777b538SAndroid Build Coastguard Worker     for (i = 0; seeds[i] != NULL; i++) {
64*6777b538SAndroid Build Coastguard Worker         strings[i] = xmlStrdup((const xmlChar *) seeds[i]);
65*6777b538SAndroid Build Coastguard Worker 	if (strings[i] == NULL) {
66*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Out of memory while generating strings\n");
67*6777b538SAndroid Build Coastguard Worker 	    exit(1);
68*6777b538SAndroid Build Coastguard Worker 	}
69*6777b538SAndroid Build Coastguard Worker     }
70*6777b538SAndroid Build Coastguard Worker     for (j = 0, k = 0; i < start_ns; i++) {
71*6777b538SAndroid Build Coastguard Worker         strings[i] = xmlStrncatNew(strings[j], strings[k], -1);
72*6777b538SAndroid Build Coastguard Worker 	if (strings[i] == NULL) {
73*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Out of memory while generating strings\n");
74*6777b538SAndroid Build Coastguard Worker 	    exit(1);
75*6777b538SAndroid Build Coastguard Worker 	}
76*6777b538SAndroid Build Coastguard Worker         if (xmlStrlen(strings[i]) > 30) {
77*6777b538SAndroid Build Coastguard Worker             fprintf(stderr, "### %s %s\n", strings[start_ns+j], strings[k]);
78*6777b538SAndroid Build Coastguard Worker             abort();
79*6777b538SAndroid Build Coastguard Worker         }
80*6777b538SAndroid Build Coastguard Worker         j++;
81*6777b538SAndroid Build Coastguard Worker 	if (j >= 50) {
82*6777b538SAndroid Build Coastguard Worker 	    j = 0;
83*6777b538SAndroid Build Coastguard Worker 	    k++;
84*6777b538SAndroid Build Coastguard Worker 	}
85*6777b538SAndroid Build Coastguard Worker     }
86*6777b538SAndroid Build Coastguard Worker     for (j = 0, k = 0; (j < NB_STRINGS_PREFIX) && (i < NB_STRINGS_MAX);
87*6777b538SAndroid Build Coastguard Worker          i++, j++) {
88*6777b538SAndroid Build Coastguard Worker         strings[i] = xmlStrncatNew(strings[k], (const xmlChar *) ":", -1);
89*6777b538SAndroid Build Coastguard Worker 	if (strings[i] == NULL) {
90*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Out of memory while generating strings\n");
91*6777b538SAndroid Build Coastguard Worker 	    exit(1);
92*6777b538SAndroid Build Coastguard Worker 	}
93*6777b538SAndroid Build Coastguard Worker         k += 1;
94*6777b538SAndroid Build Coastguard Worker         if (k >= start_ns) k = 0;
95*6777b538SAndroid Build Coastguard Worker     }
96*6777b538SAndroid Build Coastguard Worker     for (j = 0, k = 0; i < NB_STRINGS_MAX; i++) {
97*6777b538SAndroid Build Coastguard Worker         strings[i] = xmlStrncatNew(strings[start_ns+j], strings[k], -1);
98*6777b538SAndroid Build Coastguard Worker 	if (strings[i] == NULL) {
99*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Out of memory while generating strings\n");
100*6777b538SAndroid Build Coastguard Worker 	    exit(1);
101*6777b538SAndroid Build Coastguard Worker 	}
102*6777b538SAndroid Build Coastguard Worker         j++;
103*6777b538SAndroid Build Coastguard Worker         if (j >= NB_STRINGS_PREFIX) j = 0;
104*6777b538SAndroid Build Coastguard Worker 	k += 5;
105*6777b538SAndroid Build Coastguard Worker         if (k >= start_ns) k = 0;
106*6777b538SAndroid Build Coastguard Worker     }
107*6777b538SAndroid Build Coastguard Worker }
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker #ifdef WITH_PRINT
print_strings(void)110*6777b538SAndroid Build Coastguard Worker static void print_strings(void) {
111*6777b538SAndroid Build Coastguard Worker     int i;
112*6777b538SAndroid Build Coastguard Worker 
113*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < NB_STRINGS_MAX;i++) {
114*6777b538SAndroid Build Coastguard Worker         printf("%s\n", strings1[i]);
115*6777b538SAndroid Build Coastguard Worker     }
116*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < NB_STRINGS_MAX;i++) {
117*6777b538SAndroid Build Coastguard Worker         printf("%s\n", strings2[i]);
118*6777b538SAndroid Build Coastguard Worker     }
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker #endif
121*6777b538SAndroid Build Coastguard Worker 
clean_strings(void)122*6777b538SAndroid Build Coastguard Worker static void clean_strings(void) {
123*6777b538SAndroid Build Coastguard Worker     int i;
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < NB_STRINGS_MAX; i++) {
126*6777b538SAndroid Build Coastguard Worker         if (strings1[i] != NULL) /* really should not happen */
127*6777b538SAndroid Build Coastguard Worker 	    xmlFree(strings1[i]);
128*6777b538SAndroid Build Coastguard Worker     }
129*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < NB_STRINGS_MAX; i++) {
130*6777b538SAndroid Build Coastguard Worker         if (strings2[i] != NULL) /* really should not happen */
131*6777b538SAndroid Build Coastguard Worker 	    xmlFree(strings2[i]);
132*6777b538SAndroid Build Coastguard Worker     }
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker /*
136*6777b538SAndroid Build Coastguard Worker  * This tests the sub-dictionary support
137*6777b538SAndroid Build Coastguard Worker  */
138*6777b538SAndroid Build Coastguard Worker static int
test_subdict(xmlDictPtr parent)139*6777b538SAndroid Build Coastguard Worker test_subdict(xmlDictPtr parent) {
140*6777b538SAndroid Build Coastguard Worker     int i, j;
141*6777b538SAndroid Build Coastguard Worker     xmlDictPtr dict;
142*6777b538SAndroid Build Coastguard Worker     int ret = 0;
143*6777b538SAndroid Build Coastguard Worker     xmlChar prefix[40];
144*6777b538SAndroid Build Coastguard Worker     xmlChar *cur, *pref;
145*6777b538SAndroid Build Coastguard Worker     const xmlChar *tmp;
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker     dict = xmlDictCreateSub(parent);
148*6777b538SAndroid Build Coastguard Worker     if (dict == NULL) {
149*6777b538SAndroid Build Coastguard Worker 	fprintf(stderr, "Out of memory while creating sub-dictionary\n");
150*6777b538SAndroid Build Coastguard Worker 	exit(1);
151*6777b538SAndroid Build Coastguard Worker     }
152*6777b538SAndroid Build Coastguard Worker     /* Cast to avoid buggy warning on MSVC. */
153*6777b538SAndroid Build Coastguard Worker     memset((void *) test2, 0, sizeof(test2));
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker     /*
156*6777b538SAndroid Build Coastguard Worker      * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow
157*6777b538SAndroid Build Coastguard Worker      * and we allocate all those doing the fast key computations
158*6777b538SAndroid Build Coastguard Worker      * All the strings are based on a different seeds subset so we know
159*6777b538SAndroid Build Coastguard Worker      * they are allocated in the main dictionary, not coming from the parent
160*6777b538SAndroid Build Coastguard Worker      */
161*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MIN;i++) {
162*6777b538SAndroid Build Coastguard Worker         test2[i] = xmlDictLookup(dict, strings2[i], -1);
163*6777b538SAndroid Build Coastguard Worker 	if (test2[i] == NULL) {
164*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]);
165*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
166*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
167*6777b538SAndroid Build Coastguard Worker 	}
168*6777b538SAndroid Build Coastguard Worker     }
169*6777b538SAndroid Build Coastguard Worker     j = NB_STRINGS_MAX - NB_STRINGS_NS;
170*6777b538SAndroid Build Coastguard Worker     /* ":foo" like strings2 */
171*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
172*6777b538SAndroid Build Coastguard Worker         test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j]));
173*6777b538SAndroid Build Coastguard Worker 	if (test2[j] == NULL) {
174*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]);
175*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
176*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
177*6777b538SAndroid Build Coastguard Worker 	}
178*6777b538SAndroid Build Coastguard Worker     }
179*6777b538SAndroid Build Coastguard Worker     /* "a:foo" like strings2 */
180*6777b538SAndroid Build Coastguard Worker     j = NB_STRINGS_MAX - NB_STRINGS_MIN;
181*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
182*6777b538SAndroid Build Coastguard Worker         test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j]));
183*6777b538SAndroid Build Coastguard Worker 	if (test2[j] == NULL) {
184*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]);
185*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
186*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
187*6777b538SAndroid Build Coastguard Worker 	}
188*6777b538SAndroid Build Coastguard Worker     }
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker     /*
191*6777b538SAndroid Build Coastguard Worker      * At this point allocate all the strings
192*6777b538SAndroid Build Coastguard Worker      * the dictionary will grow in the process, reallocate more string tables
193*6777b538SAndroid Build Coastguard Worker      * and switch to the better key generator
194*6777b538SAndroid Build Coastguard Worker      */
195*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
196*6777b538SAndroid Build Coastguard Worker         if (test2[i] != NULL)
197*6777b538SAndroid Build Coastguard Worker 	    continue;
198*6777b538SAndroid Build Coastguard Worker 	test2[i] = xmlDictLookup(dict, strings2[i], -1);
199*6777b538SAndroid Build Coastguard Worker 	if (test2[i] == NULL) {
200*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]);
201*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
202*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
203*6777b538SAndroid Build Coastguard Worker 	}
204*6777b538SAndroid Build Coastguard Worker     }
205*6777b538SAndroid Build Coastguard Worker 
206*6777b538SAndroid Build Coastguard Worker     /*
207*6777b538SAndroid Build Coastguard Worker      * Now we can start to test things, first that all strings2 belongs to
208*6777b538SAndroid Build Coastguard Worker      * the dict, and that none of them was actually allocated in the parent
209*6777b538SAndroid Build Coastguard Worker      */
210*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
211*6777b538SAndroid Build Coastguard Worker         if (!xmlDictOwns(dict, test2[i])) {
212*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed ownership failure for '%s'\n",
213*6777b538SAndroid Build Coastguard Worker 	            strings2[i]);
214*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
215*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
216*6777b538SAndroid Build Coastguard Worker 	}
217*6777b538SAndroid Build Coastguard Worker         if (xmlDictOwns(parent, test2[i])) {
218*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed parent ownership failure for '%s'\n",
219*6777b538SAndroid Build Coastguard Worker 	            strings2[i]);
220*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
221*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
222*6777b538SAndroid Build Coastguard Worker 	}
223*6777b538SAndroid Build Coastguard Worker     }
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker     /*
226*6777b538SAndroid Build Coastguard Worker      * Also verify that all strings from the parent are seen from the subdict
227*6777b538SAndroid Build Coastguard Worker      */
228*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
229*6777b538SAndroid Build Coastguard Worker         if (!xmlDictOwns(dict, test1[i])) {
230*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed sub-ownership failure for '%s'\n",
231*6777b538SAndroid Build Coastguard Worker 	            strings1[i]);
232*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
233*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
234*6777b538SAndroid Build Coastguard Worker 	}
235*6777b538SAndroid Build Coastguard Worker     }
236*6777b538SAndroid Build Coastguard Worker 
237*6777b538SAndroid Build Coastguard Worker     /*
238*6777b538SAndroid Build Coastguard Worker      * Then that another lookup to the string in sub will return the same
239*6777b538SAndroid Build Coastguard Worker      */
240*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
241*6777b538SAndroid Build Coastguard Worker         if (xmlDictLookup(dict, strings2[i], -1) != test2[i]) {
242*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed re-lookup check for %d, '%s'\n",
243*6777b538SAndroid Build Coastguard Worker 	            i, strings2[i]);
244*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
245*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
246*6777b538SAndroid Build Coastguard Worker 	}
247*6777b538SAndroid Build Coastguard Worker     }
248*6777b538SAndroid Build Coastguard Worker     /*
249*6777b538SAndroid Build Coastguard Worker      * But also that any lookup for a string in the parent will be provided
250*6777b538SAndroid Build Coastguard Worker      * as in the parent
251*6777b538SAndroid Build Coastguard Worker      */
252*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
253*6777b538SAndroid Build Coastguard Worker         if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) {
254*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed parent string lookup check for %d, '%s'\n",
255*6777b538SAndroid Build Coastguard Worker 	            i, strings1[i]);
256*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
257*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
258*6777b538SAndroid Build Coastguard Worker 	}
259*6777b538SAndroid Build Coastguard Worker     }
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker     /*
262*6777b538SAndroid Build Coastguard Worker      * check the QName lookups
263*6777b538SAndroid Build Coastguard Worker      */
264*6777b538SAndroid Build Coastguard Worker     for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
265*6777b538SAndroid Build Coastguard Worker         cur = strings2[i];
266*6777b538SAndroid Build Coastguard Worker 	pref = &prefix[0];
267*6777b538SAndroid Build Coastguard Worker 	while (*cur != ':') *pref++ = *cur++;
268*6777b538SAndroid Build Coastguard Worker 	cur++;
269*6777b538SAndroid Build Coastguard Worker 	*pref = 0;
270*6777b538SAndroid Build Coastguard Worker 	tmp = xmlDictQLookup(dict, &prefix[0], cur);
271*6777b538SAndroid Build Coastguard Worker 	if (tmp != test2[i]) {
272*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup check for '%s':'%s'\n",
273*6777b538SAndroid Build Coastguard Worker 	            &prefix[0], cur);
274*6777b538SAndroid Build Coastguard Worker             ret = 1;
275*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
276*6777b538SAndroid Build Coastguard Worker 	}
277*6777b538SAndroid Build Coastguard Worker     }
278*6777b538SAndroid Build Coastguard Worker     /*
279*6777b538SAndroid Build Coastguard Worker      * check the QName lookups for strings from the parent
280*6777b538SAndroid Build Coastguard Worker      */
281*6777b538SAndroid Build Coastguard Worker     for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
282*6777b538SAndroid Build Coastguard Worker         cur = strings1[i];
283*6777b538SAndroid Build Coastguard Worker 	pref = &prefix[0];
284*6777b538SAndroid Build Coastguard Worker 	while (*cur != ':') *pref++ = *cur++;
285*6777b538SAndroid Build Coastguard Worker 	cur++;
286*6777b538SAndroid Build Coastguard Worker 	*pref = 0;
287*6777b538SAndroid Build Coastguard Worker 	tmp = xmlDictQLookup(dict, &prefix[0], cur);
288*6777b538SAndroid Build Coastguard Worker 	if (xmlDictQLookup(dict, &prefix[0], cur) != test1[i]) {
289*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed parent lookup check for '%s':'%s'\n",
290*6777b538SAndroid Build Coastguard Worker 	            &prefix[0], cur);
291*6777b538SAndroid Build Coastguard Worker             ret = 1;
292*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
293*6777b538SAndroid Build Coastguard Worker 	}
294*6777b538SAndroid Build Coastguard Worker     }
295*6777b538SAndroid Build Coastguard Worker 
296*6777b538SAndroid Build Coastguard Worker     xmlDictFree(dict);
297*6777b538SAndroid Build Coastguard Worker     return(ret);
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker 
300*6777b538SAndroid Build Coastguard Worker /*
301*6777b538SAndroid Build Coastguard Worker  * Test a single dictionary
302*6777b538SAndroid Build Coastguard Worker  */
303*6777b538SAndroid Build Coastguard Worker static int
test_dict(xmlDict * dict)304*6777b538SAndroid Build Coastguard Worker test_dict(xmlDict *dict) {
305*6777b538SAndroid Build Coastguard Worker     int i, j;
306*6777b538SAndroid Build Coastguard Worker     int ret = 0;
307*6777b538SAndroid Build Coastguard Worker     xmlChar prefix[40];
308*6777b538SAndroid Build Coastguard Worker     xmlChar *cur, *pref;
309*6777b538SAndroid Build Coastguard Worker     const xmlChar *tmp;
310*6777b538SAndroid Build Coastguard Worker 
311*6777b538SAndroid Build Coastguard Worker     /* Cast to avoid buggy warning on MSVC. */
312*6777b538SAndroid Build Coastguard Worker     memset((void *) test1, 0, sizeof(test1));
313*6777b538SAndroid Build Coastguard Worker 
314*6777b538SAndroid Build Coastguard Worker     /*
315*6777b538SAndroid Build Coastguard Worker      * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow
316*6777b538SAndroid Build Coastguard Worker      * and we allocate all those doing the fast key computations
317*6777b538SAndroid Build Coastguard Worker      */
318*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MIN;i++) {
319*6777b538SAndroid Build Coastguard Worker         test1[i] = xmlDictLookup(dict, strings1[i], -1);
320*6777b538SAndroid Build Coastguard Worker 	if (test1[i] == NULL) {
321*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]);
322*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
323*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
324*6777b538SAndroid Build Coastguard Worker 	}
325*6777b538SAndroid Build Coastguard Worker     }
326*6777b538SAndroid Build Coastguard Worker     j = NB_STRINGS_MAX - NB_STRINGS_NS;
327*6777b538SAndroid Build Coastguard Worker     /* ":foo" like strings1 */
328*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
329*6777b538SAndroid Build Coastguard Worker         test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j]));
330*6777b538SAndroid Build Coastguard Worker 	if (test1[j] == NULL) {
331*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]);
332*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
333*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
334*6777b538SAndroid Build Coastguard Worker 	}
335*6777b538SAndroid Build Coastguard Worker     }
336*6777b538SAndroid Build Coastguard Worker     /* "a:foo" like strings1 */
337*6777b538SAndroid Build Coastguard Worker     j = NB_STRINGS_MAX - NB_STRINGS_MIN;
338*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
339*6777b538SAndroid Build Coastguard Worker         test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j]));
340*6777b538SAndroid Build Coastguard Worker 	if (test1[j] == NULL) {
341*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]);
342*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
343*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
344*6777b538SAndroid Build Coastguard Worker 	}
345*6777b538SAndroid Build Coastguard Worker     }
346*6777b538SAndroid Build Coastguard Worker 
347*6777b538SAndroid Build Coastguard Worker     /*
348*6777b538SAndroid Build Coastguard Worker      * At this point allocate all the strings
349*6777b538SAndroid Build Coastguard Worker      * the dictionary will grow in the process, reallocate more string tables
350*6777b538SAndroid Build Coastguard Worker      * and switch to the better key generator
351*6777b538SAndroid Build Coastguard Worker      */
352*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
353*6777b538SAndroid Build Coastguard Worker         if (test1[i] != NULL)
354*6777b538SAndroid Build Coastguard Worker 	    continue;
355*6777b538SAndroid Build Coastguard Worker 	test1[i] = xmlDictLookup(dict, strings1[i], -1);
356*6777b538SAndroid Build Coastguard Worker 	if (test1[i] == NULL) {
357*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]);
358*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
359*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
360*6777b538SAndroid Build Coastguard Worker 	}
361*6777b538SAndroid Build Coastguard Worker     }
362*6777b538SAndroid Build Coastguard Worker 
363*6777b538SAndroid Build Coastguard Worker     /*
364*6777b538SAndroid Build Coastguard Worker      * Now we can start to test things, first that all strings1 belongs to
365*6777b538SAndroid Build Coastguard Worker      * the dict
366*6777b538SAndroid Build Coastguard Worker      */
367*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
368*6777b538SAndroid Build Coastguard Worker         if (!xmlDictOwns(dict, test1[i])) {
369*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed ownership failure for '%s'\n",
370*6777b538SAndroid Build Coastguard Worker 	            strings1[i]);
371*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
372*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
373*6777b538SAndroid Build Coastguard Worker 	}
374*6777b538SAndroid Build Coastguard Worker     }
375*6777b538SAndroid Build Coastguard Worker 
376*6777b538SAndroid Build Coastguard Worker     /*
377*6777b538SAndroid Build Coastguard Worker      * Then that another lookup to the string will return the same
378*6777b538SAndroid Build Coastguard Worker      */
379*6777b538SAndroid Build Coastguard Worker     for (i = 0;i < NB_STRINGS_MAX;i++) {
380*6777b538SAndroid Build Coastguard Worker         if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) {
381*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed re-lookup check for %d, '%s'\n",
382*6777b538SAndroid Build Coastguard Worker 	            i, strings1[i]);
383*6777b538SAndroid Build Coastguard Worker 	    ret = 1;
384*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
385*6777b538SAndroid Build Coastguard Worker 	}
386*6777b538SAndroid Build Coastguard Worker     }
387*6777b538SAndroid Build Coastguard Worker 
388*6777b538SAndroid Build Coastguard Worker     /*
389*6777b538SAndroid Build Coastguard Worker      * More complex, check the QName lookups
390*6777b538SAndroid Build Coastguard Worker      */
391*6777b538SAndroid Build Coastguard Worker     for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
392*6777b538SAndroid Build Coastguard Worker         cur = strings1[i];
393*6777b538SAndroid Build Coastguard Worker 	pref = &prefix[0];
394*6777b538SAndroid Build Coastguard Worker 	while (*cur != ':') *pref++ = *cur++;
395*6777b538SAndroid Build Coastguard Worker 	cur++;
396*6777b538SAndroid Build Coastguard Worker 	*pref = 0;
397*6777b538SAndroid Build Coastguard Worker 	tmp = xmlDictQLookup(dict, &prefix[0], cur);
398*6777b538SAndroid Build Coastguard Worker 	if (tmp != test1[i]) {
399*6777b538SAndroid Build Coastguard Worker 	    fprintf(stderr, "Failed lookup check for '%s':'%s'\n",
400*6777b538SAndroid Build Coastguard Worker 	            &prefix[0], cur);
401*6777b538SAndroid Build Coastguard Worker             ret = 1;
402*6777b538SAndroid Build Coastguard Worker 	    nbErrors++;
403*6777b538SAndroid Build Coastguard Worker 	}
404*6777b538SAndroid Build Coastguard Worker     }
405*6777b538SAndroid Build Coastguard Worker 
406*6777b538SAndroid Build Coastguard Worker     return(ret);
407*6777b538SAndroid Build Coastguard Worker }
408*6777b538SAndroid Build Coastguard Worker 
409*6777b538SAndroid Build Coastguard Worker static int
testall_dict(void)410*6777b538SAndroid Build Coastguard Worker testall_dict(void) {
411*6777b538SAndroid Build Coastguard Worker     xmlDictPtr dict;
412*6777b538SAndroid Build Coastguard Worker     int ret = 0;
413*6777b538SAndroid Build Coastguard Worker 
414*6777b538SAndroid Build Coastguard Worker     strings1 = xmlMalloc(NB_STRINGS_MAX * sizeof(strings1[0]));
415*6777b538SAndroid Build Coastguard Worker     memset(strings1, 0, NB_STRINGS_MAX * sizeof(strings1[0]));
416*6777b538SAndroid Build Coastguard Worker     strings2 = xmlMalloc(NB_STRINGS_MAX * sizeof(strings2[0]));
417*6777b538SAndroid Build Coastguard Worker     memset(strings2, 0, NB_STRINGS_MAX * sizeof(strings2[0]));
418*6777b538SAndroid Build Coastguard Worker     test1 = xmlMalloc(NB_STRINGS_MAX * sizeof(test1[0]));
419*6777b538SAndroid Build Coastguard Worker     memset(test1, 0, NB_STRINGS_MAX * sizeof(test1[0]));
420*6777b538SAndroid Build Coastguard Worker     test2 = xmlMalloc(NB_STRINGS_MAX * sizeof(test2[0]));
421*6777b538SAndroid Build Coastguard Worker     memset(test2, 0, NB_STRINGS_MAX * sizeof(test2[0]));
422*6777b538SAndroid Build Coastguard Worker 
423*6777b538SAndroid Build Coastguard Worker     fill_string_pool(strings1, seeds1);
424*6777b538SAndroid Build Coastguard Worker     fill_string_pool(strings2, seeds2);
425*6777b538SAndroid Build Coastguard Worker #ifdef WITH_PRINT
426*6777b538SAndroid Build Coastguard Worker     print_strings();
427*6777b538SAndroid Build Coastguard Worker #endif
428*6777b538SAndroid Build Coastguard Worker 
429*6777b538SAndroid Build Coastguard Worker     dict = xmlDictCreate();
430*6777b538SAndroid Build Coastguard Worker     if (dict == NULL) {
431*6777b538SAndroid Build Coastguard Worker 	fprintf(stderr, "Out of memory while creating dictionary\n");
432*6777b538SAndroid Build Coastguard Worker 	exit(1);
433*6777b538SAndroid Build Coastguard Worker     }
434*6777b538SAndroid Build Coastguard Worker     if (test_dict(dict) != 0) {
435*6777b538SAndroid Build Coastguard Worker         ret = 1;
436*6777b538SAndroid Build Coastguard Worker     }
437*6777b538SAndroid Build Coastguard Worker     if (test_subdict(dict) != 0) {
438*6777b538SAndroid Build Coastguard Worker         ret = 1;
439*6777b538SAndroid Build Coastguard Worker     }
440*6777b538SAndroid Build Coastguard Worker     xmlDictFree(dict);
441*6777b538SAndroid Build Coastguard Worker 
442*6777b538SAndroid Build Coastguard Worker     clean_strings();
443*6777b538SAndroid Build Coastguard Worker     xmlFree(strings1);
444*6777b538SAndroid Build Coastguard Worker     xmlFree(strings2);
445*6777b538SAndroid Build Coastguard Worker     xmlFree(test1);
446*6777b538SAndroid Build Coastguard Worker     xmlFree(test2);
447*6777b538SAndroid Build Coastguard Worker 
448*6777b538SAndroid Build Coastguard Worker     return ret;
449*6777b538SAndroid Build Coastguard Worker }
450*6777b538SAndroid Build Coastguard Worker 
451*6777b538SAndroid Build Coastguard Worker 
452*6777b538SAndroid Build Coastguard Worker /**** Hash table tests ****/
453*6777b538SAndroid Build Coastguard Worker 
454*6777b538SAndroid Build Coastguard Worker static unsigned
455*6777b538SAndroid Build Coastguard Worker rng_state[2] = { 123, 456 };
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker #define HASH_ROL(x,n) ((x) << (n) | ((x) & 0xFFFFFFFF) >> (32 - (n)))
458*6777b538SAndroid Build Coastguard Worker 
459*6777b538SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
460*6777b538SAndroid Build Coastguard Worker static unsigned
my_rand(unsigned max)461*6777b538SAndroid Build Coastguard Worker my_rand(unsigned max) {
462*6777b538SAndroid Build Coastguard Worker     unsigned s0 = rng_state[0];
463*6777b538SAndroid Build Coastguard Worker     unsigned s1 = rng_state[1];
464*6777b538SAndroid Build Coastguard Worker     unsigned result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5;
465*6777b538SAndroid Build Coastguard Worker 
466*6777b538SAndroid Build Coastguard Worker     s1 ^= s0;
467*6777b538SAndroid Build Coastguard Worker     rng_state[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9);
468*6777b538SAndroid Build Coastguard Worker     rng_state[1] = HASH_ROL(s1, 13);
469*6777b538SAndroid Build Coastguard Worker 
470*6777b538SAndroid Build Coastguard Worker     return((result & 0xFFFFFFFF) % max);
471*6777b538SAndroid Build Coastguard Worker }
472*6777b538SAndroid Build Coastguard Worker 
473*6777b538SAndroid Build Coastguard Worker static xmlChar *
gen_random_string(xmlChar id)474*6777b538SAndroid Build Coastguard Worker gen_random_string(xmlChar id) {
475*6777b538SAndroid Build Coastguard Worker     unsigned size = my_rand(64) + 1;
476*6777b538SAndroid Build Coastguard Worker     unsigned id_pos = my_rand(size);
477*6777b538SAndroid Build Coastguard Worker     size_t j;
478*6777b538SAndroid Build Coastguard Worker 
479*6777b538SAndroid Build Coastguard Worker     xmlChar *str = xmlMalloc(size + 1);
480*6777b538SAndroid Build Coastguard Worker     for (j = 0; j < size; j++) {
481*6777b538SAndroid Build Coastguard Worker         str[j] = 'a' + my_rand(26);
482*6777b538SAndroid Build Coastguard Worker     }
483*6777b538SAndroid Build Coastguard Worker     str[id_pos] = id;
484*6777b538SAndroid Build Coastguard Worker     str[size] = 0;
485*6777b538SAndroid Build Coastguard Worker 
486*6777b538SAndroid Build Coastguard Worker     /* Generate QName in 75% of cases */
487*6777b538SAndroid Build Coastguard Worker     if (size > 3 && my_rand(4) > 0) {
488*6777b538SAndroid Build Coastguard Worker         unsigned colon_pos = my_rand(size - 3) + 1;
489*6777b538SAndroid Build Coastguard Worker 
490*6777b538SAndroid Build Coastguard Worker         if (colon_pos >= id_pos)
491*6777b538SAndroid Build Coastguard Worker             colon_pos++;
492*6777b538SAndroid Build Coastguard Worker         str[colon_pos] = ':';
493*6777b538SAndroid Build Coastguard Worker     }
494*6777b538SAndroid Build Coastguard Worker 
495*6777b538SAndroid Build Coastguard Worker     return str;
496*6777b538SAndroid Build Coastguard Worker }
497*6777b538SAndroid Build Coastguard Worker 
498*6777b538SAndroid Build Coastguard Worker typedef struct {
499*6777b538SAndroid Build Coastguard Worker     xmlChar **strings;
500*6777b538SAndroid Build Coastguard Worker     size_t num_entries;
501*6777b538SAndroid Build Coastguard Worker     size_t num_keys;
502*6777b538SAndroid Build Coastguard Worker     size_t num_strings;
503*6777b538SAndroid Build Coastguard Worker     size_t index;
504*6777b538SAndroid Build Coastguard Worker     xmlChar id;
505*6777b538SAndroid Build Coastguard Worker } StringPool;
506*6777b538SAndroid Build Coastguard Worker 
507*6777b538SAndroid Build Coastguard Worker static StringPool *
pool_new(size_t num_entries,size_t num_keys,xmlChar id)508*6777b538SAndroid Build Coastguard Worker pool_new(size_t num_entries, size_t num_keys, xmlChar id) {
509*6777b538SAndroid Build Coastguard Worker     StringPool *ret;
510*6777b538SAndroid Build Coastguard Worker     size_t num_strings;
511*6777b538SAndroid Build Coastguard Worker 
512*6777b538SAndroid Build Coastguard Worker     ret = xmlMalloc(sizeof(*ret));
513*6777b538SAndroid Build Coastguard Worker     ret->num_entries = num_entries;
514*6777b538SAndroid Build Coastguard Worker     ret->num_keys = num_keys;
515*6777b538SAndroid Build Coastguard Worker     num_strings = num_entries * num_keys;
516*6777b538SAndroid Build Coastguard Worker     ret->strings = xmlMalloc(num_strings * sizeof(ret->strings[0]));
517*6777b538SAndroid Build Coastguard Worker     memset(ret->strings, 0, num_strings * sizeof(ret->strings[0]));
518*6777b538SAndroid Build Coastguard Worker     ret->num_strings = num_strings;
519*6777b538SAndroid Build Coastguard Worker     ret->index = 0;
520*6777b538SAndroid Build Coastguard Worker     ret->id = id;
521*6777b538SAndroid Build Coastguard Worker 
522*6777b538SAndroid Build Coastguard Worker     return ret;
523*6777b538SAndroid Build Coastguard Worker }
524*6777b538SAndroid Build Coastguard Worker 
525*6777b538SAndroid Build Coastguard Worker static void
pool_free(StringPool * pool)526*6777b538SAndroid Build Coastguard Worker pool_free(StringPool *pool) {
527*6777b538SAndroid Build Coastguard Worker     size_t i;
528*6777b538SAndroid Build Coastguard Worker 
529*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < pool->num_strings; i++) {
530*6777b538SAndroid Build Coastguard Worker         xmlFree(pool->strings[i]);
531*6777b538SAndroid Build Coastguard Worker     }
532*6777b538SAndroid Build Coastguard Worker     xmlFree(pool->strings);
533*6777b538SAndroid Build Coastguard Worker     xmlFree(pool);
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker 
536*6777b538SAndroid Build Coastguard Worker static int
pool_done(StringPool * pool)537*6777b538SAndroid Build Coastguard Worker pool_done(StringPool *pool) {
538*6777b538SAndroid Build Coastguard Worker     return pool->index >= pool->num_strings;
539*6777b538SAndroid Build Coastguard Worker }
540*6777b538SAndroid Build Coastguard Worker 
541*6777b538SAndroid Build Coastguard Worker static void
pool_reset(StringPool * pool)542*6777b538SAndroid Build Coastguard Worker pool_reset(StringPool *pool) {
543*6777b538SAndroid Build Coastguard Worker     pool->index = 0;
544*6777b538SAndroid Build Coastguard Worker }
545*6777b538SAndroid Build Coastguard Worker 
546*6777b538SAndroid Build Coastguard Worker static int
pool_bulk_insert(StringPool * pool,xmlHashTablePtr hash,size_t num)547*6777b538SAndroid Build Coastguard Worker pool_bulk_insert(StringPool *pool, xmlHashTablePtr hash, size_t num) {
548*6777b538SAndroid Build Coastguard Worker     size_t i, j;
549*6777b538SAndroid Build Coastguard Worker     int ret = 0;
550*6777b538SAndroid Build Coastguard Worker 
551*6777b538SAndroid Build Coastguard Worker     for (i = pool->index, j = 0; i < pool->num_strings && j < num; j++) {
552*6777b538SAndroid Build Coastguard Worker         xmlChar *str[3];
553*6777b538SAndroid Build Coastguard Worker         size_t k;
554*6777b538SAndroid Build Coastguard Worker 
555*6777b538SAndroid Build Coastguard Worker         while (1) {
556*6777b538SAndroid Build Coastguard Worker             xmlChar tmp_key[1];
557*6777b538SAndroid Build Coastguard Worker             int res;
558*6777b538SAndroid Build Coastguard Worker 
559*6777b538SAndroid Build Coastguard Worker             for (k = 0; k < pool->num_keys; k++)
560*6777b538SAndroid Build Coastguard Worker                 str[k] = gen_random_string(pool->id);
561*6777b538SAndroid Build Coastguard Worker 
562*6777b538SAndroid Build Coastguard Worker             switch (pool->num_keys) {
563*6777b538SAndroid Build Coastguard Worker                 case 1:
564*6777b538SAndroid Build Coastguard Worker                     res = xmlHashAddEntry(hash, str[0], tmp_key);
565*6777b538SAndroid Build Coastguard Worker                     if (res == 0 &&
566*6777b538SAndroid Build Coastguard Worker                         xmlHashUpdateEntry(hash, str[0], str[0], NULL) != 0)
567*6777b538SAndroid Build Coastguard Worker                         ret = -1;
568*6777b538SAndroid Build Coastguard Worker                     break;
569*6777b538SAndroid Build Coastguard Worker                 case 2:
570*6777b538SAndroid Build Coastguard Worker                     res = xmlHashAddEntry2(hash, str[0], str[1], tmp_key);
571*6777b538SAndroid Build Coastguard Worker                     if (res == 0 &&
572*6777b538SAndroid Build Coastguard Worker                         xmlHashUpdateEntry2(hash, str[0], str[1], str[0],
573*6777b538SAndroid Build Coastguard Worker                                             NULL) != 0)
574*6777b538SAndroid Build Coastguard Worker                         ret = -1;
575*6777b538SAndroid Build Coastguard Worker                     break;
576*6777b538SAndroid Build Coastguard Worker                 case 3:
577*6777b538SAndroid Build Coastguard Worker                     res = xmlHashAddEntry3(hash, str[0], str[1], str[2],
578*6777b538SAndroid Build Coastguard Worker                                            tmp_key);
579*6777b538SAndroid Build Coastguard Worker                     if (res == 0 &&
580*6777b538SAndroid Build Coastguard Worker                         xmlHashUpdateEntry3(hash, str[0], str[1], str[2],
581*6777b538SAndroid Build Coastguard Worker                                             str[0], NULL) != 0)
582*6777b538SAndroid Build Coastguard Worker                         ret = -1;
583*6777b538SAndroid Build Coastguard Worker                     break;
584*6777b538SAndroid Build Coastguard Worker             }
585*6777b538SAndroid Build Coastguard Worker 
586*6777b538SAndroid Build Coastguard Worker             if (res == 0)
587*6777b538SAndroid Build Coastguard Worker                 break;
588*6777b538SAndroid Build Coastguard Worker             for (k = 0; k < pool->num_keys; k++)
589*6777b538SAndroid Build Coastguard Worker                 xmlFree(str[k]);
590*6777b538SAndroid Build Coastguard Worker         }
591*6777b538SAndroid Build Coastguard Worker 
592*6777b538SAndroid Build Coastguard Worker         for (k = 0; k < pool->num_keys; k++)
593*6777b538SAndroid Build Coastguard Worker             pool->strings[i++] = str[k];
594*6777b538SAndroid Build Coastguard Worker     }
595*6777b538SAndroid Build Coastguard Worker 
596*6777b538SAndroid Build Coastguard Worker     pool->index = i;
597*6777b538SAndroid Build Coastguard Worker     return ret;
598*6777b538SAndroid Build Coastguard Worker }
599*6777b538SAndroid Build Coastguard Worker 
600*6777b538SAndroid Build Coastguard Worker static xmlChar *
hash_qlookup(xmlHashTable * hash,xmlChar ** names,size_t num_keys)601*6777b538SAndroid Build Coastguard Worker hash_qlookup(xmlHashTable *hash, xmlChar **names, size_t num_keys) {
602*6777b538SAndroid Build Coastguard Worker     xmlChar *prefix[3];
603*6777b538SAndroid Build Coastguard Worker     const xmlChar *local[3];
604*6777b538SAndroid Build Coastguard Worker     xmlChar *res;
605*6777b538SAndroid Build Coastguard Worker     size_t i;
606*6777b538SAndroid Build Coastguard Worker 
607*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < 3; ++i) {
608*6777b538SAndroid Build Coastguard Worker         if (i >= num_keys) {
609*6777b538SAndroid Build Coastguard Worker             prefix[i] = NULL;
610*6777b538SAndroid Build Coastguard Worker             local[i] = NULL;
611*6777b538SAndroid Build Coastguard Worker         } else {
612*6777b538SAndroid Build Coastguard Worker             const xmlChar *name = names[i];
613*6777b538SAndroid Build Coastguard Worker             const xmlChar *colon = BAD_CAST strchr((const char *) name, ':');
614*6777b538SAndroid Build Coastguard Worker 
615*6777b538SAndroid Build Coastguard Worker             if (colon == NULL) {
616*6777b538SAndroid Build Coastguard Worker                 prefix[i] = NULL;
617*6777b538SAndroid Build Coastguard Worker                 local[i] = name;
618*6777b538SAndroid Build Coastguard Worker             } else {
619*6777b538SAndroid Build Coastguard Worker                 prefix[i] = xmlStrndup(name, colon - name);
620*6777b538SAndroid Build Coastguard Worker                 local[i] = &colon[1];
621*6777b538SAndroid Build Coastguard Worker             }
622*6777b538SAndroid Build Coastguard Worker         }
623*6777b538SAndroid Build Coastguard Worker     }
624*6777b538SAndroid Build Coastguard Worker 
625*6777b538SAndroid Build Coastguard Worker     res = xmlHashQLookup3(hash, prefix[0], local[0], prefix[1], local[1],
626*6777b538SAndroid Build Coastguard Worker                           prefix[2], local[2]);
627*6777b538SAndroid Build Coastguard Worker 
628*6777b538SAndroid Build Coastguard Worker     for (i = 0; i < 3; ++i)
629*6777b538SAndroid Build Coastguard Worker         xmlFree(prefix[i]);
630*6777b538SAndroid Build Coastguard Worker 
631*6777b538SAndroid Build Coastguard Worker     return res;
632*6777b538SAndroid Build Coastguard Worker }
633*6777b538SAndroid Build Coastguard Worker 
634*6777b538SAndroid Build Coastguard Worker static int
pool_bulk_lookup(StringPool * pool,xmlHashTablePtr hash,size_t num,int existing)635*6777b538SAndroid Build Coastguard Worker pool_bulk_lookup(StringPool *pool, xmlHashTablePtr hash, size_t num,
636*6777b538SAndroid Build Coastguard Worker                  int existing) {
637*6777b538SAndroid Build Coastguard Worker     size_t i, j;
638*6777b538SAndroid Build Coastguard Worker     int ret = 0;
639*6777b538SAndroid Build Coastguard Worker 
640*6777b538SAndroid Build Coastguard Worker     for (i = pool->index, j = 0; i < pool->num_strings && j < num; j++) {
641*6777b538SAndroid Build Coastguard Worker         xmlChar **str = &pool->strings[i];
642*6777b538SAndroid Build Coastguard Worker         int q;
643*6777b538SAndroid Build Coastguard Worker 
644*6777b538SAndroid Build Coastguard Worker         for (q = 0; q < 2; q++) {
645*6777b538SAndroid Build Coastguard Worker             xmlChar *res = NULL;
646*6777b538SAndroid Build Coastguard Worker 
647*6777b538SAndroid Build Coastguard Worker             if (q) {
648*6777b538SAndroid Build Coastguard Worker                 res = hash_qlookup(hash, str, pool->num_keys);
649*6777b538SAndroid Build Coastguard Worker             } else {
650*6777b538SAndroid Build Coastguard Worker                 switch (pool->num_keys) {
651*6777b538SAndroid Build Coastguard Worker                     case 1:
652*6777b538SAndroid Build Coastguard Worker                         res = xmlHashLookup(hash, str[0]);
653*6777b538SAndroid Build Coastguard Worker                         break;
654*6777b538SAndroid Build Coastguard Worker                     case 2:
655*6777b538SAndroid Build Coastguard Worker                         res = xmlHashLookup2(hash, str[0], str[1]);
656*6777b538SAndroid Build Coastguard Worker                         break;
657*6777b538SAndroid Build Coastguard Worker                     case 3:
658*6777b538SAndroid Build Coastguard Worker                         res = xmlHashLookup3(hash, str[0], str[1], str[2]);
659*6777b538SAndroid Build Coastguard Worker                         break;
660*6777b538SAndroid Build Coastguard Worker                 }
661*6777b538SAndroid Build Coastguard Worker             }
662*6777b538SAndroid Build Coastguard Worker 
663*6777b538SAndroid Build Coastguard Worker             if (existing) {
664*6777b538SAndroid Build Coastguard Worker                 if (res != str[0])
665*6777b538SAndroid Build Coastguard Worker                     ret = -1;
666*6777b538SAndroid Build Coastguard Worker             } else {
667*6777b538SAndroid Build Coastguard Worker                 if (res != NULL)
668*6777b538SAndroid Build Coastguard Worker                     ret = -1;
669*6777b538SAndroid Build Coastguard Worker             }
670*6777b538SAndroid Build Coastguard Worker         }
671*6777b538SAndroid Build Coastguard Worker 
672*6777b538SAndroid Build Coastguard Worker         i += pool->num_keys;
673*6777b538SAndroid Build Coastguard Worker     }
674*6777b538SAndroid Build Coastguard Worker 
675*6777b538SAndroid Build Coastguard Worker     pool->index = i;
676*6777b538SAndroid Build Coastguard Worker     return ret;
677*6777b538SAndroid Build Coastguard Worker }
678*6777b538SAndroid Build Coastguard Worker 
679*6777b538SAndroid Build Coastguard Worker static int
pool_bulk_remove(StringPool * pool,xmlHashTablePtr hash,size_t num)680*6777b538SAndroid Build Coastguard Worker pool_bulk_remove(StringPool *pool, xmlHashTablePtr hash, size_t num) {
681*6777b538SAndroid Build Coastguard Worker     size_t i, j;
682*6777b538SAndroid Build Coastguard Worker     int ret = 0;
683*6777b538SAndroid Build Coastguard Worker 
684*6777b538SAndroid Build Coastguard Worker     for (i = pool->index, j = 0; i < pool->num_strings && j < num; j++) {
685*6777b538SAndroid Build Coastguard Worker         xmlChar **str = &pool->strings[i];
686*6777b538SAndroid Build Coastguard Worker         int res = -1;
687*6777b538SAndroid Build Coastguard Worker 
688*6777b538SAndroid Build Coastguard Worker         switch (pool->num_keys) {
689*6777b538SAndroid Build Coastguard Worker             case 1:
690*6777b538SAndroid Build Coastguard Worker                 res = xmlHashRemoveEntry(hash, str[0], NULL);
691*6777b538SAndroid Build Coastguard Worker                 break;
692*6777b538SAndroid Build Coastguard Worker             case 2:
693*6777b538SAndroid Build Coastguard Worker                 res = xmlHashRemoveEntry2(hash, str[0], str[1], NULL);
694*6777b538SAndroid Build Coastguard Worker                 break;
695*6777b538SAndroid Build Coastguard Worker             case 3:
696*6777b538SAndroid Build Coastguard Worker                 res = xmlHashRemoveEntry3(hash, str[0], str[1], str[2], NULL);
697*6777b538SAndroid Build Coastguard Worker                 break;
698*6777b538SAndroid Build Coastguard Worker         }
699*6777b538SAndroid Build Coastguard Worker 
700*6777b538SAndroid Build Coastguard Worker         if (res != 0)
701*6777b538SAndroid Build Coastguard Worker             ret = -1;
702*6777b538SAndroid Build Coastguard Worker 
703*6777b538SAndroid Build Coastguard Worker         i += pool->num_keys;
704*6777b538SAndroid Build Coastguard Worker     }
705*6777b538SAndroid Build Coastguard Worker 
706*6777b538SAndroid Build Coastguard Worker     pool->index = i;
707*6777b538SAndroid Build Coastguard Worker     return ret;
708*6777b538SAndroid Build Coastguard Worker }
709*6777b538SAndroid Build Coastguard Worker 
710*6777b538SAndroid Build Coastguard Worker static int
test_hash(size_t num_entries,size_t num_keys,int use_dict)711*6777b538SAndroid Build Coastguard Worker test_hash(size_t num_entries, size_t num_keys, int use_dict) {
712*6777b538SAndroid Build Coastguard Worker     xmlDict *dict = NULL;
713*6777b538SAndroid Build Coastguard Worker     xmlHashTable *hash;
714*6777b538SAndroid Build Coastguard Worker     StringPool *pool1, *pool2;
715*6777b538SAndroid Build Coastguard Worker     int ret = 0;
716*6777b538SAndroid Build Coastguard Worker 
717*6777b538SAndroid Build Coastguard Worker     if (use_dict) {
718*6777b538SAndroid Build Coastguard Worker         dict = xmlDictCreate();
719*6777b538SAndroid Build Coastguard Worker         hash = xmlHashCreateDict(0, dict);
720*6777b538SAndroid Build Coastguard Worker     } else {
721*6777b538SAndroid Build Coastguard Worker         hash = xmlHashCreate(0);
722*6777b538SAndroid Build Coastguard Worker     }
723*6777b538SAndroid Build Coastguard Worker     pool1 = pool_new(num_entries, num_keys, '1');
724*6777b538SAndroid Build Coastguard Worker     pool2 = pool_new(num_entries, num_keys, '2');
725*6777b538SAndroid Build Coastguard Worker 
726*6777b538SAndroid Build Coastguard Worker     /* Insert all strings from pool2 and about half of pool1. */
727*6777b538SAndroid Build Coastguard Worker     while (!pool_done(pool2)) {
728*6777b538SAndroid Build Coastguard Worker         if (pool_bulk_insert(pool1, hash, my_rand(50)) != 0) {
729*6777b538SAndroid Build Coastguard Worker             fprintf(stderr, "pool1: hash insert failed\n");
730*6777b538SAndroid Build Coastguard Worker             ret = 1;
731*6777b538SAndroid Build Coastguard Worker         }
732*6777b538SAndroid Build Coastguard Worker         if (pool_bulk_insert(pool2, hash, my_rand(100)) != 0) {
733*6777b538SAndroid Build Coastguard Worker             fprintf(stderr, "pool1: hash insert failed\n");
734*6777b538SAndroid Build Coastguard Worker             ret = 1;
735*6777b538SAndroid Build Coastguard Worker         }
736*6777b538SAndroid Build Coastguard Worker     }
737*6777b538SAndroid Build Coastguard Worker 
738*6777b538SAndroid Build Coastguard Worker     /* Check existing entries */
739*6777b538SAndroid Build Coastguard Worker     pool_reset(pool2);
740*6777b538SAndroid Build Coastguard Worker     if (pool_bulk_lookup(pool2, hash, pool2->num_entries, 1) != 0) {
741*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "pool2: hash lookup failed\n");
742*6777b538SAndroid Build Coastguard Worker         ret = 1;
743*6777b538SAndroid Build Coastguard Worker     }
744*6777b538SAndroid Build Coastguard Worker 
745*6777b538SAndroid Build Coastguard Worker     /* Remove all strings from pool2 and insert the rest of pool1. */
746*6777b538SAndroid Build Coastguard Worker     pool_reset(pool2);
747*6777b538SAndroid Build Coastguard Worker     while (!pool_done(pool1) || !pool_done(pool2)) {
748*6777b538SAndroid Build Coastguard Worker         if (pool_bulk_insert(pool1, hash, my_rand(50)) != 0) {
749*6777b538SAndroid Build Coastguard Worker             fprintf(stderr, "pool1: hash insert failed\n");
750*6777b538SAndroid Build Coastguard Worker             ret = 1;
751*6777b538SAndroid Build Coastguard Worker         }
752*6777b538SAndroid Build Coastguard Worker         if (pool_bulk_remove(pool2, hash, my_rand(100)) != 0) {
753*6777b538SAndroid Build Coastguard Worker             fprintf(stderr, "pool2: hash remove failed\n");
754*6777b538SAndroid Build Coastguard Worker             ret = 1;
755*6777b538SAndroid Build Coastguard Worker         }
756*6777b538SAndroid Build Coastguard Worker     }
757*6777b538SAndroid Build Coastguard Worker 
758*6777b538SAndroid Build Coastguard Worker     /* Check existing entries */
759*6777b538SAndroid Build Coastguard Worker     pool_reset(pool1);
760*6777b538SAndroid Build Coastguard Worker     if (pool_bulk_lookup(pool1, hash, pool1->num_entries, 1) != 0) {
761*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "pool1: hash lookup failed\n");
762*6777b538SAndroid Build Coastguard Worker         ret = 1;
763*6777b538SAndroid Build Coastguard Worker     }
764*6777b538SAndroid Build Coastguard Worker 
765*6777b538SAndroid Build Coastguard Worker     /* Check removed entries */
766*6777b538SAndroid Build Coastguard Worker     pool_reset(pool2);
767*6777b538SAndroid Build Coastguard Worker     if (pool_bulk_lookup(pool2, hash, pool2->num_entries, 0) != 0) {
768*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "pool2: hash lookup succeeded unexpectedly\n");
769*6777b538SAndroid Build Coastguard Worker         ret = 1;
770*6777b538SAndroid Build Coastguard Worker     }
771*6777b538SAndroid Build Coastguard Worker 
772*6777b538SAndroid Build Coastguard Worker     pool_free(pool1);
773*6777b538SAndroid Build Coastguard Worker     pool_free(pool2);
774*6777b538SAndroid Build Coastguard Worker     xmlHashFree(hash, NULL);
775*6777b538SAndroid Build Coastguard Worker     xmlDictFree(dict);
776*6777b538SAndroid Build Coastguard Worker 
777*6777b538SAndroid Build Coastguard Worker     return ret;
778*6777b538SAndroid Build Coastguard Worker }
779*6777b538SAndroid Build Coastguard Worker 
780*6777b538SAndroid Build Coastguard Worker static int
testall_hash(void)781*6777b538SAndroid Build Coastguard Worker testall_hash(void) {
782*6777b538SAndroid Build Coastguard Worker     size_t num_keys;
783*6777b538SAndroid Build Coastguard Worker 
784*6777b538SAndroid Build Coastguard Worker     for (num_keys = 1; num_keys <= 3; num_keys++) {
785*6777b538SAndroid Build Coastguard Worker         size_t num_strings;
786*6777b538SAndroid Build Coastguard Worker         size_t max_strings = num_keys == 1 ? 100000 : 1000;
787*6777b538SAndroid Build Coastguard Worker 
788*6777b538SAndroid Build Coastguard Worker         for (num_strings = 10; num_strings <= max_strings; num_strings *= 10) {
789*6777b538SAndroid Build Coastguard Worker             size_t reps, i;
790*6777b538SAndroid Build Coastguard Worker 
791*6777b538SAndroid Build Coastguard Worker             reps = 1000 / num_strings;
792*6777b538SAndroid Build Coastguard Worker             if (reps == 0)
793*6777b538SAndroid Build Coastguard Worker                 reps = 1;
794*6777b538SAndroid Build Coastguard Worker 
795*6777b538SAndroid Build Coastguard Worker             for (i = 0; i < reps; i++) {
796*6777b538SAndroid Build Coastguard Worker                 if (test_hash(num_strings, num_keys, /* use_dict */ 0) != 0)
797*6777b538SAndroid Build Coastguard Worker                     return(1);
798*6777b538SAndroid Build Coastguard Worker             }
799*6777b538SAndroid Build Coastguard Worker 
800*6777b538SAndroid Build Coastguard Worker             if (test_hash(num_strings, num_keys, /* use_dict */ 1) != 0)
801*6777b538SAndroid Build Coastguard Worker                 return(1);
802*6777b538SAndroid Build Coastguard Worker         }
803*6777b538SAndroid Build Coastguard Worker     }
804*6777b538SAndroid Build Coastguard Worker 
805*6777b538SAndroid Build Coastguard Worker     return(0);
806*6777b538SAndroid Build Coastguard Worker }
807*6777b538SAndroid Build Coastguard Worker 
808*6777b538SAndroid Build Coastguard Worker 
809*6777b538SAndroid Build Coastguard Worker /**** main ****/
810*6777b538SAndroid Build Coastguard Worker 
811*6777b538SAndroid Build Coastguard Worker int
main(void)812*6777b538SAndroid Build Coastguard Worker main(void) {
813*6777b538SAndroid Build Coastguard Worker     int ret = 0;
814*6777b538SAndroid Build Coastguard Worker 
815*6777b538SAndroid Build Coastguard Worker     LIBXML_TEST_VERSION
816*6777b538SAndroid Build Coastguard Worker 
817*6777b538SAndroid Build Coastguard Worker     if (testall_dict() != 0) {
818*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "dictionary tests failed\n");
819*6777b538SAndroid Build Coastguard Worker         ret = 1;
820*6777b538SAndroid Build Coastguard Worker     }
821*6777b538SAndroid Build Coastguard Worker     if (testall_hash() != 0) {
822*6777b538SAndroid Build Coastguard Worker         fprintf(stderr, "hash tests failed\n");
823*6777b538SAndroid Build Coastguard Worker         ret = 1;
824*6777b538SAndroid Build Coastguard Worker     }
825*6777b538SAndroid Build Coastguard Worker 
826*6777b538SAndroid Build Coastguard Worker     xmlCleanupParser();
827*6777b538SAndroid Build Coastguard Worker     return(ret);
828*6777b538SAndroid Build Coastguard Worker }
829