Coverage Report

Created: 2024-07-03 12:02

/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
48.6M
#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
731M
            const xmlChar *name2, const xmlChar *name3) {
85
731M
    unsigned long value = 0L;
86
731M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
731M
    if (name != NULL) {
92
731M
  value += 30 * (*name);
93
10.4G
  while ((ch = *name++) != 0) {
94
9.68G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
9.68G
  }
96
731M
    }
97
731M
    value = value ^ ((value << 5) + (value >> 3));
98
731M
    if (name2 != NULL) {
99
312M
  while ((ch = *name2++) != 0) {
100
267M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
267M
  }
102
45.0M
    }
103
731M
    value = value ^ ((value << 5) + (value >> 3));
104
731M
    if (name3 != NULL) {
105
302M
  while ((ch = *name3++) != 0) {
106
262M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
262M
  }
108
40.7M
    }
109
731M
    return (value % table->size);
110
731M
}
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
7.14M
       const xmlChar *prefix3, const xmlChar *name3) {
120
7.14M
    unsigned long value = 0L;
121
7.14M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
7.14M
    if (prefix != NULL)
127
465k
  value += 30 * (*prefix);
128
6.67M
    else
129
6.67M
  value += 30 * (*name);
130
131
7.14M
    if (prefix != NULL) {
132
2.60M
  while ((ch = *prefix++) != 0) {
133
2.14M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
2.14M
  }
135
465k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
465k
    }
137
7.14M
    if (name != NULL) {
138
46.4M
  while ((ch = *name++) != 0) {
139
39.2M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
39.2M
  }
141
7.14M
    }
142
7.14M
    value = value ^ ((value << 5) + (value >> 3));
143
7.14M
    if (prefix2 != NULL) {
144
2.00M
  while ((ch = *prefix2++) != 0) {
145
1.54M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
1.54M
  }
147
466k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
466k
    }
149
7.14M
    if (name2 != NULL) {
150
30.5M
  while ((ch = *name2++) != 0) {
151
23.3M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
23.3M
  }
153
7.14M
    }
154
7.14M
    value = value ^ ((value << 5) + (value >> 3));
155
7.14M
    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
7.14M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
7.14M
    return (value % table->size);
167
7.14M
}
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
4.81M
xmlHashCreate(int size) {
179
4.81M
    xmlHashTablePtr table;
180
181
4.81M
    if (size <= 0)
182
840k
        size = 256;
183
184
4.81M
    table = xmlMalloc(sizeof(xmlHashTable));
185
4.81M
    if (table) {
186
4.81M
        table->dict = NULL;
187
4.81M
        table->size = size;
188
4.81M
  table->nbElems = 0;
189
4.81M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
4.81M
        if (table->table) {
191
4.81M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
4.81M
      return(table);
196
4.81M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
4.81M
}
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
1.01M
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
1.01M
    xmlHashTablePtr table;
214
215
1.01M
    table = xmlHashCreate(size);
216
1.01M
    if (table != NULL) {
217
1.01M
        table->dict = dict;
218
1.01M
  xmlDictReference(dict);
219
1.01M
    }
220
1.01M
    return(table);
221
1.01M
}
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
50.9k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
50.9k
    unsigned long key;
235
50.9k
    int oldsize, i;
236
50.9k
    xmlHashEntryPtr iter, next;
237
50.9k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
50.9k
    if (table == NULL)
243
0
  return(-1);
244
50.9k
    if (size < 8)
245
0
        return(-1);
246
50.9k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
50.9k
    oldsize = table->size;
250
50.9k
    oldtable = table->table;
251
50.9k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
50.9k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
50.9k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
50.9k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
50.9k
    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
1.16M
    for (i = 0; i < oldsize; i++) {
269
1.11M
  if (oldtable[i].valid == 0)
270
16.5k
      continue;
271
1.09M
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
1.09M
        oldtable[i].name3);
273
1.09M
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
1.09M
  table->table[key].next = NULL;
275
1.09M
    }
276
277
1.16M
    for (i = 0; i < oldsize; i++) {
278
1.11M
  iter = oldtable[i].next;
279
5.51M
  while (iter) {
280
4.39M
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
4.39M
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
4.39M
                        iter->name3);
288
4.39M
      if (table->table[key].valid == 0) {
289
2.94M
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
2.94M
    table->table[key].next = NULL;
291
2.94M
    xmlFree(iter);
292
2.94M
      } else {
293
1.45M
    iter->next = table->table[key].next;
294
1.45M
    table->table[key].next = iter;
295
1.45M
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
4.39M
      iter = next;
302
4.39M
  }
303
1.11M
    }
304
305
50.9k
    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
50.9k
    return(0);
313
50.9k
}
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
4.81M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
4.81M
    int i;
326
4.81M
    xmlHashEntryPtr iter;
