Coverage Report

Created: 2024-01-18 20:16

/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
6.51M
#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
120M
            const xmlChar *name2, const xmlChar *name3) {
85
120M
    unsigned long value = 0L;
86
120M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
120M
    if (name != NULL) {
92
120M
  value += 30 * (*name);
93
1.39G
  while ((ch = *name++) != 0) {
94
1.27G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
1.27G
  }
96
120M
    }
97
120M
    value = value ^ ((value << 5) + (value >> 3));
98
120M
    if (name2 != NULL) {
99
40.7M
  while ((ch = *name2++) != 0) {
100
34.1M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
34.1M
  }
102
6.63M
    }
103
120M
    value = value ^ ((value << 5) + (value >> 3));
104
120M
    if (name3 != NULL) {
105
46.3M
  while ((ch = *name3++) != 0) {
106
39.6M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
39.6M
  }
108
6.68M
    }
109
120M
    return (value % table->size);
110
120M
}
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
978k
       const xmlChar *prefix3, const xmlChar *name3) {
120
978k
    unsigned long value = 0L;
121
978k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
978k
    if (prefix != NULL)
127
96.7k
  value += 30 * (*prefix);
128
882k
    else
129
882k
  value += 30 * (*name);
130
131
978k
    if (prefix != NULL) {
132
405k
  while ((ch = *prefix++) != 0) {
133
309k
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
309k
  }
135
96.7k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
96.7k
    }
137
978k
    if (name != NULL) {
138
5.55M
  while ((ch = *name++) != 0) {
139
4.57M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
4.57M
  }
141
978k
    }
142
978k
    value = value ^ ((value << 5) + (value >> 3));
143
978k
    if (prefix2 != NULL) {
144
406k
  while ((ch = *prefix2++) != 0) {
145
309k
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
309k
  }
147
97.5k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
97.5k
    }
149
978k
    if (name2 != NULL) {
150
3.72M
  while ((ch = *name2++) != 0) {
151
2.74M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
2.74M
  }
153
978k
    }
154
978k
    value = value ^ ((value << 5) + (value >> 3));
155
978k
    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
978k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
978k
    return (value % table->size);
167
978k
}
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
892k
xmlHashCreate(int size) {
179
892k
    xmlHashTablePtr table;
180
181
892k
    if (size <= 0)
182
467k
        size = 256;
183
184
892k
    table = xmlMalloc(sizeof(xmlHashTable));
185
892k
    if (table) {
186
892k
        table->dict = NULL;
187
892k
        table->size = size;
188
892k
  table->nbElems = 0;
189
892k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
892k
        if (table->table) {
191
892k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
892k
      return(table);
196
892k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
892k
}
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
552k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
552k
    xmlHashTablePtr table;
214
215
552k
    table = xmlHashCreate(size);
216
552k
    if (table != NULL) {
217
552k
        table->dict = dict;
218
552k
  xmlDictReference(dict);
219
552k
    }
220
552k
    return(table);
221
552k
}
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
6.23k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
6.23k
    unsigned long key;
235
6.23k
    int oldsize, i;
236
6.23k
    xmlHashEntryPtr iter, next;
237
6.23k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
6.23k
    if (table == NULL)
243
0
  return(-1);
244
6.23k
    if (size < 8)
245
0
        return(-1);
246
6.23k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
6.23k
    oldsize = table->size;
250
6.23k
    oldtable = table->table;
251
6.23k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
6.23k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
6.23k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
6.23k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
6.23k
    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
180k
    for (i = 0; i < oldsize; i++) {
269
174k
  if (oldtable[i].valid == 0)
270
2.26k
      continue;
271
171k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
171k
        oldtable[i].name3);
273
171k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
171k
  table->table[key].next = NULL;
275
171k
    }
276
277
180k
    for (i = 0; i < oldsize; i++) {
278
174k
  iter = oldtable[i].next;
279
867k
  while (iter) {
280
693k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
693k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
693k
                        iter->name3);
288
693k
      if (table->table[key].valid == 0) {
289
467k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
467k
    table->table[key].next = NULL;
291
467k
    xmlFree(iter);
292
467k
      } else {
293
225k
    iter->next = table->table[key].next;
294
225k
    table->table[key].next = iter;
295
225k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
693k
      iter = next;
302
693k
  }
303
174k
    }
304
305
6.23k
    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
6.23k
    return(0);
313
6.23k
}
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
892k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
892k
    int i;
326
892k
    xmlHashEntryPtr iter;
327
892k
    xmlHashEntryPtr next;
328
892k
    int inside_table = 0;
329
892k
    int nbElems;
330
331
892k
    if (table == NULL)
332
0
  return;
