Coverage Report

Created: 2025-03-12 04: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
9.77M
#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
110M
            const xmlChar *name2, const xmlChar *name3) {
85
110M
    unsigned long value = 0L;
86
110M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
110M
    if (name != NULL) {
92
110M
  value += 30 * (*name);
93
2.40G
  while ((ch = *name++) != 0) {
94
2.29G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
2.29G
  }
96
110M
    }
97
110M
    value = value ^ ((value << 5) + (value >> 3));
98
110M
    if (name2 != NULL) {
99
58.3M
  while ((ch = *name2++) != 0) {
100
48.4M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
48.4M
  }
102
9.95M
    }
103
110M
    value = value ^ ((value << 5) + (value >> 3));
104
110M
    if (name3 != NULL) {
105
50.1M
  while ((ch = *name3++) != 0) {
106
43.7M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
43.7M
  }
108
6.41M
    }
109
110M
    return (value % table->size);
110
110M
}
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
644k
       const xmlChar *prefix3, const xmlChar *name3) {
120
644k
    unsigned long value = 0L;
121
644k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
644k
    if (prefix != NULL)
127
83.9k
  value += 30 * (*prefix);
128
560k
    else
129
560k
  value += 30 * (*name);
130
131
644k
    if (prefix != NULL) {
132
335k
  while ((ch = *prefix++) != 0) {
133
252k
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
252k
  }
135
83.9k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
83.9k
    }
137
644k
    if (name != NULL) {
138
4.43M
  while ((ch = *name++) != 0) {
139
3.79M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
3.79M
  }
141
644k
    }
142
644k
    value = value ^ ((value << 5) + (value >> 3));
143
644k
    if (prefix2 != NULL) {
144
338k
  while ((ch = *prefix2++) != 0) {
145
254k
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
254k
  }
147
83.6k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
83.6k
    }
149
644k
    if (name2 != NULL) {
150
2.82M
  while ((ch = *name2++) != 0) {
151
2.18M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
2.18M
  }
153
644k
    }
154
644k
    value = value ^ ((value << 5) + (value >> 3));
155
644k
    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
644k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
644k
    return (value % table->size);
167
644k
}
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
280k
xmlHashCreate(int size) {
179
280k
    xmlHashTablePtr table;
180
181
280k
    if (size <= 0)
182
151k
        size = 256;
183
184
280k
    table = xmlMalloc(sizeof(xmlHashTable));
185
280k
    if (table) {
186
280k
        table->dict = NULL;
187
280k
        table->size = size;
188
280k
  table->nbElems = 0;
189
280k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
280k
        if (table->table) {
191
280k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
280k
      return(table);
196
280k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
280k
}
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
188k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
188k
    xmlHashTablePtr table;
214
215
188k
    table = xmlHashCreate(size);
216
188k
    if (table != NULL) {
217
188k
        table->dict = dict;
218
188k
  xmlDictReference(dict);
219
188k
    }
220
188k
    return(table);
221
188k
}
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
11.0k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
11.0k
    unsigned long key;
235
11.0k
    int oldsize, i;
236
11.0k
    xmlHashEntryPtr iter, next;
237
11.0k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
11.0k
    if (table == NULL)
243
0
  return(-1);
244
11.0k
    if (size < 8)
245
0
        return(-1);
246
11.0k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
11.0k
    oldsize = table->size;
250
11.0k
    oldtable = table->table;
251
11.0k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
11.0k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
11.0k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
11.0k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
11.0k
    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
255k
    for (i = 0; i < oldsize; i++) {
269
244k
  if (oldtable[i].valid == 0)
270
3.05k
      continue;
271
241k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
241k
        oldtable[i].name3);
273
241k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
241k
  table->table[key].next = NULL;
275
241k
    }
276
277
255k
    for (i = 0; i < oldsize; i++) {
278
244k
  iter = oldtable[i].next;
279
1.22M
  while (iter) {
280
977k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
977k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
977k
                        iter->name3);
288
977k
      if (table->table[key].valid == 0) {
289
654k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
654k
    table->table[key].next = NULL;
291
654k
    xmlFree(iter);
292
654k
      } else {
293
323k
    iter->next = table->table[key].next;
294
323k
    table->table[key].next = iter;
295
323k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
977k
      iter = next;
302
977k
  }
303
244k
    }
304
305
11.0k
    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
11.0k
    return(0);
313
11.0k
}
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
280k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
280k
    int i;
326
280k
    xmlHashEntryPtr iter;
327
280k
    xmlHashEntryPtr next;
328
280k
    int inside_table = 0;
329
280k
    int nbElems;
330
331
280k
    if (table == NULL)
332
0
  return;
