Coverage Report

Created: 2023-05-06 06:59

/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
2.75M
#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
12.5M
            const xmlChar *name2, const xmlChar *name3) {
85
12.5M
    unsigned long value = 0L;
86
12.5M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
12.5M
    if (name != NULL) {
92
12.5M
  value += 30 * (*name);
93
88.8M
  while ((ch = *name++) != 0) {
94
76.3M
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
76.3M
  }
96
12.5M
    }
97
12.5M
    value = value ^ ((value << 5) + (value >> 3));
98
12.5M
    if (name2 != NULL) {
99
9.13M
  while ((ch = *name2++) != 0) {
100
7.30M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
7.30M
  }
102
1.82M
    }
103
12.5M
    value = value ^ ((value << 5) + (value >> 3));
104
12.5M
    if (name3 != NULL) {
105
16.4M
  while ((ch = *name3++) != 0) {
106
13.7M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
13.7M
  }
108
2.71M
    }
109
12.5M
    return (value % table->size);
110
12.5M
}
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
953k
       const xmlChar *prefix3, const xmlChar *name3) {
120
953k
    unsigned long value = 0L;
121
953k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
953k
    if (prefix != NULL)
127
10.8k
  value += 30 * (*prefix);
128
942k
    else
129
942k
  value += 30 * (*name);
130
131
953k
    if (prefix != NULL) {
132
42.8k
  while ((ch = *prefix++) != 0) {
133
32.0k
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
32.0k
  }
135
10.8k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
10.8k
    }
137
953k
    if (name != NULL) {
138
5.55M
  while ((ch = *name++) != 0) {
139
4.60M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
4.60M
  }
141
953k
    }
142
953k
    value = value ^ ((value << 5) + (value >> 3));
143
953k
    if (prefix2 != NULL) {
144
4.15k
  while ((ch = *prefix2++) != 0) {
145
3.45k
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
3.45k
  }
147
691
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
691
    }
149
953k
    if (name2 != NULL) {
150
3.90M
  while ((ch = *name2++) != 0) {
151
2.95M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
2.95M
  }
153
953k
    }
154
953k
    value = value ^ ((value << 5) + (value >> 3));
155
953k
    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
953k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
953k
    return (value % table->size);
167
953k
}
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
133k
xmlHashCreate(int size) {
179
133k
    xmlHashTablePtr table;
180
181
133k
    if (size <= 0)
182
78.8k
        size = 256;
183
184
133k
    table = xmlMalloc(sizeof(xmlHashTable));
185
133k
    if (table) {
186
133k
        table->dict = NULL;
187
133k
        table->size = size;
188
133k
  table->nbElems = 0;
189
133k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
133k
        if (table->table) {
191
133k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
133k
      return(table);
196
133k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
133k
}
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
98.0k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
98.0k
    xmlHashTablePtr table;
214
215
98.0k
    table = xmlHashCreate(size);
216
98.0k
    if (table != NULL) {
217
98.0k
        table->dict = dict;
218
98.0k
  xmlDictReference(dict);
219
98.0k
    }
220
98.0k
    return(table);
221
98.0k
}
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
3.03k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
3.03k
    unsigned long key;
235
3.03k
    int oldsize, i;
236
3.03k
    xmlHashEntryPtr iter, next;
237
3.03k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
3.03k
    if (table == NULL)
243
0
  return(-1);
244
3.03k
    if (size < 8)
245
0
        return(-1);
246
3.03k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
3.03k
    oldsize = table->size;
250
3.03k
    oldtable = table->table;
251
3.03k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
3.03k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
3.03k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
3.03k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
3.03k
    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
33.3k
    for (i = 0; i < oldsize; i++) {
269
30.3k
  if (oldtable[i].valid == 0)
270
78
      continue;
271
30.2k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
30.2k
        oldtable[i].name3);
273
30.2k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
30.2k
  table->table[key].next = NULL;
275
30.2k
    }
276
277
33.3k
    for (i = 0; i < oldsize; i++) {
278
30.3k
  iter = oldtable[i].next;
279
163k
  while (iter) {
280
132k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
132k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
132k
                        iter->name3);
288
132k
      if (table->table[key].valid == 0) {
289
84.4k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
84.4k
    table->table[key].next = NULL;
291
84.4k
    xmlFree(iter);
292
84.4k
      } else {
293
48.4k
    iter->next = table->table[key].next;
294
48.4k
    table->table[key].next = iter;
295
48.4k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
132k
      iter = next;
302
132k
  }
303
30.3k
    }
