Coverage Report

Created: 2026-03-12 06:42

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
270k
#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
5.58M
            const xmlChar *name2, const xmlChar *name3) {
84
5.58M
    unsigned long value = 0L;
85
5.58M
    char ch;
86
87
5.58M
#ifdef HASH_RANDOMIZATION
88
5.58M
    value = table->random_seed;
89
5.58M
#endif
90
5.58M
    if (name != NULL) {
91
5.58M
  value += 30 * (*name);
92
3.88G
  while ((ch = *name++) != 0) {
93
3.87G
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
94
3.87G
  }
95
5.58M
    }
96
5.58M
    value = value ^ ((value << 5) + (value >> 3));
97
5.58M
    if (name2 != NULL) {
98
40.2M
  while ((ch = *name2++) != 0) {
99
39.6M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
100
39.6M
  }
101
656k
    }
102
5.58M
    value = value ^ ((value << 5) + (value >> 3));
103
5.58M
    if (name3 != NULL) {
104
11.2M
  while ((ch = *name3++) != 0) {
105
10.4M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
106
10.4M
  }
107
723k
    }
108
5.58M
    return (value % table->size);
109
5.58M
}
110
111
static unsigned long
112
xmlHashComputeQKey(xmlHashTablePtr table,
113
       const xmlChar *prefix, const xmlChar *name,
114
       const xmlChar *prefix2, const xmlChar *name2,
115
466k
       const xmlChar *prefix3, const xmlChar *name3) {
116
466k
    unsigned long value = 0L;
117
466k
    char ch;
118
119
466k
#ifdef HASH_RANDOMIZATION
120
466k
    value = table->random_seed;
121
466k
#endif
122
466k
    if (prefix != NULL)
123
20.0k
  value += 30 * (*prefix);
124
446k
    else
125
446k
  value += 30 * (*name);
126
127
466k
    if (prefix != NULL) {
128
85.3k
  while ((ch = *prefix++) != 0) {
129
65.3k
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
130
65.3k
  }
131
20.0k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
132
20.0k
    }
133
466k
    if (name != NULL) {
134
1.97M
  while ((ch = *name++) != 0) {
135
1.50M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
136
1.50M
  }
137
466k
    }
138
466k
    value = value ^ ((value << 5) + (value >> 3));
139
466k
    if (prefix2 != NULL) {
140
849k
  while ((ch = *prefix2++) != 0) {
141
752k
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
142
752k
  }
143
97.1k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
144
97.1k
    }
145
466k
    if (name2 != NULL) {
146
2.83M
  while ((ch = *name2++) != 0) {
147
2.36M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
148
2.36M
  }
149
466k
    }
150
466k
    value = value ^ ((value << 5) + (value >> 3));
151
466k
    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
466k
    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
466k
    return (value % table->size);
163
466k
}
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
104k
xmlHashCreate(int size) {
175
104k
    xmlHashTablePtr table;
176
177
104k
    if (size <= 0)
178
79.7k
        size = 256;
179
180
104k
    table = xmlMalloc(sizeof(xmlHashTable));
181
104k
    if (table) {
182
104k
        table->dict = NULL;
183
104k
        table->size = size;
184
104k
  table->nbElems = 0;
185
104k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
186
104k
        if (table->table) {
187
104k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
188
104k
#ifdef HASH_RANDOMIZATION
189
104k
            table->random_seed = __xmlRandom();
190
104k
#endif
191
104k
      return(table);
192
104k
        }
193
0
        xmlFree(table);
194
0
    }
195
0
    return(NULL);
196
104k
}
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
104k
xmlHashCreateDict(int size, xmlDictPtr dict) {
209
104k
    xmlHashTablePtr table;
210
211
104k
    table = xmlHashCreate(size);
212
104k
    if (table != NULL) {
213
104k
        table->dict = dict;
214
104k
  xmlDictReference(dict);
215
104k
    }
216
104k
    return(table);
217
104k
}
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
240
xmlHashGrow(xmlHashTablePtr table, int size) {
230
240
    unsigned long key;
231
240
    int oldsize, i;
232
240
    xmlHashEntryPtr iter, next;
233
240
    struct _xmlHashEntry *oldtable;
234
#ifdef DEBUG_GROW
235
    unsigned long nbElem = 0;
236
#endif
237
238
240
    if (table == NULL)
239
0
  return(-1);
240
240
    if (size < 8)
241
0
        return(-1);
242
240
    if (size > 8 * 2048)
243
0
  return(-1);
244
245
240
    oldsize = table->size;
246
240
    oldtable = table->table;
247
240
    if (oldtable == NULL)
248
0
        return(-1);
249
250
240
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
251
240
    if (table->table == NULL) {
252
0
  table->table = oldtable;
253
0
  return(-1);
254
0
    }
255
240
    memset(table->table, 0, size * sizeof(xmlHashEntry));
256
240
    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
4.49k
    for (i = 0; i < oldsize; i++) {
265
4.25k
  if (oldtable[i].valid == 0)
266
78
      continue;
267
4.17k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
268
4.17k
        oldtable[i].name3);
269
4.17k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
270
4.17k
  table->table[key].next = NULL;
271
4.17k
    }
