Coverage Report

Created: 2024-05-18 02:13

/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
16.4M
#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
66.2M
            const xmlChar *name2, const xmlChar *name3) {
85
66.2M
    unsigned long value = 0L;
86
66.2M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
66.2M
    if (name != NULL) {
92
66.2M
  value += 30 * (*name);
93
579M
  while ((ch = *name++) != 0) {
94
513M
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
513M
  }
96
66.2M
    }
97
66.2M
    value = value ^ ((value << 5) + (value >> 3));
98
66.2M
    if (name2 != NULL) {
99
83.7M
  while ((ch = *name2++) != 0) {
100
69.4M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
69.4M
  }
102
14.2M
    }
103
66.2M
    value = value ^ ((value << 5) + (value >> 3));
104
66.2M
    if (name3 != NULL) {
105
107M
  while ((ch = *name3++) != 0) {
106
93.1M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
93.1M
  }
108
14.2M
    }
109
66.2M
    return (value % table->size);
110
66.2M
}
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
2.07M
       const xmlChar *prefix3, const xmlChar *name3) {
120
2.07M
    unsigned long value = 0L;
121
2.07M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
2.07M
    if (prefix != NULL)
127
395k
  value += 30 * (*prefix);
128
1.68M
    else
129
1.68M
  value += 30 * (*name);
130
131
2.07M
    if (prefix != NULL) {
132
1.60M
  while ((ch = *prefix++) != 0) {
133
1.20M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
1.20M
  }
135
395k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
395k
    }
137
2.07M
    if (name != NULL) {
138
13.3M
  while ((ch = *name++) != 0) {
139
11.2M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
11.2M
  }
141
2.07M
    }
142
2.07M
    value = value ^ ((value << 5) + (value >> 3));
143
2.07M
    if (prefix2 != NULL) {
144
1.59M
  while ((ch = *prefix2++) != 0) {
145
1.20M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
1.20M
  }
147
393k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
393k
    }
149
2.07M
    if (name2 != NULL) {
150
9.14M
  while ((ch = *name2++) != 0) {
151
7.06M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
7.06M
  }
153
2.07M
    }
154
2.07M
    value = value ^ ((value << 5) + (value >> 3));
155
2.07M
    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
2.07M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
2.07M
    return (value % table->size);
167
2.07M
}
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
7.26M
xmlHashCreate(int size) {
179
7.26M
    xmlHashTablePtr table;
180
181
7.26M
    if (size <= 0)
182
588k
        size = 256;
183
184
7.26M
    table = xmlMalloc(sizeof(xmlHashTable));
185
7.26M
    if (table) {
186
7.26M
        table->dict = NULL;
187
7.26M
        table->size = size;
188
7.26M
  table->nbElems = 0;
189
7.26M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
7.26M
        if (table->table) {
191
7.26M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
7.26M
      return(table);
196
7.26M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
7.26M
}
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
656k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
656k
    xmlHashTablePtr table;
214
215
656k
    table = xmlHashCreate(size);
216
656k
    if (table != NULL) {
217
656k
        table->dict = dict;
218
656k
  xmlDictReference(dict);
219
656k
    }
220
656k
    return(table);
221
656k
}
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
14.1k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
14.1k
    unsigned long key;
235
14.1k
    int oldsize, i;
236
14.1k
    xmlHashEntryPtr iter, next;
237
14.1k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
14.1k
    if (table == NULL)
243
0
  return(-1);
244
14.1k
    if (size < 8)
245
0
        return(-1);
246
14.1k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
14.1k
    oldsize = table->size;
250
14.1k
    oldtable = table->table;
251
14.1k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
14.1k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
14.1k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
14.1k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
14.1k
    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
335k
    for (i = 0; i < oldsize; i++) {
269
320k
  if (oldtable[i].valid == 0)
270
3.07k
      continue;
271
317k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
317k
        oldtable[i].name3);
273
317k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
317k
  table->table[key].next = NULL;
275
317k
    }