327
4.81M
    xmlHashEntryPtr next;
328
4.81M
    int inside_table = 0;
329
4.81M
    int nbElems;
330
331
4.81M
    if (table == NULL)
332
0
  return;
333
4.81M
    if (table->table) {
334
4.81M
  nbElems = table->nbElems;
335
196M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
191M
      iter = &(table->table[i]);
337
191M
      if (iter->valid == 0)
338
162M
    continue;
339
28.7M
      inside_table = 1;
340
73.5M
      while (iter) {
341
44.7M
    next = iter->next;
342
44.7M
    if ((f != NULL) && (iter->payload != NULL))
343
34.6M
        f(iter->payload, iter->name);
344
44.7M
    if (table->dict == NULL) {
345
10.1M
        if (iter->name)
346
10.1M
      xmlFree(iter->name);
347
10.1M
        if (iter->name2)
348
354k
      xmlFree(iter->name2);
349
10.1M
        if (iter->name3)
350
6.03M
      xmlFree(iter->name3);
351
10.1M
    }
352
44.7M
    iter->payload = NULL;
353
44.7M
    if (!inside_table)
354
15.9M
        xmlFree(iter);
355
44.7M
    nbElems--;
356
44.7M
    inside_table = 0;
357
44.7M
    iter = next;
358
44.7M
      }
359
28.7M
  }
360
4.81M
  xmlFree(table->table);
361
4.81M
    }
362
4.81M
    if (table->dict)
363
762k
        xmlDictFree(table->dict);
364
4.81M
    xmlFree(table);
365
4.81M
}
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
928k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
928k
    xmlFree(entry);
