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

1 by Daniel Holbach
Import upstream version 2.6.22
1
/*
2
 * hash.c: chained hash tables
3
 *
4
 * Reference: Your favorite introductory book on algorithms
5
 *
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
6
 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
1 by Daniel Holbach
Import upstream version 2.6.22
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
13
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
14
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16
 *
17
 * Author: breese@users.sourceforge.net
18
 */
19
20
#define IN_LIBXML
21
#include "libxml.h"
22
23
#include <string.h>
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
24
#ifdef HAVE_STDLIB_H
25
#include <stdlib.h>
26
#endif
27
#ifdef HAVE_TIME_H
28
#include <time.h>
29
#endif
30
31
/*
32
 * Following http://www.ocert.org/advisories/ocert-2011-003.html
33
 * it seems that having hash randomization might be a good idea
34
 * when using XML with untrusted data
35
 */
36
#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
37
#define HASH_RANDOMIZATION
38
#endif
39
1 by Daniel Holbach
Import upstream version 2.6.22
40
#include <libxml/parser.h>
41
#include <libxml/hash.h>
42
#include <libxml/xmlmemory.h>
43
#include <libxml/xmlerror.h>
44
#include <libxml/globals.h>
45
46
#define MAX_HASH_LEN 8
47
48
/* #define DEBUG_GROW */
49
50
/*
51
 * A single entry in the hash table
52
 */
53
typedef struct _xmlHashEntry xmlHashEntry;
54
typedef xmlHashEntry *xmlHashEntryPtr;
55
struct _xmlHashEntry {
56
    struct _xmlHashEntry *next;
57
    xmlChar *name;
58
    xmlChar *name2;
59
    xmlChar *name3;
60
    void *payload;
61
    int valid;
62
};
63
64
/*
65
 * The entire hash table
66
 */
67
struct _xmlHashTable {
68
    struct _xmlHashEntry *table;
69
    int size;
70
    int nbElems;
71
    xmlDictPtr dict;
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
72
#ifdef HASH_RANDOMIZATION
73
    int random_seed;
74
#endif
1 by Daniel Holbach
Import upstream version 2.6.22
75
};
76
77
/*
78
 * xmlHashComputeKey:
79
 * Calculate the hash key
80
 */
