Coverage Report

Created: 2024-01-18 09:16

/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
4.64M
#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
27.7M
            const xmlChar *name2, const xmlChar *name3) {
85
27.7M
    unsigned long value = 0L;
86
27.7M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
27.7M
    if (name != NULL) {
92
27.7M
  value += 30 * (*name);
93
271M
  while ((ch = *name++) != 0) {
94
243M
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
243M
  }
96
27.7M
    }
97
27.7M
    value = value ^ ((value << 5) + (value >> 3));
98
27.7M
    if (name2 != NULL) {
99
22.9M
  while ((ch = *name2++) != 0) {
100
18.6M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
18.6M
  }
102
4.30M
    }
103
27.7M
    value = value ^ ((value << 5) + (value >> 3));
104
27.7M
    if (name3 != NULL) {
105
40.1M
  while ((ch = *name3++) != 0) {
106
34.3M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
34.3M
  }
108
5.81M
    }
109
27.7M
    return (value % table->size);
110
27.7M
}
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
1.60M
       const xmlChar *prefix3, const xmlChar *name3) {
120
1.60M
    unsigned long value = 0L;
121
1.60M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
1.60M
    if (prefix != NULL)
127
355k
  value += 30 * (*prefix);
128
1.24M
    else
129
1.24M
  value += 30 * (*name);
130
131
1.60M
    if (prefix != NULL) {
132
1.44M
  while ((ch = *prefix++) != 0) {
133
1.08M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
1.08M
  }
135
355k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
355k
    }
137
1.60M
    if (name != NULL) {
138
10.2M
  while ((ch = *name++) != 0) {
139
8.61M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
8.61M
  }
141
1.60M
    }
142
1.60M
    value = value ^ ((value << 5) + (value >> 3));
143
1.60M
    if (prefix2 != NULL) {
144
1.43M
  while ((ch = *prefix2++) != 0) {
145
1.08M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
1.08M
  }
147
352k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
352k
    }
149
1.60M
    if (name2 != NULL) {
150
6.94M
  while ((ch = *name2++) != 0) {
151
5.34M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
5.34M
  }
153
1.60M
    }
154
1.60M
    value = value ^ ((value << 5) + (value >> 3));
155
1.60M
    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
1.60M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
1.60M
    return (value % table->size);
167
1.60M
}
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
549k
xmlHashCreate(int size) {
179
549k
    xmlHashTablePtr table;
180
181
549k
    if (size <= 0)
182
335k
        size = 256;
183
184
549k
    table = xmlMalloc(sizeof(xmlHashTable));
185
549k
    if (table) {
186
549k
        table->dict = NULL;
187
549k
        table->size = size;
188
549k
  table->nbElems = 0;
189
549k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
549k
        if (table->table) {
191
549k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
549k
      return(table);
196
549k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
549k
}
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
382k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
382k
    xmlHashTablePtr table;
214
215
382k
    table = xmlHashCreate(size);
216
382k
    if (table != NULL) {
217
382k
        table->dict = dict;
218
382k
  xmlDictReference(dict);
219
382k
    }
220
382k
    return(table);
221
382k
}
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
1.97k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
1.97k
    unsigned long key;
235
1.97k
    int oldsize, i;
236
1.97k
    xmlHashEntryPtr iter, next;
237
1.97k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
1.97k
    if (table == NULL)
243
0
  return(-1);
244
1.97k
    if (size < 8)
245
0
        return(-1);
246
1.97k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
1.97k
    oldsize = table->size;
250
1.97k
    oldtable = table->table;
251
1.97k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
1.97k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
1.97k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
1.97k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
1.97k
    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
23.8k
    for (i = 0; i < oldsize; i++) {
269
21.8k
  if (oldtable[i].valid == 0)
270
349
      continue;
271
21.5k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
21.5k
        oldtable[i].name3);
273
21.5k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
21.5k
  table->table[key].next = NULL;
275
21.5k
    }