333
280k
    if (table->table) {
334
280k
  nbElems = table->nbElems;
335
35.4M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
35.1M
      iter = &(table->table[i]);
337
35.1M
      if (iter->valid == 0)
338
29.5M
    continue;
339
5.60M
      inside_table = 1;
340
14.4M
      while (iter) {
341
8.81M
    next = iter->next;
342
8.81M
    if ((f != NULL) && (iter->payload != NULL))
343
6.59M
        f(iter->payload, iter->name);
344
8.81M
    if (table->dict == NULL) {
345
1.86M
        if (iter->name)
346
1.86M
      xmlFree(iter->name);
347
1.86M
        if (iter->name2)
348
79.8k
      xmlFree(iter->name2);
349
1.86M
        if (iter->name3)
350
1.07M
      xmlFree(iter->name3);
351
1.86M
    }
352
8.81M
    iter->payload = NULL;
353
8.81M
    if (!inside_table)
354
3.20M
        xmlFree(iter);
355
8.81M
    nbElems--;
356
8.81M
    inside_table = 0;
357
8.81M
    iter = next;
358
8.81M
      }
359
5.60M
  }
360
280k
  xmlFree(table->table);
361
280k
    }
362
280k
    if (table->dict)
363
135k
        xmlDictFree(table->dict);
364
280k
    xmlFree(table);
365
280k
}
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
185k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
185k
    xmlFree(entry);
