Coverage Report

Created: 2026-04-29 07:28

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
318k
#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.07M
            const xmlChar *name2, const xmlChar *name3) {
84
6.07M
    unsigned long value = 0L;
85
6.07M
    char ch;
86
87
6.07M
#ifdef HASH_RANDOMIZATION
88
6.07M
    value = table->random_seed;
89
6.07M
#endif
90
6.07M
    if (name != NULL) {
91
6.07M
  value += 30 * (*name);
92
4.91G
  while ((ch = *name++) != 0) {
93
4.90G
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
94
4.90G
  }
95
6.07M
    }
96
6.07M
    value = value ^ ((value << 5) + (value >> 3));
97
6.07M
    if (name2 != NULL) {
98
41.1M
  while ((ch = *name2++) != 0) {
99
40.3M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
100
40.3M
  }
101
799k
    }
102
6.07M
    value = value ^ ((value << 5) + (value >> 3));
103
6.07M
    if (name3 != NULL) {
104
17.3M
  while ((ch = *name3++) != 0) {
105
16.5M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
106
16.5M
  }
107
788k
    }
108
6.07M
    return (value % table->size);
109
6.07M
}
110
111
static unsigned long
112
xmlHashComputeQKey(xmlHashTablePtr table,
113
       const xmlChar *prefix, const xmlChar *name,
114
       const xmlChar *prefix2, const xmlChar *name2,
115
486k
       const xmlChar *prefix3, const xmlChar *name3) {
116
486k
    unsigned long value = 0L;
117
486k
    char ch;
118
119
486k
#ifdef HASH_RANDOMIZATION
120
486k
    value = table->random_seed;
121
486k
#endif
122
486k
    if (prefix != NULL)
123
24.6k
  value += 30 * (*prefix);
124
461k
    else
125
461k
  value += 30 * (*name);
126
127
486k
    if (prefix != NULL) {
128
107k
  while ((ch = *prefix++) != 0) {
129
82.3k
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
130
82.3k
  }
131
24.6k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
132
24.6k
    }
133
486k
    if (name != NULL) {
134
2.10M
  while ((ch = *name++) != 0) {
135
1.62M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
136
1.62M
  }
137
486k
    }
138
486k
    value = value ^ ((value << 5) + (value >> 3));
139
486k
    if (prefix2 != NULL) {
140
679k
  while ((ch = *prefix2++) != 0) {
141
577k
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
142
577k
  }
143
102k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
144
102k
    }
145
486k
    if (name2 != NULL) {
146
2.76M
  while ((ch = *name2++) != 0) {
147
2.28M
      value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
148
2.28M
  }
149
486k
    }
150
486k
    value = value ^ ((value << 5) + (value >> 3));
151
486k
    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
486k
    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
486k
    return (value % table->size);
163
486k
}
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
110k
xmlHashCreate(int size) {
175
110k
    xmlHashTablePtr table;
176
177
110k
    if (size <= 0)
178
84.2k
        size = 256;
179
180
110k
    table = xmlMalloc(sizeof(xmlHashTable));
181
110k
    if (table) {
182
110k
        table->dict = NULL;
183
110k
        table->size = size;
184
110k
  table->nbElems = 0;
185
110k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
186
110k
        if (table->table) {
187
110k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
188
110k
#ifdef HASH_RANDOMIZATION
189
110k
            table->random_seed = __xmlRandom();
190
110k
#endif
191
110k
      return(table);
192
110k
        }
193
0
        xmlFree(table);
194
0
    }
195
0
    return(NULL);
196
110k
}
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
110k
xmlHashCreateDict(int size, xmlDictPtr dict) {
209
110k
    xmlHashTablePtr table;
210
211
110k
    table = xmlHashCreate(size);
212
110k
    if (table != NULL) {
213
110k
        table->dict = dict;
214
110k
  xmlDictReference(dict);
215
110k
    }
216
110k
    return(table);
217
110k
}
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
330
xmlHashGrow(xmlHashTablePtr table, int size) {
230
330
    unsigned long key;
231
330
    int oldsize, i;
232
330
    xmlHashEntryPtr iter, next;
233
330
    struct _xmlHashEntry *oldtable;
234
#ifdef DEBUG_GROW
235
    unsigned long nbElem = 0;
236
#endif
237
238
330
    if (table == NULL)
239
0
  return(-1);
240
330
    if (size < 8)
241
0
        return(-1);
242
330
    if (size > 8 * 2048)
243
0
  return(-1);
244
245
330
    oldsize = table->size;
246
330
    oldtable = table->table;
247
330
    if (oldtable == NULL)
248
0
        return(-1);
249
250
330
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
251
330
    if (table->table == NULL) {
252
0
  table->table = oldtable;
253
0
  return(-1);
254
0
    }
255
330
    memset(table->table, 0, size * sizeof(xmlHashEntry));
256
330
    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
6.29k
    for (i = 0; i < oldsize; i++) {
265
5.96k
  if (oldtable[i].valid == 0)
266
64
      continue;
267
5.89k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
268
5.89k
        oldtable[i].name3);
269
5.89k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
270
5.89k
  table->table[key].next = NULL;
271
5.89k
    }