276
277
23.8k
    for (i = 0; i < oldsize; i++) {
278
21.8k
  iter = oldtable[i].next;
279
113k
  while (iter) {
280
91.1k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
91.1k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
91.1k
                        iter->name3);
288
91.1k
      if (table->table[key].valid == 0) {
289
58.4k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
58.4k
    table->table[key].next = NULL;
291
58.4k
    xmlFree(iter);
292
58.4k
      } else {
293
32.6k
    iter->next = table->table[key].next;
294
32.6k
    table->table[key].next = iter;
295
32.6k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
91.1k
      iter = next;
302
91.1k
  }
303
21.8k
    }
304
305
1.97k
    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
1.97k
    return(0);
313
1.97k
}
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
624k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
624k
    int i;
326
624k
    xmlHashEntryPtr iter;
327
624k
    xmlHashEntryPtr next;
328
624k
    int inside_table = 0;
329
624k
    int nbElems;
330
331
624k
    if (table == NULL)
332
76.3k
  return;
333
548k
    if (table->table) {
334
548k
  nbElems = table->nbElems;
335
68.8M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
68.2M
      iter = &(table->table[i]);
337
68.2M
      if (iter->valid == 0)
338
64.5M
    continue;
339
3.75M
      inside_table = 1;
340
8.23M
      while (iter) {
341
4.48M
    next = iter->next;
342
4.48M
    if ((f != NULL) && (iter->payload != NULL))
343
2.94M
        f(iter->payload, iter->name);
344
4.48M
    if (table->dict == NULL) {
345
1.75M
        if (iter->name)
346
1.75M
      xmlFree(iter->name);
347
1.75M
        if (iter->name2)
348
123k
      xmlFree(iter->name2);
349
1.75M
        if (iter->name3)
350
223k
      xmlFree(iter->name3);
351
1.75M
    }
352
4.48M
    iter->payload = NULL;
353
4.48M
    if (!inside_table)
354
729k
        xmlFree(iter);
355
4.48M
    nbElems--;
356
4.48M
    inside_table = 0;
357
4.48M
    iter = next;
358
4.48M
      }
359
3.75M
  }
360
548k
  xmlFree(table->table);
361
548k
    }
362
548k
    if (table->dict)
363
315k
        xmlDictFree(table->dict);
364
548k
    xmlFree(table);
365
548k
}
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
220k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
220k
    xmlFree(entry);
377
220k
}
378
379
/**
380
 * xmlHashAddEntry:
381
 * @table: the hash table
382
 * @name: the name of the userdata
383
 * @userdata: a pointer to the userdata
384
 *
385
 * Add the @userdata to the hash @table. This can later be retrieved
386
 * by using the @name. Duplicate names generate errors.
387
 *
388
 * Returns 0 the addition succeeded and -1 in case of error.
389
 */