81
static unsigned long
82
xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
83
	          const xmlChar *name2, const xmlChar *name3) {
84
    unsigned long value = 0L;
85
    char ch;
43.1.5 by Aron Xu
* Multi-Arch ready. (Closes: #643026)
86
    
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
87
#ifdef HASH_RANDOMIZATION
88
    value = table->random_seed;
89
#endif
1 by Daniel Holbach
Import upstream version 2.6.22
90
    if (name != NULL) {
91
	value += 30 * (*name);
92
	while ((ch = *name++) != 0) {
93
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
94
	}
95
    }
96
    if (name2 != NULL) {
97
	while ((ch = *name2++) != 0) {
98
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
99
	}
100
    }
101
    if (name3 != NULL) {
102
	while ((ch = *name3++) != 0) {
103
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
104
	}
105
    }
106
    return (value % table->size);
107
}
108
109
static unsigned long
110
xmlHashComputeQKey(xmlHashTablePtr table,
111
		   const xmlChar *prefix, const xmlChar *name,
112
		   const xmlChar *prefix2, const xmlChar *name2,
113
		   const xmlChar *prefix3, const xmlChar *name3) {
114
    unsigned long value = 0L;
115
    char ch;
116
    
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
117
#ifdef HASH_RANDOMIZATION
118
    value = table->random_seed;
119
#endif
1 by Daniel Holbach
Import upstream version 2.6.22
120
    if (prefix != NULL)
121
	value += 30 * (*prefix);
122
    else
123
	value += 30 * (*name);
124
125
    if (prefix != NULL) {
126
	while ((ch = *prefix++) != 0) {
127
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
128
	}
129
	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
130
    }
131
    if (name != NULL) {
132
	while ((ch = *name++) != 0) {
133
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
134
	}
135
    }
136
    if (prefix2 != NULL) {
137
	while ((ch = *prefix2++) != 0) {
138
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
139
	}
140
	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
141
    }
142
    if (name2 != NULL) {
143
	while ((ch = *name2++) != 0) {
144
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
145
	}
146
    }
147
    if (prefix3 != NULL) {
148
	while ((ch = *prefix3++) != 0) {
149
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
150
	}
151
	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
152
    }
153
    if (name3 != NULL) {
154
	while ((ch = *name3++) != 0) {
155
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
156
	}
157
    }
158
    return (value % table->size);
159
}
160
161
/**
162
 * xmlHashCreate:
163
 * @size: the size of the hash table
164
 *
165
 * Create a new xmlHashTablePtr.
166
 *
167
 * Returns the newly created object, or NULL if an error occured.
168
 */
169
xmlHashTablePtr
170
xmlHashCreate(int size) {
171
    xmlHashTablePtr table;
172
  
173
    if (size <= 0)
174
        size = 256;
175
  
176
    table = xmlMalloc(sizeof(xmlHashTable));
177
    if (table) {
178
        table->dict = NULL;
179
        table->size = size;
180
	table->nbElems = 0;
181
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
182
        if (table->table) {
183
  	    memset(table->table, 0, size * sizeof(xmlHashEntry));
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
184
#ifdef HASH_RANDOMIZATION
1.1.16 by Aron Xu
Import upstream version 2.8.0+dfsg1
185
            table->random_seed = __xmlRandom();
54 by Jamie Strandboge
* SECURITY UPDATE: add randomization to dictionaries with hash tables
186
#endif
1 by Daniel Holbach
Import upstream version 2.6.22
187
  	    return(table);
188
        }
189
        xmlFree(table);
190
    }
191
    return(NULL);
192
}
193
194
/**
195
 * xmlHashCreateDict:
196
 * @size: the size of the hash table
197
 * @dict: a dictionary to use for the hash
198
 *
199
 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
200
 *
201
 * Returns the newly created object, or NULL if an error occured.
202
 */
203
xmlHashTablePtr
204
xmlHashCreateDict(int size, xmlDictPtr dict) {
205
    xmlHashTablePtr table;
206
207
    table = xmlHashCreate(size);
208
    if (table != NULL) {
209
        table->dict = dict;
210
	xmlDictReference(dict);
211
    }
212
    return(table);
213
}
214
215
/**
216
 * xmlHashGrow:
217
 * @table: the hash table
218
 * @size: the new size of the hash table
219
 *
220
 * resize the hash table
221
 *
222
 * Returns 0 in case of success, -1 in case of failure
223
 */
224
static int
225
xmlHashGrow(xmlHashTablePtr table, int size) {
226
    unsigned long key;
227
    int oldsize, i;
228
    xmlHashEntryPtr iter, next;
229
    struct _xmlHashEntry *oldtable;
230
#ifdef DEBUG_GROW
231
    unsigned long nbElem = 0;
232
#endif
233
  
234
    if (table == NULL)
235
	return(-1);
236
    if (size < 8)
237
        return(-1);
238
    if (size > 8 * 2048)
239
	return(-1);
240
241
    oldsize = table->size;
242
    oldtable = table->table;
243
    if (oldtable == NULL)
244
        return(-1);
245
  
246
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
247
    if (table->table == NULL) {
248
	table->table = oldtable;
249
	return(-1);
250
    }
251
    memset(table->table, 0, size * sizeof(xmlHashEntry));
252
    table->size = size;
253
254
    /*	If the two loops are merged, there would be situations where
255
	a new entry needs to allocated and data copied into it from 
256
	the main table. So instead, we run through the array twice, first
257
	copying all the elements in the main array (where we can't get
258
	conflicts) and then the rest, so we only free (and don't allocate)
259
    */
260
    for (i = 0; i < oldsize; i++) {
261
	if (oldtable[i].valid == 0) 
262
	    continue;
263
	key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
264
				oldtable[i].name3);
265
	memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
266
	table->table[key].next = NULL;
267
    }
268
269
    for (i = 0; i < oldsize; i++) {
270
	iter = oldtable[i].next;
271
	while (iter) {
272
	    next = iter->next;
273
274
	    /*
275
	     * put back the entry in the new table
276
	     */
277
278
	    key = xmlHashComputeKey(table, iter->name, iter->name2,
279
		                    iter->name3);
280
	    if (table->table[key].valid == 0) {
281
		memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
282
		table->table[key].next = NULL;
283
		xmlFree(iter);
284
	    } else {
285
	    	iter->next = table->table[key].next;
286
	    	table->table[key].next = iter;
287
	    }
288
289
#ifdef DEBUG_GROW
290
	    nbElem++;
291
#endif
292
293
	    iter = next;
294
	}
295
    }
296
297
    xmlFree(oldtable);
298
299
#ifdef DEBUG_GROW
300
    xmlGenericError(xmlGenericErrorContext,
301
	    "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
302
#endif
303
304
    return(0);
305
}
306
307
/**
308
 * xmlHashFree:
309
 * @table: the hash table
310
 * @f:  the deallocator function for items in the hash
311
 *
312
 * Free the hash @table and its contents. The userdata is
313
 * deallocated with @f if provided.
314
 */
315
void
316
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
317
    int i;
318
    xmlHashEntryPtr iter;
319
    xmlHashEntryPtr next;
320
    int inside_table = 0;
321
    int nbElems;
322
323
    if (table == NULL)
324
	return;
325
    if (table->table) {
326
	nbElems = table->nbElems;
327
	for(i = 0; (i < table->size) && (nbElems > 0); i++) {
328
	    iter = &(table->table[i]);
329
	    if (iter->valid == 0)
330
		continue;
331
	    inside_table = 1;
332
	    while (iter) {
333
		next = iter->next;
334
		if ((f != NULL) && (iter->payload != NULL))
335
		    f(iter->payload, iter->name);
336
		if (table->dict == NULL) {
337
		    if (iter->name)
338
			xmlFree(iter->name);
339
		    if (iter->name2)
340
			xmlFree(iter->name2);
341
		    if (iter->name3)
342
			xmlFree(iter->name3);
343
		}
344
		iter->payload = NULL;
345
		if (!inside_table)
346
		    xmlFree(iter);
347
		nbElems--;
348
		inside_table = 0;
349
		iter = next;
350
	    }
351
	}
352
	xmlFree(table->table);
353
    }
354
    if (table->dict)
355
        xmlDictFree(table->dict);
356
    xmlFree(table);
357
}
358
359
/**
360
 * xmlHashAddEntry:
361
 * @table: the hash table
362
 * @name: the name of the userdata
363
 * @userdata: a pointer to the userdata
364
 *
365
 * Add the @userdata to the hash @table. This can later be retrieved
366
 * by using the @name. Duplicate names generate errors.
367
 *
368
 * Returns 0 the addition succeeded and -1 in case of error.
369
 */