272
273
6.29k
    for (i = 0; i < oldsize; i++) {
274
5.96k
  iter = oldtable[i].next;
275
31.0k
  while (iter) {
276
25.1k
      next = iter->next;
277
278
      /*
279
       * put back the entry in the new table
280
       */
281
282
25.1k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
283
25.1k
                        iter->name3);
284
25.1k
      if (table->table[key].valid == 0) {
285
16.5k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
286
16.5k
    table->table[key].next = NULL;
287
16.5k
    xmlFree(iter);
288
16.5k
      } else {
289
8.55k
    iter->next = table->table[key].next;
290
8.55k
    table->table[key].next = iter;
291
8.55k
      }
292
293
#ifdef DEBUG_GROW
294
      nbElem++;
295
#endif
296
297
25.1k
      iter = next;
298
25.1k
  }
299
5.96k
    }
300
301
330
    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
330
    return(0);
309
330
}
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
110k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
321
110k
    int i;
322
110k
    xmlHashEntryPtr iter;
323
110k
    xmlHashEntryPtr next;
324
110k
    int inside_table = 0;
325
110k
    int nbElems;
326
327
110k
    if (table == NULL)
328
0
  return;
329
110k
    if (table->table) {
330
110k
  nbElems = table->nbElems;
331
12.1M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
332
12.0M
      iter = &(table->table[i]);
333
12.0M
      if (iter->valid == 0)
334
11.8M
    continue;
335
266k
      inside_table = 1;
336
592k
      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
59.5k
        xmlFree(iter);
351
325k
    nbElems--;
352
325k
    inside_table = 0;
353
325k
    iter = next;
354
325k
      }
355
266k
  }
356
110k
  xmlFree(table->table);
357
110k
    }
358
110k
    if (table->dict)
359
110k
        xmlDictFree(table->dict);
360
110k
    xmlFree(table);
361
110k
}
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
430k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
376
430k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
377
430k
}
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
113k
          const xmlChar *name2, void *userdata) {
394
113k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
395
113k
}
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
27.9k
       xmlHashDeallocator f) {
434
27.9k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
435
27.9k
}
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.01M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
448
3.01M
    return(xmlHashLookup3(table, name, NULL, NULL));
449
3.01M
}
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.65M
        const xmlChar *name2) {
464
1.65M
    return(xmlHashLookup3(table, name, name2, NULL));
465
1.65M
}
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
486k
          const xmlChar *name2) {
499
486k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
500
486k
}
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
222k
      name = xmlDictLookup(table->dict, name, -1);
533
222k
      if (name == NULL)
534
0
          return(-1);
535
222k
  }
536
778k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
537
4.07k
      name2 = xmlDictLookup(table->dict, name2, -1);
538
4.07k
      if (name2 == NULL)
539
0
          return(-1);
540
4.07k
  }
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
674k
      for (insert = &(table->table[key]); insert->next != NULL;
557
539k
     insert = insert->next) {
558
149k
    if ((insert->name == name) &&
559
36.1k
        (insert->name2 == name2) &&
560
15.7k
        (insert->name3 == name3))
561
15.0k
        return(-1);
562
134k
    len++;
563
134k
      }
564
524k
      if ((insert->name == name) &&
565
468k
    (insert->name2 == name2) &&
566
445k
    (insert->name3 == name3))
567
444k
    return(-1);
568
524k
  } 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
318k
    if (insert == NULL) {
585
238k
  entry = &(table->table[key]);
586
238k
    } else {
587
79.9k
  entry = xmlMalloc(sizeof(xmlHashEntry));
588
79.9k
  if (entry == NULL)
589
0
       return(-1);
590
79.9k
    }
