Coverage Report

Created: 2023-05-18 19:11

/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
29.7M
#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
549M
            const xmlChar *name2, const xmlChar *name3) {
85
549M
    unsigned long value = 0L;
86
549M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
549M
    if (name != NULL) {
92
549M
  value += 30 * (*name);
93
11.1G
  while ((ch = *name++) != 0) {
94
10.6G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
10.6G
  }
96
549M
    }
97
549M
    value = value ^ ((value << 5) + (value >> 3));
98
549M
    if (name2 != NULL) {
99
146M
  while ((ch = *name2++) != 0) {
100
121M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
121M
  }
102
25.2M
    }
103
549M
    value = value ^ ((value << 5) + (value >> 3));
104
549M
    if (name3 != NULL) {
105
185M
  while ((ch = *name3++) != 0) {
106
159M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
159M
  }
108
26.3M
    }
109
549M
    return (value % table->size);
110
549M
}
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
4.32M
       const xmlChar *prefix3, const xmlChar *name3) {
120
4.32M
    unsigned long value = 0L;
121
4.32M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
4.32M
    if (prefix != NULL)
127
334k
  value += 30 * (*prefix);
128
3.98M
    else
129
3.98M
  value += 30 * (*name);
130
131
4.32M
    if (prefix != NULL) {
132
1.33M
  while ((ch = *prefix++) != 0) {
133
1.00M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
1.00M
  }
135
334k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
334k
    }
137
4.32M
    if (name != NULL) {
138
26.4M
  while ((ch = *name++) != 0) {
139
22.0M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
22.0M
  }
141
4.32M
    }
142
4.32M
    value = value ^ ((value << 5) + (value >> 3));
143
4.32M
    if (prefix2 != NULL) {
144
1.34M
  while ((ch = *prefix2++) != 0) {
145
1.01M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
1.01M
  }
147
332k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
332k
    }
149
4.32M
    if (name2 != NULL) {
150
18.3M
  while ((ch = *name2++) != 0) {
151
14.0M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
14.0M
  }
153
4.32M
    }
154
4.32M
    value = value ^ ((value << 5) + (value >> 3));
155
4.32M
    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
4.32M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
4.32M
    return (value % table->size);
167
4.32M
}
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
1.15M
xmlHashCreate(int size) {
179
1.15M
    xmlHashTablePtr table;
180
181
1.15M
    if (size <= 0)
182
732k
        size = 256;
183
184
1.15M
    table = xmlMalloc(sizeof(xmlHashTable));
185
1.15M
    if (table) {
186
1.15M
        table->dict = NULL;
187
1.15M
        table->size = size;
188
1.15M
  table->nbElems = 0;
189
1.15M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
1.15M
        if (table->table) {
191
1.15M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
1.15M
      return(table);
196
1.15M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
1.15M
}
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
887k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
887k
    xmlHashTablePtr table;
214
215
887k
    table = xmlHashCreate(size);
216
887k
    if (table != NULL) {
217
887k
        table->dict = dict;
218
887k
  xmlDictReference(dict);
219
887k
    }
220
887k
    return(table);
221
887k
}
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
33.3k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
33.3k
    unsigned long key;
235
33.3k
    int oldsize, i;
236
33.3k
    xmlHashEntryPtr iter, next;
237
33.3k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
33.3k
    if (table == NULL)
243
0
  return(-1);
244
33.3k
    if (size < 8)
245
0
        return(-1);
246
33.3k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
33.3k
    oldsize = table->size;
250
33.3k
    oldtable = table->table;
251
33.3k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
33.3k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
33.3k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
33.3k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
33.3k
    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
988k
    for (i = 0; i < oldsize; i++) {
269
955k
  if (oldtable[i].valid == 0)
270
44.5k
      continue;
271
910k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
910k
        oldtable[i].name3);
273
910k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
910k
  table->table[key].next = NULL;
275
910k
    }
276
277
988k
    for (i = 0; i < oldsize; i++) {
278
955k
  iter = oldtable[i].next;
279
4.11M
  while (iter) {
280
3.15M
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
3.15M
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
3.15M
                        iter->name3);
288
3.15M
      if (table->table[key].valid == 0) {
289
2.14M
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
2.14M
    table->table[key].next = NULL;
291
2.14M
    xmlFree(iter);
292
2.14M
      } else {
293
1.01M
    iter->next = table->table[key].next;
294
1.01M
    table->table[key].next = iter;
295
1.01M
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
3.15M
      iter = next;
302
3.15M
  }
303
955k
    }
304
305
33.3k
    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
33.3k
    return(0);
313
33.3k
}
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
1.15M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
1.15M
    int i;
326
1.15M
    xmlHashEntryPtr iter;
327
1.15M
    xmlHashEntryPtr next;
