Coverage Report

Created: 2024-01-18 20:16

/src/libxml2/hash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * hash.c: chained hash tables
3
 *
4
 * Reference: Your favorite introductory book on algorithms
5
 *
6
 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
13
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16
 *
17
 * Author: breese@users.sourceforge.net
18
 */
19
20
#define IN_LIBXML
21
#include "libxml.h"
22
23
#include <string.h>
24
#include <stdlib.h>
25
#include <time.h>
26
27
/*
28
 * Following http://www.ocert.org/advisories/ocert-2011-003.html
29
 * it seems that having hash randomization might be a good idea
30
 * when using XML with untrusted data
31
 */
32
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
33
#define HASH_RANDOMIZATION
34
#endif
35
36
#include <libxml/parser.h>
37
#include <libxml/hash.h>
38
#include <libxml/xmlmemory.h>
39
#include <libxml/xmlerror.h>
40
#include <libxml/globals.h>
41
42
#include "private/dict.h"
43
44
77.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
893M
            const xmlChar *name2, const xmlChar *name3) {
85
893M
    unsigned long value = 0L;
86
893M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
893M
    if (name != NULL) {
92
893M
  value += 30 * (*name);
93
24.5G
  while ((ch = *name++) != 0) {
94
23.6G
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
23.6G
  }
96
893M
    }
97
893M
    value = value ^ ((value << 5) + (value >> 3));
98
893M
    if (name2 != NULL) {
99
462M
  while ((ch = *name2++) != 0) {
100
388M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
388M
  }
102
73.0M
    }
103
893M
    value = value ^ ((value << 5) + (value >> 3));
104
893M
    if (name3 != NULL) {
105
670M
  while ((ch = *name3++) != 0) {
106
561M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
561M
  }
108
109M
    }
109
893M
    return (value % table->size);
110
893M
}
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
21.9M
       const xmlChar *prefix3, const xmlChar *name3) {
120
21.9M
    unsigned long value = 0L;
121
21.9M
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
21.9M
    if (prefix != NULL)
127
674k
  value += 30 * (*prefix);
128
21.3M
    else
129
21.3M
  value += 30 * (*name);
130
131
21.9M
    if (prefix != NULL) {
132
2.52M
  while ((ch = *prefix++) != 0) {
133
1.84M
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
1.84M
  }
135
674k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
674k
    }
137
21.9M
    if (name != NULL) {
138
125M
  while ((ch = *name++) != 0) {
139
103M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
103M
  }
141
21.9M
    }
142
21.9M
    value = value ^ ((value << 5) + (value >> 3));
143
21.9M
    if (prefix2 != NULL) {
144
2.99M
  while ((ch = *prefix2++) != 0) {
145
2.31M
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
2.31M
  }
147
684k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
684k
    }
149
21.9M
    if (name2 != NULL) {
150
92.7M
  while ((ch = *name2++) != 0) {
151
70.7M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
70.7M
  }
153
21.9M
    }
154
21.9M
    value = value ^ ((value << 5) + (value >> 3));
155
21.9M
    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
21.9M
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
21.9M
    return (value % table->size);
167
21.9M
}
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
2.52M
xmlHashCreate(int size) {
179
2.52M
    xmlHashTablePtr table;
180
181
2.52M
    if (size <= 0)
182
1.47M
        size = 256;
183
184
2.52M
    table = xmlMalloc(sizeof(xmlHashTable));
185
2.52M
    if (table) {
186
2.52M
        table->dict = NULL;
187
2.52M
        table->size = size;
188
2.52M
  table->nbElems = 0;
189
2.52M
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
2.52M
        if (table->table) {
191
2.52M
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
2.52M
      return(table);
196
2.52M
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
2.52M
}
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.85M
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
1.85M
    xmlHashTablePtr table;
214
215
1.85M
    table = xmlHashCreate(size);
216
1.85M
    if (table != NULL) {
217
1.85M
        table->dict = dict;
218
1.85M
  xmlDictReference(dict);
219
1.85M
    }
220
1.85M
    return(table);
221
1.85M
}
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
90.2k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
90.2k
    unsigned long key;
235
90.2k
    int oldsize, i;
236
90.2k
    xmlHashEntryPtr iter, next;
237
90.2k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
90.2k
    if (table == NULL)
243
0
  return(-1);
244
90.2k
    if (size < 8)
245
0
        return(-1);
246
90.2k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
90.2k
    oldsize = table->size;
250
90.2k
    oldtable = table->table;
251
90.2k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
90.2k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
90.2k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
90.2k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
90.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
2.24M
    for (i = 0; i < oldsize; i++) {
269
2.15M
  if (oldtable[i].valid == 0)
270
31.4k
      continue;
271
2.12M
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
2.12M
        oldtable[i].name3);
273
2.12M
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
2.12M
  table->table[key].next = NULL;
275
2.12M
    }
