Coverage Report

Created: 2024-05-29 15:23

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