390
int
391
1.52M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
1.52M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
1.52M
}
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
2.45M
          const xmlChar *name2, void *userdata) {
410
2.45M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
2.45M
}
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
50.6k
       xmlHashDeallocator f) {
450
50.6k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
50.6k
}
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
6.66M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
6.66M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
6.66M
}
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
11.1M
        const xmlChar *name2) {
480
11.1M
    return(xmlHashLookup3(table, name, name2, NULL));
481
11.1M
}
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
1.60M
          const xmlChar *name2) {
515
1.60M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
1.60M
}
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
4.87M
     void *userdata) {
536
4.87M
    unsigned long key, len = 0;
537
4.87M
    xmlHashEntryPtr entry;
538
4.87M
    xmlHashEntryPtr insert;
539
540
4.87M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
4.87M
    if (table->dict) {
547
3.02M
        if (!xmlDictOwns(table->dict, name)) {
548
699k
      name = xmlDictLookup(table->dict, name, -1);
549
699k
      if (name == NULL)
550
0
          return(-1);
551
699k
  }
552
3.02M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
171k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
171k
      if (name2 == NULL)
555
0
          return(-1);
556
171k
  }
557
3.02M
        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
3.02M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
4.87M
    key = xmlHashComputeKey(table, name, name2, name3);
568
4.87M
    if (table->table[key].valid == 0) {
569
3.73M
  insert = NULL;
570
3.73M
    } else {
571
1.14M
        if (table->dict) {
572
1.54M
      for (insert = &(table->table[key]); insert->next != NULL;
573
907k
     insert = insert->next) {
574
643k
    if ((insert->name == name) &&
575
643k
        (insert->name2 == name2) &&
576
643k
        (insert->name3 == name3))
577
1.42k
        return(-1);
578
642k
    len++;
579
642k
      }
580
906k
      if ((insert->name == name) &&
581
906k
    (insert->name2 == name2) &&
582
906k
    (insert->name3 == name3))
583
139k
    return(-1);
584
906k
  } else {
585
300k
      for (insert = &(table->table[key]); insert->next != NULL;
586
238k
     insert = insert->next) {
587
62.6k
    if ((xmlStrEqual(insert->name, name)) &&
588
62.6k
        (xmlStrEqual(insert->name2, name2)) &&
589
62.6k
        (xmlStrEqual(insert->name3, name3)))
590
917
        return(-1);
591
61.7k
    len++;
592
61.7k
      }
593
237k
      if ((xmlStrEqual(insert->name, name)) &&
594
237k
    (xmlStrEqual(insert->name2, name2)) &&
595
237k
    (xmlStrEqual(insert->name3, name3)))
596
89.6k
    return(-1);
597
237k
  }
598
1.14M
    }
599
600
4.64M
    if (insert == NULL) {
601
3.73M
  entry = &(table->table[key]);
602
3.73M
    } else {
603
914k
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
914k
  if (entry == NULL)
605
0
       return(-1);
606
914k
    }
607
608
4.64M
    if (table->dict != NULL) {
609
2.88M
        entry->name = (xmlChar *) name;
610
2.88M
        entry->name2 = (xmlChar *) name2;
611
2.88M
        entry->name3 = (xmlChar *) name3;
612
2.88M
    } else {
613
1.76M
  entry->name = xmlStrdup(name);
614
1.76M
  entry->name2 = xmlStrdup(name2);
615
1.76M
  entry->name3 = xmlStrdup(name3);
616
1.76M
    }
617
4.64M
    entry->payload = userdata;
618
4.64M
    entry->next = NULL;
619
4.64M
    entry->valid = 1;
620
621
622
4.64M
    if (insert != NULL)
623
914k
  insert->next = entry;
624
625
4.64M
    table->nbElems++;
626
627
4.64M
    if (len > MAX_HASH_LEN)
628
1.97k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
4.64M
    return(0);
631
4.64M
}
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
50.6k
       void *userdata, xmlHashDeallocator f) {
652
50.6k
    unsigned long key;
653
50.6k
    xmlHashEntryPtr entry;
654
50.6k
    xmlHashEntryPtr insert;
655
656
50.6k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
50.6k
    if (table->dict) {
663
50.6k
        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
50.6k
        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
50.6k
        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
50.6k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
50.6k
    key = xmlHashComputeKey(table, name, name2, name3);
684
50.6k
    if (table->table[key].valid == 0) {
685
40.1k
  insert = NULL;
686
40.1k
    } else {
687
10.5k
        if (table ->dict) {
688
11.0k
      for (insert = &(table->table[key]); insert->next != NULL;
689
10.5k
     insert = insert->next) {
690
593
    if ((insert->name == name) &&
691
593
        (insert->name2 == name2) &&
692
593
        (insert->name3 == name3)) {
693
65
        if (f)
694
0
      f(insert->payload, insert->name);
695
65
        insert->payload = userdata;
696
65
        return(0);
697
65
    }
698
593
      }
699
10.4k
      if ((insert->name == name) &&
700
10.4k
    (insert->name2 == name2) &&
701
10.4k
    (insert->name3 == name3)) {
702
3.42k
    if (f)
703
0
        f(insert->payload, insert->name);
704
3.42k
    insert->payload = userdata;
705
3.42k
    return(0);
706
3.42k
      }
707
10.4k
  } 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.5k
    }
729
730
47.1k
    if (insert == NULL) {
731
40.1k
  entry =  &(table->table[key]);
732
40.1k
    } else {
733
7.06k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
7.06k
  if (entry == NULL)
735
0
       return(-1);
736
7.06k
    }
737
738
47.1k
    if (table->dict != NULL) {
739
47.1k
        entry->name = (xmlChar *) name;
740
47.1k
        entry->name2 = (xmlChar *) name2;
741
47.1k
        entry->name3 = (xmlChar *) name3;
742
47.1k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
47.1k
    entry->payload = userdata;
748
47.1k
    entry->next = NULL;
749
47.1k
    entry->valid = 1;
750
47.1k
    table->nbElems++;
751
752
753
47.1k
    if (insert != NULL) {
754
7.06k
  insert->next = entry;
755
7.06k
    }
756
47.1k
    return(0);
757
47.1k
}
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
22.7M
         const xmlChar *name2, const xmlChar *name3) {
773
22.7M
    unsigned long key;
774
22.7M
    xmlHashEntryPtr entry;
775
776
22.7M
    if (table == NULL)
777
287k
  return(NULL);
778
22.4M
    if (name == NULL)
779
0
  return(NULL);
780
22.4M
    key = xmlHashComputeKey(table, name, name2, name3);
781
22.4M
    if (table->table[key].valid == 0)
782
8.21M
  return(NULL);
783
14.2M
    if (table->dict) {
784
17.0M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
12.9M
      if ((entry->name == name) &&
786
12.9M
    (entry->name2 == name2) &&
787
12.9M
    (entry->name3 == name3))
788
6.07M
    return(entry->payload);
789
12.9M
  }
790
10.2M
    }
791
11.4M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
9.73M
  if ((xmlStrEqual(entry->name, name)) &&
793
9.73M
      (xmlStrEqual(entry->name2, name2)) &&
794
9.73M
      (xmlStrEqual(entry->name3, name3)))
795
6.42M
      return(entry->payload);
796
9.73M
    }