370
int
371
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
372
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
373
}
374
375
/**
376
 * xmlHashAddEntry2:
377
 * @table: the hash table
378
 * @name: the name of the userdata
379
 * @name2: a second name of the userdata
380
 * @userdata: a pointer to the userdata
381
 *
382
 * Add the @userdata to the hash @table. This can later be retrieved
383
 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
384
 *
385
 * Returns 0 the addition succeeded and -1 in case of error.
386
 */
387
int
388
xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
389
	        const xmlChar *name2, void *userdata) {
390
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
391
}
392
393
/**
394
 * xmlHashUpdateEntry:
395
 * @table: the hash table
396
 * @name: the name of the userdata
397
 * @userdata: a pointer to the userdata
398
 * @f: the deallocator function for replaced item (if any)
399
 *
400
 * Add the @userdata to the hash @table. This can later be retrieved
401
 * by using the @name. Existing entry for this @name will be removed
402
 * and freed with @f if found.
403
 *
404
 * Returns 0 the addition succeeded and -1 in case of error.
405
 */
406
int
407
xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
408
	           void *userdata, xmlHashDeallocator f) {
409
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
410
}
411
412
/**
413
 * xmlHashUpdateEntry2:
414
 * @table: the hash table
415
 * @name: the name of the userdata
416
 * @name2: a second name of the userdata
417
 * @userdata: a pointer to the userdata
418
 * @f: the deallocator function for replaced item (if any)
419
 *
420
 * Add the @userdata to the hash @table. This can later be retrieved
421
 * by using the (@name, @name2) tuple. Existing entry for this tuple will
422
 * be removed and freed with @f if found.
423
 *
424
 * Returns 0 the addition succeeded and -1 in case of error.
425
 */
426
int
427
xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
428
	           const xmlChar *name2, void *userdata,
429
		   xmlHashDeallocator f) {
430
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
431
}
432
433
/**
434
 * xmlHashLookup:
435
 * @table: the hash table
436
 * @name: the name of the userdata
437
 *
438
 * Find the userdata specified by the @name.
439
 *
440
 * Returns the pointer to the userdata
441
 */