591
592
318k
    if (table->dict != NULL) {
593
318k
        entry->name = (xmlChar *) name;
594
318k
        entry->name2 = (xmlChar *) name2;
595
318k
        entry->name3 = (xmlChar *) name3;
596
318k
    } else {
597
0
  entry->name = xmlStrdup(name);
598
0
  entry->name2 = xmlStrdup(name2);
599
0
  entry->name3 = xmlStrdup(name3);
600
0
    }
601
318k
    entry->payload = userdata;
602
318k
    entry->next = NULL;
603
318k
    entry->valid = 1;
604
605
606
318k
    if (insert != NULL)
607
79.9k
  insert->next = entry;
608
609
318k
    table->nbElems++;
610
611
318k
    if (len > MAX_HASH_LEN)
612
330
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
613
614
318k
    return(0);
615
318k
}
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
27.9k
       void *userdata, xmlHashDeallocator f) {
636
27.9k
    unsigned long key;
637
27.9k
    xmlHashEntryPtr entry;
638
27.9k
    xmlHashEntryPtr insert;
639
640
27.9k
    if ((table == NULL) || name == NULL)
641
0
  return(-1);
642
643
    /*
644
     * If using a dict internalize if needed
645
     */
646
27.9k
    if (table->dict) {
647
27.9k
        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
27.9k
        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
27.9k
        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
27.9k
    }
663
664
    /*
665
     * Check for duplicate and insertion location.
666
     */
667
27.9k
    key = xmlHashComputeKey(table, name, name2, name3);
668
27.9k
    if (table->table[key].valid == 0) {
669
15.4k
  insert = NULL;
670
15.4k
    } else {
671
12.4k
        if (table ->dict) {
672
21.3k
      for (insert = &(table->table[key]); insert->next != NULL;
673
12.4k
     insert = insert->next) {
674
9.06k
    if ((insert->name == name) &&
675
1.76k
        (insert->name2 == name2) &&
676
204
        (insert->name3 == name3)) {
677
204
        if (f)
678
0
      f(insert->payload, insert->name);
679
204
        insert->payload = userdata;
680
204
        return(0);
681
204
    }
682
9.06k
      }
683
12.2k
      if ((insert->name == name) &&
684
10.2k
    (insert->name2 == name2) &&
685
9.80k
    (insert->name3 == name3)) {
686
9.80k
    if (f)
687
0
        f(insert->payload, insert->name);
688
9.80k
    insert->payload = userdata;
689
9.80k
    return(0);
690
9.80k
      }
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
17.9k
    if (insert == NULL) {
715
15.4k
  entry =  &(table->table[key]);
716
15.4k
    } else {
717
2.47k
  entry = xmlMalloc(sizeof(xmlHashEntry));
718
2.47k
  if (entry == NULL)
719
0
       return(-1);
720
2.47k
    }
721
722
17.9k
    if (table->dict != NULL) {
723
17.9k
        entry->name = (xmlChar *) name;
724
17.9k
        entry->name2 = (xmlChar *) name2;
725
17.9k
        entry->name3 = (xmlChar *) name3;
726
17.9k
    } else {
727
0
  entry->name = xmlStrdup(name);
728
0
  entry->name2 = xmlStrdup(name2);
729
0
  entry->name3 = xmlStrdup(name3);
730
0
    }
731
17.9k
    entry->payload = userdata;
732
17.9k
    entry->next = NULL;
733
17.9k
    entry->valid = 1;
734
17.9k
    table->nbElems++;
735
736
737
17.9k
    if (insert != NULL) {
738
2.47k
  insert->next = entry;
739
2.47k
    }
740
17.9k
    return(0);
741
17.9k
}
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.22M
         const xmlChar *name2, const xmlChar *name3) {
757
5.22M
    unsigned long key;
758
5.22M
    xmlHashEntryPtr entry;
759
760
5.22M
    if (table == NULL)
761
0
  return(NULL);
762
5.22M
    if (name == NULL)
763
0
  return(NULL);
764
5.22M
    key = xmlHashComputeKey(table, name, name2, name3);
765
5.22M
    if (table->table[key].valid == 0)
766
2.09M
  return(NULL);
767
3.12M
    if (table->dict) {
768
4.81M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
769
3.55M
      if ((entry->name == name) &&
770
2.02M
    (entry->name2 == name2) &&
771
1.86M
    (entry->name3 == name3))
772
1.86M
    return(entry->payload);
773
3.55M
  }
774
3.12M
    }
775
1.71M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
776
1.48M
  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.48M
    }