304
305
3.03k
    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
3.03k
    return(0);
313
3.03k
}
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
133k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
133k
    int i;
326
133k
    xmlHashEntryPtr iter;
327
133k
    xmlHashEntryPtr next;
328
133k
    int inside_table = 0;
329
133k
    int nbElems;
330
331
133k
    if (table == NULL)
332
0
  return;
333
133k
    if (table->table) {
334
133k
  nbElems = table->nbElems;
335
18.0M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
17.9M
      iter = &(table->table[i]);
337
17.9M
      if (iter->valid == 0)
338
16.0M
    continue;
339
1.84M
      inside_table = 1;
340
4.50M
      while (iter) {
341
2.65M
    next = iter->next;
342
2.65M
    if ((f != NULL) && (iter->payload != NULL))
343
2.08M
        f(iter->payload, iter->name);
344
2.65M
    if (table->dict == NULL) {
345
570k
        if (iter->name)
346
570k
      xmlFree(iter->name);
347
570k
        if (iter->name2)
348
4.16k
      xmlFree(iter->name2);
349
570k
        if (iter->name3)
350
216k
      xmlFree(iter->name3);
351
570k
    }
352
2.65M
    iter->payload = NULL;
353
2.65M
    if (!inside_table)
354
807k
        xmlFree(iter);
355
2.65M
    nbElems--;
356
2.65M
    inside_table = 0;
357
2.65M
    iter = next;
358
2.65M
      }
359
1.84M
  }
360
133k
  xmlFree(table->table);
361
133k
    }
362
133k
    if (table->dict)
363
78.8k
        xmlDictFree(table->dict);
364
133k
    xmlFree(table);
365
133k
}
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
76.9k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
76.9k
    xmlFree(entry);
377
76.9k
}
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
853k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
853k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
853k
}
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
1.06M
          const xmlChar *name2, void *userdata) {
410
1.06M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
1.06M
}
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
33.2k
       xmlHashDeallocator f) {
450
33.2k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
33.2k
}
452
453
/**
454
 * xmlHashLookup:
455
 * @table: the hash table
456
 * @name: the name of the userdata
457
 *
458
 * Find the userdata specified by the @name.
459
 *
460
 * Returns the pointer to the userdata
461
 */
462
void *
463
2.25M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
2.25M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
2.25M
}
466
467
/**
468
 * xmlHashLookup2:
469
 * @table: the hash table
470
 * @name: the name of the userdata
471
 * @name2: a second name of the userdata
472
 *
473
 * Find the userdata specified by the (@name, @name2) tuple.
474
 *
475
 * Returns the pointer to the userdata
476
 */
477
void *
478
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
479
5.65M
        const xmlChar *name2) {
480
5.65M
    return(xmlHashLookup3(table, name, name2, NULL));
481
5.65M
}
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
953k
          const xmlChar *name2) {
515
953k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
953k
}
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
2.75M
     void *userdata) {
536
2.75M
    unsigned long key, len = 0;
537
2.75M
    xmlHashEntryPtr entry;
538
2.75M
    xmlHashEntryPtr insert;
539
540
2.75M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
2.75M
    if (table->dict) {
547
2.18M
        if (!xmlDictOwns(table->dict, name)) {
548
249k
      name = xmlDictLookup(table->dict, name, -1);
549
249k
      if (name == NULL)
550
0
          return(-1);
551
249k
  }
552
2.18M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
91
      name2 = xmlDictLookup(table->dict, name2, -1);
554
91
      if (name2 == NULL)
555
0
          return(-1);
556
91
  }
557
2.18M
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
558
0
      name3 = xmlDictLookup(table->dict, name3, -1);
559
0
      if (name3 == NULL)
560
0
          return(-1);
561
0
  }
562
2.18M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
2.75M
    key = xmlHashComputeKey(table, name, name2, name3);
