Coverage Report

Created: 2024-01-21 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
4.40M
#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
68.0M
            const xmlChar *name2, const xmlChar *name3) {
85
68.0M
    unsigned long value = 0L;
86
68.0M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
68.0M
    if (name != NULL) {
92
68.0M
  value += 30 * (*name);
93
1.54G
  while ((ch = *name++) != 0) {
94
1.47G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
1.47G
  }
96
68.0M
    }
97
68.0M
    value = value ^ ((value << 5) + (value >> 3));
98
68.0M
    if (name2 != NULL) {
99
21.7M
  while ((ch = *name2++) != 0) {
100
18.2M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
18.2M
  }
102
3.54M
    }
103
68.0M
    value = value ^ ((value << 5) + (value >> 3));
104
68.0M
    if (name3 != NULL) {
105
24.3M
  while ((ch = *name3++) != 0) {
106
20.6M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
20.6M
  }
108
3.65M
    }
109
68.0M
    return (value % table->size);
110
68.0M
}
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
812k
       const xmlChar *prefix3, const xmlChar *name3) {
120
812k
    unsigned long value = 0L;
121
812k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
812k
    if (prefix != NULL)
127
110k
  value += 30 * (*prefix);
128
701k
    else
129
701k
  value += 30 * (*name);
130
131
812k
    if (prefix != NULL) {
132
407k
  while ((ch = *prefix++) != 0) {
133
296k
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
296k
  }
135
110k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
110k
    }
137
812k
    if (name != NULL) {
138
4.79M
  while ((ch = *name++) != 0) {
139
3.98M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
3.98M
  }
141
812k
    }
142
812k
    value = value ^ ((value << 5) + (value >> 3));
143
812k
    if (prefix2 != NULL) {
144
563k
  while ((ch = *prefix2++) != 0) {
145
454k
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
454k
  }
147
108k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
108k
    }
149
812k
    if (name2 != NULL) {
150
3.63M
  while ((ch = *name2++) != 0) {
151
2.82M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
2.82M
  }
153
812k
    }
154
812k
    value = value ^ ((value << 5) + (value >> 3));
155
812k
    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
812k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
812k
    return (value % table->size);
167
812k
}
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.05M
xmlHashCreate(int size) {
179
1.05M
    xmlHashTablePtr table;
180
181
1.05M
    if (size <= 0)
182
556k
        size = 256;
183
184
1.05M
    table = xmlMalloc(sizeof(xmlHashTable));
185
1.05M
    if (table) {
186
1.05M
        table->dict = NULL;
187
1.05M
        table->size = size;
188
1.05M
  table->nbElems = 0;
189
1.05M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
1.05M
        if (table->table) {
191
1.05M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
1.05M
      return(table);
196
1.05M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
1.05M
}
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
691k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
691k
    xmlHashTablePtr table;
214
215
691k
    table = xmlHashCreate(size);
216
691k
    if (table != NULL) {
217
691k
        table->dict = dict;
218
691k
  xmlDictReference(dict);
219
691k
    }
220
691k
    return(table);
221
691k
}
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.87k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
3.87k
    unsigned long key;
235
3.87k
    int oldsize, i;
236
3.87k
    xmlHashEntryPtr iter, next;
237
3.87k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
3.87k
    if (table == NULL)
243
0
  return(-1);
244
3.87k
    if (size < 8)
245
0
        return(-1);
246
3.87k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
3.87k
    oldsize = table->size;
250
3.87k
    oldtable = table->table;
251
3.87k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
3.87k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
3.87k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
3.87k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
3.87k
    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
65.6k
    for (i = 0; i < oldsize; i++) {
269
61.7k
  if (oldtable[i].valid == 0)
270
1.41k
      continue;
271
60.3k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
60.3k
        oldtable[i].name3);
273
60.3k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
60.3k
  table->table[key].next = NULL;
275
60.3k
    }
276
277
65.6k
    for (i = 0; i < oldsize; i++) {
278
61.7k
  iter = oldtable[i].next;
279
312k
  while (iter) {
280
250k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
250k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
250k
                        iter->name3);
288
250k
      if (table->table[key].valid == 0) {
289
165k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
165k
    table->table[key].next = NULL;
291
165k
    xmlFree(iter);
292
165k
      } else {
293
85.4k
    iter->next = table->table[key].next;
294
85.4k
    table->table[key].next = iter;
295
85.4k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
250k
      iter = next;
302
250k
  }
303
61.7k
    }
304
305
3.87k
    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.87k
    return(0);
313
3.87k
}
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.05M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
1.05M
    int i;
326
1.05M
    xmlHashEntryPtr iter;
327
1.05M
    xmlHashEntryPtr next;
328
1.05M
    int inside_table = 0;
329
1.05M
    int nbElems;