442
void *
443
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
444
    return(xmlHashLookup3(table, name, NULL, NULL));
445
}
446
447
/**
448
 * xmlHashLookup2:
449
 * @table: the hash table
450
 * @name: the name of the userdata
451
 * @name2: a second name of the userdata
452
 *
453
 * Find the userdata specified by the (@name, @name2) tuple.
454
 *
455
 * Returns the pointer to the userdata
456
 */
457
void *
458
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
459
	      const xmlChar *name2) {
460
    return(xmlHashLookup3(table, name, name2, NULL));
461
}
462
463
/**
464
 * xmlHashQLookup:
465
 * @table: the hash table
466
 * @prefix: the prefix of the userdata
467
 * @name: the name of the userdata
468
 *
469
 * Find the userdata specified by the QName @prefix:@name/@name.
470
 *
471
 * Returns the pointer to the userdata
472
 */
473
void *
474
xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
475
               const xmlChar *name) {
476
    return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
477
}
478
479
/**
480
 * xmlHashQLookup2:
481
 * @table: the hash table
482
 * @prefix: the prefix of the userdata
483
 * @name: the name of the userdata
484
 * @prefix2: the second prefix of the userdata
485
 * @name2: a second name of the userdata
486
 *
487
 * Find the userdata specified by the QNames tuple
488
 *
489
 * Returns the pointer to the userdata
490
 */
491
void *
492
xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
493
                const xmlChar *name, const xmlChar *prefix2,
494
	        const xmlChar *name2) {
495
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
496
}
497
498
/**
499
 * xmlHashAddEntry3:
500
 * @table: the hash table
501
 * @name: the name of the userdata
502
 * @name2: a second name of the userdata
503
 * @name3: a third name of the userdata
504
 * @userdata: a pointer to the userdata
505
 *
506
 * Add the @userdata to the hash @table. This can later be retrieved
507
 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
508
 * errors.
509
 *
510
 * Returns 0 the addition succeeded and -1 in case of error.
511
 */
512
int
513
xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
514
	         const xmlChar *name2, const xmlChar *name3,
515
		 void *userdata) {
516
    unsigned long key, len = 0;
517
    xmlHashEntryPtr entry;
518
    xmlHashEntryPtr insert;
519
520
    if ((table == NULL) || (name == NULL))
521
	return(-1);
522
523
    /*
524
     * If using a dict internalize if needed
525
     */
526
    if (table->dict) {
527
        if (!xmlDictOwns(table->dict, name)) {
528
	    name = xmlDictLookup(table->dict, name, -1);
529
	    if (name == NULL)
530
	        return(-1);
531
	}
532
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
533
	    name2 = xmlDictLookup(table->dict, name2, -1);
534
	    if (name2 == NULL)
535
	        return(-1);
536
	}
537
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
538
	    name3 = xmlDictLookup(table->dict, name3, -1);
539
	    if (name3 == NULL)
540
	        return(-1);
541
	}
542
    }
543
544
    /*
545
     * Check for duplicate and insertion location.
546
     */
547
    key = xmlHashComputeKey(table, name, name2, name3);
548
    if (table->table[key].valid == 0) {
549
	insert = NULL;
550
    } else {
551
        if (table->dict) {
552
	    for (insert = &(table->table[key]); insert->next != NULL;
553
		 insert = insert->next) {
554
		if ((insert->name == name) &&
555
		    (insert->name2 == name2) &&
556
		    (insert->name3 == name3))
557
		    return(-1);
558
		len++;
559
	    }
560
	    if ((insert->name == name) &&
561
		(insert->name2 == name2) &&
562
		(insert->name3 == name3))
563
		return(-1);
564
	} else {
565
	    for (insert = &(table->table[key]); insert->next != NULL;
566
		 insert = insert->next) {
567
		if ((xmlStrEqual(insert->name, name)) &&
568
		    (xmlStrEqual(insert->name2, name2)) &&
569
		    (xmlStrEqual(insert->name3, name3)))
570
		    return(-1);
571
		len++;
572
	    }
573
	    if ((xmlStrEqual(insert->name, name)) &&
574
		(xmlStrEqual(insert->name2, name2)) &&
575
		(xmlStrEqual(insert->name3, name3)))
576
		return(-1);
577
	}
578
    }