568
2.75M
    if (table->table[key].valid == 0) {
569
1.75M
  insert = NULL;
570
1.75M
    } else {
571
1.00M
        if (table->dict) {
572
1.82M
      for (insert = &(table->table[key]); insert->next != NULL;
573
944k
     insert = insert->next) {
574
944k
    if ((insert->name == name) &&
575
944k
        (insert->name2 == name2) &&
576
944k
        (insert->name3 == name3))
577
346
        return(-1);
578
943k
    len++;
579
943k
      }
580
876k
      if ((insert->name == name) &&
581
876k
    (insert->name2 == name2) &&
582
876k
    (insert->name3 == name3))
583
2.81k
    return(-1);
584
876k
  } else {
585
156k
      for (insert = &(table->table[key]); insert->next != NULL;
586
122k
     insert = insert->next) {
587
33.6k
    if ((xmlStrEqual(insert->name, name)) &&
588
33.6k
        (xmlStrEqual(insert->name2, name2)) &&
589
33.6k
        (xmlStrEqual(insert->name3, name3)))
590
195
        return(-1);
591
33.4k
    len++;
592
33.4k
      }
593
122k
      if ((xmlStrEqual(insert->name, name)) &&
594
122k
    (xmlStrEqual(insert->name2, name2)) &&
595
122k
    (xmlStrEqual(insert->name3, name3)))
596
1.85k
    return(-1);
597
122k
  }
598
1.00M
    }
599
600
2.75M
    if (insert == NULL) {
601
1.75M
  entry = &(table->table[key]);
602
1.75M
    } else {
603
995k
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
995k
  if (entry == NULL)
605
0
       return(-1);
606
995k
    }
607
608
2.75M
    if (table->dict != NULL) {
609
2.18M
        entry->name = (xmlChar *) name;
610
2.18M
        entry->name2 = (xmlChar *) name2;
611
2.18M
        entry->name3 = (xmlChar *) name3;
612
2.18M
    } else {
613
570k
  entry->name = xmlStrdup(name);
614
570k
  entry->name2 = xmlStrdup(name2);
615
570k
  entry->name3 = xmlStrdup(name3);
616
570k
    }
617
2.75M
    entry->payload = userdata;
618
2.75M
    entry->next = NULL;
619
2.75M
    entry->valid = 1;
620
621
622
2.75M
    if (insert != NULL)
623
995k
  insert->next = entry;
624
625
2.75M
    table->nbElems++;
626
627
2.75M
    if (len > MAX_HASH_LEN)
628
3.03k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
2.75M
    return(0);
631
2.75M
}
632
633
/**
634
 * xmlHashUpdateEntry3:
635
 * @table: the hash table
636
 * @name: the name of the userdata
637
 * @name2: a second name of the userdata
638
 * @name3: a third name of the userdata
639
 * @userdata: a pointer to the userdata
640
 * @f: the deallocator function for replaced item (if any)
641
 *
642
 * Add the @userdata to the hash @table. This can later be retrieved
643
 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
644
 * will be removed and freed with @f if found.
645
 *
646
 * Returns 0 the addition succeeded and -1 in case of error.
647
 */
648
int
649
xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
650
             const xmlChar *name2, const xmlChar *name3,
651
33.2k
       void *userdata, xmlHashDeallocator f) {
652
33.2k
    unsigned long key;
653
33.2k
    xmlHashEntryPtr entry;
654
33.2k
    xmlHashEntryPtr insert;
655
656
33.2k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
33.2k
    if (table->dict) {
663
33.2k
        if (!xmlDictOwns(table->dict, name)) {
664
0
      name = xmlDictLookup(table->dict, name, -1);
665
0
      if (name == NULL)
666
0
          return(-1);
667
0
  }
668
33.2k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
669
0
      name2 = xmlDictLookup(table->dict, name2, -1);
670
0
      if (name2 == NULL)
671
0
          return(-1);
672
0
  }
673
33.2k
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
674
0
      name3 = xmlDictLookup(table->dict, name3, -1);
675
0
      if (name3 == NULL)
676
0
          return(-1);
677
0
  }
678
33.2k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
33.2k
    key = xmlHashComputeKey(table, name, name2, name3);