330
331
1.05M
    if (table == NULL)
332
0
  return;
333
1.05M
    if (table->table) {
334
1.05M
  nbElems = table->nbElems;
335
112M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
111M
      iter = &(table->table[i]);
337
111M
      if (iter->valid == 0)
338
107M
    continue;
339
3.48M
      inside_table = 1;
340
7.74M
      while (iter) {
341
4.25M
    next = iter->next;
342
4.25M
    if ((f != NULL) && (iter->payload != NULL))
343
3.59M
        f(iter->payload, iter->name);
344
4.25M
    if (table->dict == NULL) {
345
1.49M
        if (iter->name)
346
1.49M
      xmlFree(iter->name);
347
1.49M
        if (iter->name2)
348
66.9k
      xmlFree(iter->name2);
349
1.49M
        if (iter->name3)
350
341k
      xmlFree(iter->name3);
351
1.49M
    }
352
4.25M
    iter->payload = NULL;
353
4.25M
    if (!inside_table)
354
771k
        xmlFree(iter);
355
4.25M
    nbElems--;
356
4.25M
    inside_table = 0;
357
4.25M
    iter = next;
358
4.25M
      }
359
3.48M
  }
360
1.05M
  xmlFree(table->table);
361
1.05M
    }
362
1.05M
    if (table->dict)
363
469k
        xmlDictFree(table->dict);
364
1.05M
    xmlFree(table);
365
1.05M
}
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
635k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
635k
    xmlFree(entry);