579
580
    if (insert == NULL) {
581
	entry = &(table->table[key]);
582
    } else {
583
	entry = xmlMalloc(sizeof(xmlHashEntry));
584
	if (entry == NULL)
585
	     return(-1);
586
    }
587
588
    if (table->dict != NULL) {
589
        entry->name = (xmlChar *) name;
590
        entry->name2 = (xmlChar *) name2;
591
        entry->name3 = (xmlChar *) name3;
592
    } else {
593
	entry->name = xmlStrdup(name);
594
	entry->name2 = xmlStrdup(name2);
595
	entry->name3 = xmlStrdup(name3);
596
    }
597
    entry->payload = userdata;
598
    entry->next = NULL;
599
    entry->valid = 1;
600
601
602
    if (insert != NULL) 
603
	insert->next = entry;
604
605
    table->nbElems++;
606
607
    if (len > MAX_HASH_LEN)
608
	xmlHashGrow(table, MAX_HASH_LEN * table->size);
609
610
    return(0);
611
}
612
613
/**
614
 * xmlHashUpdateEntry3:
615
 * @table: the hash table
616
 * @name: the name of the userdata
617
 * @name2: a second name of the userdata
618
 * @name3: a third name of the userdata
619
 * @userdata: a pointer to the userdata
620
 * @f: the deallocator function for replaced item (if any)
621
 *
622
 * Add the @userdata to the hash @table. This can later be retrieved
623
 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
624
 * will be removed and freed with @f if found.
625
 *
626
 * Returns 0 the addition succeeded and -1 in case of error.
627
 */
628
int
629
xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
630
	           const xmlChar *name2, const xmlChar *name3,
631
		   void *userdata, xmlHashDeallocator f) {
632
    unsigned long key;
633
    xmlHashEntryPtr entry;
634
    xmlHashEntryPtr insert;
635
636
    if ((table == NULL) || name == NULL)
637
	return(-1);
638
639
    /*
640
     * If using a dict internalize if needed
641
     */
642
    if (table->dict) {
643
        if (!xmlDictOwns(table->dict, name)) {
644
	    name = xmlDictLookup(table->dict, name, -1);
645
	    if (name == NULL)
646
	        return(-1);
647
	}
648
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
649
	    name2 = xmlDictLookup(table->dict, name2, -1);
650
	    if (name2 == NULL)
651
	        return(-1);
652
	}
653
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
654
	    name3 = xmlDictLookup(table->dict, name3, -1);
655
	    if (name3 == NULL)
656
	        return(-1);
657
	}
658
    }
659
660
    /*
661
     * Check for duplicate and insertion location.
662
     */
663
    key = xmlHashComputeKey(table, name, name2, name3);
664
    if (table->table[key].valid == 0) {
665
	insert = NULL;
666
    } else {
667
        if (table ->dict) {
668
	    for (insert = &(table->table[key]); insert->next != NULL;
669
		 insert = insert->next) {
670
		if ((insert->name == name) &&
671
		    (insert->name2 == name2) &&
672
		    (insert->name3 == name3)) {
673
		    if (f)
674
			f(insert->payload, insert->name);
675
		    insert->payload = userdata;
676
		    return(0);
677
		}
678
	    }
679
	    if ((insert->name == name) &&
680
		(insert->name2 == name2) &&
681
		(insert->name3 == name3)) {
682
		if (f)
683
		    f(insert->payload, insert->name);
684
		insert->payload = userdata;
685
		return(0);
686
	    }
687
	} else {
688
	    for (insert = &(table->table[key]); insert->next != NULL;
689
		 insert = insert->next) {
690
		if ((xmlStrEqual(insert->name, name)) &&
691
		    (xmlStrEqual(insert->name2, name2)) &&
692
		    (xmlStrEqual(insert->name3, name3))) {
693
		    if (f)
694
			f(insert->payload, insert->name);
695
		    insert->payload = userdata;
696
		    return(0);
697
		}
698
	    }
699
	    if ((xmlStrEqual(insert->name, name)) &&
700
		(xmlStrEqual(insert->name2, name2)) &&
701
		(xmlStrEqual(insert->name3, name3))) {
702
		if (f)
703
		    f(insert->payload, insert->name);
704
		insert->payload = userdata;
705
		return(0);
706
	    }
707
	}
708
    }