333
892k
    if (table->table) {
334
892k
  nbElems = table->nbElems;
335
93.4M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
92.5M
      iter = &(table->table[i]);
337
92.5M
      if (iter->valid == 0)
338
88.0M
    continue;
339
4.49M
      inside_table = 1;
340
10.6M
      while (iter) {
341
6.12M
    next = iter->next;
342
6.12M
    if ((f != NULL) && (iter->payload != NULL))
343
4.93M
        f(iter->payload, iter->name);
344
6.12M
    if (table->dict == NULL) {
345
1.99M
        if (iter->name)
346
1.99M
      xmlFree(iter->name);
347
1.99M
        if (iter->name2)
348
134k
      xmlFree(iter->name2);
349
1.99M
        if (iter->name3)
350
997k
      xmlFree(iter->name3);
351
1.99M
    }
352
6.12M
    iter->payload = NULL;
353
6.12M
    if (!inside_table)
354
1.62M
        xmlFree(iter);
355
6.12M
    nbElems--;
356
6.12M
    inside_table = 0;
357
6.12M
    iter = next;
358
6.12M
      }
359
4.49M
  }
360
892k
  xmlFree(table->table);
361
892k
    }
362
892k
    if (table->dict)
363
374k
        xmlDictFree(table->dict);
364
892k
    xmlFree(table);
365
892k
}
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
328k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
328k
    xmlFree(entry);