377
635k
}
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.98M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
1.98M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
1.98M
}
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.62M
          const xmlChar *name2, void *userdata) {
410
1.62M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
1.62M
}
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
80.5k
       xmlHashDeallocator f) {
450
80.5k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
80.5k
}
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
53.5M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
53.5M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
53.5M
}
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
6.84M
        const xmlChar *name2) {
480
6.84M
    return(xmlHashLookup3(table, name, name2, NULL));
481
6.84M
}
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
812k
          const xmlChar *name2) {
515
812k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
812k
}
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.85M
     void *userdata) {
536
4.85M
    unsigned long key, len = 0;
537
4.85M
    xmlHashEntryPtr entry;
538
4.85M
    xmlHashEntryPtr insert;
539
540
4.85M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
4.85M
    if (table->dict) {
547
3.14M
        if (!xmlDictOwns(table->dict, name)) {
548
299k
      name = xmlDictLookup(table->dict, name, -1);
549
299k
      if (name == NULL)
550
0
          return(-1);
551
299k
  }
552
3.14M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
39.0k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
39.0k
      if (name2 == NULL)
555
0
          return(-1);
556
39.0k
  }
557
3.14M
        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.14M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
4.85M
    key = xmlHashComputeKey(table, name, name2, name3);
568
4.85M
    if (table->table[key].valid == 0) {
569
3.34M
  insert = NULL;
570
3.34M
    } else {
571
1.51M
        if (table->dict) {
572
2.18M
      for (insert = &(table->table[key]); insert->next != NULL;
573
1.14M
     insert = insert->next) {
574
1.06M
    if ((insert->name == name) &&
575
1.06M
        (insert->name2 == name2) &&
576
1.06M
        (insert->name3 == name3))
577
15.6k
        return(-1);
578
1.04M
    len++;
579
1.04M
      }
580
1.12M
      if ((insert->name == name) &&
581
1.12M
    (insert->name2 == name2) &&
582
1.12M
    (insert->name3 == name3))
583
227k
    return(-1);
584
1.12M
  } else {
585
482k
      for (insert = &(table->table[key]); insert->next != NULL;
586
374k
     insert = insert->next) {
587
119k
    if ((xmlStrEqual(insert->name, name)) &&
588
119k
        (xmlStrEqual(insert->name2, name2)) &&
589
119k
        (xmlStrEqual(insert->name3, name3)))
590
11.0k
        return(-1);
591
108k
    len++;
592
108k
      }
593
362k
      if ((xmlStrEqual(insert->name, name)) &&
594
362k
    (xmlStrEqual(insert->name2, name2)) &&
595
362k
    (xmlStrEqual(insert->name3, name3)))
596
200k
    return(-1);
597
362k
  }
598
1.51M
    }
599
600
4.40M
    if (insert == NULL) {
601
3.34M
  entry = &(table->table[key]);
602
3.34M
    } else {
603
1.06M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
1.06M
  if (entry == NULL)
605
0
       return(-1);
606
1.06M
    }
607
608
4.40M
    if (table->dict != NULL) {
609
2.90M
        entry->name = (xmlChar *) name;
610
2.90M
        entry->name2 = (xmlChar *) name2;
611
2.90M
        entry->name3 = (xmlChar *) name3;
612
2.90M
    } else {
613
1.49M
  entry->name = xmlStrdup(name);
614
1.49M
  entry->name2 = xmlStrdup(name2);
615
1.49M
  entry->name3 = xmlStrdup(name3);
616
1.49M
    }
617
4.40M
    entry->payload = userdata;
618
4.40M
    entry->next = NULL;
619
4.40M
    entry->valid = 1;
620
621
622
4.40M
    if (insert != NULL)
623
1.06M
  insert->next = entry;
624
625
4.40M
    table->nbElems++;
626
627
4.40M
    if (len > MAX_HASH_LEN)
628
3.87k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
4.40M
    return(0);
631
4.40M
}
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
80.5k
       void *userdata, xmlHashDeallocator f) {
652
80.5k
    unsigned long key;
653
80.5k
    xmlHashEntryPtr entry;
654
80.5k
    xmlHashEntryPtr insert;
655
656
80.5k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
80.5k
    if (table->dict) {
663
80.5k
        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
80.5k
        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
80.5k
        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
80.5k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
80.5k
    key = xmlHashComputeKey(table, name, name2, name3);
684
80.5k
    if (table->table[key].valid == 0) {
685
68.5k
  insert = NULL;
686
68.5k
    } else {
687
12.0k
        if (table ->dict) {
688
13.8k
      for (insert = &(table->table[key]); insert->next != NULL;
689
12.0k
     insert = insert->next) {
690
2.02k
    if ((insert->name == name) &&
691
2.02k
        (insert->name2 == name2) &&
692
2.02k
        (insert->name3 == name3)) {
693
142
        if (f)
694
0
      f(insert->payload, insert->name);
695
142
        insert->payload = userdata;
696
142
        return(0);
697
142
    }
698
2.02k
      }
699
11.8k
      if ((insert->name == name) &&
700
11.8k
    (insert->name2 == name2) &&
701
11.8k
    (insert->name3 == name3)) {
702
2.04k
    if (f)
703
0
        f(insert->payload, insert->name);
704
2.04k
    insert->payload = userdata;
705
2.04k
    return(0);
706
2.04k
      }
707
11.8k
  } 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
12.0k
    }
729
730
78.3k
    if (insert == NULL) {
731
68.5k
  entry =  &(table->table[key]);
732
68.5k
    } else {
733
9.82k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
9.82k
  if (entry == NULL)
735
0
       return(-1);
736
9.82k
    }
737
738
78.3k
    if (table->dict != NULL) {
739
78.3k
        entry->name = (xmlChar *) name;
740
78.3k
        entry->name2 = (xmlChar *) name2;
741
78.3k
        entry->name3 = (xmlChar *) name3;
742
78.3k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
78.3k
    entry->payload = userdata;
748
78.3k
    entry->next = NULL;
749
78.3k
    entry->valid = 1;
750
78.3k
    table->nbElems++;
751
752
753
78.3k
    if (insert != NULL) {
754
9.82k
  insert->next = entry;
755
9.82k
    }
756
78.3k
    return(0);
757
78.3k
}
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
62.8M
         const xmlChar *name2, const xmlChar *name3) {
773
62.8M
    unsigned long key;
774
62.8M
    xmlHashEntryPtr entry;
775
776
62.8M
    if (table == NULL)
777
301k
  return(NULL);
778
62.5M
    if (name == NULL)
779
0
  return(NULL);
780
62.5M
    key = xmlHashComputeKey(table, name, name2, name3);
781
62.5M
    if (table->table[key].valid == 0)
782
12.0M
  return(NULL);
783
50.5M
    if (table->dict) {
784
69.1M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
43.9M
      if ((entry->name == name) &&
786
43.9M
    (entry->name2 == name2) &&
787
43.9M
    (entry->name3 == name3))
788
16.6M
    return(entry->payload);
789
43.9M
  }
790
41.8M
    }
791
37.5M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
35.5M
  if ((xmlStrEqual(entry->name, name)) &&
793
35.5M
      (xmlStrEqual(entry->name2, name2)) &&
794
35.5M
      (xmlStrEqual(entry->name3, name3)))
795
31.8M
      return(entry->payload);
796
35.5M
    }
797
2.00M
    return(NULL);
798
33.8M
}
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
812k
    const xmlChar *prefix3, const xmlChar *name3) {
819
812k
    unsigned long key;
820
812k
    xmlHashEntryPtr entry;
821
822
812k
    if (table == NULL)
823
0
  return(NULL);
824
812k
    if (name == NULL)
825
0
  return(NULL);
826
812k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
812k
                             name2, prefix3, name3);
828
812k
    if (table->table[key].valid == 0)
829
271k
  return(NULL);
830
1.34M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
1.16M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
1.16M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
1.16M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
363k
      return(entry->payload);
835
1.16M
    }
836
177k
    return(NULL);