276
277
2.24M
    for (i = 0; i < oldsize; i++) {
278
2.15M
  iter = oldtable[i].next;
279
10.6M
  while (iter) {
280
8.46M
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
8.46M
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
8.46M
                        iter->name3);
288
8.46M
      if (table->table[key].valid == 0) {
289
5.68M
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
5.68M
    table->table[key].next = NULL;
291
5.68M
    xmlFree(iter);
292
5.68M
      } else {
293
2.77M
    iter->next = table->table[key].next;
294
2.77M
    table->table[key].next = iter;
295
2.77M
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
8.46M
      iter = next;
302
8.46M
  }
303
2.15M
    }
304
305
90.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
90.2k
    return(0);
313
90.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
2.52M
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
2.52M
    int i;
326
2.52M
    xmlHashEntryPtr iter;
327
2.52M
    xmlHashEntryPtr next;
328
2.52M
    int inside_table = 0;
329
2.52M
    int nbElems;
330
331
2.52M
    if (table == NULL)
332
0
  return;
333
2.52M
    if (table->table) {
334
2.52M
  nbElems = table->nbElems;
335
332M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
329M
      iter = &(table->table[i]);
337
329M
      if (iter->valid == 0)
338
281M
    continue;
339
47.8M
      inside_table = 1;
340
119M
      while (iter) {
341
71.3M
    next = iter->next;
342
71.3M
    if ((f != NULL) && (iter->payload != NULL))
343
54.0M
        f(iter->payload, iter->name);
344
71.3M
    if (table->dict == NULL) {
345
9.98M
        if (iter->name)
346
9.98M
      xmlFree(iter->name);
347
9.98M
        if (iter->name2)
348
257k
      xmlFree(iter->name2);
349
9.98M
        if (iter->name3)
350
4.64M
      xmlFree(iter->name3);
351
9.98M
    }
352
71.3M
    iter->payload = NULL;
353
71.3M
    if (!inside_table)
354
23.5M
        xmlFree(iter);
355
71.3M
    nbElems--;
356
71.3M
    inside_table = 0;
357
71.3M
    iter = next;
358
71.3M
      }
359
47.8M
  }
360
2.52M
  xmlFree(table->table);
361
2.52M
    }
362
2.52M
    if (table->dict)
363
1.51M
        xmlDictFree(table->dict);
364
2.52M
    xmlFree(table);
365
2.52M
}
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.74M
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
1.74M
    xmlFree(entry);
