Git init
[external/libxml2.git] / dict.c
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  */
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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
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
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"