• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * dict.c: dictionary of reusable strings, just used to avoid allocation
3  *         and freeing operations.
4  *
5  * Copyright (C) 2003 Daniel Veillard.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15  *
16  * Author: daniel@veillard.com
17  */
18 
19 #define IN_LIBXML
20 #include "libxml.h"
21 
22 #include <string.h>
23 #ifdef HAVE_STDINT_H
24 #include <stdint.h>
25 #else
26 #ifdef HAVE_INTTYPES_H
27 #include <inttypes.h>
28 #elif defined(WIN32)
29 typedef unsigned __int32 uint32_t;
30 #endif
31 #endif
32 #include <libxml/tree.h>
33 #include <libxml/dict.h>
34 #include <libxml/xmlmemory.h>
35 #include <libxml/xmlerror.h>
36 #include <libxml/globals.h>
37 
38 /* #define DEBUG_GROW */
39 /* #define DICT_DEBUG_PATTERNS */
40 
41 #define MAX_HASH_LEN 3
42 #define MIN_DICT_SIZE 128
43 #define MAX_DICT_HASH 8 * 2048
44 #define WITH_BIG_KEY
45 
46 #ifdef WITH_BIG_KEY
47 #define xmlDictComputeKey(dict, name, len)			\
48     (((dict)->size == MIN_DICT_SIZE) ?				\
49      xmlDictComputeFastKey(name, len) :				\
50      xmlDictComputeBigKey(name, len))
51 
52 #define xmlDictComputeQKey(dict, prefix, plen, name, len)	\
53     (((prefix) == NULL) ?					\
54       (xmlDictComputeKey(dict, name, len)) :			\
55       (((dict)->size == MIN_DICT_SIZE) ?			\
56        xmlDictComputeFastQKey(prefix, plen, name, len) :	\
57        xmlDictComputeBigQKey(prefix, plen, name, len)))
58 
59 #else /* !WITH_BIG_KEY */
60 #define xmlDictComputeKey(dict, name, len)			\
61         xmlDictComputeFastKey(name, len)
62 #define xmlDictComputeQKey(dict, prefix, plen, name, len)	\
63         xmlDictComputeFastQKey(prefix, plen, name, len)
64 #endif /* WITH_BIG_KEY */
65 
66 /*
67  * An entry in the dictionnary
68  */
69 typedef struct _xmlDictEntry xmlDictEntry;
70 typedef xmlDictEntry *xmlDictEntryPtr;
71 struct _xmlDictEntry {
72     struct _xmlDictEntry *next;
73     const xmlChar *name;
74     int len;
75     int valid;
76     unsigned long okey;
77 };
78 
79 typedef struct _xmlDictStrings xmlDictStrings;
80 typedef xmlDictStrings *xmlDictStringsPtr;
81 struct _xmlDictStrings {
82     xmlDictStringsPtr next;
83     xmlChar *free;
84     xmlChar *end;
85     int size;
86     int nbStrings;
87     xmlChar array[1];
88 };
89 /*
90  * The entire dictionnary
91  */
92 struct _xmlDict {
93     int ref_counter;
94 
95     struct _xmlDictEntry *dict;
96     int size;
97     int nbElems;
98     xmlDictStringsPtr strings;
99 
100     struct _xmlDict *subdict;
101 };
102 
103 /*
104  * A mutex for modifying the reference counter for shared
105  * dictionaries.
106  */
107 static xmlRMutexPtr xmlDictMutex = NULL;
108 
109 /*
110  * Whether the dictionary mutex was initialized.
111  */
112 static int xmlDictInitialized = 0;
113 
114 /**
115  * xmlInitializeDict:
116  *
117  * Do the dictionary mutex initialization.
118  * this function is not thread safe, initialization should
119  * preferably be done once at startup
120  */
xmlInitializeDict(void)121 static int xmlInitializeDict(void) {
122     if (xmlDictInitialized)
123         return(1);
124 
125     if ((xmlDictMutex = xmlNewRMutex()) == NULL)
126         return(0);
127 
128     xmlDictInitialized = 1;
129     return(1);
130 }
131 
132 /**
133  * xmlDictCleanup:
134  *
135  * Free the dictionary mutex.
136  */
137 void
xmlDictCleanup(void)138 xmlDictCleanup(void) {
139     if (!xmlDictInitialized)
140         return;
141 
142     xmlFreeRMutex(xmlDictMutex);
143 
144     xmlDictInitialized = 0;
145 }
146 
147 /*
148  * xmlDictAddString:
149  * @dict: the dictionnary
150  * @name: the name of the userdata
151  * @len: the length of the name, if -1 it is recomputed
152  *
153  * Add the string to the array[s]
154  *
155  * Returns the pointer of the local string, or NULL in case of error.
156  */
157 static const xmlChar *
xmlDictAddString(xmlDictPtr dict,const xmlChar * name,int namelen)158 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
159     xmlDictStringsPtr pool;
160     const xmlChar *ret;
161     int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
162 
163 #ifdef DICT_DEBUG_PATTERNS
164     fprintf(stderr, "-");
165 #endif
166     pool = dict->strings;
167     while (pool != NULL) {
168 	if (pool->end - pool->free > namelen)
169 	    goto found_pool;
170 	if (pool->size > size) size = pool->size;
171 	pool = pool->next;
172     }
173     /*
174      * Not found, need to allocate
175      */
176     if (pool == NULL) {
177         if (size == 0) size = 1000;
178 	else size *= 4; /* exponential growth */
179         if (size < 4 * namelen)
180 	    size = 4 * namelen; /* just in case ! */
181 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
182 	if (pool == NULL)
183 	    return(NULL);
184 	pool->size = size;
185 	pool->nbStrings = 0;
186 	pool->free = &pool->array[0];
187 	pool->end = &pool->array[size];
188 	pool->next = dict->strings;
189 	dict->strings = pool;
190 #ifdef DICT_DEBUG_PATTERNS
191         fprintf(stderr, "+");
192 #endif
193     }
194 found_pool:
195     ret = pool->free;
196     memcpy(pool->free, name, namelen);
197     pool->free += namelen;
198     *(pool->free++) = 0;
199     pool->nbStrings++;
200     return(ret);
201 }
202 
203 /*
204  * xmlDictAddQString:
205  * @dict: the dictionnary
206  * @prefix: the prefix of the userdata
207  * @plen: the prefix length
208  * @name: the name of the userdata
209  * @len: the length of the name, if -1 it is recomputed
210  *
211  * Add the QName to the array[s]
212  *
213  * Returns the pointer of the local string, or NULL in case of error.
214  */
215 static const xmlChar *
xmlDictAddQString(xmlDictPtr dict,const xmlChar * prefix,int plen,const xmlChar * name,int namelen)216 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
217                  const xmlChar *name, int namelen)
218 {
219     xmlDictStringsPtr pool;
220     const xmlChar *ret;
221     int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
222 
223     if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
224 
225 #ifdef DICT_DEBUG_PATTERNS
226     fprintf(stderr, "=");
227 #endif
228     pool = dict->strings;
229     while (pool != NULL) {
230 	if (pool->end - pool->free > namelen + plen + 1)
231 	    goto found_pool;
232 	if (pool->size > size) size = pool->size;
233 	pool = pool->next;
234     }
235     /*
236      * Not found, need to allocate
237      */
238     if (pool == NULL) {
239         if (size == 0) size = 1000;
240 	else size *= 4; /* exponential growth */
241         if (size < 4 * (namelen + plen + 1))
242 	    size = 4 * (namelen + plen + 1); /* just in case ! */
243 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
244 	if (pool == NULL)
245 	    return(NULL);
246 	pool->size = size;
247 	pool->nbStrings = 0;
248 	pool->free = &pool->array[0];
249 	pool->end = &pool->array[size];
250 	pool->next = dict->strings;
251 	dict->strings = pool;
252 #ifdef DICT_DEBUG_PATTERNS
253         fprintf(stderr, "+");
254 #endif
255     }
256 found_pool:
257     ret = pool->free;
258     memcpy(pool->free, prefix, plen);
259     pool->free += plen;
260     *(pool->free++) = ':';
261     memcpy(pool->free, name, namelen);
262     pool->free += namelen;
263     *(pool->free++) = 0;
264     pool->nbStrings++;
265     return(ret);
266 }
267 
268 #ifdef WITH_BIG_KEY
269 /*
270  * xmlDictComputeBigKey:
271  *
272  * Calculate a hash key using a good hash function that works well for
273  * larger hash table sizes.
274  *
275  * Hash function by "One-at-a-Time Hash" see
276  * http://burtleburtle.net/bob/hash/doobs.html
277  */
278 
279 static uint32_t
xmlDictComputeBigKey(const xmlChar * data,int namelen)280 xmlDictComputeBigKey(const xmlChar* data, int namelen) {
281     uint32_t hash;
282     int i;
283 
284     if (namelen <= 0 || data == NULL) return(0);
285 
286     hash = 0;
287 
288     for (i = 0;i < namelen; i++) {
289         hash += data[i];
290 	hash += (hash << 10);
291 	hash ^= (hash >> 6);
292     }
293     hash += (hash << 3);
294     hash ^= (hash >> 11);
295     hash += (hash << 15);
296 
297     return hash;
298 }
299 
300 /*
301  * xmlDictComputeBigQKey:
302  *
303  * Calculate a hash key for two strings using a good hash function
304  * that works well for larger hash table sizes.
305  *
306  * Hash function by "One-at-a-Time Hash" see
307  * http://burtleburtle.net/bob/hash/doobs.html
308  *
309  * Neither of the two strings must be NULL.
310  */
311 static unsigned long
xmlDictComputeBigQKey(const xmlChar * prefix,int plen,const xmlChar * name,int len)312 xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
313                       const xmlChar *name, int len)
314 {
315     uint32_t hash;
316     int i;
317 
318     hash = 0;
319 
320     for (i = 0;i < plen; i++) {
321         hash += prefix[i];
322 	hash += (hash << 10);
323 	hash ^= (hash >> 6);
324     }
325     hash += ':';
326     hash += (hash << 10);
327     hash ^= (hash >> 6);
328 
329     for (i = 0;i < len; i++) {
330         hash += name[i];
331 	hash += (hash << 10);
332 	hash ^= (hash >> 6);
333     }
334     hash += (hash << 3);
335     hash ^= (hash >> 11);
336     hash += (hash << 15);
337 
338     return hash;
339 }
340 #endif /* WITH_BIG_KEY */
341 
342 /*
343  * xmlDictComputeFastKey:
344  *
345  * Calculate a hash key using a fast hash function that works well
346  * for low hash table fill.
347  */
348 static unsigned long
xmlDictComputeFastKey(const xmlChar * name,int namelen)349 xmlDictComputeFastKey(const xmlChar *name, int namelen) {
350     unsigned long value = 0L;
351 
352     if (name == NULL) return(0);
353     value = *name;
354     value <<= 5;
355     if (namelen > 10) {
356         value += name[namelen - 1];
357         namelen = 10;
358     }
359     switch (namelen) {
360         case 10: value += name[9];
361         case 9: value += name[8];
362         case 8: value += name[7];
363         case 7: value += name[6];
364         case 6: value += name[5];
365         case 5: value += name[4];
366         case 4: value += name[3];
367         case 3: value += name[2];
368         case 2: value += name[1];
369         default: break;
370     }
371     return(value);
372 }
373 
374 /*
375  * xmlDictComputeFastQKey:
376  *
377  * Calculate a hash key for two strings using a fast hash function
378  * that works well for low hash table fill.
379  *
380  * Neither of the two strings must be NULL.
381  */
382 static unsigned long
xmlDictComputeFastQKey(const xmlChar * prefix,int plen,const xmlChar * name,int len)383 xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
384                        const xmlChar *name, int len)
385 {
386     unsigned long value = 0L;
387 
388     if (plen == 0)
389 	value += 30 * (unsigned long) ':';
390     else
391 	value += 30 * (*prefix);
392 
393     if (len > 10) {
394         value += name[len - (plen + 1 + 1)];
395         len = 10;
396 	if (plen > 10)
397 	    plen = 10;
398     }
399     switch (plen) {
400         case 10: value += prefix[9];
401         case 9: value += prefix[8];
402         case 8: value += prefix[7];
403         case 7: value += prefix[6];
404         case 6: value += prefix[5];
405         case 5: value += prefix[4];
406         case 4: value += prefix[3];
407         case 3: value += prefix[2];
408         case 2: value += prefix[1];
409         case 1: value += prefix[0];
410         default: break;
411     }
412     len -= plen;
413     if (len > 0) {
414         value += (unsigned long) ':';
415 	len--;
416     }
417     switch (len) {
418         case 10: value += name[9];
419         case 9: value += name[8];
420         case 8: value += name[7];
421         case 7: value += name[6];
422         case 6: value += name[5];
423         case 5: value += name[4];
424         case 4: value += name[3];
425         case 3: value += name[2];
426         case 2: value += name[1];
427         case 1: value += name[0];
428         default: break;
429     }
430     return(value);
431 }
432 
433 /**
434  * xmlDictCreate:
435  *
436  * Create a new dictionary
437  *
438  * Returns the newly created dictionnary, or NULL if an error occured.
439  */
440 xmlDictPtr
xmlDictCreate(void)441 xmlDictCreate(void) {
442     xmlDictPtr dict;
443 
444     if (!xmlDictInitialized)
445         if (!xmlInitializeDict())
446             return(NULL);
447 
448 #ifdef DICT_DEBUG_PATTERNS
449     fprintf(stderr, "C");
450 #endif
451 
452     dict = xmlMalloc(sizeof(xmlDict));
453     if (dict) {
454         dict->ref_counter = 1;
455 
456         dict->size = MIN_DICT_SIZE;
457 	dict->nbElems = 0;
458         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
459 	dict->strings = NULL;
460 	dict->subdict = NULL;
461         if (dict->dict) {
462 	    memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
463 	    return(dict);
464         }
465         xmlFree(dict);
466     }
467     return(NULL);
468 }
469 
470 /**
471  * xmlDictCreateSub:
472  * @sub: an existing dictionnary
473  *
474  * Create a new dictionary, inheriting strings from the read-only
475  * dictionnary @sub. On lookup, strings are first searched in the
476  * new dictionnary, then in @sub, and if not found are created in the
477  * new dictionnary.
478  *
479  * Returns the newly created dictionnary, or NULL if an error occured.
480  */
481 xmlDictPtr
xmlDictCreateSub(xmlDictPtr sub)482 xmlDictCreateSub(xmlDictPtr sub) {
483     xmlDictPtr dict = xmlDictCreate();
484 
485     if ((dict != NULL) && (sub != NULL)) {
486 #ifdef DICT_DEBUG_PATTERNS
487         fprintf(stderr, "R");
488 #endif
489         dict->subdict = sub;
490 	xmlDictReference(dict->subdict);
491     }
492     return(dict);
493 }
494 
495 /**
496  * xmlDictReference:
497  * @dict: the dictionnary
498  *
499  * Increment the reference counter of a dictionary
500  *
501  * Returns 0 in case of success and -1 in case of error
502  */
503 int
xmlDictReference(xmlDictPtr dict)504 xmlDictReference(xmlDictPtr dict) {
505     if (!xmlDictInitialized)
506         if (!xmlInitializeDict())
507             return(-1);
508 
509     if (dict == NULL) return -1;
510     xmlRMutexLock(xmlDictMutex);
511     dict->ref_counter++;
512     xmlRMutexUnlock(xmlDictMutex);
513     return(0);
514 }
515 
516 /**
517  * xmlDictGrow:
518  * @dict: the dictionnary
519  * @size: the new size of the dictionnary
520  *
521  * resize the dictionnary
522  *
523  * Returns 0 in case of success, -1 in case of failure
524  */
525 static int
xmlDictGrow(xmlDictPtr dict,int size)526 xmlDictGrow(xmlDictPtr dict, int size) {
527     unsigned long key, okey;
528     int oldsize, i;
529     xmlDictEntryPtr iter, next;
530     struct _xmlDictEntry *olddict;
531 #ifdef DEBUG_GROW
532     unsigned long nbElem = 0;
533 #endif
534     int ret = 0;
535     int keep_keys = 1;
536 
537     if (dict == NULL)
538 	return(-1);
539     if (size < 8)
540         return(-1);
541     if (size > 8 * 2048)
542 	return(-1);
543 
544 #ifdef DICT_DEBUG_PATTERNS
545     fprintf(stderr, "*");
546 #endif
547 
548     oldsize = dict->size;
549     olddict = dict->dict;
550     if (olddict == NULL)
551         return(-1);
552     if (oldsize == MIN_DICT_SIZE)
553         keep_keys = 0;
554 
555     dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
556     if (dict->dict == NULL) {
557 	dict->dict = olddict;
558 	return(-1);
559     }
560     memset(dict->dict, 0, size * sizeof(xmlDictEntry));
561     dict->size = size;
562 
563     /*	If the two loops are merged, there would be situations where
564 	a new entry needs to allocated and data copied into it from
565 	the main dict. It is nicer to run through the array twice, first
566 	copying all the elements in the main array (less probability of
567 	allocate) and then the rest, so we only free in the second loop.
568     */
569     for (i = 0; i < oldsize; i++) {
570 	if (olddict[i].valid == 0)
571 	    continue;
572 
573 	if (keep_keys)
574 	    okey = olddict[i].okey;
575 	else
576 	    okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
577 	key = okey % dict->size;
578 
579 	if (dict->dict[key].valid == 0) {
580 	    memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
581 	    dict->dict[key].next = NULL;
582 	    dict->dict[key].okey = okey;
583 	} else {
584 	    xmlDictEntryPtr entry;
585 
586 	    entry = xmlMalloc(sizeof(xmlDictEntry));
587 	    if (entry != NULL) {
588 		entry->name = olddict[i].name;
589 		entry->len = olddict[i].len;
590 		entry->okey = okey;
591 		entry->next = dict->dict[key].next;
592 		entry->valid = 1;
593 		dict->dict[key].next = entry;
594 	    } else {
595 	        /*
596 		 * we don't have much ways to alert from herei
597 		 * result is loosing an entry and unicity garantee
598 		 */
599 	        ret = -1;
600 	    }
601 	}
602 #ifdef DEBUG_GROW
603 	nbElem++;
604 #endif
605     }
606 
607     for (i = 0; i < oldsize; i++) {
608 	iter = olddict[i].next;
609 	while (iter) {
610 	    next = iter->next;
611 
612 	    /*
613 	     * put back the entry in the new dict
614 	     */
615 
616 	    if (keep_keys)
617 		okey = iter->okey;
618 	    else
619 		okey = xmlDictComputeKey(dict, iter->name, iter->len);
620 	    key = okey % dict->size;
621 	    if (dict->dict[key].valid == 0) {
622 		memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
623 		dict->dict[key].next = NULL;
624 		dict->dict[key].valid = 1;
625 		dict->dict[key].okey = okey;
626 		xmlFree(iter);
627 	    } else {
628 		iter->next = dict->dict[key].next;
629 		iter->okey = okey;
630 		dict->dict[key].next = iter;
631 	    }
632 
633 #ifdef DEBUG_GROW
634 	    nbElem++;
635 #endif
636 
637 	    iter = next;
638 	}
639     }
640 
641     xmlFree(olddict);
642 
643 #ifdef DEBUG_GROW
644     xmlGenericError(xmlGenericErrorContext,
645 	    "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
646 #endif
647 
648     return(ret);
649 }
650 
651 /**
652  * xmlDictFree:
653  * @dict: the dictionnary
654  *
655  * Free the hash @dict and its contents. The userdata is
656  * deallocated with @f if provided.
657  */
658 void
xmlDictFree(xmlDictPtr dict)659 xmlDictFree(xmlDictPtr dict) {
660     int i;
661     xmlDictEntryPtr iter;
662     xmlDictEntryPtr next;
663     int inside_dict = 0;
664     xmlDictStringsPtr pool, nextp;
665 
666     if (dict == NULL)
667 	return;
668 
669     if (!xmlDictInitialized)
670         if (!xmlInitializeDict())
671             return;
672 
673     /* decrement the counter, it may be shared by a parser and docs */
674     xmlRMutexLock(xmlDictMutex);
675     dict->ref_counter--;
676     if (dict->ref_counter > 0) {
677         xmlRMutexUnlock(xmlDictMutex);
678         return;
679     }
680 
681     xmlRMutexUnlock(xmlDictMutex);
682 
683     if (dict->subdict != NULL) {
684         xmlDictFree(dict->subdict);
685     }
686 
687     if (dict->dict) {
688 	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
689 	    iter = &(dict->dict[i]);
690 	    if (iter->valid == 0)
691 		continue;
692 	    inside_dict = 1;
693 	    while (iter) {
694 		next = iter->next;
695 		if (!inside_dict)
696 		    xmlFree(iter);
697 		dict->nbElems--;
698 		inside_dict = 0;
699 		iter = next;
700 	    }
701 	}
702 	xmlFree(dict->dict);
703     }
704     pool = dict->strings;
705     while (pool != NULL) {
706         nextp = pool->next;
707 	xmlFree(pool);
708 	pool = nextp;
709     }
710     xmlFree(dict);
711 }
712 
713 /**
714  * xmlDictLookup:
715  * @dict: the dictionnary
716  * @name: the name of the userdata
717  * @len: the length of the name, if -1 it is recomputed
718  *
719  * Add the @name to the dictionnary @dict if not present.
720  *
721  * Returns the internal copy of the name or NULL in case of internal error
722  */
723 const xmlChar *
xmlDictLookup(xmlDictPtr dict,const xmlChar * name,int len)724 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
725     unsigned long key, okey, nbi = 0;
726     xmlDictEntryPtr entry;
727     xmlDictEntryPtr insert;
728     const xmlChar *ret;
729 
730     if ((dict == NULL) || (name == NULL))
731 	return(NULL);
732 
733     if (len < 0)
734         len = strlen((const char *) name);
735 
736     /*
737      * Check for duplicate and insertion location.
738      */
739     okey = xmlDictComputeKey(dict, name, len);
740     key = okey % dict->size;
741     if (dict->dict[key].valid == 0) {
742 	insert = NULL;
743     } else {
744 	for (insert = &(dict->dict[key]); insert->next != NULL;
745 	     insert = insert->next) {
746 #ifdef __GNUC__
747 	    if ((insert->okey == okey) && (insert->len == len)) {
748 		if (!memcmp(insert->name, name, len))
749 		    return(insert->name);
750 	    }
751 #else
752 	    if ((insert->okey == okey) && (insert->len == len) &&
753 	        (!xmlStrncmp(insert->name, name, len)))
754 		return(insert->name);
755 #endif
756 	    nbi++;
757 	}
758 #ifdef __GNUC__
759 	if ((insert->okey == okey) && (insert->len == len)) {
760 	    if (!memcmp(insert->name, name, len))
761 		return(insert->name);
762 	}
763 #else
764 	if ((insert->okey == okey) && (insert->len == len) &&
765 	    (!xmlStrncmp(insert->name, name, len)))
766 	    return(insert->name);
767 #endif
768     }
769 
770     if (dict->subdict) {
771         unsigned long skey;
772 
773         /* we cannot always reuse the same okey for the subdict */
774         if (((dict->size == MIN_DICT_SIZE) &&
775 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
776             ((dict->size != MIN_DICT_SIZE) &&
777 	     (dict->subdict->size == MIN_DICT_SIZE)))
778 	    skey = xmlDictComputeKey(dict->subdict, name, len);
779 	else
780 	    skey = okey;
781 
782 	key = skey % dict->subdict->size;
783 	if (dict->subdict->dict[key].valid != 0) {
784 	    xmlDictEntryPtr tmp;
785 
786 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
787 		 tmp = tmp->next) {
788 #ifdef __GNUC__
789 		if ((tmp->okey == skey) && (tmp->len == len)) {
790 		    if (!memcmp(tmp->name, name, len))
791 			return(tmp->name);
792 		}
793 #else
794 		if ((tmp->okey == skey) && (tmp->len == len) &&
795 		    (!xmlStrncmp(tmp->name, name, len)))
796 		    return(tmp->name);
797 #endif
798 		nbi++;
799 	    }
800 #ifdef __GNUC__
801 	    if ((tmp->okey == skey) && (tmp->len == len)) {
802 		if (!memcmp(tmp->name, name, len))
803 		    return(tmp->name);
804 	    }
805 #else
806 	    if ((tmp->okey == skey) && (tmp->len == len) &&
807 		(!xmlStrncmp(tmp->name, name, len)))
808 		return(tmp->name);
809 #endif
810 	}
811 	key = okey % dict->size;
812     }
813 
814     ret = xmlDictAddString(dict, name, len);
815     if (ret == NULL)
816         return(NULL);
817     if (insert == NULL) {
818 	entry = &(dict->dict[key]);
819     } else {
820 	entry = xmlMalloc(sizeof(xmlDictEntry));
821 	if (entry == NULL)
822 	     return(NULL);
823     }
824     entry->name = ret;
825     entry->len = len;
826     entry->next = NULL;
827     entry->valid = 1;
828     entry->okey = okey;
829 
830 
831     if (insert != NULL)
832 	insert->next = entry;
833 
834     dict->nbElems++;
835 
836     if ((nbi > MAX_HASH_LEN) &&
837         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
838 	if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
839 	    return(NULL);
840     }
841     /* Note that entry may have been freed at this point by xmlDictGrow */
842 
843     return(ret);
844 }
845 
846 /**
847  * xmlDictExists:
848  * @dict: the dictionnary
849  * @name: the name of the userdata
850  * @len: the length of the name, if -1 it is recomputed
851  *
852  * Check if the @name exists in the dictionnary @dict.
853  *
854  * Returns the internal copy of the name or NULL if not found.
855  */
856 const xmlChar *
xmlDictExists(xmlDictPtr dict,const xmlChar * name,int len)857 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
858     unsigned long key, okey, nbi = 0;
859     xmlDictEntryPtr insert;
860 
861     if ((dict == NULL) || (name == NULL))
862 	return(NULL);
863 
864     if (len < 0)
865         len = strlen((const char *) name);
866 
867     /*
868      * Check for duplicate and insertion location.
869      */
870     okey = xmlDictComputeKey(dict, name, len);
871     key = okey % dict->size;
872     if (dict->dict[key].valid == 0) {
873 	insert = NULL;
874     } else {
875 	for (insert = &(dict->dict[key]); insert->next != NULL;
876 	     insert = insert->next) {
877 #ifdef __GNUC__
878 	    if ((insert->okey == okey) && (insert->len == len)) {
879 		if (!memcmp(insert->name, name, len))
880 		    return(insert->name);
881 	    }
882 #else
883 	    if ((insert->okey == okey) && (insert->len == len) &&
884 	        (!xmlStrncmp(insert->name, name, len)))
885 		return(insert->name);
886 #endif
887 	    nbi++;
888 	}
889 #ifdef __GNUC__
890 	if ((insert->okey == okey) && (insert->len == len)) {
891 	    if (!memcmp(insert->name, name, len))
892 		return(insert->name);
893 	}
894 #else
895 	if ((insert->okey == okey) && (insert->len == len) &&
896 	    (!xmlStrncmp(insert->name, name, len)))
897 	    return(insert->name);
898 #endif
899     }
900 
901     if (dict->subdict) {
902         unsigned long skey;
903 
904         /* we cannot always reuse the same okey for the subdict */
905         if (((dict->size == MIN_DICT_SIZE) &&
906 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
907             ((dict->size != MIN_DICT_SIZE) &&
908 	     (dict->subdict->size == MIN_DICT_SIZE)))
909 	    skey = xmlDictComputeKey(dict->subdict, name, len);
910 	else
911 	    skey = okey;
912 
913 	key = skey % dict->subdict->size;
914 	if (dict->subdict->dict[key].valid != 0) {
915 	    xmlDictEntryPtr tmp;
916 
917 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
918 		 tmp = tmp->next) {
919 #ifdef __GNUC__
920 		if ((tmp->okey == skey) && (tmp->len == len)) {
921 		    if (!memcmp(tmp->name, name, len))
922 			return(tmp->name);
923 		}
924 #else
925 		if ((tmp->okey == skey) && (tmp->len == len) &&
926 		    (!xmlStrncmp(tmp->name, name, len)))
927 		    return(tmp->name);
928 #endif
929 		nbi++;
930 	    }
931 #ifdef __GNUC__
932 	    if ((tmp->okey == skey) && (tmp->len == len)) {
933 		if (!memcmp(tmp->name, name, len))
934 		    return(tmp->name);
935 	    }
936 #else
937 	    if ((tmp->okey == skey) && (tmp->len == len) &&
938 		(!xmlStrncmp(tmp->name, name, len)))
939 		return(tmp->name);
940 #endif
941 	}
942     }
943 
944     /* not found */
945     return(NULL);
946 }
947 
948 /**
949  * xmlDictQLookup:
950  * @dict: the dictionnary
951  * @prefix: the prefix
952  * @name: the name
953  *
954  * Add the QName @prefix:@name to the hash @dict if not present.
955  *
956  * Returns the internal copy of the QName or NULL in case of internal error
957  */
958 const xmlChar *
xmlDictQLookup(xmlDictPtr dict,const xmlChar * prefix,const xmlChar * name)959 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
960     unsigned long okey, key, nbi = 0;
961     xmlDictEntryPtr entry;
962     xmlDictEntryPtr insert;
963     const xmlChar *ret;
964     int len, plen, l;
965 
966     if ((dict == NULL) || (name == NULL))
967 	return(NULL);
968     if (prefix == NULL)
969         return(xmlDictLookup(dict, name, -1));
970 
971     l = len = strlen((const char *) name);
972     plen = strlen((const char *) prefix);
973     len += 1 + plen;
974 
975     /*
976      * Check for duplicate and insertion location.
977      */
978     okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
979     key = okey % dict->size;
980     if (dict->dict[key].valid == 0) {
981 	insert = NULL;
982     } else {
983 	for (insert = &(dict->dict[key]); insert->next != NULL;
984 	     insert = insert->next) {
985 	    if ((insert->okey == okey) && (insert->len == len) &&
986 	        (xmlStrQEqual(prefix, name, insert->name)))
987 		return(insert->name);
988 	    nbi++;
989 	}
990 	if ((insert->okey == okey) && (insert->len == len) &&
991 	    (xmlStrQEqual(prefix, name, insert->name)))
992 	    return(insert->name);
993     }
994 
995     if (dict->subdict) {
996         unsigned long skey;
997 
998         /* we cannot always reuse the same okey for the subdict */
999         if (((dict->size == MIN_DICT_SIZE) &&
1000 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
1001             ((dict->size != MIN_DICT_SIZE) &&
1002 	     (dict->subdict->size == MIN_DICT_SIZE)))
1003 	    skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
1004 	else
1005 	    skey = okey;
1006 
1007 	key = skey % dict->subdict->size;
1008 	if (dict->subdict->dict[key].valid != 0) {
1009 	    xmlDictEntryPtr tmp;
1010 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1011 		 tmp = tmp->next) {
1012 		if ((tmp->okey == skey) && (tmp->len == len) &&
1013 		    (xmlStrQEqual(prefix, name, tmp->name)))
1014 		    return(tmp->name);
1015 		nbi++;
1016 	    }
1017 	    if ((tmp->okey == skey) && (tmp->len == len) &&
1018 		(xmlStrQEqual(prefix, name, tmp->name)))
1019 		return(tmp->name);
1020 	}
1021 	key = okey % dict->size;
1022     }
1023 
1024     ret = xmlDictAddQString(dict, prefix, plen, name, l);
1025     if (ret == NULL)
1026         return(NULL);
1027     if (insert == NULL) {
1028 	entry = &(dict->dict[key]);
1029     } else {
1030 	entry = xmlMalloc(sizeof(xmlDictEntry));
1031 	if (entry == NULL)
1032 	     return(NULL);
1033     }
1034     entry->name = ret;
1035     entry->len = len;
1036     entry->next = NULL;
1037     entry->valid = 1;
1038     entry->okey = okey;
1039 
1040     if (insert != NULL)
1041 	insert->next = entry;
1042 
1043     dict->nbElems++;
1044 
1045     if ((nbi > MAX_HASH_LEN) &&
1046         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1047 	xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1048     /* Note that entry may have been freed at this point by xmlDictGrow */
1049 
1050     return(ret);
1051 }
1052 
1053 /**
1054  * xmlDictOwns:
1055  * @dict: the dictionnary
1056  * @str: the string
1057  *
1058  * check if a string is owned by the disctionary
1059  *
1060  * Returns 1 if true, 0 if false and -1 in case of error
1061  * -1 in case of error
1062  */
1063 int
xmlDictOwns(xmlDictPtr dict,const xmlChar * str)1064 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1065     xmlDictStringsPtr pool;
1066 
1067     if ((dict == NULL) || (str == NULL))
1068 	return(-1);
1069     pool = dict->strings;
1070     while (pool != NULL) {
1071         if ((str >= &pool->array[0]) && (str <= pool->free))
1072 	    return(1);
1073 	pool = pool->next;
1074     }
1075     if (dict->subdict)
1076         return(xmlDictOwns(dict->subdict, str));
1077     return(0);
1078 }
1079 
1080 /**
1081  * xmlDictSize:
1082  * @dict: the dictionnary
1083  *
1084  * Query the number of elements installed in the hash @dict.
1085  *
1086  * Returns the number of elements in the dictionnary or
1087  * -1 in case of error
1088  */
1089 int
xmlDictSize(xmlDictPtr dict)1090 xmlDictSize(xmlDictPtr dict) {
1091     if (dict == NULL)
1092 	return(-1);
1093     if (dict->subdict)
1094         return(dict->nbElems + dict->subdict->nbElems);
1095     return(dict->nbElems);
1096 }
1097 
1098 
1099 #define bottom_dict
1100 #include "elfgcchack.h"
1101