~ubuntu-branches/ubuntu/quantal/libxml2/quantal-updates

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