328
1.15M
    int inside_table = 0;
329
1.15M
    int nbElems;
330
331
1.15M
    if (table == NULL)
332
0
  return;
333
1.15M
    if (table->table) {
334
1.15M
  nbElems = table->nbElems;
335
162M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
161M
      iter = &(table->table[i]);
337
161M
      if (iter->valid == 0)
338
141M
    continue;
339
19.5M
      inside_table = 1;
340
47.4M
      while (iter) {
341
27.9M
    next = iter->next;
342
27.9M
    if ((f != NULL) && (iter->payload != NULL))
343
22.1M
        f(iter->payload, iter->name);
344
27.9M
    if (table->dict == NULL) {
345
8.20M
        if (iter->name)
346
8.20M
      xmlFree(iter->name);
347
8.20M
        if (iter->name2)
348
272k
      xmlFree(iter->name2);
349
8.20M
        if (iter->name3)
350
4.40M
      xmlFree(iter->name3);
351
8.20M
    }
352
27.9M
    iter->payload = NULL;
353
27.9M
    if (!inside_table)
354
8.38M
        xmlFree(iter);
355
27.9M
    nbElems--;
356
27.9M
    inside_table = 0;
357
27.9M
    iter = next;
358
27.9M
      }
359
19.5M
  }
360
1.15M
  xmlFree(table->table);
361
1.15M
    }
362
1.15M
    if (table->dict)
363
627k
        xmlDictFree(table->dict);
364
1.15M
    xmlFree(table);
365
1.15M
}
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
693k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
693k
    xmlFree(entry);