272
273
4.49k
    for (i = 0; i < oldsize; i++) {
274
4.25k
  iter = oldtable[i].next;
275
22.3k
  while (iter) {
276
18.0k
      next = iter->next;
277
278
      /*
279
       * put back the entry in the new table
280
       */
281
282
18.0k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
283
18.0k
                        iter->name3);
284
18.0k
      if (table->table[key].valid == 0) {
285
11.8k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
286
11.8k
    table->table[key].next = NULL;
287
11.8k
    xmlFree(iter);
288
11.8k
      } else {
289
6.21k
    iter->next = table->table[key].next;
290
6.21k
    table->table[key].next = iter;
291
6.21k
      }
292
293
#ifdef DEBUG_GROW
294
      nbElem++;
295
#endif
296
297
18.0k
      iter = next;
298
18.0k
  }
299
4.25k
    }
300
301
240
    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
240
    return(0);
309
240
}
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
104k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
321
104k
    int i;
322
104k
    xmlHashEntryPtr iter;
323
104k
    xmlHashEntryPtr next;
324
104k
    int inside_table = 0;
325
104k
    int nbElems;
326
327
104k
    if (table == NULL)
328
0
  return;
329
104k
    if (table->table) {
330
104k
  nbElems = table->nbElems;
331
11.5M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
332
11.4M
      iter = &(table->table[i]);
333
11.4M
      if (iter->valid == 0)
334
11.2M
    continue;
335
235k
      inside_table = 1;
336
514k
      while (iter) {
337
278k
    next = iter->next;
338
278k
    if ((f != NULL) && (iter->payload != NULL))
339
212k
        f(iter->payload, iter->name);
340
278k
    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
278k
    iter->payload = NULL;
349
278k
    if (!inside_table)
350
42.5k
        xmlFree(iter);
351
278k
    nbElems--;
352
278k
    inside_table = 0;
353
278k
    iter = next;
354
278k
      }
355
235k
  }
356
104k
  xmlFree(table->table);
357
104k
    }
358
104k
    if (table->dict)
359
104k
        xmlDictFree(table->dict);
360
104k
    xmlFree(table);
361
104k
}
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
399k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
376
399k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
377
399k
}
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
90.7k
          const xmlChar *name2, void *userdata) {
394
90.7k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
395
90.7k
}
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
23.0k
       xmlHashDeallocator f) {
434
23.0k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
435
23.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
2.82M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
448
2.82M
    return(xmlHashLookup3(table, name, NULL, NULL));
449
2.82M
}
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.49M
        const xmlChar *name2) {
464
1.49M
    return(xmlHashLookup3(table, name, name2, NULL));
465
1.49M
}
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
466k
          const xmlChar *name2) {
499
466k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
500
466k
}
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
692k
     void *userdata) {
520
692k
    unsigned long key, len = 0;
521
692k
    xmlHashEntryPtr entry;
522
692k
    xmlHashEntryPtr insert;
523
524
692k
    if ((table == NULL) || (name == NULL))
525
0
  return(-1);
526
527
    /*
528
     * If using a dict internalize if needed
529
     */
530
692k
    if (table->dict) {
531
692k
        if (!xmlDictOwns(table->dict, name)) {
532
196k
      name = xmlDictLookup(table->dict, name, -1);
533
196k
      if (name == NULL)
534
0
          return(-1);
535
196k
  }
536
692k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
537
3.20k
      name2 = xmlDictLookup(table->dict, name2, -1);
538
3.20k
      if (name2 == NULL)
539
0
          return(-1);
540
3.20k
  }
541
692k
        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
692k
    }
547
548
    /*
549
     * Check for duplicate and insertion location.
550
     */
551
692k
    key = xmlHashComputeKey(table, name, name2, name3);
552
692k
    if (table->table[key].valid == 0) {
553
213k
  insert = NULL;
554
479k
    } else {
555
479k
        if (table->dict) {
556
576k
      for (insert = &(table->table[key]); insert->next != NULL;
557
479k
     insert = insert->next) {
558
110k
    if ((insert->name == name) &&
559
31.9k
        (insert->name2 == name2) &&
560
14.2k
        (insert->name3 == name3))
561
13.7k
        return(-1);
562
96.3k
    len++;
563
96.3k
      }
564
466k
      if ((insert->name == name) &&
565
428k
    (insert->name2 == name2) &&
566
409k
    (insert->name3 == name3))
567
409k
    return(-1);
568
466k
  } 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
479k
    }