377
328k
}
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
1.46M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
1.46M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
1.46M
}
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
2.66M
          const xmlChar *name2, void *userdata) {
410
2.66M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
2.66M
}
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
80.7k
       xmlHashDeallocator f) {
450
80.7k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
80.7k
}
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
97.6M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
97.6M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
97.6M
}
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
11.0M
        const xmlChar *name2) {
480
11.0M
    return(xmlHashLookup3(table, name, name2, NULL));
481
11.0M
}
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
978k
          const xmlChar *name2) {
515
978k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
978k
}
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
6.96M
     void *userdata) {
536
6.96M
    unsigned long key, len = 0;
537
6.96M
    xmlHashEntryPtr entry;
538
6.96M
    xmlHashEntryPtr insert;
539
540
6.96M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
6.96M
    if (table->dict) {
547
4.73M
        if (!xmlDictOwns(table->dict, name)) {
548
249k
      name = xmlDictLookup(table->dict, name, -1);
549
249k
      if (name == NULL)
550
0
          return(-1);
551
249k
  }
552
4.73M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
70.0k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
70.0k
      if (name2 == NULL)
555
0
          return(-1);
556
70.0k
  }
557
4.73M
        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
4.73M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
6.96M
    key = xmlHashComputeKey(table, name, name2, name3);
568
6.96M
    if (table->table[key].valid == 0) {
569
4.16M
  insert = NULL;
570
4.16M
    } else {
571
2.79M
        if (table->dict) {
572
4.71M
      for (insert = &(table->table[key]); insert->next != NULL;
573
2.65M
     insert = insert->next) {
574
2.65M
    if ((insert->name == name) &&
575
2.65M
        (insert->name2 == name2) &&
576
2.65M
        (insert->name3 == name3))
577
66.2k
        return(-1);
578
2.58M
    len++;
579
2.58M
      }
580
2.05M
      if ((insert->name == name) &&
581
2.05M
    (insert->name2 == name2) &&
582
2.05M
    (insert->name3 == name3))
583
158k
    return(-1);
584
2.05M
  } else {
585
1.05M
      for (insert = &(table->table[key]); insert->next != NULL;
586
674k
     insert = insert->next) {
587
457k
    if ((xmlStrEqual(insert->name, name)) &&
588
457k
        (xmlStrEqual(insert->name2, name2)) &&
589
457k
        (xmlStrEqual(insert->name3, name3)))
590
76.6k
        return(-1);
591
381k
    len++;
592
381k
      }
593
598k
      if ((xmlStrEqual(insert->name, name)) &&
594
598k
    (xmlStrEqual(insert->name2, name2)) &&
595
598k
    (xmlStrEqual(insert->name3, name3)))
596
146k
    return(-1);
597
598k
  }
598
2.79M
    }
599
600
6.51M
    if (insert == NULL) {
601
4.16M
  entry = &(table->table[key]);
602
4.16M
    } else {
603
2.34M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
2.34M
  if (entry == NULL)
605
0
       return(-1);
606
2.34M
    }
607
608
6.51M
    if (table->dict != NULL) {
609
4.51M
        entry->name = (xmlChar *) name;
610
4.51M
        entry->name2 = (xmlChar *) name2;
611
4.51M
        entry->name3 = (xmlChar *) name3;
612
4.51M
    } else {
613
1.99M
  entry->name = xmlStrdup(name);
614
1.99M
  entry->name2 = xmlStrdup(name2);
615
1.99M
  entry->name3 = xmlStrdup(name3);
616
1.99M
    }
617
6.51M
    entry->payload = userdata;
618
6.51M
    entry->next = NULL;
619
6.51M
    entry->valid = 1;
620
621
622
6.51M
    if (insert != NULL)
623
2.34M
  insert->next = entry;
624
625
6.51M
    table->nbElems++;
626
627
6.51M
    if (len > MAX_HASH_LEN)
628
6.23k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
6.51M
    return(0);
631
6.51M
}
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
80.7k
       void *userdata, xmlHashDeallocator f) {
652
80.7k
    unsigned long key;
653
80.7k
    xmlHashEntryPtr entry;
654
80.7k
    xmlHashEntryPtr insert;
655
656
80.7k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
80.7k
    if (table->dict) {
663
80.7k
        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
80.7k
        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
80.7k
        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
80.7k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
80.7k
    key = xmlHashComputeKey(table, name, name2, name3);
684
80.7k
    if (table->table[key].valid == 0) {
685
59.5k
  insert = NULL;
686
59.5k
    } else {
687
21.1k
        if (table ->dict) {
688
29.5k
      for (insert = &(table->table[key]); insert->next != NULL;
689
21.1k
     insert = insert->next) {
690
8.50k
    if ((insert->name == name) &&
691
8.50k
        (insert->name2 == name2) &&
692
8.50k
        (insert->name3 == name3)) {
693
121
        if (f)
694
0
      f(insert->payload, insert->name);
695
121
        insert->payload = userdata;
696
121
        return(0);
697
121
    }
698
8.50k
      }
699
21.0k
      if ((insert->name == name) &&
700
21.0k
    (insert->name2 == name2) &&
701
21.0k
    (insert->name3 == name3)) {
702
3.91k
    if (f)
703
0
        f(insert->payload, insert->name);
704
3.91k
    insert->payload = userdata;
705
3.91k
    return(0);
706
3.91k
      }
707
21.0k
  } 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
21.1k
    }
729
730
76.6k
    if (insert == NULL) {
731
59.5k
  entry =  &(table->table[key]);
732
59.5k
    } else {
733
17.1k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
17.1k
  if (entry == NULL)
735
0
       return(-1);
736
17.1k
    }
737
738
76.6k
    if (table->dict != NULL) {
739
76.6k
        entry->name = (xmlChar *) name;
740
76.6k
        entry->name2 = (xmlChar *) name2;
741
76.6k
        entry->name3 = (xmlChar *) name3;
742
76.6k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
76.6k
    entry->payload = userdata;
748
76.6k
    entry->next = NULL;
749
76.6k
    entry->valid = 1;
750
76.6k
    table->nbElems++;
751
752
753
76.6k
    if (insert != NULL) {
754
17.1k
  insert->next = entry;
755
17.1k
    }
756
76.6k
    return(0);
757
76.6k
}
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
112M
         const xmlChar *name2, const xmlChar *name3) {
773
112M
    unsigned long key;
774
112M
    xmlHashEntryPtr entry;
775
776
112M
    if (table == NULL)
777
237k
  return(NULL);
778
112M
    if (name == NULL)
779
0
  return(NULL);
780
112M
    key = xmlHashComputeKey(table, name, name2, name3);
781
112M
    if (table->table[key].valid == 0)
782
18.5M
  return(NULL);
783
93.8M
    if (table->dict) {
784
119M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
83.9M
      if ((entry->name == name) &&
786
83.9M
    (entry->name2 == name2) &&
787
83.9M
    (entry->name3 == name3))
788
44.9M
    return(entry->payload);
789
83.9M
  }
790
80.0M
    }
791
54.9M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
52.2M
  if ((xmlStrEqual(entry->name, name)) &&
793
52.2M
      (xmlStrEqual(entry->name2, name2)) &&
794
52.2M
      (xmlStrEqual(entry->name3, name3)))
795
46.1M
      return(entry->payload);
796
52.2M
    }
797
2.68M
    return(NULL);
798
48.8M
}
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
978k
    const xmlChar *prefix3, const xmlChar *name3) {
819
978k
    unsigned long key;
820
978k
    xmlHashEntryPtr entry;
821
822
978k
    if (table == NULL)
823
0
  return(NULL);
824
978k
    if (name == NULL)
825
0
  return(NULL);
826
978k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
978k
                             name2, prefix3, name3);
828
978k
    if (table->table[key].valid == 0)
829
364k
  return(NULL);
830
1.72M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
1.46M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
1.46M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
1.46M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
352k
      return(entry->payload);
835
1.46M
    }
836
261k
    return(NULL);
