Coverage Report

Created: 2024-10-19 16:35

/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
69.8M
#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
1.24G
            const xmlChar *name2, const xmlChar *name3) {
85
1.24G
    unsigned long value = 0L;
86
1.24G
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
1.24G
    if (name != NULL) {
92
1.24G
  value += 30 * (*name);
93
13.0G
  while ((ch = *name++) != 0) {
94
11.7G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
11.7G
  }
96
1.24G
    }
97
1.24G
    value = value ^ ((value << 5) + (value >> 3));
98
1.24G
    if (name2 != NULL) {
99
930M
  while ((ch = *name2++) != 0) {
100
867M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
867M
  }
102
63.4M
    }
103
1.24G
    value = value ^ ((value << 5) + (value >> 3));
104
1.24G
    if (name3 != NULL) {
105
487M
  while ((ch = *name3++) != 0) {
106
423M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
423M
  }
108
64.7M
    }
109
1.24G
    return (value % table->size);
110
1.24G
}
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
11.4M
       const xmlChar *prefix3, const xmlChar *name3) {
120
11.4M
    unsigned long value = 0L;
121
11.4M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
11.4M
    if (prefix != NULL)
127
969k
  value += 30 * (*prefix);
128
10.4M
    else
129
10.4M
  value += 30 * (*name);
130
131
11.4M
    if (prefix != NULL) {
132
4.40M
  while ((ch = *prefix++) != 0) {
133
3.43M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
3.43M
  }
135
969k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
969k
    }
137
11.4M
    if (name != NULL) {
138
72.3M
  while ((ch = *name++) != 0) {
139
60.9M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
60.9M
  }
141
11.4M
    }
142
11.4M
    value = value ^ ((value << 5) + (value >> 3));
143
11.4M
    if (prefix2 != NULL) {
144
4.05M
  while ((ch = *prefix2++) != 0) {
145
3.06M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
3.06M
  }
147
986k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
986k
    }
149
11.4M
    if (name2 != NULL) {
150
49.0M
  while ((ch = *name2++) != 0) {
151
37.6M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
37.6M
  }
153
11.4M
    }
154
11.4M
    value = value ^ ((value << 5) + (value >> 3));
155
11.4M
    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
11.4M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
11.4M
    return (value % table->size);
167
11.4M
}
168
169
/**
170
 * xmlHashCreate:
171
 * @size: the size of the hash table
172
 *
173
 * Create a new xmlHashTablePtr.
174
 *
175
 * Returns the newly created object, or NULL if an error occurred.
176
 */
177
xmlHashTablePtr
178
7.15M
xmlHashCreate(int size) {
179
7.15M
    xmlHashTablePtr table;
180
181
7.15M
    if (size <= 0)
182
1.23M
        size = 256;
183
184
7.15M
    table = xmlMalloc(sizeof(xmlHashTable));
185
7.15M
    if (table) {
186
7.15M
        table->dict = NULL;
187
7.15M
        table->size = size;
188
7.15M
  table->nbElems = 0;
189
7.15M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
7.15M
        if (table->table) {
191
7.15M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
7.15M
      return(table);
196
7.15M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
7.15M
}
201
202
/**
203
 * xmlHashCreateDict:
204
 * @size: the size of the hash table
205
 * @dict: a dictionary to use for the hash
206
 *
207
 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
208
 *
209
 * Returns the newly created object, or NULL if an error occurred.
210
 */
211
xmlHashTablePtr
212
1.49M
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
1.49M
    xmlHashTablePtr table;
214
215
1.49M
    table = xmlHashCreate(size);
216
1.49M
    if (table != NULL) {
217
1.49M
        table->dict = dict;
218
1.49M
  xmlDictReference(dict);
219
1.49M
    }
220
1.49M
    return(table);
221
1.49M
}
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
68.1k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
68.1k
    unsigned long key;
235
68.1k
    int oldsize, i;
236
68.1k
    xmlHashEntryPtr iter, next;
237
68.1k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
68.1k
    if (table == NULL)
243
0
  return(-1);
244
68.1k
    if (size < 8)
245
0
        return(-1);
246
68.1k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
68.1k
    oldsize = table->size;
250
68.1k
    oldtable = table->table;
251
68.1k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
68.1k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
68.1k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
68.1k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
68.1k
    table->size = size;
261
262
    /*  If the two loops are merged, there would be situations where
263
  a new entry needs to allocated and data copied into it from
264
  the main table. So instead, we run through the array twice, first
265
  copying all the elements in the main array (where we can't get
266
  conflicts) and then the rest, so we only free (and don't allocate)
267
    */
268
1.68M
    for (i = 0; i < oldsize; i++) {
269
1.61M
  if (oldtable[i].valid == 0)
270
25.8k
      continue;
271
1.58M
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
1.58M
        oldtable[i].name3);
273
1.58M
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
1.58M
  table->table[key].next = NULL;
275
1.58M
    }