781
229k
    return(NULL);
782
1.26M
}
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
486k
    const xmlChar *prefix3, const xmlChar *name3) {
803
486k
    unsigned long key;
804
486k
    xmlHashEntryPtr entry;
805
806
486k
    if (table == NULL)
807
0
  return(NULL);
808
486k
    if (name == NULL)
809
0
  return(NULL);
810
486k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
811
486k
                             name2, prefix3, name3);
812
486k
    if (table->table[key].valid == 0)
813
344k
  return(NULL);
814
206k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
815
155k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
816
110k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
817
90.6k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
818
90.6k
      return(entry->payload);
819
155k
    }
820
51.2k
    return(NULL);
821
141k
}
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.6k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
862
13.6k
    int i, nb;
863
13.6k
    xmlHashEntryPtr iter;
864
13.6k
    xmlHashEntryPtr next;
865
866
13.6k
    if (table == NULL)
867
0
  return;
868
13.6k
    if (f == NULL)
869
0
  return;
870
871
13.6k
    if (table->table) {
872
192k
  for(i = 0; i < table->size; i++) {
873
178k
      if (table->table[i].valid == 0)
874
126k
    continue;
875
51.5k
      iter = &(table->table[i]);
876
143k
      while (iter) {
877
92.0k
    next = iter->next;
878
92.0k
                nb = table->nbElems;
879
92.0k
    if ((f != NULL) && (iter->payload != NULL))
880
92.0k
        f(iter->payload, data, iter->name,
881
92.0k
          iter->name2, iter->name3);
882
92.0k
                if (nb != table->nbElems) {
883
                    /* table was modified by the callback, be careful */
884
9.24k
                    if (iter == &(table->table[i])) {
885
5.52k
                        if (table->table[i].valid == 0)
886
2.97k
                            iter = NULL;
887
5.52k
                        if (table->table[i].next != next)
888
2.54k
          iter = &(table->table[i]);
889
5.52k
                    } else
890
3.72k
            iter = next;
891
9.24k
                } else
892
82.7k
        iter = next;
893
92.0k
      }
894
51.5k
  }
895
13.6k
    }
896
13.6k
}
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.6k
xmlHashSize(xmlHashTablePtr table) {
1018
13.6k
    if (table == NULL)
1019
0
  return(-1);
1020
13.6k
    return(table->nbElems);
1021
13.6k
}
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
1.01k
           xmlHashDeallocator f) {
1037
1.01k
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1038
1.01k
}
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
9.24k
      const xmlChar *name2, xmlHashDeallocator f) {
1056
9.24k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1057
9.24k
}
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
10.2k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1076
10.2k
    unsigned long key;
1077
10.2k
    xmlHashEntryPtr entry;
1078
10.2k
    xmlHashEntryPtr prev = NULL;
1079
1080
10.2k
    if (table == NULL || name == NULL)
1081
0
        return(-1);
1082
1083
10.2k
    key = xmlHashComputeKey(table, name, name2, name3);
1084
10.2k
    if (table->table[key].valid == 0) {
1085
0
        return(-1);
1086
10.2k
    } else {
1087
17.5k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1088
17.5k
            if (xmlStrEqual(entry->name, name) &&
1089
11.2k
                    xmlStrEqual(entry->name2, name2) &&
1090
10.2k
                    xmlStrEqual(entry->name3, name3)) {
1091
10.2k
                if ((f != NULL) && (entry->payload != NULL))
1092
1.01k
                    f(entry->payload, entry->name);
1093
10.2k
                entry->payload = NULL;
1094
10.2k
    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
10.2k
                if(prev) {
1103
3.73k
                    prev->next = entry->next;
1104
3.73k
        xmlFree(entry);
1105
6.52k
    } else {
1106
6.52k
        if (entry->next == NULL) {
1107
3.96k
      entry->valid = 0;
1108
3.96k
        } else {
1109
2.55k
      entry = entry->next;
1110
2.55k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1111
2.55k
      xmlFree(entry);
1112
2.55k
        }
1113
6.52k
    }
1114
10.2k
                table->nbElems--;
1115
10.2k
                return(0);
1116
10.2k
            }
1117
7.32k
            prev = entry;
1118
7.32k
        }
1119
0
        return(-1);
1120
10.2k
    }
1121
10.2k
}
1122
1123
#define bottom_hash
1124
#include "elfgcchack.h"