377
1.74M
}
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
16.5M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
16.5M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
16.5M
}
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
33.7M
          const xmlChar *name2, void *userdata) {
410
33.7M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
33.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
866k
       xmlHashDeallocator f) {
450
866k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
866k
}
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
554M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
554M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
554M
}
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
166M
        const xmlChar *name2) {
480
166M
    return(xmlHashLookup3(table, name, name2, NULL));
481
166M
}
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
21.9M
          const xmlChar *name2) {
515
21.9M
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
21.9M
}
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
77.9M
     void *userdata) {
536
77.9M
    unsigned long key, len = 0;
537
77.9M
    xmlHashEntryPtr entry;
538
77.9M
    xmlHashEntryPtr insert;
539
540
77.9M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
77.9M
    if (table->dict) {
547
67.7M
        if (!xmlDictOwns(table->dict, name)) {
548
6.17M
      name = xmlDictLookup(table->dict, name, -1);
549
6.17M
      if (name == NULL)
550
0
          return(-1);
551
6.17M
  }
552
67.7M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
276k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
276k
      if (name2 == NULL)
555
0
          return(-1);
556
276k
  }
557
67.7M
        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
67.7M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
77.9M
    key = xmlHashComputeKey(table, name, name2, name3);
568
77.9M
    if (table->table[key].valid == 0) {
569
43.7M
  insert = NULL;
570
43.7M
    } else {
571
34.2M
        if (table->dict) {
572
66.9M
      for (insert = &(table->table[key]); insert->next != NULL;
573
35.5M
     insert = insert->next) {
574
35.5M
    if ((insert->name == name) &&
575
35.5M
        (insert->name2 == name2) &&
576
35.5M
        (insert->name3 == name3))
577
19.7k
        return(-1);
578
35.5M
    len++;
579
35.5M
      }
580
31.3M
      if ((insert->name == name) &&
581
31.3M
    (insert->name2 == name2) &&
582
31.3M
    (insert->name3 == name3))
583
425k
    return(-1);
584
31.3M
  } else {
585
4.14M
      for (insert = &(table->table[key]); insert->next != NULL;
586
2.87M
     insert = insert->next) {
587
1.28M
    if ((xmlStrEqual(insert->name, name)) &&
588
1.28M
        (xmlStrEqual(insert->name2, name2)) &&
589
1.28M
        (xmlStrEqual(insert->name3, name3)))
590
19.3k
        return(-1);
591
1.27M
    len++;
592
1.27M
      }
593
2.85M
      if ((xmlStrEqual(insert->name, name)) &&
594
2.85M
    (xmlStrEqual(insert->name2, name2)) &&
595
2.85M
    (xmlStrEqual(insert->name3, name3)))
596
240k
    return(-1);
597
2.85M
  }
598
34.2M
    }
599
600
77.2M
    if (insert == NULL) {
601
43.7M
  entry = &(table->table[key]);
602
43.7M
    } else {
603
33.5M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
33.5M
  if (entry == NULL)
605
0
       return(-1);
606
33.5M
    }
607
608
77.2M
    if (table->dict != NULL) {
609
67.2M
        entry->name = (xmlChar *) name;
610
67.2M
        entry->name2 = (xmlChar *) name2;
611
67.2M
        entry->name3 = (xmlChar *) name3;
612
67.2M
    } else {
613
9.99M
  entry->name = xmlStrdup(name);
614
9.99M
  entry->name2 = xmlStrdup(name2);
615
9.99M
  entry->name3 = xmlStrdup(name3);
616
9.99M
    }
617
77.2M
    entry->payload = userdata;
618
77.2M
    entry->next = NULL;
619
77.2M
    entry->valid = 1;
620
621
622
77.2M
    if (insert != NULL)
623
33.5M
  insert->next = entry;
624
625
77.2M
    table->nbElems++;
626
627
77.2M
    if (len > MAX_HASH_LEN)
628
90.2k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
77.2M
    return(0);
631
77.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
866k
       void *userdata, xmlHashDeallocator f) {
652
866k
    unsigned long key;
653
866k
    xmlHashEntryPtr entry;
654
866k
    xmlHashEntryPtr insert;
655
656
866k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
866k
    if (table->dict) {
663
866k
        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
866k
        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
866k
        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
866k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
866k
    key = xmlHashComputeKey(table, name, name2, name3);
684
866k
    if (table->table[key].valid == 0) {
685
583k
  insert = NULL;
686
583k
    } else {
687
283k
        if (table ->dict) {
688
368k
      for (insert = &(table->table[key]); insert->next != NULL;
689
283k
     insert = insert->next) {
690
85.3k
    if ((insert->name == name) &&
691
85.3k
        (insert->name2 == name2) &&
692
85.3k
        (insert->name3 == name3)) {
693
172
        if (f)
694
0
      f(insert->payload, insert->name);
695
172
        insert->payload = userdata;
696
172
        return(0);
697
172
    }
698
85.3k
      }
699
282k
      if ((insert->name == name) &&
700
282k
    (insert->name2 == name2) &&
701
282k
    (insert->name3 == name3)) {
702
4.54k
    if (f)
703
0
        f(insert->payload, insert->name);
704
4.54k
    insert->payload = userdata;
705
4.54k
    return(0);
706
4.54k
      }
707
282k
  } 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
283k
    }
729
730
861k
    if (insert == NULL) {
731
583k
  entry =  &(table->table[key]);
732
583k
    } else {
733
278k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
278k
  if (entry == NULL)
735
0
       return(-1);
736
278k
    }
737
738
861k
    if (table->dict != NULL) {
739
861k
        entry->name = (xmlChar *) name;
740
861k
        entry->name2 = (xmlChar *) name2;
741
861k
        entry->name3 = (xmlChar *) name3;
742
861k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
861k
    entry->payload = userdata;
748
861k
    entry->next = NULL;
749
861k
    entry->valid = 1;
750
861k
    table->nbElems++;
751
752
753
861k
    if (insert != NULL) {
754
278k
  insert->next = entry;
755
278k
    }
756
861k
    return(0);
757
861k
}
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
802M
         const xmlChar *name2, const xmlChar *name3) {
773
802M
    unsigned long key;
774
802M
    xmlHashEntryPtr entry;
775
776
802M
    if (table == NULL)
777
5.42M
  return(NULL);
778
796M
    if (name == NULL)
779
0
  return(NULL);
780
796M
    key = xmlHashComputeKey(table, name, name2, name3);
781
796M
    if (table->table[key].valid == 0)
782
186M
  return(NULL);
783
610M
    if (table->dict) {
784
681M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
496M
      if ((entry->name == name) &&
786
496M
    (entry->name2 == name2) &&
787
496M
    (entry->name3 == name3))
788
234M
    return(entry->payload);
789
496M
  }
790
419M
    }
791
478M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
432M
  if ((xmlStrEqual(entry->name, name)) &&
793
432M
      (xmlStrEqual(entry->name2, name2)) &&
794
432M
      (xmlStrEqual(entry->name3, name3)))
795
330M
      return(entry->payload);
796
432M
    }