709
710
    if (insert == NULL) {
711
	entry =  &(table->table[key]);
712
    } else {
713
	entry = xmlMalloc(sizeof(xmlHashEntry));
714
	if (entry == NULL)
715
	     return(-1);
716
    }
717
718
    if (table->dict != NULL) {
719
        entry->name = (xmlChar *) name;
720
        entry->name2 = (xmlChar *) name2;
721
        entry->name3 = (xmlChar *) name3;
722
    } else {
723
	entry->name = xmlStrdup(name);
724
	entry->name2 = xmlStrdup(name2);
725
	entry->name3 = xmlStrdup(name3);
726
    }
727
    entry->payload = userdata;
728
    entry->next = NULL;
729
    entry->valid = 1;
730
    table->nbElems++;
731
732
733
    if (insert != NULL) {
734
	insert->next = entry;
735
    }
736
    return(0);
737
}
738
739
/**
740
 * xmlHashLookup3:
741
 * @table: the hash table
742
 * @name: the name of the userdata
743
 * @name2: a second name of the userdata
744
 * @name3: a third name of the userdata
745
 *
746
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
747
 *
748
 * Returns the a pointer to the userdata
749
 */
750
void *
751
xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, 
752
	       const xmlChar *name2, const xmlChar *name3) {
753
    unsigned long key;
754
    xmlHashEntryPtr entry;
755
756
    if (table == NULL)
757
	return(NULL);
758
    if (name == NULL)
759
	return(NULL);
760
    key = xmlHashComputeKey(table, name, name2, name3);
761
    if (table->table[key].valid == 0)
762
	return(NULL);
763
    if (table->dict) {
764
	for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
765
	    if ((entry->name == name) &&
766
		(entry->name2 == name2) &&
767
		(entry->name3 == name3))
768
		return(entry->payload);
769
	}
770
    }
771
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
772
	if ((xmlStrEqual(entry->name, name)) &&
773
	    (xmlStrEqual(entry->name2, name2)) &&
774
	    (xmlStrEqual(entry->name3, name3)))
775
	    return(entry->payload);
776
    }
777
    return(NULL);
778
}
779
780
/**
781
 * xmlHashQLookup3:
782
 * @table: the hash table
783
 * @prefix: the prefix of the userdata
784
 * @name: the name of the userdata
785
 * @prefix2: the second prefix of the userdata
786
 * @name2: a second name of the userdata
787
 * @prefix3: the third prefix of the userdata
788
 * @name3: a third name of the userdata
789
 *
790
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
791
 *
792
 * Returns the a pointer to the userdata
793
 */
794
void *
795
xmlHashQLookup3(xmlHashTablePtr table,
796
                const xmlChar *prefix, const xmlChar *name,
797
		const xmlChar *prefix2, const xmlChar *name2,
798
		const xmlChar *prefix3, const xmlChar *name3) {
799
    unsigned long key;
800
    xmlHashEntryPtr entry;
801
802
    if (table == NULL)
803
	return(NULL);
804
    if (name == NULL)
805
	return(NULL);
806
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
807
                             name2, prefix3, name3);
808
    if (table->table[key].valid == 0)
809
	return(NULL);
810
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
811
	if ((xmlStrQEqual(prefix, name, entry->name)) &&
812
	    (xmlStrQEqual(prefix2, name2, entry->name2)) &&
813
	    (xmlStrQEqual(prefix3, name3, entry->name3)))
814
	    return(entry->payload);
815
    }
816
    return(NULL);
817
}
818
819
typedef struct {
820
    xmlHashScanner hashscanner;
821
    void *data;
822
} stubData;
823
824
static void 
825
stubHashScannerFull (void *payload, void *data, const xmlChar *name, 
826
                     const xmlChar *name2 ATTRIBUTE_UNUSED,
827
		     const xmlChar *name3 ATTRIBUTE_UNUSED) {
828
    stubData *stubdata = (stubData *) data;
829
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
830
}                                  
831
 
832
/**
833
 * xmlHashScan:
834
 * @table: the hash table
835
 * @f:  the scanner function for items in the hash
836
 * @data:  extra data passed to f
837
 *
838
 * Scan the hash @table and applied @f to each value.
839
 */
840
void
841
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
842
    stubData stubdata;
843
    stubdata.data = data;
844
    stubdata.hashscanner = f; 
