Coverage Report

Created: 2024-08-16 12:09

/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
5.46M
#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
18.1M
            const xmlChar *name2, const xmlChar *name3) {
85
18.1M
    unsigned long value = 0L;
86
18.1M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
18.1M
    if (name != NULL) {
92
18.1M
  value += 30 * (*name);
93
191M
  while ((ch = *name++) != 0) {
94
173M
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
173M
  }
96
18.1M
    }
97
18.1M
    value = value ^ ((value << 5) + (value >> 3));
98
18.1M
    if (name2 != NULL) {
99
33.6M
  while ((ch = *name2++) != 0) {
100
28.0M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
28.0M
  }
102
5.66M
    }
103
18.1M
    value = value ^ ((value << 5) + (value >> 3));
104
18.1M
    if (name3 != NULL) {
105
28.1M
  while ((ch = *name3++) != 0) {
106
25.2M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
25.2M
  }
108
2.89M
    }
109
18.1M
    return (value % table->size);
110
18.1M
}
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
731k
       const xmlChar *prefix3, const xmlChar *name3) {
120
731k
    unsigned long value = 0L;
121
731k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
731k
    if (prefix != NULL)
127
477k
  value += 30 * (*prefix);
128
254k
    else
129
254k
  value += 30 * (*name);
130
131
731k
    if (prefix != NULL) {
132
1.93M
  while ((ch = *prefix++) != 0) {
133
1.45M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
1.45M
  }
135
477k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
477k
    }
137
731k
    if (name != NULL) {
138
5.42M
  while ((ch = *name++) != 0) {
139
4.69M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
4.69M
  }
141
731k
    }
142
731k
    value = value ^ ((value << 5) + (value >> 3));
143
731k
    if (prefix2 != NULL) {
144
1.92M
  while ((ch = *prefix2++) != 0) {
145
1.44M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
1.44M
  }
147
474k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
474k
    }
149
731k
    if (name2 != NULL) {
150
3.53M
  while ((ch = *name2++) != 0) {
151
2.80M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
2.80M
  }
153
731k
    }
154
731k
    value = value ^ ((value << 5) + (value >> 3));
155
731k
    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
731k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
731k
    return (value % table->size);
167
731k
}
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
742k
xmlHashCreate(int size) {
179
742k
    xmlHashTablePtr table;
180
181
742k
    if (size <= 0)
182
423k
        size = 256;
183
184
742k
    table = xmlMalloc(sizeof(xmlHashTable));
185
742k
    if (table) {
186
742k
        table->dict = NULL;
187
742k
        table->size = size;
188
742k
  table->nbElems = 0;
189
742k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
742k
        if (table->table) {
191
742k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
742k
      return(table);
196
742k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
742k
}
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
454k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
454k
    xmlHashTablePtr table;
214
215
454k
    table = xmlHashCreate(size);
216
454k
    if (table != NULL) {
217
454k
        table->dict = dict;
218
454k
  xmlDictReference(dict);
219
454k
    }
220
454k
    return(table);
221
454k
}
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
2.82k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
2.82k
    unsigned long key;
235
2.82k
    int oldsize, i;
236
2.82k
    xmlHashEntryPtr iter, next;
237
2.82k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
2.82k
    if (table == NULL)
243
0
  return(-1);
244
2.82k
    if (size < 8)
245
0
        return(-1);
246
2.82k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
2.82k
    oldsize = table->size;
250
2.82k
    oldtable = table->table;
251
2.82k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
2.82k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
2.82k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
2.82k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
2.82k
    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
40.0k
    for (i = 0; i < oldsize; i++) {
269
37.2k
  if (oldtable[i].valid == 0)
270
298
      continue;
271
36.9k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
36.9k
        oldtable[i].name3);
273
36.9k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
36.9k
  table->table[key].next = NULL;
275
36.9k
    }
276
277
40.0k
    for (i = 0; i < oldsize; i++) {
278
37.2k
  iter = oldtable[i].next;
279
217k
  while (iter) {
280
179k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
179k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
179k
                        iter->name3);
288
179k
      if (table->table[key].valid == 0) {
289
118k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
118k
    table->table[key].next = NULL;
291
118k
    xmlFree(iter);
292
118k
      } else {
293
61.5k
    iter->next = table->table[key].next;
294
61.5k
    table->table[key].next = iter;
295
61.5k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
179k
      iter = next;
302
179k
  }
303
37.2k
    }
304
305
2.82k
    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
2.82k
    return(0);
313
2.82k
}
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
873k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
873k
    int i;
326
873k
    xmlHashEntryPtr iter;
327
873k
    xmlHashEntryPtr next;
328
873k
    int inside_table = 0;
329
873k
    int nbElems;