276
277
335k
    for (i = 0; i < oldsize; i++) {
278
320k
  iter = oldtable[i].next;
279
1.63M
  while (iter) {
280
1.31M
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
1.31M
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
1.31M
                        iter->name3);
288
1.31M
      if (table->table[key].valid == 0) {
289
882k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
882k
    table->table[key].next = NULL;
291
882k
    xmlFree(iter);
292
882k
      } else {
293
432k
    iter->next = table->table[key].next;
294
432k
    table->table[key].next = iter;
295
432k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
1.31M
      iter = next;
302
1.31M
  }
303
320k
    }
304
305
14.1k
    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
14.1k
    return(0);
313
14.1k
}
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
7.37M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
7.37M
    int i;
326
7.37M
    xmlHashEntryPtr iter;
327
7.37M
    xmlHashEntryPtr next;
328
7.37M
    int inside_table = 0;
329
7.37M
    int nbElems;
330
331
7.37M
    if (table == NULL)
332
108k
  return;
333
7.26M
    if (table->table) {
334
7.26M
  nbElems = table->nbElems;
335
134M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
127M
      iter = &(table->table[i]);
337
127M
      if (iter->valid == 0)
338
116M
    continue;
339
11.4M
      inside_table = 1;
340
26.7M
      while (iter) {
341
15.2M
    next = iter->next;
342
15.2M
    if ((f != NULL) && (iter->payload != NULL))
343
11.4M
        f(iter->payload, iter->name);
344
15.2M
    if (table->dict == NULL) {
345
5.89M
        if (iter->name)
346
5.89M
      xmlFree(iter->name);
347
5.89M
        if (iter->name2)
348
341k
      xmlFree(iter->name2);
349
5.89M
        if (iter->name3)
350
2.12M
      xmlFree(iter->name3);
351
5.89M
    }
352
15.2M
    iter->payload = NULL;
353
15.2M
    if (!inside_table)
354
3.79M
        xmlFree(iter);
355
15.2M
    nbElems--;
356
15.2M
    inside_table = 0;
357
15.2M
    iter = next;
358
15.2M
      }
359
11.4M
  }
360
7.26M
  xmlFree(table->table);
361
7.26M
    }
362
7.26M
    if (table->dict)
363
487k
        xmlDictFree(table->dict);
364
7.26M
    xmlFree(table);
365
7.26M
}
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
510k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
510k
    xmlFree(entry);
377
510k
}
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
2.93M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
2.93M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
2.93M
}
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
7.56M
          const xmlChar *name2, void *userdata) {
410
7.56M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
7.56M
}
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
146k
       xmlHashDeallocator f) {
450
146k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
146k
}
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
11.0M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
11.0M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
11.0M
}
466
467
/**
468
 * xmlHashLookup2:
469
 * @table: the hash table
470
 * @name: the name of the userdata
471
 * @name2: a second name of the userdata
472
 *
473
 * Find the userdata specified by the (@name, @name2) tuple.
474
 *
475
 * Returns the pointer to the userdata
476
 */
