Coverage Report

Created: 2023-10-08 19:14

/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
36.3M
#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.31G
            const xmlChar *name2, const xmlChar *name3) {
85
1.31G
    unsigned long value = 0L;
86
1.31G
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
1.31G
    if (name != NULL) {
92
1.31G
  value += 30 * (*name);
93
24.7G
  while ((ch = *name++) != 0) {
94
23.4G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
23.4G
  }
96
1.31G
    }
97
1.31G
    value = value ^ ((value << 5) + (value >> 3));
98
1.31G
    if (name2 != NULL) {
99
190M
  while ((ch = *name2++) != 0) {
100
157M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
157M
  }
102
32.3M
    }
103
1.31G
    value = value ^ ((value << 5) + (value >> 3));
104
1.31G
    if (name3 != NULL) {
105
248M
  while ((ch = *name3++) != 0) {
106
213M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
213M
  }
108
35.1M
    }
109
1.31G
    return (value % table->size);
110
1.31G
}
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
5.42M
       const xmlChar *prefix3, const xmlChar *name3) {
120
5.42M
    unsigned long value = 0L;
121
5.42M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
5.42M
    if (prefix != NULL)
127
414k
  value += 30 * (*prefix);
128
5.01M
    else
129
5.01M
  value += 30 * (*name);
130
131
5.42M
    if (prefix != NULL) {
132
1.65M
  while ((ch = *prefix++) != 0) {
133
1.24M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
1.24M
  }
135
414k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
414k
    }
137
5.42M
    if (name != NULL) {
138
33.8M
  while ((ch = *name++) != 0) {
139
28.4M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
28.4M
  }
141
5.42M
    }
142
5.42M
    value = value ^ ((value << 5) + (value >> 3));
143
5.42M
    if (prefix2 != NULL) {
144
1.66M
  while ((ch = *prefix2++) != 0) {
145
1.25M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
1.25M
  }
147
405k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
405k
    }
149
5.42M
    if (name2 != NULL) {
150
23.0M
  while ((ch = *name2++) != 0) {
151
17.5M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
17.5M
  }
153
5.42M
    }
154
5.42M
    value = value ^ ((value << 5) + (value >> 3));
155
5.42M
    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
5.42M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
5.42M
    return (value % table->size);
167
5.42M
}
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.47M
xmlHashCreate(int size) {
179
1.47M
    xmlHashTablePtr table;
180
181
1.47M
    if (size <= 0)
182
946k
        size = 256;
183
184
1.47M
    table = xmlMalloc(sizeof(xmlHashTable));
185
1.47M
    if (table) {
186
1.47M
        table->dict = NULL;
187
1.47M
        table->size = size;
188
1.47M
  table->nbElems = 0;
189
1.47M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
1.47M
        if (table->table) {
191
1.47M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
1.47M
      return(table);
196
1.47M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
1.47M
}
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.13M
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
1.13M
    xmlHashTablePtr table;
214
215
1.13M
    table = xmlHashCreate(size);
216
1.13M
    if (table != NULL) {
217
1.13M
        table->dict = dict;
218
1.13M
  xmlDictReference(dict);
219
1.13M
    }
220
1.13M
    return(table);
221
1.13M
}
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
39.2k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
39.2k
    unsigned long key;
235
39.2k
    int oldsize, i;
236
39.2k
    xmlHashEntryPtr iter, next;
237
39.2k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
39.2k
    if (table == NULL)
243
0
  return(-1);
244
39.2k
    if (size < 8)
245
0
        return(-1);
246
39.2k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
39.2k
    oldsize = table->size;
250
39.2k
    oldtable = table->table;
251
39.2k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
39.2k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
39.2k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
39.2k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
39.2k
    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.04M
    for (i = 0; i < oldsize; i++) {
269
1.00M
  if (oldtable[i].valid == 0)
270
27.6k
      continue;
271
980k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
980k
        oldtable[i].name3);
273
980k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
980k
  table->table[key].next = NULL;
275
980k
    }
276
277
1.04M
    for (i = 0; i < oldsize; i++) {
278
1.00M
  iter = oldtable[i].next;
279
4.74M
  while (iter) {
280
3.74M
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
3.74M
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
3.74M
                        iter->name3);
288
3.74M
      if (table->table[key].valid == 0) {
289
2.52M
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
2.52M
    table->table[key].next = NULL;
291
2.52M
    xmlFree(iter);
292
2.52M
      } else {
293
1.21M
    iter->next = table->table[key].next;
294
1.21M
    table->table[key].next = iter;
295
1.21M
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
3.74M
      iter = next;
302
3.74M
  }
303
1.00M
    }