583
584
270k
    if (insert == NULL) {
585
213k
  entry = &(table->table[key]);
586
213k
    } else {
587
57.0k
  entry = xmlMalloc(sizeof(xmlHashEntry));
588
57.0k
  if (entry == NULL)
589
0
       return(-1);
590
57.0k
    }
591
592
270k
    if (table->dict != NULL) {
593
270k
        entry->name = (xmlChar *) name;
594
270k
        entry->name2 = (xmlChar *) name2;
595
270k
        entry->name3 = (xmlChar *) name3;
596
270k
    } else {
597
0
  entry->name = xmlStrdup(name);
598
0
  entry->name2 = xmlStrdup(name2);
599
0
  entry->name3 = xmlStrdup(name3);
600
0
    }
601
270k
    entry->payload = userdata;
602
270k
    entry->next = NULL;
603
270k
    entry->valid = 1;
604
605
606
270k
    if (insert != NULL)
607
57.0k
  insert->next = entry;
608
609
270k
    table->nbElems++;
610
611
270k
    if (len > MAX_HASH_LEN)
612
240
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
613
614
270k
    return(0);
615
270k
}
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
23.0k
       void *userdata, xmlHashDeallocator f) {
636
23.0k
    unsigned long key;
637
23.0k
    xmlHashEntryPtr entry;
638
23.0k
    xmlHashEntryPtr insert;
639
640
23.0k
    if ((table == NULL) || name == NULL)
641
0
  return(-1);
642
643
    /*
644
     * If using a dict internalize if needed
645
     */
646
23.0k
    if (table->dict) {
647
23.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
23.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
23.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
23.0k
    }
663
664
    /*
665
     * Check for duplicate and insertion location.
666
     */
667
23.0k
    key = xmlHashComputeKey(table, name, name2, name3);
668
23.0k
    if (table->table[key].valid == 0) {
669
14.0k
  insert = NULL;
670
14.0k
    } else {
671
8.94k
        if (table ->dict) {
672
13.9k
      for (insert = &(table->table[key]); insert->next != NULL;
673
8.94k
     insert = insert->next) {
674
5.12k
    if ((insert->name == name) &&
675
1.17k
        (insert->name2 == name2) &&
676
130
        (insert->name3 == name3)) {
677
130
        if (f)
678
0
      f(insert->payload, insert->name);
679
130
        insert->payload = userdata;
680
130
        return(0);
681
130
    }
682
5.12k
      }
683
8.81k
      if ((insert->name == name) &&
684
7.53k
    (insert->name2 == name2) &&
685
7.23k
    (insert->name3 == name3)) {
686
7.23k
    if (f)
687
0
        f(insert->payload, insert->name);
688
7.23k
    insert->payload = userdata;
689
7.23k
    return(0);
690
7.23k
      }
691
8.81k
  } 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
8.94k
    }
713
714
15.6k
    if (insert == NULL) {
715
14.0k
  entry =  &(table->table[key]);
716
14.0k
    } else {
717
1.58k
  entry = xmlMalloc(sizeof(xmlHashEntry));
718
1.58k
  if (entry == NULL)
719
0
       return(-1);
720
1.58k
    }
721
722
15.6k
    if (table->dict != NULL) {
723
15.6k
        entry->name = (xmlChar *) name;
724
15.6k
        entry->name2 = (xmlChar *) name2;
725
15.6k
        entry->name3 = (xmlChar *) name3;
726
15.6k
    } else {
727
0
  entry->name = xmlStrdup(name);
728
0
  entry->name2 = xmlStrdup(name2);
729
0
  entry->name3 = xmlStrdup(name3);
730
0
    }
731
15.6k
    entry->payload = userdata;
732
15.6k
    entry->next = NULL;
733
15.6k
    entry->valid = 1;
734
15.6k
    table->nbElems++;
735
736
737
15.6k
    if (insert != NULL) {
738
1.58k
  insert->next = entry;
739
1.58k
    }
740
15.6k
    return(0);
741
15.6k
}
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
4.83M
         const xmlChar *name2, const xmlChar *name3) {
757
4.83M
    unsigned long key;
758
4.83M
    xmlHashEntryPtr entry;
759
760
4.83M
    if (table == NULL)
761
0
  return(NULL);
762
4.83M
    if (name == NULL)
763
0
  return(NULL);
764
4.83M
    key = xmlHashComputeKey(table, name, name2, name3);
765
4.83M
    if (table->table[key].valid == 0)
766
1.95M
  return(NULL);
767
2.88M
    if (table->dict) {
768
4.31M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
769
3.19M
      if ((entry->name == name) &&
770
1.90M
    (entry->name2 == name2) &&
771
1.76M
    (entry->name3 == name3))
772
1.76M
    return(entry->payload);
773
3.19M
  }
774
2.88M
    }