845
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
846
}
847
848
/**
849
 * xmlHashScanFull:
850
 * @table: the hash table
851
 * @f:  the scanner function for items in the hash
852
 * @data:  extra data passed to f
853
 *
854
 * Scan the hash @table and applied @f to each value.
855
 */
856
void
857
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
1.1.8 by Matthias Klose
Import upstream version 2.6.31.dfsg
858
    int i, nb;
1 by Daniel Holbach
Import upstream version 2.6.22
859
    xmlHashEntryPtr iter;
860
    xmlHashEntryPtr next;
861
862
    if (table == NULL)
863
	return;
864
    if (f == NULL)
865
	return;
866
867
    if (table->table) {
868
	for(i = 0; i < table->size; i++) {
869
	    if (table->table[i].valid == 0) 
870
		continue;
871
	    iter = &(table->table[i]);
872
	    while (iter) {
873
		next = iter->next;
1.1.8 by Matthias Klose
Import upstream version 2.6.31.dfsg
874
                nb = table->nbElems;
1 by Daniel Holbach
Import upstream version 2.6.22
875
		if ((f != NULL) && (iter->payload != NULL))
876
		    f(iter->payload, data, iter->name,
877
		      iter->name2, iter->name3);
1.1.8 by Matthias Klose
Import upstream version 2.6.31.dfsg
878
                if (nb != table->nbElems) {
879
                    /* table was modified by the callback, be careful */
880
                    if (iter == &(table->table[i])) {
881
                        if (table->table[i].valid == 0)
882
                            iter = NULL;
883
                        if (table->table[i].next != next)
884
			    iter = &(table->table[i]);
885
                    } else
886
		        iter = next;
887
                } else
888
		    iter = next;
1 by Daniel Holbach
Import upstream version 2.6.22
889
	    }
890
	}
891
    }
892
}
893
894
/**
895
 * xmlHashScan3:
896
 * @table: the hash table
897
 * @name: the name of the userdata or NULL
898
 * @name2: a second name of the userdata or NULL
899
 * @name3: a third name of the userdata or NULL
900
 * @f:  the scanner function for items in the hash
901
 * @data:  extra data passed to f
902
 *
903
 * Scan the hash @table and applied @f to each value matching
904
 * (@name, @name2, @name3) tuple. If one of the names is null,
905
 * the comparison is considered to match.
906
 */
907
void
908
xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, 
909
	     const xmlChar *name2, const xmlChar *name3,
910
	     xmlHashScanner f, void *data) {
911
    xmlHashScanFull3 (table, name, name2, name3,
912
		      (xmlHashScannerFull) f, data);
913
}
914
915
/**
916
 * xmlHashScanFull3:
917
 * @table: the hash table
918
 * @name: the name of the userdata or NULL
919
 * @name2: a second name of the userdata or NULL
920
 * @name3: a third name of the userdata or NULL
921
 * @f:  the scanner function for items in the hash
922
 * @data:  extra data passed to f
923
 *
924
 * Scan the hash @table and applied @f to each value matching
925
 * (@name, @name2, @name3) tuple. If one of the names is null,
926
 * the comparison is considered to match.
927
 */
928
void
929
xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, 
930
		 const xmlChar *name2, const xmlChar *name3,
931
		 xmlHashScannerFull f, void *data) {
932
    int i;
933
    xmlHashEntryPtr iter;
934
    xmlHashEntryPtr next;
935
936
    if (table == NULL)
937
	return;
938
    if (f == NULL)
939
	return;
940
941
    if (table->table) {
942
	for(i = 0; i < table->size; i++) {
943
	    if (table->table[i].valid == 0)
944
		continue;
945
	    iter = &(table->table[i]);
946
	    while (iter) {
947
		next = iter->next;
948
		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
949
		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
950
		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
951
		    (iter->payload != NULL)) {
952
		    f(iter->payload, data, iter->name,
953
		      iter->name2, iter->name3);
954
		}
955
		iter = next;
956
	    }
957
	}
958
    }
959
}
960
961
/**
962
 * xmlHashCopy:
963
 * @table: the hash table
964
 * @f:  the copier function for items in the hash
965
 *
966
 * Scan the hash @table and applied @f to each value.
967
 *
968
 * Returns the new table or NULL in case of error.
969
 */
970
xmlHashTablePtr
971
xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
972
    int i;
973
    xmlHashEntryPtr iter;
974
    xmlHashEntryPtr next;
975
    xmlHashTablePtr ret;