477
void *
478
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
479
28.3M
        const xmlChar *name2) {
480
28.3M
    return(xmlHashLookup3(table, name, name2, NULL));
481
28.3M
}
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
2.07M
          const xmlChar *name2) {
515
2.07M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
2.07M
}
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
16.4M
     void *userdata) {
536
16.4M
    unsigned long key, len = 0;
537
16.4M
    xmlHashEntryPtr entry;
538
16.4M
    xmlHashEntryPtr insert;
539
540
16.4M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
16.4M
    if (table->dict) {
547
10.5M
        if (!xmlDictOwns(table->dict, name)) {
548
659k
      name = xmlDictLookup(table->dict, name, -1);
549
659k
      if (name == NULL)
550
0
          return(-1);
551
659k
  }
552
10.5M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
229k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
229k
      if (name2 == NULL)
555
0
          return(-1);
556
229k
  }
557
10.5M
        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
10.5M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
16.4M
    key = xmlHashComputeKey(table, name, name2, name3);
568
16.4M
    if (table->table[key].valid == 0) {
569
11.0M
  insert = NULL;
570
11.0M
    } else {
571
5.47M
        if (table->dict) {
572
9.63M
      for (insert = &(table->table[key]); insert->next != NULL;
573
5.19M
     insert = insert->next) {
574
5.19M
    if ((insert->name == name) &&
575
5.19M
        (insert->name2 == name2) &&
576
5.19M
        (insert->name3 == name3))
577
110
        return(-1);
578
5.19M
    len++;
579
5.19M
      }
580
4.43M
      if ((insert->name == name) &&
581
4.43M
    (insert->name2 == name2) &&
582
4.43M
    (insert->name3 == name3))
583
10.8k
    return(-1);
584
4.43M
  } else {
585
1.44M
      for (insert = &(table->table[key]); insert->next != NULL;
586
1.03M
     insert = insert->next) {
587
412k
    if ((xmlStrEqual(insert->name, name)) &&
588
412k
        (xmlStrEqual(insert->name2, name2)) &&
589
412k
        (xmlStrEqual(insert->name3, name3)))
590
344
        return(-1);
591
412k
    len++;
592
412k
      }
593
1.03M
      if ((xmlStrEqual(insert->name, name)) &&
594
1.03M
    (xmlStrEqual(insert->name2, name2)) &&
595
1.03M
    (xmlStrEqual(insert->name3, name3)))
596
7.72k
    return(-1);
597
1.03M
  }
598
5.47M
    }
599
600
16.4M
    if (insert == NULL) {
601
11.0M
  entry = &(table->table[key]);
602
11.0M
    } else {
603
5.45M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
5.45M
  if (entry == NULL)
605
0
       return(-1);
606
5.45M
    }
607
608
16.4M
    if (table->dict != NULL) {
609
10.5M
        entry->name = (xmlChar *) name;
610
10.5M
        entry->name2 = (xmlChar *) name2;
611
10.5M
        entry->name3 = (xmlChar *) name3;
612
10.5M
    } else {
613
5.89M
  entry->name = xmlStrdup(name);
614
5.89M
  entry->name2 = xmlStrdup(name2);
615
5.89M
  entry->name3 = xmlStrdup(name3);
616
5.89M
    }
617
16.4M
    entry->payload = userdata;
618
16.4M
    entry->next = NULL;
619
16.4M
    entry->valid = 1;
620
621
622
16.4M
    if (insert != NULL)
623
5.45M
  insert->next = entry;
624
625
16.4M
    table->nbElems++;
626
627
16.4M
    if (len > MAX_HASH_LEN)
628
14.1k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
16.4M
    return(0);
631
16.4M
}
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
146k
       void *userdata, xmlHashDeallocator f) {
652
146k
    unsigned long key;
653
146k
    xmlHashEntryPtr entry;
654
146k
    xmlHashEntryPtr insert;
655
656
146k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
146k
    if (table->dict) {
663
146k
        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
146k
        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
146k
        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
146k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
146k
    key = xmlHashComputeKey(table, name, name2, name3);
684
146k
    if (table->table[key].valid == 0) {
685
99.6k
  insert = NULL;
686
99.6k
    } else {
687
46.6k
        if (table ->dict) {
688
90.1k
      for (insert = &(table->table[key]); insert->next != NULL;
689
46.6k
     insert = insert->next) {
690
43.7k
    if ((insert->name == name) &&
691
43.7k
        (insert->name2 == name2) &&
692
43.7k
        (insert->name3 == name3)) {
693
269
        if (f)
694
0
      f(insert->payload, insert->name);
695
269
        insert->payload = userdata;
696
269
        return(0);
697
269
    }
698
43.7k
      }
699
46.3k
      if ((insert->name == name) &&
700
46.3k
    (insert->name2 == name2) &&
701
46.3k
    (insert->name3 == name3)) {
702
3.20k
    if (f)
703
0
        f(insert->payload, insert->name);
704
3.20k
    insert->payload = userdata;
705
3.20k
    return(0);
706
3.20k
      }
707
46.3k
  } 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
46.6k
    }
729
730
142k
    if (insert == NULL) {
731
99.6k
  entry =  &(table->table[key]);
732
99.6k
    } else {
733
43.1k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
43.1k
  if (entry == NULL)
735
0
       return(-1);
736
43.1k
    }
737
738
142k
    if (table->dict != NULL) {
739
142k
        entry->name = (xmlChar *) name;
740
142k
        entry->name2 = (xmlChar *) name2;
741
142k
        entry->name3 = (xmlChar *) name3;
742
142k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
142k
    entry->payload = userdata;
748
142k
    entry->next = NULL;
749
142k
    entry->valid = 1;
750
142k
    table->nbElems++;
751
752
753
142k
    if (insert != NULL) {
754
43.1k
  insert->next = entry;
755
43.1k
    }
756
142k
    return(0);
757
142k
}
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
47.7M
         const xmlChar *name2, const xmlChar *name3) {
773
47.7M
    unsigned long key;
774
47.7M
    xmlHashEntryPtr entry;
775
776
47.7M
    if (table == NULL)
777
1.09M
  return(NULL);
778
46.6M
    if (name == NULL)
779
0
  return(NULL);
780
46.6M
    key = xmlHashComputeKey(table, name, name2, name3);
781
46.6M
    if (table->table[key].valid == 0)
782
13.5M
  return(NULL);
783
33.0M
    if (table->dict) {
784
42.3M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
30.8M
      if ((entry->name == name) &&
786
30.8M
    (entry->name2 == name2) &&
787
30.8M
    (entry->name3 == name3))
788
10.0M
    return(entry->payload);
789
30.8M
  }
790
21.5M
    }
791
38.2M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
32.0M
  if ((xmlStrEqual(entry->name, name)) &&
793
32.0M
      (xmlStrEqual(entry->name2, name2)) &&
794
32.0M
      (xmlStrEqual(entry->name3, name3)))
795
16.8M
      return(entry->payload);
796
32.0M
    }