797
1.76M
    return(NULL);
798
8.19M
}
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
1.60M
    const xmlChar *prefix3, const xmlChar *name3) {
819
1.60M
    unsigned long key;
820
1.60M
    xmlHashEntryPtr entry;
821
822
1.60M
    if (table == NULL)
823
0
  return(NULL);
824
1.60M
    if (name == NULL)
825
0
  return(NULL);
826
1.60M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
1.60M
                             name2, prefix3, name3);
828
1.60M
    if (table->table[key].valid == 0)
829
292k
  return(NULL);
830
3.61M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
3.30M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
3.30M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
3.30M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
1.00M
      return(entry->payload);
835
3.30M
    }
836
311k
    return(NULL);
837
1.31M
}
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
1.80M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
1.80M
    stubData *stubdata = (stubData *) data;
849
1.80M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
1.80M
}
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
538k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
538k
    stubData stubdata;
863
538k
    stubdata.data = data;
864
538k
    stubdata.hashscanner = f;
865
538k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
538k
}
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
593k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
593k
    int i, nb;
879
593k
    xmlHashEntryPtr iter;
880
593k
    xmlHashEntryPtr next;
881
882
593k
    if (table == NULL)
883
7.45k
  return;
884
586k
    if (f == NULL)
885
0
  return;