837
613k
}
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
799k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
799k
    stubData *stubdata = (stubData *) data;
849
799k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
799k
}
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
107k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
107k
    stubData stubdata;
863
107k
    stubdata.data = data;
864
107k
    stubdata.hashscanner = f;
865
107k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
107k
}
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
150k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
150k
    int i, nb;
879
150k
    xmlHashEntryPtr iter;
880
150k
    xmlHashEntryPtr next;
881
882
150k
    if (table == NULL)
883
13.2k
  return;
884
137k
    if (f == NULL)
885
0
  return;
886
887
137k
    if (table->table) {
888
25.4M
  for(i = 0; i < table->size; i++) {
889
25.3M
      if (table->table[i].valid == 0)
890
24.0M
    continue;
891
1.26M
      iter = &(table->table[i]);
892
3.24M
      while (iter) {
893
1.98M
    next = iter->next;
894
1.98M
                nb = table->nbElems;
895
1.98M
    if ((f != NULL) && (iter->payload != NULL))
896
1.98M
        f(iter->payload, data, iter->name,
897
1.98M
          iter->name2, iter->name3);
898
1.98M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
463k
                    if (iter == &(table->table[i])) {
901
317k
                        if (table->table[i].valid == 0)
902
191k
                            iter = NULL;
903
317k
                        if (table->table[i].next != next)
904
126k
          iter = &(table->table[i]);
905
317k
                    } else
906
145k
            iter = next;
907
463k
                } else
908
1.52M
        iter = next;
909
1.98M
      }
910
1.26M
  }
911
137k
    }
912
137k
}
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
79.0k
       xmlHashScanner f, void *data) {
931
79.0k
    stubData stubdata;
932
79.0k
    stubdata.data = data;
933
79.0k
    stubdata.hashscanner = f;
934
79.0k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
79.0k
                     &stubdata);
936
79.0k
}
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
79.0k
     xmlHashScannerFull f, void *data) {
955
79.0k
    int i;
956
79.0k
    xmlHashEntryPtr iter;
957
79.0k
    xmlHashEntryPtr next;
958
959
79.0k
    if (table == NULL)
960
68.7k
  return;
961
10.3k
    if (f == NULL)
962
0
  return;
963
964
10.3k
    if (table->table) {
965
2.65M
  for(i = 0; i < table->size; i++) {
966
2.64M
      if (table->table[i].valid == 0)
967
428k
    continue;
968
2.21M
      iter = &(table->table[i]);
969
7.34M
      while (iter) {
970
5.12M
    next = iter->next;
971
5.12M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
5.12M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
5.12M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
5.12M
        (iter->payload != NULL)) {
975
54
        f(iter->payload, data, iter->name,
976
54
          iter->name2, iter->name3);
977
54
    }
978
5.12M
    iter = next;
979
5.12M
      }
980
2.21M
  }
981
10.3k
    }
982
10.3k
}
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
43.2k
xmlHashSize(xmlHashTablePtr table) {
1037
43.2k
    if (table == NULL)
1038
0
  return(-1);
1039
43.2k
    return(table->nbElems);
1040
43.2k
}
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
562
           xmlHashDeallocator f) {
1056
562
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
562
}
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
465k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
465k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
465k
}
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
465k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
465k
    unsigned long key;
1096
465k
    xmlHashEntryPtr entry;
1097
465k
    xmlHashEntryPtr prev = NULL;
1098
1099
465k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
465k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
465k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
465k
    } else {
1106
678k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
678k
            if (xmlStrEqual(entry->name, name) &&
1108
678k
                    xmlStrEqual(entry->name2, name2) &&
1109
678k
                    xmlStrEqual(entry->name3, name3)) {
1110
465k
                if ((f != NULL) && (entry->payload != NULL))
1111
562
                    f(entry->payload, entry->name);
1112
465k
                entry->payload = NULL;
1113
465k
    if (table->dict == NULL) {
1114
901
        if(entry->name)
1115
901
      xmlFree(entry->name);
1116
901
        if(entry->name2)
1117
247
      xmlFree(entry->name2);
1118
901
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
901
    }
1121
465k
                if(prev) {
1122
145k
                    prev->next = entry->next;
1123
145k
        xmlFree(entry);
1124
320k
    } else {
1125
320k
        if (entry->next == NULL) {
1126
193k
      entry->valid = 0;
1127
193k
        } else {
1128
126k
      entry = entry->next;
1129
126k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
126k
      xmlFree(entry);
1131
126k
        }
1132
320k
    }
1133
465k
                table->nbElems--;
1134
465k
                return(0);
1135
465k
            }
1136
212k
            prev = entry;
1137
212k
        }
1138
0
        return(-1);
1139
465k
    }
1140
465k
}
1141