276
277
1.68M
    for (i = 0; i < oldsize; i++) {
278
1.61M
  iter = oldtable[i].next;
279
7.91M
  while (iter) {
280
6.29M
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
6.29M
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
6.29M
                        iter->name3);
288
6.29M
      if (table->table[key].valid == 0) {
289
4.23M
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
4.23M
    table->table[key].next = NULL;
291
4.23M
    xmlFree(iter);
292
4.23M
      } else {
293
2.06M
    iter->next = table->table[key].next;
294
2.06M
    table->table[key].next = iter;
295
2.06M
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
6.29M
      iter = next;
302
6.29M
  }
303
1.61M
    }
304
305
68.1k
    xmlFree(oldtable);
306
307
#ifdef DEBUG_GROW
308
    xmlGenericError(xmlGenericErrorContext,
309
      "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
310
#endif
311
312
68.1k
    return(0);
313
68.1k
}
314
315
/**
316
 * xmlHashFree:
317
 * @table: the hash table
318
 * @f:  the deallocator function for items in the hash
319
 *
320
 * Free the hash @table and its contents. The userdata is
321
 * deallocated with @f if provided.
322
 */
323
void
324
7.15M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
7.15M
    int i;
326
7.15M
    xmlHashEntryPtr iter;
327
7.15M
    xmlHashEntryPtr next;
328
7.15M
    int inside_table = 0;
329
7.15M
    int nbElems;
330
331
7.15M
    if (table == NULL)
332
0
  return;
333
7.15M
    if (table->table) {
334
7.15M
  nbElems = table->nbElems;
335
289M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
281M
      iter = &(table->table[i]);
337
281M
      if (iter->valid == 0)
338
240M
    continue;
339
41.7M
      inside_table = 1;
340
106M
      while (iter) {
341
64.2M
    next = iter->next;
342
64.2M
    if ((f != NULL) && (iter->payload != NULL))
343
50.8M
        f(iter->payload, iter->name);
344
64.2M
    if (table->dict == NULL) {
345
16.4M
        if (iter->name)
346
16.4M
      xmlFree(iter->name);
347
16.4M
        if (iter->name2)
348
622k
      xmlFree(iter->name2);
349
16.4M
        if (iter->name3)
350
9.60M
      xmlFree(iter->name3);
351
16.4M
    }
352
64.2M
    iter->payload = NULL;
353
64.2M
    if (!inside_table)
354
22.4M
        xmlFree(iter);
355
64.2M
    nbElems--;
356
64.2M
    inside_table = 0;
357
64.2M
    iter = next;
358
64.2M
      }
359
41.7M
  }
360
7.15M
  xmlFree(table->table);
361
7.15M
    }
362
7.15M
    if (table->dict)
363
1.07M
        xmlDictFree(table->dict);
364
7.15M
    xmlFree(table);
365
7.15M
}
366
367
/**
368
 * xmlHashDefaultDeallocator:
369
 * @entry: the hash table entry
370
 * @name: the entry's name
371
 *
372
 * Free a hash table entry with xmlFree.
373
 */
374
void
375
1.25M
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
1.25M
    xmlFree(entry);