304
305
39.2k
    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
39.2k
    return(0);
313
39.2k
}
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.47M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
1.47M
    int i;
326
1.47M
    xmlHashEntryPtr iter;
327
1.47M
    xmlHashEntryPtr next;
328
1.47M
    int inside_table = 0;
329
1.47M
    int nbElems;
330
331
1.47M
    if (table == NULL)
332
0
  return;
333
1.47M
    if (table->table) {
334
1.47M
  nbElems = table->nbElems;
335
208M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
206M
      iter = &(table->table[i]);
337
206M
      if (iter->valid == 0)
338
183M
    continue;
339
23.6M
      inside_table = 1;
340
57.8M
      while (iter) {
341
34.1M
    next = iter->next;
342
34.1M
    if ((f != NULL) && (iter->payload != NULL))
343
27.1M
        f(iter->payload, iter->name);
344
34.1M
    if (table->dict == NULL) {
345
10.3M
        if (iter->name)
346
10.3M
      xmlFree(iter->name);
347
10.3M
        if (iter->name2)
348
361k
      xmlFree(iter->name2);
349
10.3M
        if (iter->name3)
350
5.51M
      xmlFree(iter->name3);
351
10.3M
    }
352
34.1M
    iter->payload = NULL;
353
34.1M
    if (!inside_table)
354
10.5M
        xmlFree(iter);
355
34.1M
    nbElems--;
356
34.1M
    inside_table = 0;
357
34.1M
    iter = next;
358
34.1M
      }
359
23.6M
  }
360
1.47M
  xmlFree(table->table);
361
1.47M
    }
362
1.47M
    if (table->dict)
363
785k
        xmlDictFree(table->dict);
364
1.47M
    xmlFree(table);
365
1.47M
}
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
863k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
863k
    xmlFree(entry);
377
863k
}
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
9.79M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
9.79M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
9.79M
}
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
14.7M
          const xmlChar *name2, void *userdata) {
410
14.7M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
14.7M
}
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
382k
       xmlHashDeallocator f) {
450
382k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
382k
}
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
1.17G
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
1.17G
    return(xmlHashLookup3(table, name, NULL, NULL));