976
977
    if (table == NULL)
978
	return(NULL);
979
    if (f == NULL)
980
	return(NULL);
981
982
    ret = xmlHashCreate(table->size);
983
    if (table->table) {
984
	for(i = 0; i < table->size; i++) {
985
	    if (table->table[i].valid == 0)
986
		continue;
987
	    iter = &(table->table[i]);
988
	    while (iter) {
989
		next = iter->next;
990
		xmlHashAddEntry3(ret, iter->name, iter->name2,
991
			         iter->name3, f(iter->payload, iter->name));
992
		iter = next;
993
	    }
994
	}
995
    }
996
    ret->nbElems = table->nbElems;
997
    return(ret);
998
}
999
1000
/**
1001
 * xmlHashSize:
1002
 * @table: the hash table
1003
 *
1004
 * Query the number of elements installed in the hash @table.
1005
 *
1006
 * Returns the number of elements in the hash table or
1007
 * -1 in case of error
1008
 */
1009
int
1010
xmlHashSize(xmlHashTablePtr table) {
1011
    if (table == NULL)
1012
	return(-1);
1013
    return(table->nbElems);
1014
}
1015
1016
/**
1017
 * xmlHashRemoveEntry:
1018
 * @table: the hash table
1019
 * @name: the name of the userdata
1020
 * @f: the deallocator function for removed item (if any)
1021
 *
1022
 * Find the userdata specified by the @name and remove
1023
 * it from the hash @table. Existing userdata for this tuple will be removed
1024
 * and freed with @f.
1025
 *
1026
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1027
 */
1028
int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
1029
		       xmlHashDeallocator f) {
1030
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1031
}
1032
1033
/**
1034
 * xmlHashRemoveEntry2:
1035
 * @table: the hash table
1036
 * @name: the name of the userdata
1037
 * @name2: a second name of the userdata
1038
 * @f: the deallocator function for removed item (if any)
1039
 *
1040
 * Find the userdata specified by the (@name, @name2) tuple and remove
1041
 * it from the hash @table. Existing userdata for this tuple will be removed
1042
 * and freed with @f.
1043
 *
1044
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1045
 */
1046
int
1047
xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
1048
			const xmlChar *name2, xmlHashDeallocator f) {
1049
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1050
}
1051
1052
/**
1053
 * xmlHashRemoveEntry3:
1054
 * @table: the hash table
1055
 * @name: the name of the userdata
1056
 * @name2: a second name of the userdata
1057
 * @name3: a third name of the userdata
1058
 * @f: the deallocator function for removed item (if any)
1059
 *
1060
 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1061
 * it from the hash @table. Existing userdata for this tuple will be removed
1062
 * and freed with @f.
1063
 *
1064
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1065
 */
1066
int
1067
xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
1068
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1069
    unsigned long key;
1070
    xmlHashEntryPtr entry;
1071
    xmlHashEntryPtr prev = NULL;
1072
1073
    if (table == NULL || name == NULL)
1074
        return(-1);
1075
1076
    key = xmlHashComputeKey(table, name, name2, name3);
1077
    if (table->table[key].valid == 0) {
1078
        return(-1);
1079
    } else {
1080
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1081
            if (xmlStrEqual(entry->name, name) &&
1082
                    xmlStrEqual(entry->name2, name2) &&
1083
                    xmlStrEqual(entry->name3, name3)) {
1084
                if ((f != NULL) && (entry->payload != NULL))
1085
                    f(entry->payload, entry->name);
1086
                entry->payload = NULL;
1087
		if (table->dict == NULL) {
1088
		    if(entry->name)
1089
			xmlFree(entry->name);
1090
		    if(entry->name2)
1091
			xmlFree(entry->name2);
1092
		    if(entry->name3)
1093
			xmlFree(entry->name3);
1094
		}
1095
                if(prev) {
1096
                    prev->next = entry->next;
1097
		    xmlFree(entry);
1098
		} else {
1099
		    if (entry->next == NULL) {
1100
			entry->valid = 0;
1101
		    } else {
1102
			entry = entry->next;
1103
			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1104
			xmlFree(entry);
1105
		    }
1106
		}
1107
                table->nbElems--;
1108
                return(0);
1109
            }
1110
            prev = entry;
1111
        }
1112
        return(-1);
1113
    }
1114
}
1115
1116
#define bottom_hash
1117
#include "elfgcchack.h"