377
185k
}
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.11M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
1.11M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
1.11M
}
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
4.65M
          const xmlChar *name2, void *userdata) {
410
4.65M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
4.65M
}
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
119k
       xmlHashDeallocator f) {
450
119k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
119k
}
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
81.3M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
81.3M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
81.3M
}
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
15.2M
        const xmlChar *name2) {
480
15.2M
    return(xmlHashLookup3(table, name, name2, NULL));
481
15.2M
}
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
644k
          const xmlChar *name2) {
515
644k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
644k
}
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
9.76M
     void *userdata) {
536
9.76M
    unsigned long key, len = 0;
537
9.76M
    xmlHashEntryPtr entry;
538
9.76M
    xmlHashEntryPtr insert;
539
540
9.76M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
9.76M
    if (table->dict) {
547
7.90M
        if (!xmlDictOwns(table->dict, name)) {
548
186k
      name = xmlDictLookup(table->dict, name, -1);
549
186k
      if (name == NULL)
550
0
          return(-1);
551
186k
  }
552
7.90M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
37.8k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
37.8k
      if (name2 == NULL)
555
0
          return(-1);
556
37.8k
  }
557
7.90M
        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
7.90M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
9.76M
    key = xmlHashComputeKey(table, name, name2, name3);
568
9.76M
    if (table->table[key].valid == 0) {
569
5.19M
  insert = NULL;
570
5.19M
    } else {
571
4.57M
        if (table->dict) {
572
9.03M
      for (insert = &(table->table[key]); insert->next != NULL;
573
4.97M
     insert = insert->next) {
574
4.97M
    if ((insert->name == name) &&
575
4.97M
        (insert->name2 == name2) &&
576
4.97M
        (insert->name3 == name3))
577
58
        return(-1);
578
4.97M
    len++;
579
4.97M
      }
580
4.05M
      if ((insert->name == name) &&
581
4.05M
    (insert->name2 == name2) &&
582
4.05M
    (insert->name3 == name3))
583
2.44k
    return(-1);
584
4.05M
  } else {
585
762k
      for (insert = &(table->table[key]); insert->next != NULL;
586
521k
     insert = insert->next) {
587
240k
    if ((xmlStrEqual(insert->name, name)) &&
588
240k
        (xmlStrEqual(insert->name2, name2)) &&
589
240k
        (xmlStrEqual(insert->name3, name3)))
590
107
        return(-1);
591
240k
    len++;
592
240k
      }
593
521k
      if ((xmlStrEqual(insert->name, name)) &&
594
521k
    (xmlStrEqual(insert->name2, name2)) &&
595
521k
    (xmlStrEqual(insert->name3, name3)))
596
6.02k
    return(-1);
597
521k
  }
598
4.57M
    }
599
600
9.75M
    if (insert == NULL) {
601
5.19M
  entry = &(table->table[key]);
602
5.19M
    } else {
603
4.56M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
4.56M
  if (entry == NULL)
605
0
       return(-1);
606
4.56M
    }
607
608
9.75M
    if (table->dict != NULL) {
609
7.89M
        entry->name = (xmlChar *) name;
610
7.89M
        entry->name2 = (xmlChar *) name2;
611
7.89M
        entry->name3 = (xmlChar *) name3;
612
7.89M
    } else {
613
1.86M
  entry->name = xmlStrdup(name);
614
1.86M
  entry->name2 = xmlStrdup(name2);
615
1.86M
  entry->name3 = xmlStrdup(name3);
616
1.86M
    }
617
9.75M
    entry->payload = userdata;
618
9.75M
    entry->next = NULL;
619
9.75M
    entry->valid = 1;
620
621
622
9.75M
    if (insert != NULL)
623
4.56M
  insert->next = entry;
624
625
9.75M
    table->nbElems++;
626
627
9.75M
    if (len > MAX_HASH_LEN)
628
11.0k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
9.75M
    return(0);
631
9.75M
}
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
119k
       void *userdata, xmlHashDeallocator f) {
652
119k
    unsigned long key;
653
119k
    xmlHashEntryPtr entry;
654
119k
    xmlHashEntryPtr insert;
655
656
119k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
119k
    if (table->dict) {
663
119k
        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
119k
        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
119k
        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
119k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
119k
    key = xmlHashComputeKey(table, name, name2, name3);
684
119k
    if (table->table[key].valid == 0) {
685
71.8k
  insert = NULL;
686
71.8k
    } else {
687
47.1k
        if (table ->dict) {
688
74.2k
      for (insert = &(table->table[key]); insert->next != NULL;
689
47.1k
     insert = insert->next) {
690
27.0k
    if ((insert->name == name) &&
691
27.0k
        (insert->name2 == name2) &&
692
27.0k
        (insert->name3 == name3)) {
693
61
        if (f)
694
0
      f(insert->payload, insert->name);
695
61
        insert->payload = userdata;
696
61
        return(0);
697
61
    }
698
27.0k
      }
699
47.1k
      if ((insert->name == name) &&
700
47.1k
    (insert->name2 == name2) &&
701
47.1k
    (insert->name3 == name3)) {
702
652
    if (f)
703
0
        f(insert->payload, insert->name);
704
652
    insert->payload = userdata;
705
652
    return(0);
706
652
      }
707
47.1k
  } 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
47.1k
    }
729
730
118k
    if (insert == NULL) {
731
71.8k
  entry =  &(table->table[key]);
732
71.8k
    } else {
733
46.4k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
46.4k
  if (entry == NULL)
735
0
       return(-1);
736
46.4k
    }
737
738
118k
    if (table->dict != NULL) {
739
118k
        entry->name = (xmlChar *) name;
740
118k
        entry->name2 = (xmlChar *) name2;
741
118k
        entry->name3 = (xmlChar *) name3;
742
118k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
118k
    entry->payload = userdata;
748
118k
    entry->next = NULL;
749
118k
    entry->valid = 1;
750
118k
    table->nbElems++;
751
752
753
118k
    if (insert != NULL) {
754
46.4k
  insert->next = entry;
755
46.4k
    }
756
118k
    return(0);
757
118k
}
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
99.0M
         const xmlChar *name2, const xmlChar *name3) {
773
99.0M
    unsigned long key;
774
99.0M
    xmlHashEntryPtr entry;
775
776
99.0M
    if (table == NULL)
777
842k
  return(NULL);
778
98.1M
    if (name == NULL)
779
0
  return(NULL);
780
98.1M
    key = xmlHashComputeKey(table, name, name2, name3);
781
98.1M
    if (table->table[key].valid == 0)
782
19.0M
  return(NULL);
783
79.1M
    if (table->dict) {
784
77.6M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
56.9M
      if ((entry->name == name) &&
786
56.9M
    (entry->name2 == name2) &&
787
56.9M
    (entry->name3 == name3))
788
28.3M
    return(entry->payload);
789
56.9M
  }
790
49.0M
    }
791
62.6M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
57.7M
  if ((xmlStrEqual(entry->name, name)) &&
793
57.7M
      (xmlStrEqual(entry->name2, name2)) &&
794
57.7M
      (xmlStrEqual(entry->name3, name3)))
795
46.0M
      return(entry->payload);
796
57.7M
    }
797
4.81M
    return(NULL);
798
50.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
644k
    const xmlChar *prefix3, const xmlChar *name3) {
819
644k
    unsigned long key;
820
644k
    xmlHashEntryPtr entry;
821
822
644k
    if (table == NULL)
823
0
  return(NULL);
824
644k
    if (name == NULL)
825
0
  return(NULL);
826
644k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
644k
                             name2, prefix3, name3);
828
644k
    if (table->table[key].valid == 0)
829
90.5k
  return(NULL);
830
2.08M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
1.82M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
1.82M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
1.82M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
292k
      return(entry->payload);
835
1.82M
    }
836
261k
    return(NULL);
837
553k
}
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
1.50M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
1.50M
    stubData *stubdata = (stubData *) data;
849
1.50M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
1.50M
}
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
26.2k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
26.2k
    stubData stubdata;