465
1.17G
}
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
70.6M
        const xmlChar *name2) {
480
70.6M
    return(xmlHashLookup3(table, name, name2, NULL));
481
70.6M
}
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
5.42M
          const xmlChar *name2) {
515
5.42M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
5.42M
}
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
39.5M
     void *userdata) {
536
39.5M
    unsigned long key, len = 0;
537
39.5M
    xmlHashEntryPtr entry;
538
39.5M
    xmlHashEntryPtr insert;
539
540
39.5M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
39.5M
    if (table->dict) {
547
28.0M
        if (!xmlDictOwns(table->dict, name)) {
548
1.71M
      name = xmlDictLookup(table->dict, name, -1);
549
1.71M
      if (name == NULL)
550
0
          return(-1);
551
1.71M
  }
552
28.0M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
189k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
189k
      if (name2 == NULL)
555
0
          return(-1);
556
189k
  }
557
28.0M
        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
28.0M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
39.5M
    key = xmlHashComputeKey(table, name, name2, name3);
568
39.5M
    if (table->table[key].valid == 0) {
569
21.7M
  insert = NULL;
570
21.7M
    } else {
571
17.8M
        if (table->dict) {
572
28.2M
      for (insert = &(table->table[key]); insert->next != NULL;
573
14.4M
     insert = insert->next) {
574
14.4M
    if ((insert->name == name) &&
575
14.4M
        (insert->name2 == name2) &&
576
14.4M
        (insert->name3 == name3))
577
23.1k
        return(-1);
578
14.4M
    len++;
579
14.4M
      }
580
13.7M
      if ((insert->name == name) &&
581
13.7M
    (insert->name2 == name2) &&
582
13.7M
    (insert->name3 == name3))
583
2.04M
    return(-1);
584
13.7M
  } else {
585
5.44M
      for (insert = &(table->table[key]); insert->next != NULL;
586
4.02M
     insert = insert->next) {
587
1.43M
    if ((xmlStrEqual(insert->name, name)) &&
588
1.43M
        (xmlStrEqual(insert->name2, name2)) &&
589
1.43M
        (xmlStrEqual(insert->name3, name3)))
590
19.6k
        return(-1);
591
1.41M
    len++;
592
1.41M
      }
593
4.00M
      if ((xmlStrEqual(insert->name, name)) &&
594
4.00M
    (xmlStrEqual(insert->name2, name2)) &&
595
4.00M
    (xmlStrEqual(insert->name3, name3)))
596
1.19M
    return(-1);
597
4.00M
  }
598
17.8M
    }
599
600
36.2M
    if (insert == NULL) {
601
21.7M
  entry = &(table->table[key]);
602
21.7M
    } else {
603
14.5M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
14.5M
  if (entry == NULL)
605
0
       return(-1);
606
14.5M
    }
607
608
36.2M
    if (table->dict != NULL) {
609
25.9M
        entry->name = (xmlChar *) name;
610
25.9M
        entry->name2 = (xmlChar *) name2;
611
25.9M
        entry->name3 = (xmlChar *) name3;
612
25.9M
    } else {
613
10.3M
  entry->name = xmlStrdup(name);
614
10.3M
  entry->name2 = xmlStrdup(name2);
615
10.3M
  entry->name3 = xmlStrdup(name3);
616
10.3M
    }
617
36.2M
    entry->payload = userdata;
618
36.2M
    entry->next = NULL;
619
36.2M
    entry->valid = 1;
620
621
622
36.2M
    if (insert != NULL)
623
14.5M
  insert->next = entry;
624
625
36.2M
    table->nbElems++;
626
627
36.2M
    if (len > MAX_HASH_LEN)
628
39.2k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
36.2M
    return(0);
631
36.2M
}
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
382k
       void *userdata, xmlHashDeallocator f) {
652
382k
    unsigned long key;
653
382k
    xmlHashEntryPtr entry;
654
382k
    xmlHashEntryPtr insert;
655
656
382k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
382k
    if (table->dict) {
663
382k
        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
382k
        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
382k
        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
382k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
382k
    key = xmlHashComputeKey(table, name, name2, name3);
684
382k
    if (table->table[key].valid == 0) {
685
244k
  insert = NULL;
686
244k
    } else {
687
138k
        if (table ->dict) {
688
246k
      for (insert = &(table->table[key]); insert->next != NULL;
689
138k
     insert = insert->next) {
690
108k
    if ((insert->name == name) &&
691
108k
        (insert->name2 == name2) &&
692
108k
        (insert->name3 == name3)) {
693
139
        if (f)
694
0
      f(insert->payload, insert->name);
695
139
        insert->payload = userdata;
696
139
        return(0);
697
139
    }
698
108k
      }
699
138k
      if ((insert->name == name) &&
700
138k
    (insert->name2 == name2) &&
701
138k
    (insert->name3 == name3)) {
702
3.14k
    if (f)
703
0
        f(insert->payload, insert->name);
704
3.14k
    insert->payload = userdata;
705
3.14k
    return(0);
706
3.14k
      }
707
138k
  } 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
138k
    }
729
730
379k
    if (insert == NULL) {
731
244k
  entry =  &(table->table[key]);
732
244k
    } else {
733
135k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
135k
  if (entry == NULL)
735
0
       return(-1);
736
135k
    }
737
738
379k
    if (table->dict != NULL) {
739
379k
        entry->name = (xmlChar *) name;
740
379k
        entry->name2 = (xmlChar *) name2;
741
379k
        entry->name3 = (xmlChar *) name3;
742
379k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
379k
    entry->payload = userdata;
748
379k
    entry->next = NULL;
749
379k
    entry->valid = 1;
750
379k
    table->nbElems++;
751
752
753
379k
    if (insert != NULL) {
754
135k
  insert->next = entry;
755
135k
    }
756
379k
    return(0);
757
379k
}
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.26G
         const xmlChar *name2, const xmlChar *name3) {
773
1.26G
    unsigned long key;
774
1.26G
    xmlHashEntryPtr entry;
775
776
1.26G
    if (table == NULL)
777
2.84M
  return(NULL);
778
1.26G
    if (name == NULL)
779
0
  return(NULL);
780
1.26G
    key = xmlHashComputeKey(table, name, name2, name3);
781
1.26G
    if (table->table[key].valid == 0)
782
320M
  return(NULL);
783
946M
    if (table->dict) {
784
804M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
570M
      if ((entry->name == name) &&
786
570M
    (entry->name2 == name2) &&
787
570M
    (entry->name3 == name3))
788
308M
    return(entry->payload);
789
570M
  }
790
542M
    }
791
683M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
664M
  if ((xmlStrEqual(entry->name, name)) &&
793
664M
      (xmlStrEqual(entry->name2, name2)) &&
794
664M
      (xmlStrEqual(entry->name3, name3)))
795
618M
      return(entry->payload);
796
664M
    }