797
6.21M
    return(NULL);
798
23.0M
}
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
2.07M
    const xmlChar *prefix3, const xmlChar *name3) {
819
2.07M
    unsigned long key;
820
2.07M
    xmlHashEntryPtr entry;
821
822
2.07M
    if (table == NULL)
823
0
  return(NULL);
824
2.07M
    if (name == NULL)
825
0
  return(NULL);
826
2.07M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
2.07M
                             name2, prefix3, name3);
828
2.07M
    if (table->table[key].valid == 0)
829
431k
  return(NULL);
830
4.73M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
3.91M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
3.91M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
3.91M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
821k
      return(entry->payload);
835
3.91M
    }
836
823k
    return(NULL);
837
1.64M
}
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
3.15M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
3.15M
    stubData *stubdata = (stubData *) data;
849
3.15M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
3.15M
}
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
263k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
263k
    stubData stubdata;
863
263k
    stubdata.data = data;
864
263k
    stubdata.hashscanner = f;
865
263k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
263k
}
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
341k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
341k
    int i, nb;
879
341k
    xmlHashEntryPtr iter;
880
341k
    xmlHashEntryPtr next;
881
882
341k
    if (table == NULL)
883
11.0k
  return;
884
330k
    if (f == NULL)
885
0
  return;
886
887
330k
    if (table->table) {
888
68.0M
  for(i = 0; i < table->size; i++) {
889
67.6M
      if (table->table[i].valid == 0)
890
63.6M
    continue;
891
4.05M
      iter = &(table->table[i]);
892
10.8M
      while (iter) {
893
6.74M
    next = iter->next;
894
6.74M
                nb = table->nbElems;
895
6.74M
    if ((f != NULL) && (iter->payload != NULL))
896
6.74M
        f(iter->payload, data, iter->name,
897
6.74M
          iter->name2, iter->name3);
898
6.74M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
1.32M
                    if (iter == &(table->table[i])) {
901
871k
                        if (table->table[i].valid == 0)
902
498k
                            iter = NULL;
903
871k
                        if (table->table[i].next != next)
904
372k
          iter = &(table->table[i]);
905
871k
                    } else
906
450k
            iter = next;
907
1.32M
                } else
908
5.42M
        iter = next;
909
6.74M
      }
910
4.05M
  }