863
26.2k
    stubdata.data = data;
864
26.2k
    stubdata.hashscanner = f;
865
26.2k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
26.2k
}
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
43.7k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
43.7k
    int i, nb;
879
43.7k
    xmlHashEntryPtr iter;
880
43.7k
    xmlHashEntryPtr next;
881
882
43.7k
    if (table == NULL)
883
1.45k
  return;
884
42.2k
    if (f == NULL)
885
0
  return;
886
887
42.2k
    if (table->table) {
888
8.00M
  for(i = 0; i < table->size; i++) {
889
7.96M
      if (table->table[i].valid == 0)
890
5.83M
    continue;
891
2.12M
      iter = &(table->table[i]);
892
6.64M
      while (iter) {
893
4.52M
    next = iter->next;
894
4.52M
                nb = table->nbElems;
895
4.52M
    if ((f != NULL) && (iter->payload != NULL))
896
4.52M
        f(iter->payload, data, iter->name,
897
4.52M
          iter->name2, iter->name3);
898
4.52M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
1.06M
                    if (iter == &(table->table[i])) {
901
582k
                        if (table->table[i].valid == 0)
902
309k
                            iter = NULL;
903
582k
                        if (table->table[i].next != next)
904
272k
          iter = &(table->table[i]);
905
582k
                    } else
906
481k
            iter = next;
907
1.06M
                } else
908
3.45M
        iter = next;
909
4.52M
      }
910
2.12M
  }
911
42.2k
    }
912
42.2k
}
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
360k
       xmlHashScanner f, void *data) {
931
360k
    stubData stubdata;
932
360k
    stubdata.data = data;
933
360k
    stubdata.hashscanner = f;
934
360k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
360k
                     &stubdata);
936
360k
}
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
360k
     xmlHashScannerFull f, void *data) {
955
360k
    int i;
956
360k
    xmlHashEntryPtr iter;
957
360k
    xmlHashEntryPtr next;
958
959
360k
    if (table == NULL)
960
321k
  return;
961
39.6k
    if (f == NULL)
962
0
  return;
963
964
39.6k
    if (table->table) {
965
10.1M
  for(i = 0; i < table->size; i++) {
966
10.1M
      if (table->table[i].valid == 0)
967
2.02M
    continue;
968
8.13M
      iter = &(table->table[i]);
969
26.0M
      while (iter) {
970
17.9M
    next = iter->next;
971
17.9M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
17.9M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
17.9M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
17.9M
        (iter->payload != NULL)) {
975
0
        f(iter->payload, data, iter->name,
976
0
          iter->name2, iter->name3);
977
0
    }
978
17.9M
    iter = next;
979
17.9M
      }
980
8.13M
  }
981
39.6k
    }
982
39.6k
}
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
17.5k
xmlHashSize(xmlHashTablePtr table) {
1037
17.5k
    if (table == NULL)
1038
0
  return(-1);
1039
17.5k
    return(table->nbElems);
1040
17.5k
}
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
31
           xmlHashDeallocator f) {
1056
31
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
31
}
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
1.06M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
1.06M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
1.06M
}
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
1.06M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
1.06M
    unsigned long key;
1096
1.06M
    xmlHashEntryPtr entry;
1097
1.06M
    xmlHashEntryPtr prev = NULL;
1098
1099
1.06M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
1.06M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
1.06M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
1.06M
    } else {
1106
1.89M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
1.89M
            if (xmlStrEqual(entry->name, name) &&
1108
1.89M
                    xmlStrEqual(entry->name2, name2) &&
1109
1.89M
                    xmlStrEqual(entry->name3, name3)) {
1110
1.06M
                if ((f != NULL) && (entry->payload != NULL))
1111
31
                    f(entry->payload, entry->name);
1112
1.06M
                entry->payload = NULL;
1113
1.06M
    if (table->dict == NULL) {
1114
54
        if(entry->name)
1115
54
      xmlFree(entry->name);
1116
54
        if(entry->name2)
1117
13
      xmlFree(entry->name2);
1118
54
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
54
    }
1121
1.06M
                if(prev) {
1122
481k
                    prev->next = entry->next;
1123
481k
        xmlFree(entry);
1124
582k
    } else {
1125
582k
        if (entry->next == NULL) {
1126
309k
      entry->valid = 0;
1127
309k
        } else {
1128
272k
      entry = entry->next;
1129
272k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
272k
      xmlFree(entry);
1131
272k
        }
1132
582k
    }
1133
1.06M
                table->nbElems--;
1134
1.06M
                return(0);
1135
1.06M
            }
1136
833k
            prev = entry;
1137
833k
        }
1138
0
        return(-1);
1139
1.06M
    }
1140
1.06M
}
1141