377
1.25M
}
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
11.7M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
11.7M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
11.7M
}
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
29.5M
          const xmlChar *name2, void *userdata) {
410
29.5M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
29.5M
}
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
726k
       xmlHashDeallocator f) {
450
726k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
726k
}
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
991M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
991M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
991M
}
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
136M
        const xmlChar *name2) {
480
136M
    return(xmlHashLookup3(table, name, name2, NULL));
481
136M
}
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
11.4M
          const xmlChar *name2) {
515
11.4M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
11.4M
}
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
71.6M
     void *userdata) {
536
71.6M
    unsigned long key, len = 0;
537
71.6M
    xmlHashEntryPtr entry;
538
71.6M
    xmlHashEntryPtr insert;
539
540
71.6M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
71.6M
    if (table->dict) {
547
54.4M
        if (!xmlDictOwns(table->dict, name)) {
548
3.32M
      name = xmlDictLookup(table->dict, name, -1);
549
3.32M
      if (name == NULL)
550
0
          return(-1);
551
3.32M
  }
552
54.4M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
335k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
335k
      if (name2 == NULL)
555
0
          return(-1);
556
335k
  }
557
54.4M
        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
54.4M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
71.6M
    key = xmlHashComputeKey(table, name, name2, name3);
568
71.6M
    if (table->table[key].valid == 0) {
569
39.0M
  insert = NULL;
570
39.0M
    } else {
571
32.5M
        if (table->dict) {
572
56.9M
      for (insert = &(table->table[key]); insert->next != NULL;
573
30.1M
     insert = insert->next) {
574
30.1M
    if ((insert->name == name) &&
575
30.1M
        (insert->name2 == name2) &&
576
30.1M
        (insert->name3 == name3))
577
43.3k
        return(-1);
578
30.1M
    len++;
579
30.1M
      }
580
26.7M
      if ((insert->name == name) &&
581
26.7M
    (insert->name2 == name2) &&
582
26.7M
    (insert->name3 == name3))
583
1.14M
    return(-1);
584
26.7M
  } else {
585
8.46M
      for (insert = &(table->table[key]); insert->next != NULL;
586
5.75M
     insert = insert->next) {
587
2.75M
    if ((xmlStrEqual(insert->name, name)) &&
588
2.75M
        (xmlStrEqual(insert->name2, name2)) &&
589
2.75M
        (xmlStrEqual(insert->name3, name3)))
590
43.1k
        return(-1);
591
2.71M
    len++;
592
2.71M
      }
593
5.71M
      if ((xmlStrEqual(insert->name, name)) &&
594
5.71M
    (xmlStrEqual(insert->name2, name2)) &&
595
5.71M
    (xmlStrEqual(insert->name3, name3)))
596
605k
    return(-1);
597
5.71M
  }
598
32.5M
    }
599
600
69.7M
    if (insert == NULL) {
601
39.0M
  entry = &(table->table[key]);
602
39.0M
    } else {
603
30.7M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
30.7M
  if (entry == NULL)
605
0
       return(-1);
606
30.7M
    }
607
608
69.7M
    if (table->dict != NULL) {
609
53.2M
        entry->name = (xmlChar *) name;
610
53.2M
        entry->name2 = (xmlChar *) name2;
611
53.2M
        entry->name3 = (xmlChar *) name3;
612
53.2M
    } else {
613
16.4M
  entry->name = xmlStrdup(name);
614
16.4M
  entry->name2 = xmlStrdup(name2);
615
16.4M
  entry->name3 = xmlStrdup(name3);
616
16.4M
    }
617
69.7M
    entry->payload = userdata;
618
69.7M
    entry->next = NULL;
619
69.7M
    entry->valid = 1;
620
621
622
69.7M
    if (insert != NULL)
623
30.7M
  insert->next = entry;
624
625
69.7M
    table->nbElems++;
626
627
69.7M
    if (len > MAX_HASH_LEN)
628
68.1k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
69.7M
    return(0);
631
69.7M
}
632
633
/**
634
 * xmlHashUpdateEntry3:
635
 * @table: the hash table
636
 * @name: the name of the userdata
637
 * @name2: a second name of the userdata
638
 * @name3: a third name of the userdata
639
 * @userdata: a pointer to the userdata
640
 * @f: the deallocator function for replaced item (if any)
641
 *
642
 * Add the @userdata to the hash @table. This can later be retrieved
643
 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
644
 * will be removed and freed with @f if found.
645
 *
646
 * Returns 0 the addition succeeded and -1 in case of error.
647
 */
648
int
649
xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
650
             const xmlChar *name2, const xmlChar *name3,