684
33.2k
    if (table->table[key].valid == 0) {
685
23.0k
  insert = NULL;
686
23.0k
    } else {
687
10.2k
        if (table ->dict) {
688
10.9k
      for (insert = &(table->table[key]); insert->next != NULL;
689
10.2k
     insert = insert->next) {
690
660
    if ((insert->name == name) &&
691
660
        (insert->name2 == name2) &&
692
660
        (insert->name3 == name3)) {
693
0
        if (f)
694
0
      f(insert->payload, insert->name);
695
0
        insert->payload = userdata;
696
0
        return(0);
697
0
    }
698
660
      }
699
10.2k
      if ((insert->name == name) &&
700
10.2k
    (insert->name2 == name2) &&
701
10.2k
    (insert->name3 == name3)) {
702
0
    if (f)
703
0
        f(insert->payload, insert->name);
704
0
    insert->payload = userdata;
705
0
    return(0);
706
0
      }
707
10.2k
  } 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
10.2k
    }
729
730
33.2k
    if (insert == NULL) {
731
23.0k
  entry =  &(table->table[key]);
732
23.0k
    } else {
733
10.2k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
10.2k
  if (entry == NULL)
735
0
       return(-1);
736
10.2k
    }
737
738
33.2k
    if (table->dict != NULL) {
739
33.2k
        entry->name = (xmlChar *) name;
740
33.2k
        entry->name2 = (xmlChar *) name2;
741
33.2k
        entry->name3 = (xmlChar *) name3;
742
33.2k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
33.2k
    entry->payload = userdata;
748
33.2k
    entry->next = NULL;
749
33.2k
    entry->valid = 1;
750
33.2k
    table->nbElems++;
751
752
753
33.2k
    if (insert != NULL) {
754
10.2k
  insert->next = entry;
755
10.2k
    }
756
33.2k
    return(0);
757
33.2k
}
758
759
/**
760
 * xmlHashLookup3:
761
 * @table: the hash table
762
 * @name: the name of the userdata
763
 * @name2: a second name of the userdata
764
 * @name3: a third name of the userdata
765
 *
766
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
767
 *
768
 * Returns the a pointer to the userdata
769
 */
770
void *
771
xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
772
9.79M
         const xmlChar *name2, const xmlChar *name3) {
773
9.79M
    unsigned long key;
774
9.79M
    xmlHashEntryPtr entry;
775
776
9.79M
    if (table == NULL)
777
333k
  return(NULL);
778
9.45M
    if (name == NULL)
779
0
  return(NULL);
780
9.45M
    key = xmlHashComputeKey(table, name, name2, name3);
781
9.45M
    if (table->table[key].valid == 0)
782
1.98M
  return(NULL);
783
7.47M
    if (table->dict) {
784
10.4M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
8.14M
      if ((entry->name == name) &&
786
8.14M
    (entry->name2 == name2) &&
787
8.14M
    (entry->name3 == name3))
788
3.01M
    return(entry->payload);
789
8.14M
  }
790
5.34M
    }
791
8.15M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
6.49M
  if ((xmlStrEqual(entry->name, name)) &&
793
6.49M
      (xmlStrEqual(entry->name2, name2)) &&
794
6.49M
      (xmlStrEqual(entry->name3, name3)))
795
2.79M
      return(entry->payload);
796
6.49M
    }
797
1.66M
    return(NULL);
798
4.45M
}
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
953k
    const xmlChar *prefix3, const xmlChar *name3) {
819
953k
    unsigned long key;
820
953k
    xmlHashEntryPtr entry;
821
822
953k
    if (table == NULL)
823
0
  return(NULL);
824
953k
    if (name == NULL)
825
0
  return(NULL);
826
953k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
953k
                             name2, prefix3, name3);
828
953k
    if (table->table[key].valid == 0)
829
45.3k
  return(NULL);
830
2.84M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
2.63M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
2.63M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
2.63M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
701k
      return(entry->payload);
835
2.63M
    }
836
206k
    return(NULL);
837
908k
}
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
358k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
358k
    stubData *stubdata = (stubData *) data;
849
358k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
358k
}
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
16.5k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
16.5k
    stubData stubdata;
863
16.5k
    stubdata.data = data;
864
16.5k
    stubdata.hashscanner = f;
865
16.5k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
16.5k
}
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
27.0k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
27.0k
    int i, nb;
879
27.0k
    xmlHashEntryPtr iter;
880
27.0k
    xmlHashEntryPtr next;
881
882
27.0k
    if (table == NULL)