837
540k
}
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
434k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
434k
    stubData *stubdata = (stubData *) data;
849
434k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
434k
}
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
110k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
110k
    stubData stubdata;
863
110k
    stubdata.data = data;
864
110k
    stubdata.hashscanner = f;
865
110k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
110k
}
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
166k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
166k
    int i, nb;
879
166k
    xmlHashEntryPtr iter;
880
166k
    xmlHashEntryPtr next;
881
882
166k
    if (table == NULL)
883
5.35k
  return;
884
160k
    if (f == NULL)
885
0
  return;
886
887
160k
    if (table->table) {
888
27.8M
  for(i = 0; i < table->size; i++) {
889
27.7M
      if (table->table[i].valid == 0)
890
26.9M
    continue;
891
732k
      iter = &(table->table[i]);
892
1.86M
      while (iter) {
893
1.13M
    next = iter->next;
894
1.13M
                nb = table->nbElems;
895
1.13M
    if ((f != NULL) && (iter->payload != NULL))
896
1.13M
        f(iter->payload, data, iter->name,
897
1.13M
          iter->name2, iter->name3);
898
1.13M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
219k
                    if (iter == &(table->table[i])) {
901
136k
                        if (table->table[i].valid == 0)
902
84.5k
                            iter = NULL;
903
136k
                        if (table->table[i].next != next)
904
52.1k
          iter = &(table->table[i]);
905
136k
                    } else
906
82.4k
            iter = next;
907
219k
                } else
908
911k
        iter = next;
909
1.13M
      }
910
732k
  }
911
160k
    }
912
160k
}
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
55.9k
       xmlHashScanner f, void *data) {
931
55.9k
    stubData stubdata;
932
55.9k
    stubdata.data = data;
933
55.9k
    stubdata.hashscanner = f;
934
55.9k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
55.9k
                     &stubdata);
936
55.9k
}
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
55.9k
     xmlHashScannerFull f, void *data) {
955
55.9k
    int i;
956
55.9k
    xmlHashEntryPtr iter;
957
55.9k
    xmlHashEntryPtr next;
958
959
55.9k
    if (table == NULL)
960
53.6k
  return;
961
2.32k
    if (f == NULL)
962
0
  return;
963
964
2.32k
    if (table->table) {
965
598k
  for(i = 0; i < table->size; i++) {
966
596k
      if (table->table[i].valid == 0)
967
107k
    continue;
968
488k
      iter = &(table->table[i]);
969
1.62M
      while (iter) {
970
1.13M
    next = iter->next;
971
1.13M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
1.13M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
1.13M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
1.13M
        (iter->payload != NULL)) {
975
12
        f(iter->payload, data, iter->name,
976
12
          iter->name2, iter->name3);
977
12
    }
978
1.13M
    iter = next;
979
1.13M
      }
980
488k
  }
981
2.32k
    }
982
2.32k
}
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
55.9k
xmlHashSize(xmlHashTablePtr table) {
1037
55.9k
    if (table == NULL)
1038
0
  return(-1);
1039
55.9k
    return(table->nbElems);
1040
55.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
194
           xmlHashDeallocator f) {
1056
194
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
194
}
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
221k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
221k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
221k
}
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
222k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
222k
    unsigned long key;
1096
222k
    xmlHashEntryPtr entry;
1097
222k
    xmlHashEntryPtr prev = NULL;
1098
1099
222k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
222k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
222k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
222k
    } else {
1106
357k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
357k
            if (xmlStrEqual(entry->name, name) &&
1108
357k
                    xmlStrEqual(entry->name2, name2) &&
1109
357k
                    xmlStrEqual(entry->name3, name3)) {
1110
222k
                if ((f != NULL) && (entry->payload != NULL))
1111
194
                    f(entry->payload, entry->name);
1112
222k
                entry->payload = NULL;
1113
222k
    if (table->dict == NULL) {
1114
1.30k
        if(entry->name)
1115
1.30k
      xmlFree(entry->name);
1116
1.30k
        if(entry->name2)
1117
290
      xmlFree(entry->name2);
1118
1.30k
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
1.30k
    }
1121
222k
                if(prev) {
1122
82.4k
                    prev->next = entry->next;
1123
82.4k
        xmlFree(entry);
1124
139k
    } else {
1125
139k
        if (entry->next == NULL) {
1126
87.5k
      entry->valid = 0;
1127
87.5k
        } else {
1128
52.1k
      entry = entry->next;
1129
52.1k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
52.1k
      xmlFree(entry);
1131
52.1k
        }
1132
139k
    }
1133
222k
                table->nbElems--;
1134
222k
                return(0);
1135
222k
            }
1136
135k
            prev = entry;
1137
135k
        }
1138
0
        return(-1);
1139
222k
    }
1140
222k
}
1141