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