377
928k
}
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
11.2M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
11.2M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
11.2M
}
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
21.3M
          const xmlChar *name2, void *userdata) {
410
21.3M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
21.3M
}
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
566k
       xmlHashDeallocator f) {
450
566k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
566k
}
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
561M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
561M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
561M
}
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
90.9M
        const xmlChar *name2) {
480
90.9M
    return(xmlHashLookup3(table, name, name2, NULL));
481
90.9M
}
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
7.14M
          const xmlChar *name2) {
515
7.14M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
7.14M
}
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
52.6M
     void *userdata) {
536
52.6M
    unsigned long key, len = 0;
537
52.6M
    xmlHashEntryPtr entry;
538
52.6M
    xmlHashEntryPtr insert;
539
540
52.6M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
52.6M
    if (table->dict) {
547
40.7M
        if (!xmlDictOwns(table->dict, name)) {
548
2.33M
      name = xmlDictLookup(table->dict, name, -1);
549
2.33M
      if (name == NULL)
550
0
          return(-1);
551
2.33M
  }
552
40.7M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
182k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
182k
      if (name2 == NULL)
555
0
          return(-1);
556
182k
  }
557
40.7M
        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
40.7M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
52.6M
    key = xmlHashComputeKey(table, name, name2, name3);
568
52.6M
    if (table->table[key].valid == 0) {
569
26.7M
  insert = NULL;
570
26.7M
    } else {
571
25.9M
        if (table->dict) {
572
43.3M
      for (insert = &(table->table[key]); insert->next != NULL;
573
22.4M
     insert = insert->next) {
574
22.4M
    if ((insert->name == name) &&
575
22.4M
        (insert->name2 == name2) &&
576
22.4M
        (insert->name3 == name3))
577
34.9k
        return(-1);
578
22.3M
    len++;
579
22.3M
      }
580
20.8M
      if ((insert->name == name) &&
581
20.8M
    (insert->name2 == name2) &&
582
20.8M
    (insert->name3 == name3))
583
2.25M
    return(-1);
584
20.8M
  } else {
585
6.77M
      for (insert = &(table->table[key]); insert->next != NULL;
586
4.99M
     insert = insert->next) {
587
1.82M
    if ((xmlStrEqual(insert->name, name)) &&
588
1.82M
        (xmlStrEqual(insert->name2, name2)) &&
589
1.82M
        (xmlStrEqual(insert->name3, name3)))
590
46.3k
        return(-1);
591
1.78M
    len++;
592
1.78M
      }
593
4.94M
      if ((xmlStrEqual(insert->name, name)) &&
594
4.94M
    (xmlStrEqual(insert->name2, name2)) &&
595
4.94M
    (xmlStrEqual(insert->name3, name3)))
596
1.71M
    return(-1);
597
4.94M
  }
598
25.9M
    }
599
600
48.6M
    if (insert == NULL) {
601
26.7M
  entry = &(table->table[key]);
602
26.7M
    } else {
603
21.8M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
21.8M
  if (entry == NULL)
605
0
       return(-1);
606
21.8M
    }
607
608
48.6M
    if (table->dict != NULL) {
609
38.4M
        entry->name = (xmlChar *) name;
610
38.4M
        entry->name2 = (xmlChar *) name2;
611
38.4M
        entry->name3 = (xmlChar *) name3;
612
38.4M
    } else {
613
10.1M
  entry->name = xmlStrdup(name);
614
10.1M
  entry->name2 = xmlStrdup(name2);
615
10.1M
  entry->name3 = xmlStrdup(name3);
616
10.1M
    }
617
48.6M
    entry->payload = userdata;
618
48.6M
    entry->next = NULL;
619
48.6M
    entry->valid = 1;
620
621
622
48.6M
    if (insert != NULL)
623
21.8M
  insert->next = entry;
624
625
48.6M
    table->nbElems++;
626
627
48.6M
    if (len > MAX_HASH_LEN)
628
50.9k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
48.6M
    return(0);
631
48.6M
}
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
566k
       void *userdata, xmlHashDeallocator f) {
652
566k
    unsigned long key;
653
566k
    xmlHashEntryPtr entry;
654
566k
    xmlHashEntryPtr insert;
655
656
566k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
566k
    if (table->dict) {
663
566k
        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
566k
        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
566k
        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
566k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
566k
    key = xmlHashComputeKey(table, name, name2, name3);
684
566k
    if (table->table[key].valid == 0) {
685
341k
  insert = NULL;
686
341k
    } else {
687
225k
        if (table ->dict) {
688
344k
      for (insert = &(table->table[key]); insert->next != NULL;
689
225k
     insert = insert->next) {
690
119k
    if ((insert->name == name) &&
691
119k
        (insert->name2 == name2) &&
692
119k
        (insert->name3 == name3)) {
693
399
        if (f)
694
0
      f(insert->payload, insert->name);
695
399
        insert->payload = userdata;
696
399
        return(0);
697
399
    }
698
119k
      }
699
224k
      if ((insert->name == name) &&
700
224k
    (insert->name2 == name2) &&
701
224k
    (insert->name3 == name3)) {
702
3.93k
    if (f)
703
0
        f(insert->payload, insert->name);
704
3.93k
    insert->payload = userdata;
705
3.93k
    return(0);
706
3.93k
      }
707
224k
  } 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
225k
    }
729
730
562k
    if (insert == NULL) {
731
341k
  entry =  &(table->table[key]);
732
341k
    } else {
733
220k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
220k
  if (entry == NULL)
735
0
       return(-1);
736
220k
    }
737
738
562k
    if (table->dict != NULL) {
739
562k
        entry->name = (xmlChar *) name;
740
562k
        entry->name2 = (xmlChar *) name2;
741
562k
        entry->name3 = (xmlChar *) name3;
742
562k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
562k
    entry->payload = userdata;
748
562k
    entry->next = NULL;
749
562k
    entry->valid = 1;
750
562k
    table->nbElems++;
751
752
753
562k
    if (insert != NULL) {
754
220k
  insert->next = entry;
755
220k
    }
756
562k
    return(0);
757
562k
}
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
672M
         const xmlChar *name2, const xmlChar *name3) {
773
672M
    unsigned long key;
774
672M
    xmlHashEntryPtr entry;
775
776
672M
    if (table == NULL)
777
4.38M
  return(NULL);
778
668M
    if (name == NULL)
779
0
  return(NULL);
780
668M
    key = xmlHashComputeKey(table, name, name2, name3);
781
668M
    if (table->table[key].valid == 0)
782
127M
  return(NULL);
783
541M
    if (table->dict) {
784
584M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
447M
      if ((entry->name == name) &&
786
447M
    (entry->name2 == name2) &&
787
447M
    (entry->name3 == name3))
788
267M
    return(entry->payload);
789
447M
  }
790
404M
    }
791
338M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
311M
  if ((xmlStrEqual(entry->name, name)) &&
793
311M
      (xmlStrEqual(entry->name2, name2)) &&
794
311M
      (xmlStrEqual(entry->name3, name3)))
795
247M
      return(entry->payload);
796
311M
    }
797
26.8M
    return(NULL);
798
274M
}
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
7.14M
    const xmlChar *prefix3, const xmlChar *name3) {
819
7.14M
    unsigned long key;
820
7.14M
    xmlHashEntryPtr entry;
821
822
7.14M
    if (table == NULL)
823
0
  return(NULL);
824
7.14M
    if (name == NULL)
825
0
  return(NULL);
826
7.14M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
7.14M
                             name2, prefix3, name3);
828
7.14M
    if (table->table[key].valid == 0)
829
808k
  return(NULL);
830
20.3M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
18.4M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
18.4M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
18.4M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
4.37M
      return(entry->payload);
835
18.4M
    }
836
1.95M
    return(NULL);
837
6.33M
}
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
9.44M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
9.44M
    stubData *stubdata = (stubData *) data;
849
9.44M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
9.44M
}
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
195k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
195k
    stubData stubdata;