330
331
873k
    if (table == NULL)
332
131k
  return;
333
742k
    if (table->table) {
334
742k
  nbElems = table->nbElems;
335
89.6M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
88.9M
      iter = &(table->table[i]);
337
88.9M
      if (iter->valid == 0)
338
84.2M
    continue;
339
4.71M
      inside_table = 1;
340
9.84M
      while (iter) {
341
5.12M
    next = iter->next;
342
5.12M
    if ((f != NULL) && (iter->payload != NULL))
343
2.90M
        f(iter->payload, iter->name);
344
5.12M
    if (table->dict == NULL) {
345
2.85M
        if (iter->name)
346
2.85M
      xmlFree(iter->name);
347
2.85M
        if (iter->name2)
348
236k
      xmlFree(iter->name2);
349
2.85M
        if (iter->name3)
350
294k
      xmlFree(iter->name3);
351
2.85M
    }
352
5.12M
    iter->payload = NULL;
353
5.12M
    if (!inside_table)
354
410k
        xmlFree(iter);
355
5.12M
    nbElems--;
356
5.12M
    inside_table = 0;
357
5.12M
    iter = next;
358
5.12M
      }
359
4.71M
  }
360
742k
  xmlFree(table->table);
361
742k
    }
362
742k
    if (table->dict)
363
358k
        xmlDictFree(table->dict);
364
742k
    xmlFree(table);
365
742k
}
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
331k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
331k
    xmlFree(entry);