797
19.0M
    return(NULL);
798
637M
}
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
5.42M
    const xmlChar *prefix3, const xmlChar *name3) {
819
5.42M
    unsigned long key;
820
5.42M
    xmlHashEntryPtr entry;
821
822
5.42M
    if (table == NULL)
823
0
  return(NULL);
824
5.42M
    if (name == NULL)
825
0
  return(NULL);
826
5.42M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
5.42M
                             name2, prefix3, name3);
828
5.42M
    if (table->table[key].valid == 0)
829
644k
  return(NULL);
830
14.9M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
13.0M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
13.0M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
13.0M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
2.92M
      return(entry->payload);
835
13.0M
    }
836
1.85M
    return(NULL);
837
4.78M
}
838
839
typedef struct {
840
    xmlHashScanner hashscanner;
841
    void *data;
842
} stubData;
843
844
static void
845
stubHashScannerFull (void *payload, void *data, const xmlChar *name,
846
                     const xmlChar *name2 ATTRIBUTE_UNUSED,
847
6.58M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
6.58M
    stubData *stubdata = (stubData *) data;
849
6.58M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
6.58M
}
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
213k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
213k
    stubData stubdata;
863
213k
    stubdata.data = data;
864
213k
    stubdata.hashscanner = f;
865
213k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
213k
}
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
304k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
304k
    int i, nb;
879
304k
    xmlHashEntryPtr iter;
880
304k
    xmlHashEntryPtr next;
881
882
304k
    if (table == NULL)
883
16.1k
  return;
884
288k
    if (f == NULL)
885
0
  return;
886
887
288k
    if (table->table) {
888
56.3M
  for(i = 0; i < table->size; i++) {
889
56.0M
      if (table->table[i].valid == 0)
890
48.0M
    continue;
891
7.99M
      iter = &(table->table[i]);
892
22.0M
      while (iter) {
893
14.0M
    next = iter->next;
894
14.0M
                nb = table->nbElems;
895
14.0M
    if ((f != NULL) && (iter->payload != NULL))
896
14.0M
        f(iter->payload, data, iter->name,
897
14.0M
          iter->name2, iter->name3);
898
14.0M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
2.48M
                    if (iter == &(table->table[i])) {
901
1.49M
                        if (table->table[i].valid == 0)
902
849k
                            iter = NULL;
903
1.49M
                        if (table->table[i].next != next)
904
648k
          iter = &(table->table[i]);
905
1.49M
                    } else
906
983k
            iter = next;
907
2.48M
                } else
908
11.5M
        iter = next;
909
14.0M
      }
910
7.99M
  }
911
288k
    }
912
288k
}
913
914
/**
915
 * xmlHashScan3:
916
 * @table: the hash table
917
 * @name: the name of the userdata or NULL
918
 * @name2: a second name of the userdata or NULL
919
 * @name3: a third name of the userdata or NULL
920
 * @f:  the scanner function for items in the hash
921
 * @data:  extra data passed to f
922
 *
923
 * Scan the hash @table and applied @f to each value matching
924
 * (@name, @name2, @name3) tuple. If one of the names is null,
925
 * the comparison is considered to match.
926
 */
927
void
928
xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
929
       const xmlChar *name2, const xmlChar *name3,
930
1.55M
       xmlHashScanner f, void *data) {
931
1.55M
    stubData stubdata;
932
1.55M
    stubdata.data = data;
933
1.55M
    stubdata.hashscanner = f;
934
1.55M
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
1.55M
                     &stubdata);
936
1.55M
}
937
938
/**
939
 * xmlHashScanFull3:
940
 * @table: the hash table
941
 * @name: the name of the userdata or NULL
942
 * @name2: a second name of the userdata or NULL
943
 * @name3: a third name of the userdata or NULL
944
 * @f:  the scanner function for items in the hash
945
 * @data:  extra data passed to f
946
 *
947
 * Scan the hash @table and applied @f to each value matching
948
 * (@name, @name2, @name3) tuple. If one of the names is null,
949
 * the comparison is considered to match.
950
 */
951
void
952
xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
953
     const xmlChar *name2, const xmlChar *name3,