883
268
  return;
884
26.8k
    if (f == NULL)
885
0
  return;
886
887
26.8k
    if (table->table) {
888
4.49M
  for(i = 0; i < table->size; i++) {
889
4.47M
      if (table->table[i].valid == 0)
890
4.00M
    continue;
891
468k
      iter = &(table->table[i]);
892
1.48M
      while (iter) {
893
1.01M
    next = iter->next;
894
1.01M
                nb = table->nbElems;
895
1.01M
    if ((f != NULL) && (iter->payload != NULL))
896
1.01M
        f(iter->payload, data, iter->name,
897
1.01M
          iter->name2, iter->name3);
898
1.01M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
129k
                    if (iter == &(table->table[i])) {
901
37.1k
                        if (table->table[i].valid == 0)
902
15.8k
                            iter = NULL;
903
37.1k
                        if (table->table[i].next != next)
904
21.2k
          iter = &(table->table[i]);
905
37.1k
                    } else
906
92.3k
            iter = next;
907
129k
                } else
908
885k
        iter = next;
909
1.01M
      }
910
468k
  }
911
26.8k
    }
912
26.8k
}
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
117k
       xmlHashScanner f, void *data) {
931
117k
    stubData stubdata;
932
117k
    stubdata.data = data;
933
117k
    stubdata.hashscanner = f;
934
117k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
117k
                     &stubdata);
936
117k
}
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
117k
     xmlHashScannerFull f, void *data) {
955
117k
    int i;
956
117k
    xmlHashEntryPtr iter;
957
117k
    xmlHashEntryPtr next;
958
959
117k
    if (table == NULL)
960
115k
  return;
961
2.22k
    if (f == NULL)
962
0
  return;
963
964
2.22k
    if (table->table) {
965
570k
  for(i = 0; i < table->size; i++) {
966
568k
      if (table->table[i].valid == 0)
967
566k
    continue;
968
2.22k
      iter = &(table->table[i]);
969
4.44k
      while (iter) {
970
2.22k
    next = iter->next;
971
2.22k
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
2.22k
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
2.22k
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
2.22k
        (iter->payload != NULL)) {
975
0
        f(iter->payload, data, iter->name,
976
0
          iter->name2, iter->name3);
977
0
    }
978
2.22k
    iter = next;
979
2.22k
      }
980
2.22k
  }
981
2.22k
    }
982
2.22k
}
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
10.5k
xmlHashSize(xmlHashTablePtr table) {
1037
10.5k
    if (table == NULL)
1038
0
  return(-1);
1039
10.5k
    return(table->nbElems);
1040
10.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
3
           xmlHashDeallocator f) {
1056
3
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
3
}
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
129k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
129k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
129k
}
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
129k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
129k
    unsigned long key;
1096
129k
    xmlHashEntryPtr entry;
1097
129k
    xmlHashEntryPtr prev = NULL;
1098
1099
129k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
129k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
129k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
129k
    } else {
1106
317k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
317k
            if (xmlStrEqual(entry->name, name) &&
1108
317k
                    xmlStrEqual(entry->name2, name2) &&
1109
317k
                    xmlStrEqual(entry->name3, name3)) {
1110
129k
                if ((f != NULL) && (entry->payload != NULL))
1111
3
                    f(entry->payload, entry->name);
1112
129k
                entry->payload = NULL;
1113
129k
    if (table->dict == NULL) {
1114
43
        if(entry->name)
1115
43
      xmlFree(entry->name);
1116
43
        if(entry->name2)
1117
0
      xmlFree(entry->name2);
1118
43
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
43
    }
1121
129k
                if(prev) {
1122
92.3k
                    prev->next = entry->next;
1123
92.3k
        xmlFree(entry);
1124
92.3k
    } else {
1125
37.4k
        if (entry->next == NULL) {
1126
16.1k
      entry->valid = 0;
1127
21.2k
        } else {
1128
21.2k
      entry = entry->next;
1129
21.2k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
21.2k
      xmlFree(entry);
1131
21.2k
        }
1132
37.4k
    }
1133
129k
                table->nbElems--;
1134
129k
                return(0);
1135
129k
            }
1136
187k
            prev = entry;
1137
187k
        }
1138
0
        return(-1);
1139
129k
    }
1140
129k
}
1141