863
195k
    stubdata.data = data;
864
195k
    stubdata.hashscanner = f;
865
195k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
195k
}
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
282k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
282k
    int i, nb;
879
282k
    xmlHashEntryPtr iter;
880
282k
    xmlHashEntryPtr next;
881
882
282k
    if (table == NULL)
883
14.5k
  return;
884
267k
    if (f == NULL)
885
0
  return;
886
887
267k
    if (table->table) {
888
53.8M
  for(i = 0; i < table->size; i++) {
889
53.5M
      if (table->table[i].valid == 0)
890
42.5M
    continue;
891
10.9M
      iter = &(table->table[i]);
892
33.5M
      while (iter) {
893
22.5M
    next = iter->next;
894
22.5M
                nb = table->nbElems;
895
22.5M
    if ((f != NULL) && (iter->payload != NULL))
896
22.5M
        f(iter->payload, data, iter->name,
897
22.5M
          iter->name2, iter->name3);
898
22.5M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
4.39M
                    if (iter == &(table->table[i])) {
901
2.34M
                        if (table->table[i].valid == 0)
902
1.25M
                            iter = NULL;
903
2.34M
                        if (table->table[i].next != next)
904
1.09M
          iter = &(table->table[i]);
905
2.34M
                    } else
906
2.04M
            iter = next;
907
4.39M
                } else
908
18.1M
        iter = next;
909
22.5M
      }
910
10.9M
  }
911
267k
    }
912
267k
}
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
2.13M
       xmlHashScanner f, void *data) {
931
2.13M
    stubData stubdata;
932
2.13M
    stubdata.data = data;
933
2.13M
    stubdata.hashscanner = f;
934
2.13M
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
2.13M
                     &stubdata);
936
2.13M
}
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
2.13M
     xmlHashScannerFull f, void *data) {
955
2.13M
    int i;
956
2.13M
    xmlHashEntryPtr iter;
957
2.13M
    xmlHashEntryPtr next;
958
959
2.13M
    if (table == NULL)
960
1.96M
  return;
961
171k
    if (f == NULL)
962
0
  return;
963
964
171k
    if (table->table) {
965
56.7M
  for(i = 0; i < table->size; i++) {
966
56.5M
      if (table->table[i].valid == 0)
967
18.0M
    continue;
968
38.5M
      iter = &(table->table[i]);
969
123M
      while (iter) {
970
84.8M
    next = iter->next;
971
84.8M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
84.8M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
84.8M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
84.8M
        (iter->payload != NULL)) {
975
468
        f(iter->payload, data, iter->name,
976
468
          iter->name2, iter->name3);
977
468
    }
978
84.8M
    iter = next;
979
84.8M
      }
980
38.5M
  }
981
171k
    }
982
171k
}
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
86.5k
xmlHashSize(xmlHashTablePtr table) {
1037
86.5k
    if (table == NULL)
1038
0
  return(-1);
1039
86.5k
    return(table->nbElems);
1040
86.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
418
           xmlHashDeallocator f) {
1056
418
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
418
}
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
4.39M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
4.39M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
4.39M
}
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
4.39M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
4.39M
    unsigned long key;
1096
4.39M
    xmlHashEntryPtr entry;
1097
4.39M
    xmlHashEntryPtr prev = NULL;
1098
1099
4.39M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
4.39M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
4.39M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
4.39M
    } else {
1106
8.03M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
8.03M
            if (xmlStrEqual(entry->name, name) &&
1108
8.03M
                    xmlStrEqual(entry->name2, name2) &&
1109
8.03M
                    xmlStrEqual(entry->name3, name3)) {
1110
4.39M
                if ((f != NULL) && (entry->payload != NULL))
1111
418
                    f(entry->payload, entry->name);
1112
4.39M
                entry->payload = NULL;
1113
4.39M
    if (table->dict == NULL) {
1114
831
        if(entry->name)
1115
831
      xmlFree(entry->name);
1116
831
        if(entry->name2)
1117
413
      xmlFree(entry->name2);
1118
831
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
831
    }
1121
4.39M
                if(prev) {
1122
2.04M
                    prev->next = entry->next;
1123
2.04M
        xmlFree(entry);
1124
2.35M
    } else {
1125
2.35M
        if (entry->next == NULL) {
1126
1.25M
      entry->valid = 0;
1127
1.25M
        } else {
1128
1.09M
      entry = entry->next;
1129
1.09M
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
1.09M
      xmlFree(entry);
1131
1.09M
        }
1132
2.35M
    }
1133
4.39M
                table->nbElems--;
1134
4.39M
                return(0);
1135
4.39M
            }
1136
3.63M
            prev = entry;
1137
3.63M
        }
1138
0
        return(-1);
1139
4.39M
    }
1140
4.39M
}
1141