651
726k
       void *userdata, xmlHashDeallocator f) {
652
726k
    unsigned long key;
653
726k
    xmlHashEntryPtr entry;
654
726k
    xmlHashEntryPtr insert;
655
656
726k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
726k
    if (table->dict) {
663
726k
        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
726k
        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
726k
        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
726k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
726k
    key = xmlHashComputeKey(table, name, name2, name3);
684
726k
    if (table->table[key].valid == 0) {
685
443k
  insert = NULL;
686
443k
    } else {
687
282k
        if (table ->dict) {
688
460k
      for (insert = &(table->table[key]); insert->next != NULL;
689
282k
     insert = insert->next) {
690
179k
    if ((insert->name == name) &&
691
179k
        (insert->name2 == name2) &&
692
179k
        (insert->name3 == name3)) {
693
930
        if (f)
694
0
      f(insert->payload, insert->name);
695
930
        insert->payload = userdata;
696
930
        return(0);
697
930
    }
698
179k
      }
699
281k
      if ((insert->name == name) &&
700
281k
    (insert->name2 == name2) &&
701
281k
    (insert->name3 == name3)) {
702
4.76k
    if (f)
703
0
        f(insert->payload, insert->name);
704
4.76k
    insert->payload = userdata;
705
4.76k
    return(0);
706
4.76k
      }
707
281k
  } 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
282k
    }
729
730
720k
    if (insert == NULL) {
731
443k
  entry =  &(table->table[key]);
732
443k
    } else {
733
277k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
277k
  if (entry == NULL)
735
0
       return(-1);
736
277k
    }
737
738
720k
    if (table->dict != NULL) {
739
720k
        entry->name = (xmlChar *) name;
740
720k
        entry->name2 = (xmlChar *) name2;
741
720k
        entry->name3 = (xmlChar *) name3;
742
720k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
720k
    entry->payload = userdata;
748
720k
    entry->next = NULL;
749
720k
    entry->valid = 1;
750
720k
    table->nbElems++;
751
752
753
720k
    if (insert != NULL) {
754
277k
  insert->next = entry;
755
277k
    }
756
720k
    return(0);
757
720k
}
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
1.16G
         const xmlChar *name2, const xmlChar *name3) {
773
1.16G
    unsigned long key;
774
1.16G
    xmlHashEntryPtr entry;
775
776
1.16G
    if (table == NULL)
777
5.53M
  return(NULL);
778
1.15G
    if (name == NULL)
779
0
  return(NULL);
780
1.15G
    key = xmlHashComputeKey(table, name, name2, name3);
781
1.15G
    if (table->table[key].valid == 0)
782
248M
  return(NULL);
783
908M
    if (table->dict) {
784
977M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
716M
      if ((entry->name == name) &&
786
716M
    (entry->name2 == name2) &&
787
716M
    (entry->name3 == name3))
788
397M
    return(entry->payload);
789
716M
  }
790
658M
    }
791
602M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
562M
  if ((xmlStrEqual(entry->name, name)) &&
793
562M
      (xmlStrEqual(entry->name2, name2)) &&
794
562M
      (xmlStrEqual(entry->name3, name3)))
795
471M
      return(entry->payload);
796
562M
    }
797
39.4M
    return(NULL);
798
511M
}
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
11.4M
    const xmlChar *prefix3, const xmlChar *name3) {
819
11.4M
    unsigned long key;
820
11.4M
    xmlHashEntryPtr entry;
821
822
11.4M
    if (table == NULL)
823
0
  return(NULL);
824
11.4M
    if (name == NULL)
825
0
  return(NULL);
826
11.4M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
11.4M
                             name2, prefix3, name3);
828
11.4M
    if (table->table[key].valid == 0)
829
1.44M
  return(NULL);
830
30.8M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
27.0M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
27.0M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
27.0M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
6.15M
      return(entry->payload);
835
27.0M
    }
836
3.84M
    return(NULL);
837
9.99M
}
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
14.1M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
14.1M
    stubData *stubdata = (stubData *) data;
849
14.1M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
14.1M
}
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
295k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
295k
    stubData stubdata;
863
295k
    stubdata.data = data;
864
295k
    stubdata.hashscanner = f;
865
295k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
295k
}
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
424k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
424k
    int i, nb;
879
424k
    xmlHashEntryPtr iter;
880
424k
    xmlHashEntryPtr next;
881
882
424k
    if (table == NULL)
883
23.0k
  return;
884
401k
    if (f == NULL)
885
0
  return;