797
45.9M
    return(NULL);
798
376M
}
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
21.9M
    const xmlChar *prefix3, const xmlChar *name3) {
819
21.9M
    unsigned long key;
820
21.9M
    xmlHashEntryPtr entry;
821
822
21.9M
    if (table == NULL)
823
0
  return(NULL);
824
21.9M
    if (name == NULL)
825
0
  return(NULL);
826
21.9M
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
21.9M
                             name2, prefix3, name3);
828
21.9M
    if (table->table[key].valid == 0)
829
3.27M
  return(NULL);
830
55.8M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
51.6M
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
51.6M
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
51.6M
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
14.4M
      return(entry->payload);
835
51.6M
    }
836
4.22M
    return(NULL);
837
18.7M
}
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
5.88M
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
5.88M
    stubData *stubdata = (stubData *) data;
849
5.88M
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
5.88M
}
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
205k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
205k
    stubData stubdata;
863
205k
    stubdata.data = data;
864
205k
    stubdata.hashscanner = f;
865
205k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
205k
}
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
382k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
382k
    int i, nb;
879
382k
    xmlHashEntryPtr iter;
880
382k
    xmlHashEntryPtr next;
881
882
382k
    if (table == NULL)
883
17.5k
  return;
884
364k
    if (f == NULL)
885
0
  return;
886
887
364k
    if (table->table) {
888
61.1M
  for(i = 0; i < table->size; i++) {
889
60.7M
      if (table->table[i].valid == 0)
890
48.0M
    continue;
891
12.7M
      iter = &(table->table[i]);
892
38.1M
      while (iter) {
893
25.4M
    next = iter->next;
894
25.4M
                nb = table->nbElems;
895
25.4M
    if ((f != NULL) && (iter->payload != NULL))
896
25.4M
        f(iter->payload, data, iter->name,
897
25.4M
          iter->name2, iter->name3);
898
25.4M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
6.78M
                    if (iter == &(table->table[i])) {
901
3.92M
                        if (table->table[i].valid == 0)
902
2.18M
                            iter = NULL;
903
3.92M
                        if (table->table[i].next != next)
904
1.74M
          iter = &(table->table[i]);
905
3.92M
                    } else
906
2.85M
            iter = next;
907
6.78M
                } else
908
18.6M
        iter = next;
909
25.4M
      }
910
12.7M
  }