911
330k
    }
912
330k
}
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
546k
       xmlHashScanner f, void *data) {
931
546k
    stubData stubdata;
932
546k
    stubdata.data = data;
933
546k
    stubdata.hashscanner = f;
934
546k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
546k
                     &stubdata);
936
546k
}
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
546k
     xmlHashScannerFull f, void *data) {
955
546k
    int i;
956
546k
    xmlHashEntryPtr iter;
957
546k
    xmlHashEntryPtr next;
958
959
546k
    if (table == NULL)
960
487k
  return;
961
59.4k
    if (f == NULL)
962
0
  return;
963
964
59.4k
    if (table->table) {
965
15.2M
  for(i = 0; i < table->size; i++) {
966
15.2M
      if (table->table[i].valid == 0)
967
3.33M
    continue;
968
11.8M
      iter = &(table->table[i]);
969
38.9M
      while (iter) {
970
27.0M
    next = iter->next;
971
27.0M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
27.0M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
27.0M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
27.0M
        (iter->payload != NULL)) {
975
112
        f(iter->payload, data, iter->name,
976
112
          iter->name2, iter->name3);
977
112
    }
978
27.0M
    iter = next;
979
27.0M
      }
980
11.8M
  }
981
59.4k
    }
982
59.4k
}
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
77.8k
xmlHashSize(xmlHashTablePtr table) {
1037
77.8k
    if (table == NULL)
1038
0
  return(-1);
1039
77.8k
    return(table->nbElems);
1040
77.8k
}
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
2.68k
           xmlHashDeallocator f) {
1056
2.68k
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
2.68k
}
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.32M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
1.32M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
1.32M
}
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.32M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
1.32M
    unsigned long key;
1096
1.32M
    xmlHashEntryPtr entry;
1097
1.32M
    xmlHashEntryPtr prev = NULL;
1098
1099
1.32M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
1.32M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
1.32M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
1.32M
    } else {
1106
1.97M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
1.97M
            if (xmlStrEqual(entry->name, name) &&
1108
1.97M
                    xmlStrEqual(entry->name2, name2) &&
1109
1.97M
                    xmlStrEqual(entry->name3, name3)) {
1110
1.32M
                if ((f != NULL) && (entry->payload != NULL))
1111
2.68k
                    f(entry->payload, entry->name);
1112
1.32M
                entry->payload = NULL;
1113
1.32M
    if (table->dict == NULL) {
1114
1.44k
        if(entry->name)
1115
1.44k
      xmlFree(entry->name);
1116
1.44k
        if(entry->name2)
1117
73
      xmlFree(entry->name2);
1118
1.44k
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
1.44k
    }
1121
1.32M
                if(prev) {
1122
450k
                    prev->next = entry->next;
1123
450k
        xmlFree(entry);
1124
876k
    } else {
1125
876k
        if (entry->next == NULL) {
1126
503k
      entry->valid = 0;
1127
503k
        } else {
1128
372k
      entry = entry->next;
1129
372k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
372k
      xmlFree(entry);
1131
372k
        }
1132
876k
    }
1133
1.32M
                table->nbElems--;
1134
1.32M
                return(0);
1135
1.32M
            }
1136
644k
            prev = entry;
1137
644k
        }
1138
0
        return(-1);
1139
1.32M
    }
1140
1.32M
}
1141