377
331k
}
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.10M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
1.10M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
1.10M
}
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
3.36M
          const xmlChar *name2, void *userdata) {
410
3.36M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
3.36M
}
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
49.2k
       xmlHashDeallocator f) {
450
49.2k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
49.2k
}
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
4.44M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
4.44M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
4.44M
}
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
5.77M
        const xmlChar *name2) {
480
5.77M
    return(xmlHashLookup3(table, name, name2, NULL));
481
5.77M
}
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
731k
          const xmlChar *name2) {
515
731k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
731k
}
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
5.49M
     void *userdata) {
536
5.49M
    unsigned long key, len = 0;
537
5.49M
    xmlHashEntryPtr entry;
538
5.49M
    xmlHashEntryPtr insert;
539
540
5.49M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
5.49M
    if (table->dict) {
547
2.62M
        if (!xmlDictOwns(table->dict, name)) {
548
267k
      name = xmlDictLookup(table->dict, name, -1);
549
267k
      if (name == NULL)
550
0
          return(-1);
551
267k
  }
552
2.62M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
231k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
231k
      if (name2 == NULL)
555
0
          return(-1);
556
231k
  }
557
2.62M
        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
2.62M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
5.49M
    key = xmlHashComputeKey(table, name, name2, name3);
568
5.49M
    if (table->table[key].valid == 0) {
569
4.71M
  insert = NULL;
570
4.71M
    } else {
571
784k
        if (table->dict) {
572
1.37M
      for (insert = &(table->table[key]); insert->next != NULL;
573
746k
     insert = insert->next) {
574
746k
    if ((insert->name == name) &&
575
746k
        (insert->name2 == name2) &&
576
746k
        (insert->name3 == name3))
577
675
        return(-1);
578
746k
    len++;
579
746k
      }
580
632k
      if ((insert->name == name) &&
581
632k
    (insert->name2 == name2) &&
582
632k
    (insert->name3 == name3))
583
16.6k
    return(-1);
584
632k
  } else {
585
164k
      for (insert = &(table->table[key]); insert->next != NULL;
586
151k
     insert = insert->next) {
587
13.9k
    if ((xmlStrEqual(insert->name, name)) &&
588
13.9k
        (xmlStrEqual(insert->name2, name2)) &&
589
13.9k
        (xmlStrEqual(insert->name3, name3)))
590
371
        return(-1);
591
13.5k
    len++;
592
13.5k
      }
593
150k
      if ((xmlStrEqual(insert->name, name)) &&
594
150k
    (xmlStrEqual(insert->name2, name2)) &&
595
150k
    (xmlStrEqual(insert->name3, name3)))
596
15.3k
    return(-1);
597
150k
  }
598
784k
    }
599
600
5.46M
    if (insert == NULL) {
601
4.71M
  entry = &(table->table[key]);
602
4.71M
    } else {
603
751k
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
751k
  if (entry == NULL)
605
0
       return(-1);
606
751k
    }
607
608
5.46M
    if (table->dict != NULL) {
609
2.60M
        entry->name = (xmlChar *) name;
610
2.60M
        entry->name2 = (xmlChar *) name2;
611
2.60M
        entry->name3 = (xmlChar *) name3;
612
2.86M
    } else {
613
2.86M
  entry->name = xmlStrdup(name);
614
2.86M
  entry->name2 = xmlStrdup(name2);
615
2.86M
  entry->name3 = xmlStrdup(name3);
616
2.86M
    }
617
5.46M
    entry->payload = userdata;
618
5.46M
    entry->next = NULL;
619
5.46M
    entry->valid = 1;
620
621
622
5.46M
    if (insert != NULL)
623
751k
  insert->next = entry;
624
625
5.46M
    table->nbElems++;
626
627
5.46M
    if (len > MAX_HASH_LEN)
628
2.82k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
5.46M
    return(0);
631
5.46M
}
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
49.2k
       void *userdata, xmlHashDeallocator f) {
652
49.2k
    unsigned long key;
653
49.2k
    xmlHashEntryPtr entry;
654
49.2k
    xmlHashEntryPtr insert;
655
656
49.2k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
49.2k
    if (table->dict) {
663
49.2k
        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
49.2k
        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
49.2k
        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
49.2k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
49.2k
    key = xmlHashComputeKey(table, name, name2, name3);
684
49.2k
    if (table->table[key].valid == 0) {
685
43.4k
  insert = NULL;
686
43.4k
    } else {
687
5.86k
        if (table ->dict) {
688
6.42k
      for (insert = &(table->table[key]); insert->next != NULL;
689
5.86k
     insert = insert->next) {
690
712
    if ((insert->name == name) &&
691
712
        (insert->name2 == name2) &&
692
712
        (insert->name3 == name3)) {
693
155
        if (f)
694
0
      f(insert->payload, insert->name);
695
155
        insert->payload = userdata;
696
155
        return(0);
697
155
    }
698
712
      }
699
5.71k
      if ((insert->name == name) &&
700
5.71k
    (insert->name2 == name2) &&
701
5.71k
    (insert->name3 == name3)) {
702
2.84k
    if (f)
703
0
        f(insert->payload, insert->name);
704
2.84k
    insert->payload = userdata;
705
2.84k
    return(0);
706
2.84k
      }
707
5.71k
  } 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
5.86k
    }
729
730
46.2k
    if (insert == NULL) {
731
43.4k
  entry =  &(table->table[key]);
732
43.4k
    } else {
733
2.87k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
2.87k
  if (entry == NULL)
735
0
       return(-1);
736
2.87k
    }
737
738
46.2k
    if (table->dict != NULL) {
739
46.2k
        entry->name = (xmlChar *) name;
740
46.2k
        entry->name2 = (xmlChar *) name2;
741
46.2k
        entry->name3 = (xmlChar *) name3;
742
46.2k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
46.2k
    entry->payload = userdata;
748
46.2k
    entry->next = NULL;
749
46.2k
    entry->valid = 1;
750
46.2k
    table->nbElems++;
751
752
753
46.2k
    if (insert != NULL) {
754
2.87k
  insert->next = entry;
755
2.87k
    }
756
46.2k
    return(0);
757
46.2k
}
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
12.0M
         const xmlChar *name2, const xmlChar *name3) {
773
12.0M
    unsigned long key;
774
12.0M
    xmlHashEntryPtr entry;
775
776
12.0M
    if (table == NULL)
777
111k
  return(NULL);
778
11.9M
    if (name == NULL)
779
0
  return(NULL);
780
11.9M
    key = xmlHashComputeKey(table, name, name2, name3);
781
11.9M
    if (table->table[key].valid == 0)
782
4.66M
  return(NULL);
783
7.31M
    if (table->dict) {
784
7.78M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
5.49M
      if ((entry->name == name) &&
786
5.49M
    (entry->name2 == name2) &&
787
5.49M
    (entry->name3 == name3))
788
2.32M
    return(entry->payload);
789
5.49M
  }
790
4.61M
    }
791
6.83M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
6.03M
  if ((xmlStrEqual(entry->name, name)) &&
793
6.03M
      (xmlStrEqual(entry->name2, name2)) &&
794
6.03M
      (xmlStrEqual(entry->name3, name3)))
795
4.19M
      return(entry->payload);
796
6.03M
    }
797
793k
    return(NULL);
798
4.98M
}
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
731k
    const xmlChar *prefix3, const xmlChar *name3) {
819
731k
    unsigned long key;
820
731k
    xmlHashEntryPtr entry;
821
822
731k
    if (table == NULL)
823
0
  return(NULL);
824
731k
    if (name == NULL)
825
0
  return(NULL);
826
731k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
731k
                             name2, prefix3, name3);
828
731k
    if (table->table[key].valid == 0)
829
406k
  return(NULL);
830
647k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
501k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
501k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
501k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
179k
      return(entry->payload);
835
501k
    }
836
146k
    return(NULL);
