Coverage Report

Created: 2026-05-16 06:38

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