886
887
586k
    if (table->table) {
888
137M
  for(i = 0; i < table->size; i++) {
889
136M
      if (table->table[i].valid == 0)
890
134M
    continue;
891
1.91M
      iter = &(table->table[i]);
892
4.38M
      while (iter) {
893
2.47M
    next = iter->next;
894
2.47M
                nb = table->nbElems;
895
2.47M
    if ((f != NULL) && (iter->payload != NULL))
896
2.47M
        f(iter->payload, data, iter->name,
897
2.47M
          iter->name2, iter->name3);
898
2.47M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
208k
                    if (iter == &(table->table[i])) {
901
115k
                        if (table->table[i].valid == 0)
902
73.9k
                            iter = NULL;
903
115k
                        if (table->table[i].next != next)
904
41.6k
          iter = &(table->table[i]);
905
115k
                    } else
906
92.3k
            iter = next;
907
208k
                } else
908
2.26M
        iter = next;
909
2.47M
      }
910
1.91M
  }
911
586k
    }
912
586k
}
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
143k
       xmlHashScanner f, void *data) {
931
143k
    stubData stubdata;
932
143k
    stubdata.data = data;
933
143k
    stubdata.hashscanner = f;
934
143k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
143k
                     &stubdata);
936
143k
}
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
143k
     xmlHashScannerFull f, void *data) {
955
143k
    int i;
956
143k
    xmlHashEntryPtr iter;
957
143k
    xmlHashEntryPtr next;
958
959
143k
    if (table == NULL)
960
143k
  return;
961
283
    if (f == NULL)
962
0
  return;
963
964
283
    if (table->table) {
965
72.7k
  for(i = 0; i < table->size; i++) {
966
72.4k
      if (table->table[i].valid == 0)
967
72.1k
    continue;
968
293
      iter = &(table->table[i]);
969
586
      while (iter) {
970
293
    next = iter->next;
971
293
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
293
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
293
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
293
        (iter->payload != NULL)) {
975
203
        f(iter->payload, data, iter->name,
976
203
          iter->name2, iter->name3);
977
203
    }
978
293
    iter = next;
979
293
      }
980
293
  }
981
283
    }
982
283
}
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
54.9k
xmlHashSize(xmlHashTablePtr table) {
1037
54.9k
    if (table == NULL)
1038
0
  return(-1);
1039
54.9k
    return(table->nbElems);
1040
54.9k
}
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
605
           xmlHashDeallocator f) {
1056
605
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
605
}
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
209k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
209k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
209k
}
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
209k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
209k
    unsigned long key;
1096
209k
    xmlHashEntryPtr entry;
1097
209k
    xmlHashEntryPtr prev = NULL;
1098
1099
209k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
209k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
209k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
209k
    } else {
1106
360k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
360k
            if (xmlStrEqual(entry->name, name) &&
1108
360k
                    xmlStrEqual(entry->name2, name2) &&
1109
360k
                    xmlStrEqual(entry->name3, name3)) {
1110
209k
                if ((f != NULL) && (entry->payload != NULL))
1111
605
                    f(entry->payload, entry->name);
1112
209k
                entry->payload = NULL;
1113
209k
    if (table->dict == NULL) {
1114
681
        if(entry->name)
1115
681
      xmlFree(entry->name);
1116
681
        if(entry->name2)
1117
127
      xmlFree(entry->name2);
1118
681
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
681
    }
1121
209k
                if(prev) {
1122
92.3k
                    prev->next = entry->next;
1123
92.3k
        xmlFree(entry);
1124
117k
    } else {
1125
117k
        if (entry->next == NULL) {
1126
75.7k
      entry->valid = 0;
1127
75.7k
        } else {
1128
41.6k
      entry = entry->next;
1129
41.6k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
41.6k
      xmlFree(entry);
1131
41.6k
        }
1132
117k
    }
1133
209k
                table->nbElems--;
1134
209k
                return(0);
1135
209k
            }
1136
150k
            prev = entry;
1137
150k
        }
1138
0
        return(-1);
1139
209k
    }
1140
209k
}
1141