837
325k
}
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
730k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
730k
    stubData *stubdata = (stubData *) data;
849
730k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
730k
}
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
254k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
254k
    stubData stubdata;
863
254k
    stubdata.data = data;
864
254k
    stubdata.hashscanner = f;
865
254k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
254k
}
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
316k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
316k
    int i, nb;
879
316k
    xmlHashEntryPtr iter;
880
316k
    xmlHashEntryPtr next;
881
882
316k
    if (table == NULL)
883
9.62k
  return;
884
306k
    if (f == NULL)
885
0
  return;
886
887
306k
    if (table->table) {
888
63.7M
  for(i = 0; i < table->size; i++) {
889
63.4M
      if (table->table[i].valid == 0)
890
62.3M
    continue;
891
1.09M
      iter = &(table->table[i]);
892
2.59M
      while (iter) {
893
1.49M
    next = iter->next;
894
1.49M
                nb = table->nbElems;
895
1.49M
    if ((f != NULL) && (iter->payload != NULL))
896
1.49M
        f(iter->payload, data, iter->name,
897
1.49M
          iter->name2, iter->name3);
898
1.49M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
379k
                    if (iter == &(table->table[i])) {
901
271k
                        if (table->table[i].valid == 0)
902
153k
                            iter = NULL;
903
271k
                        if (table->table[i].next != next)
904
118k
          iter = &(table->table[i]);
905
271k
                    } else
906
107k
            iter = next;
907
379k
                } else
908
1.11M
        iter = next;
909
1.49M
      }
910
1.09M
  }
911
306k
    }
912
306k
}
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
31.8k
       xmlHashScanner f, void *data) {
931
31.8k
    stubData stubdata;
932
31.8k
    stubdata.data = data;
933
31.8k
    stubdata.hashscanner = f;
934
31.8k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
31.8k
                     &stubdata);
936
31.8k
}
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
31.8k
     xmlHashScannerFull f, void *data) {
955
31.8k
    int i;
956
31.8k
    xmlHashEntryPtr iter;
957
31.8k
    xmlHashEntryPtr next;
958
959
31.8k
    if (table == NULL)
960
28.4k
  return;
961
3.40k
    if (f == NULL)
962
0
  return;
963
964
3.40k
    if (table->table) {
965
875k
  for(i = 0; i < table->size; i++) {
966
871k
      if (table->table[i].valid == 0)
967
664k
    continue;
968
207k
      iter = &(table->table[i]);
969
575k
      while (iter) {
970
368k
    next = iter->next;
971
368k
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
368k
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
368k
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
368k
        (iter->payload != NULL)) {
975
52
        f(iter->payload, data, iter->name,
976
52
          iter->name2, iter->name3);
977
52
    }
978
368k
    iter = next;
979
368k
      }
980
207k
  }
981
3.40k
    }
982
3.40k
}
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
62.1k
xmlHashSize(xmlHashTablePtr table) {
1037
62.1k
    if (table == NULL)
1038
0
  return(-1);
1039
62.1k
    return(table->nbElems);
1040
62.1k
}
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
1.05k
           xmlHashDeallocator f) {
1056
1.05k
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
1.05k
}
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
381k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
381k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
381k
}
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
382k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
382k
    unsigned long key;
1096
382k
    xmlHashEntryPtr entry;
1097
382k
    xmlHashEntryPtr prev = NULL;
1098
1099
382k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
382k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
382k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
382k
    } else {
1106
510k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
510k
            if (xmlStrEqual(entry->name, name) &&
1108
510k
                    xmlStrEqual(entry->name2, name2) &&
1109
510k
                    xmlStrEqual(entry->name3, name3)) {
1110
382k
                if ((f != NULL) && (entry->payload != NULL))
1111
1.05k
                    f(entry->payload, entry->name);
1112
382k
                entry->payload = NULL;
1113
382k
    if (table->dict == NULL) {
1114
1.16k
        if(entry->name)
1115
1.16k
      xmlFree(entry->name);
1116
1.16k
        if(entry->name2)
1117
117
      xmlFree(entry->name2);
1118
1.16k
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
1.16k
    }
1121
382k
                if(prev) {
1122
107k
                    prev->next = entry->next;
1123
107k
        xmlFree(entry);
1124
274k
    } else {
1125
274k
        if (entry->next == NULL) {
1126
156k
      entry->valid = 0;
1127
156k
        } else {
1128
118k
      entry = entry->next;
1129
118k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
118k
      xmlFree(entry);
1131
118k
        }
1132
274k
    }
1133
382k
                table->nbElems--;
1134
382k
                return(0);
1135
382k
            }
1136
128k
            prev = entry;
1137
128k
        }
1138
0
        return(-1);
1139
382k
    }
1140
382k
}
1141