886
887
401k
    if (table->table) {
888
80.7M
  for(i = 0; i < table->size; i++) {
889
80.3M
      if (table->table[i].valid == 0)
890
64.3M
    continue;
891
15.9M
      iter = &(table->table[i]);
892
47.7M
      while (iter) {
893
31.7M
    next = iter->next;
894
31.7M
                nb = table->nbElems;
895
31.7M
    if ((f != NULL) && (iter->payload != NULL))
896
31.7M
        f(iter->payload, data, iter->name,
897
31.7M
          iter->name2, iter->name3);
898
31.7M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
6.22M
                    if (iter == &(table->table[i])) {
901
3.50M
                        if (table->table[i].valid == 0)
902
1.89M
                            iter = NULL;
903
3.50M
                        if (table->table[i].next != next)
904
1.60M
          iter = &(table->table[i]);
905
3.50M
                    } else
906
2.71M
            iter = next;
907
6.22M
                } else
908
25.4M
        iter = next;
909
31.7M
      }
910
15.9M
  }
911
401k
    }
912
401k
}
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
2.89M
       xmlHashScanner f, void *data) {
931
2.89M
    stubData stubdata;
932
2.89M
    stubdata.data = data;
933
2.89M
    stubdata.hashscanner = f;
934
2.89M
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
2.89M
                     &stubdata);
936
2.89M
}
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
2.89M
     xmlHashScannerFull f, void *data) {
955
2.89M
    int i;
956
2.89M
    xmlHashEntryPtr iter;
957
2.89M
    xmlHashEntryPtr next;
958
959
2.89M
    if (table == NULL)
960
2.50M
  return;
961
388k
    if (f == NULL)
962
0
  return;
963
964
388k
    if (table->table) {
965
121M
  for(i = 0; i < table->size; i++) {
966
121M
      if (table->table[i].valid == 0)
967
35.6M
    continue;
968
85.5M
      iter = &(table->table[i]);
969
275M
      while (iter) {
970
190M
    next = iter->next;
971
190M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
190M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
190M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
190M
        (iter->payload != NULL)) {
975
141
        f(iter->payload, data, iter->name,
976
141
          iter->name2, iter->name3);
977
141
    }
978
190M
    iter = next;
979
190M
      }
980
85.5M
  }
981
388k
    }
982
388k
}
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
128k
xmlHashSize(xmlHashTablePtr table) {
1037
128k
    if (table == NULL)
1038
0
  return(-1);
1039
128k
    return(table->nbElems);
1040
128k
}
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
225
           xmlHashDeallocator f) {
1056
225
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
225
}
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
6.22M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
6.22M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
6.22M
}
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
6.22M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
6.22M
    unsigned long key;
1096
6.22M
    xmlHashEntryPtr entry;
1097
6.22M
    xmlHashEntryPtr prev = NULL;
1098
1099
6.22M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
6.22M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
6.22M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
6.22M
    } else {
1106
10.7M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
10.7M
            if (xmlStrEqual(entry->name, name) &&
1108
10.7M
                    xmlStrEqual(entry->name2, name2) &&
1109
10.7M
                    xmlStrEqual(entry->name3, name3)) {
1110
6.22M
                if ((f != NULL) && (entry->payload != NULL))
1111
225
                    f(entry->payload, entry->name);
1112
6.22M
                entry->payload = NULL;
1113
6.22M
    if (table->dict == NULL) {
1114
1.04k
        if(entry->name)
1115
1.04k
      xmlFree(entry->name);
1116
1.04k
        if(entry->name2)
1117
358
      xmlFree(entry->name2);
1118
1.04k
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
1.04k
    }
1121
6.22M
                if(prev) {
1122
2.71M
                    prev->next = entry->next;
1123
2.71M
        xmlFree(entry);
1124
3.51M
    } else {
1125
3.51M
        if (entry->next == NULL) {
1126
1.90M
      entry->valid = 0;
1127
1.90M
        } else {
1128
1.60M
      entry = entry->next;
1129
1.60M
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
1.60M
      xmlFree(entry);
1131
1.60M
        }
1132
3.51M
    }
1133
6.22M
                table->nbElems--;
1134
6.22M
                return(0);
1135
6.22M
            }
1136
4.56M
            prev = entry;
1137
4.56M
        }
1138
0
        return(-1);
1139
6.22M
    }
1140
6.22M
}
1141