775
1.45M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
776
1.26M
  if ((xmlStrEqual(entry->name, name)) &&
777
1.00M
      (xmlStrEqual(entry->name2, name2)) &&
778
936k
      (xmlStrEqual(entry->name3, name3)))
779
936k
      return(entry->payload);
780
1.26M
    }
781
181k
    return(NULL);
782
1.11M
}
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
466k
    const xmlChar *prefix3, const xmlChar *name3) {
803
466k
    unsigned long key;
804
466k
    xmlHashEntryPtr entry;
805
806
466k
    if (table == NULL)
807
0
  return(NULL);
808
466k
    if (name == NULL)
809
0
  return(NULL);
810
466k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
811
466k
                             name2, prefix3, name3);
812
466k
    if (table->table[key].valid == 0)
813
334k
  return(NULL);
814
198k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
815
152k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
816
119k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
817
85.9k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
818
85.9k
      return(entry->payload);
819
152k
    }
820
46.4k
    return(NULL);
821
132k
}
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
12.8k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
862
12.8k
    int i, nb;
863
12.8k
    xmlHashEntryPtr iter;
864
12.8k
    xmlHashEntryPtr next;
865
866
12.8k
    if (table == NULL)
867
0
  return;
868
12.8k
    if (f == NULL)
869
0
  return;
870
871
12.8k
    if (table->table) {
872
169k
  for(i = 0; i < table->size; i++) {
873
156k
      if (table->table[i].valid == 0)
874
114k
    continue;
875
42.0k
      iter = &(table->table[i]);
876
114k
      while (iter) {
877
72.0k
    next = iter->next;
878
72.0k
                nb = table->nbElems;
879
72.0k
    if ((f != NULL) && (iter->payload != NULL))
880
72.0k
        f(iter->payload, data, iter->name,
881
72.0k
          iter->name2, iter->name3);
882
72.0k
                if (nb != table->nbElems) {
883
                    /* table was modified by the callback, be careful */
884
6.33k
                    if (iter == &(table->table[i])) {
885
4.09k
                        if (table->table[i].valid == 0)
886
2.16k
                            iter = NULL;
887
4.09k
                        if (table->table[i].next != next)
888
1.92k
          iter = &(table->table[i]);
889
4.09k
                    } else
890
2.24k
            iter = next;
891
6.33k
                } else
892
65.7k
        iter = next;
893
72.0k
      }
894
42.0k
  }
895
12.8k
    }
896
12.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
12.8k
xmlHashSize(xmlHashTablePtr table) {
1018
12.8k
    if (table == NULL)
1019
0
  return(-1);
1020
12.8k
    return(table->nbElems);
1021
12.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
6.33k
      const xmlChar *name2, xmlHashDeallocator f) {
1056
6.33k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1057
6.33k
}
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
7.31k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1076
7.31k
    unsigned long key;
1077
7.31k
    xmlHashEntryPtr entry;
1078
7.31k
    xmlHashEntryPtr prev = NULL;
1079
1080
7.31k
    if (table == NULL || name == NULL)
1081
0
        return(-1);
1082
1083
7.31k
    key = xmlHashComputeKey(table, name, name2, name3);
1084
7.31k
    if (table->table[key].valid == 0) {
1085
0
        return(-1);
1086
7.31k
    } else {
1087
11.2k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1088
11.2k
            if (xmlStrEqual(entry->name, name) &&
1089
8.01k
                    xmlStrEqual(entry->name2, name2) &&
1090
7.31k
                    xmlStrEqual(entry->name3, name3)) {
1091
7.31k
                if ((f != NULL) && (entry->payload != NULL))
1092
980
                    f(entry->payload, entry->name);
1093
7.31k
                entry->payload = NULL;
1094
7.31k
    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
7.31k
                if(prev) {
1103
2.24k
                    prev->next = entry->next;
1104
2.24k
        xmlFree(entry);
1105
5.06k
    } else {
1106
5.06k
        if (entry->next == NULL) {
1107
3.13k
      entry->valid = 0;
1108
3.13k
        } else {
1109
1.93k
      entry = entry->next;
1110
1.93k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1111
1.93k
      xmlFree(entry);
1112
1.93k
        }
1113
5.06k
    }
1114
7.31k
                table->nbElems--;
1115
7.31k
                return(0);
1116
7.31k
            }
1117
3.96k
            prev = entry;
1118
3.96k
        }
1119
0
        return(-1);
1120
7.31k
    }
1121
7.31k
}
1122
1123
#define bottom_hash
1124
#include "elfgcchack.h"