377
693k
}
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
5.89M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
5.89M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
5.89M
}
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
12.1M
          const xmlChar *name2, void *userdata) {
410
12.1M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
12.1M
}
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
330k
       xmlHashDeallocator f) {
450
330k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
330k
}
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
445M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
445M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
445M
}
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
55.5M
        const xmlChar *name2) {
480
55.5M
    return(xmlHashLookup3(table, name, name2, NULL));
481
55.5M
}
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
4.32M
          const xmlChar *name2) {
515
4.32M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
4.32M
}
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
29.7M
     void *userdata) {
536
29.7M
    unsigned long key, len = 0;
537
29.7M
    xmlHashEntryPtr entry;
538
29.7M
    xmlHashEntryPtr insert;
539
540
29.7M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
29.7M
    if (table->dict) {
547
21.5M
        if (!xmlDictOwns(table->dict, name)) {
548
1.44M
      name = xmlDictLookup(table->dict, name, -1);
549
1.44M
      if (name == NULL)
550
0
          return(-1);
551
1.44M
  }
552
21.5M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
165k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
165k
      if (name2 == NULL)
555
0
          return(-1);
556
165k
  }
557
21.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
21.5M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
29.7M
    key = xmlHashComputeKey(table, name, name2, name3);
568
29.7M
    if (table->table[key].valid == 0) {
569
17.9M
  insert = NULL;
570
17.9M
    } else {
571
11.8M
        if (table->dict) {
572
21.5M
      for (insert = &(table->table[key]); insert->next != NULL;
573
11.8M
     insert = insert->next) {
574
11.8M
    if ((insert->name == name) &&
575
11.8M
        (insert->name2 == name2) &&
576
11.8M
        (insert->name3 == name3))
577
10.3k
        return(-1);
578
11.8M
    len++;
579
11.8M
      }
580
9.70M
      if ((insert->name == name) &&
581
9.70M
    (insert->name2 == name2) &&
582
9.70M
    (insert->name3 == name3))
583
49.2k
    return(-1);
584
9.70M
  } else {
585
3.17M
      for (insert = &(table->table[key]); insert->next != NULL;
586
2.17M
     insert = insert->next) {
587
1.00M
    if ((xmlStrEqual(insert->name, name)) &&
588
1.00M
        (xmlStrEqual(insert->name2, name2)) &&
589
1.00M
        (xmlStrEqual(insert->name3, name3)))
590
3.25k
        return(-1);
591
1.00M
    len++;
592
1.00M
      }
593
2.16M
      if ((xmlStrEqual(insert->name, name)) &&
594
2.16M
    (xmlStrEqual(insert->name2, name2)) &&
595
2.16M
    (xmlStrEqual(insert->name3, name3)))
596
14.6k
    return(-1);
597
2.16M
  }
598
11.8M
    }
599
600
29.7M
    if (insert == NULL) {
601
17.9M
  entry = &(table->table[key]);
602
17.9M
    } else {
603
11.8M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
11.8M
  if (entry == NULL)
605
0
       return(-1);
606
11.8M
    }
607
608
29.7M
    if (table->dict != NULL) {
609
21.5M
        entry->name = (xmlChar *) name;
610
21.5M
        entry->name2 = (xmlChar *) name2;
611
21.5M
        entry->name3 = (xmlChar *) name3;
612
21.5M
    } else {
613
8.20M
  entry->name = xmlStrdup(name);
614
8.20M
  entry->name2 = xmlStrdup(name2);
615
8.20M
  entry->name3 = xmlStrdup(name3);
616
8.20M
    }
617
29.7M
    entry->payload = userdata;
618
29.7M
    entry->next = NULL;
619
29.7M
    entry->valid = 1;
620
621
622
29.7M
    if (insert != NULL)
623
11.8M
  insert->next = entry;
624
625
29.7M
    table->nbElems++;
626
627
29.7M
    if (len > MAX_HASH_LEN)
628
33.3k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
29.7M
    return(0);
631
29.7M
}
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
330k
       void *userdata, xmlHashDeallocator f) {
652
330k
    unsigned long key;
653
330k
    xmlHashEntryPtr entry;
654
330k
    xmlHashEntryPtr insert;
655
656
330k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
330k
    if (table->dict) {
663
330k
        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
330k
        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
330k
        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
330k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
330k
    key = xmlHashComputeKey(table, name, name2, name3);
684
330k
    if (table->table[key].valid == 0) {
685
205k
  insert = NULL;
686
205k
    } else {
687
125k
        if (table ->dict) {
688
268k
      for (insert = &(table->table[key]); insert->next != NULL;
689
143k
     insert = insert->next) {
690
143k
    if ((insert->name == name) &&
691
143k
        (insert->name2 == name2) &&
692
143k
        (insert->name3 == name3)) {
693
212
        if (f)
694
0
      f(insert->payload, insert->name);
695
212
        insert->payload = userdata;
696
212
        return(0);
697
212
    }
698
143k
      }
699
124k
      if ((insert->name == name) &&
700
124k
    (insert->name2 == name2) &&
701
124k
    (insert->name3 == name3)) {
702
2.72k
    if (f)
703
0
        f(insert->payload, insert->name);
704
2.72k
    insert->payload = userdata;
705
2.72k
    return(0);
706
2.72k
      }
707
124k
  } 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
125k
    }
729
730
327k
    if (insert == NULL) {
731
205k
  entry =  &(table->table[key]);
732
205k
    } else {
733
122k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
122k
  if (entry == NULL)
735
0
       return(-1);
736
122k
    }
737
738
327k
    if (table->dict != NULL) {
739
327k
        entry->name = (xmlChar *) name;
740
327k
        entry->name2 = (xmlChar *) name2;
741
327k
        entry->name3 = (xmlChar *) name3;
742
327k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
327k
    entry->payload = userdata;
748
327k
    entry->next = NULL;
749
327k
    entry->valid = 1;
750
327k
    table->nbElems++;
751
752
753
327k
    if (insert != NULL) {
754
122k
  insert->next = entry;
755
122k
    }
756
327k
    return(0);
757
327k
}
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
515M
         const xmlChar *name2, const xmlChar *name3) {
773
515M
    unsigned long key;
774
515M
    xmlHashEntryPtr entry;
775
776
515M
    if (table == NULL)
777
2.42M
  return(NULL);
778
512M
    if (name == NULL)
779
0
  return(NULL);
780
512M
    key = xmlHashComputeKey(table, name, name2, name3);
781
512M
    if (table->table[key].valid == 0)
782
100M
  return(NULL);
783
412M
    if (table->dict) {
784
368M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
280M
      if ((entry->name == name) &&
786
280M
    (entry->name2 == name2) &&
787
280M
    (entry->name3 == name3))
788
170M
    return(entry->payload);
789
280M
  }
790
258M
    }
791
276M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
261M
  if ((xmlStrEqual(entry->name, name)) &&
793
261M
      (xmlStrEqual(entry->name2, name2)) &&
794
261M
      (xmlStrEqual(entry->name3, name3)))
795
227M
      return(entry->payload);
796
261M
    }
797
14.4M
    return(NULL);
798
241M
}
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
4.32M
    const xmlChar *prefix3, const xmlChar *name3) {
819
4.32M
    unsigned long key;
820
4.32M
    xmlHashEntryPtr entry;
821
822
4.32M
    if (table == NULL)
823
0
  return(NULL);
824
4.32M
    if (name == NULL)
825
0
  return(NULL);
826
4.32M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
4.32M
                             name2, prefix3, name3);
828
4.32M
    if (table->table[key].valid == 0)
829
406k
  return(NULL);
830
12.1M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
10.7M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
10.7M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
10.7M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
2.52M
      return(entry->payload);
835
10.7M
    }
836
1.38M
    return(NULL);
837
3.91M
}
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
6.08M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
6.08M
    stubData *stubdata = (stubData *) data;