911
364k
    }
912
364k
}
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.30M
       xmlHashScanner f, void *data) {
931
1.30M
    stubData stubdata;
932
1.30M
    stubdata.data = data;
933
1.30M
    stubdata.hashscanner = f;
934
1.30M
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
1.30M
                     &stubdata);
936
1.30M
}
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.30M
     xmlHashScannerFull f, void *data) {
955
1.30M
    int i;
956
1.30M
    xmlHashEntryPtr iter;
957
1.30M
    xmlHashEntryPtr next;
958
959
1.30M
    if (table == NULL)
960
1.17M
  return;
961
127k
    if (f == NULL)
962
0
  return;
963
964
127k
    if (table->table) {
965
32.7M
  for(i = 0; i < table->size; i++) {
966
32.6M
      if (table->table[i].valid == 0)
967
7.20M
    continue;
968
25.4M
      iter = &(table->table[i]);
969
82.8M
      while (iter) {
970
57.3M
    next = iter->next;
971
57.3M
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
57.3M
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
57.3M
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
57.3M
        (iter->payload != NULL)) {
975
557
        f(iter->payload, data, iter->name,
976
557
          iter->name2, iter->name3);
977
557
    }
978
57.3M
    iter = next;
979
57.3M
      }
980
25.4M
  }
981
127k
    }
982
127k
}
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
176k
xmlHashSize(xmlHashTablePtr table) {
1037
176k
    if (table == NULL)
1038
0
  return(-1);
1039
176k
    return(table->nbElems);
1040
176k
}
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
1.39k
           xmlHashDeallocator f) {
1056
1.39k
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
1.39k
}
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.78M
      const xmlChar *name2, xmlHashDeallocator f) {
1075
6.78M
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
6.78M
}
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.79M
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
6.79M
    unsigned long key;
1096
6.79M
    xmlHashEntryPtr entry;
1097
6.79M
    xmlHashEntryPtr prev = NULL;
1098
1099
6.79M
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
6.79M
    key = xmlHashComputeKey(table, name, name2, name3);
1103
6.79M
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
6.79M
    } else {
1106
11.3M
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
11.3M
            if (xmlStrEqual(entry->name, name) &&
1108
11.3M
                    xmlStrEqual(entry->name2, name2) &&
1109
11.3M
                    xmlStrEqual(entry->name3, name3)) {
1110
6.79M
                if ((f != NULL) && (entry->payload != NULL))
1111
1.39k
                    f(entry->payload, entry->name);
1112
6.79M
                entry->payload = NULL;
1113
6.79M
    if (table->dict == NULL) {
1114
2.40k
        if(entry->name)
1115
2.40k
      xmlFree(entry->name);
1116
2.40k
        if(entry->name2)
1117
199
      xmlFree(entry->name2);
1118
2.40k
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
2.40k
    }
1121
6.79M
                if(prev) {
1122
2.85M
                    prev->next = entry->next;
1123
2.85M
        xmlFree(entry);
1124
3.93M
    } else {
1125
3.93M
        if (entry->next == NULL) {
1126
2.18M
      entry->valid = 0;
1127
2.18M
        } else {
1128
1.74M
      entry = entry->next;
1129
1.74M
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
1.74M
      xmlFree(entry);
1131
1.74M
        }
1132
3.93M
    }
1133
6.79M
                table->nbElems--;
1134
6.79M
                return(0);
1135
6.79M
            }
1136
4.59M
            prev = entry;
1137
4.59M
        }
1138
0
        return(-1);
1139
6.79M
    }
1140
6.79M
}
1141