954
1.55M
     xmlHashScannerFull f, void *data) {
955
1.55M
    int i;
956
1.55M
    xmlHashEntryPtr iter;
957
1.55M
    xmlHashEntryPtr next;
958
959
1.55M
    if (table == NULL)
960
1.43M
  return;
961
115k
    if (f == NULL)
962
0
  return;
963
964
115k
    if (table->table) {
965
34.2M
  for(i = 0; i < table->size; i++) {
966
34.1M
      if (table->table[i].valid == 0)
967
13.1M
    continue;
968
21.0M
      iter = &(table->table[i]);
969
65.3M
      while (iter) {
970
44.3M
    next = iter->next;
971
44.3M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
44.3M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
44.3M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
44.3M
        (iter->payload != NULL)) {
975
212
        f(iter->payload, data, iter->name,
976
212
          iter->name2, iter->name3);
977
212
    }
978
44.3M
    iter = next;
979
44.3M
      }
980
21.0M
  }
981
115k
    }
982
115k
}
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
91.1k
xmlHashSize(xmlHashTablePtr table) {
1037
91.1k
    if (table == NULL)
1038
0
  return(-1);
1039
91.1k
    return(table->nbElems);
1040
91.1k
}
1041
1042
/**
1043
 * xmlHashRemoveEntry:
1044
 * @table: the hash table
1045
 * @name: the name of the userdata
1046
 * @f: the deallocator function for removed item (if any)
1047
 *
1048
 * Find the userdata specified by the @name and remove
1049
 * it from the hash @table. Existing userdata for this tuple will be removed
1050
 * and freed with @f.
1051
 *
1052
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1053
 */
1054
int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
1055
485
           xmlHashDeallocator f) {
1056
485
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
485
}
1058
1059
/**
1060
 * xmlHashRemoveEntry2:
1061
 * @table: the hash table
1062
 * @name: the name of the userdata
1063
 * @name2: a second name of the userdata
1064
 * @f: the deallocator function for removed item (if any)
1065
 *
1066
 * Find the userdata specified by the (@name, @name2) tuple and remove
1067
 * it from the hash @table. Existing userdata for this tuple will be removed
1068
 * and freed with @f.
1069
 *
1070
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1071
 */
1072
int
1073
xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
1074
2.48M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
2.48M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
2.48M
}
1077
1078
/**
1079
 * xmlHashRemoveEntry3:
1080
 * @table: the hash table
1081
 * @name: the name of the userdata
1082
 * @name2: a second name of the userdata
1083
 * @name3: a third name of the userdata
1084
 * @f: the deallocator function for removed item (if any)
1085
 *
1086
 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1087
 * it from the hash @table. Existing userdata for this tuple will be removed
1088
 * and freed with @f.
1089
 *
1090
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1091
 */
1092
int
1093
xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
1094
2.48M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
2.48M
    unsigned long key;
1096
2.48M
    xmlHashEntryPtr entry;
1097
2.48M
    xmlHashEntryPtr prev = NULL;
1098
1099
2.48M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
2.48M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
2.48M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
2.48M
    } else {
1106
4.08M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
4.08M
            if (xmlStrEqual(entry->name, name) &&
1108
4.08M
                    xmlStrEqual(entry->name2, name2) &&
1109
4.08M
                    xmlStrEqual(entry->name3, name3)) {
1110
2.48M
                if ((f != NULL) && (entry->payload != NULL))
1111
485
                    f(entry->payload, entry->name);
1112
2.48M
                entry->payload = NULL;
1113
2.48M
    if (table->dict == NULL) {
1114
1.11k
        if(entry->name)
1115
1.11k
      xmlFree(entry->name);
1116
1.11k
        if(entry->name2)
1117
195
      xmlFree(entry->name2);
1118
1.11k
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
1.11k
    }
1121
2.48M
                if(prev) {
1122
983k
                    prev->next = entry->next;
1123
983k
        xmlFree(entry);
1124
1.50M
    } else {
1125
1.50M
        if (entry->next == NULL) {
1126
852k
      entry->valid = 0;
1127
852k
        } else {
1128
648k
      entry = entry->next;
1129
648k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
648k
      xmlFree(entry);
1131
648k
        }
1132
1.50M
    }
1133
2.48M
                table->nbElems--;
1134
2.48M
                return(0);
1135
2.48M
            }
1136
1.59M
            prev = entry;
1137
1.59M
        }
1138
0
        return(-1);
1139
2.48M
    }
1140
2.48M
}
1141