849
6.08M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
6.08M
}
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
166k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
166k
    stubData stubdata;
863
166k
    stubdata.data = data;
864
166k
    stubdata.hashscanner = f;
865
166k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
166k
}
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
241k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
241k
    int i, nb;
879
241k
    xmlHashEntryPtr iter;
880
241k
    xmlHashEntryPtr next;
881
882
241k
    if (table == NULL)
883
11.0k
  return;
884
230k
    if (f == NULL)
885
0
  return;
886
887
230k
    if (table->table) {
888
45.2M
  for(i = 0; i < table->size; i++) {
889
45.0M
      if (table->table[i].valid == 0)
890
37.8M
    continue;
891
7.21M
      iter = &(table->table[i]);
892
19.8M
      while (iter) {
893
12.6M
    next = iter->next;
894
12.6M
                nb = table->nbElems;
895
12.6M
    if ((f != NULL) && (iter->payload != NULL))
896
12.6M
        f(iter->payload, data, iter->name,
897
12.6M
          iter->name2, iter->name3);
898
12.6M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
2.13M
                    if (iter == &(table->table[i])) {
901
1.29M
                        if (table->table[i].valid == 0)
902
728k
                            iter = NULL;
903
1.29M
                        if (table->table[i].next != next)
904
562k
          iter = &(table->table[i]);
905
1.29M
                    } else
906
842k
            iter = next;
907
2.13M
                } else
908
10.4M
        iter = next;
909
12.6M
      }
910
7.21M
  }
911
230k
    }
912
230k
}
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
1.36M
       xmlHashScanner f, void *data) {
931
1.36M
    stubData stubdata;
932
1.36M
    stubdata.data = data;
933
1.36M
    stubdata.hashscanner = f;
934
1.36M
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
1.36M
                     &stubdata);
936
1.36M
}
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
1.36M
     xmlHashScannerFull f, void *data) {
955
1.36M
    int i;
956
1.36M
    xmlHashEntryPtr iter;
957
1.36M
    xmlHashEntryPtr next;
958
959
1.36M
    if (table == NULL)
960
1.26M
  return;
961
101k
    if (f == NULL)
962
0
  return;
963
964
101k
    if (table->table) {
965
31.8M
  for(i = 0; i < table->size; i++) {
966
31.7M
      if (table->table[i].valid == 0)
967
13.0M
    continue;
968
18.7M
      iter = &(table->table[i]);
969
59.2M
      while (iter) {
970
40.4M
    next = iter->next;
971
40.4M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
40.4M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
40.4M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
40.4M
        (iter->payload != NULL)) {
975
28
        f(iter->payload, data, iter->name,
976
28
          iter->name2, iter->name3);
977
28
    }
978
40.4M
    iter = next;
979
40.4M
      }
980
18.7M
  }
981
101k
    }
982
101k
}
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
75.1k
xmlHashSize(xmlHashTablePtr table) {
1037
75.1k
    if (table == NULL)
1038
0
  return(-1);
1039
75.1k
    return(table->nbElems);
1040
75.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
158
           xmlHashDeallocator f) {
1056
158
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
158
}
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
2.13M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
2.13M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
2.13M
}
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
2.13M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
2.13M
    unsigned long key;
1096
2.13M
    xmlHashEntryPtr entry;
1097
2.13M
    xmlHashEntryPtr prev = NULL;
1098
1099
2.13M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
2.13M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
2.13M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
2.13M
    } else {
1106
3.50M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
3.50M
            if (xmlStrEqual(entry->name, name) &&
1108
3.50M
                    xmlStrEqual(entry->name2, name2) &&
1109
3.50M
                    xmlStrEqual(entry->name3, name3)) {
1110
2.13M
                if ((f != NULL) && (entry->payload != NULL))
1111
158
                    f(entry->payload, entry->name);
1112
2.13M
                entry->payload = NULL;
1113
2.13M
    if (table->dict == NULL) {
1114
807
        if(entry->name)
1115
807
      xmlFree(entry->name);
1116
807
        if(entry->name2)
1117
114
      xmlFree(entry->name2);
1118
807
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
807
    }
1121
2.13M
                if(prev) {
1122
842k
                    prev->next = entry->next;
1123
842k
        xmlFree(entry);
1124
1.29M
    } else {
1125
1.29M
        if (entry->next == NULL) {
1126
730k
      entry->valid = 0;
1127
730k
        } else {
1128
562k
      entry = entry->next;
1129
562k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
562k
      xmlFree(entry);
1131
562k
        }
1132
1.29M
    }
1133
2.13M
                table->nbElems--;
1134
2.13M
                return(0);
1135
2.13M
            }
1136
1.37M
            prev = entry;
1137
1.37M
        }
1138
0
        return(-1);
1139
2.13M
    }
1140
2.13M
}
1141