Coverage Report

Created: 2024-08-17 11:00

/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
103k
#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
2.84M
            const xmlChar *name2, const xmlChar *name3) {
85
2.84M
    unsigned long value = 0L;
86
2.84M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
2.84M
    if (name != NULL) {
92
2.84M
  value += 30 * (*name);
93
69.0M
  while ((ch = *name++) != 0) {
94
66.1M
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
66.1M
  }
96
2.84M
    }
97
2.84M
    value = value ^ ((value << 5) + (value >> 3));
98
2.84M
    if (name2 != NULL) {
99
365k
  while ((ch = *name2++) != 0) {
100
292k
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
292k
  }
102
72.5k
    }
103
2.84M
    value = value ^ ((value << 5) + (value >> 3));
104
2.84M
    if (name3 != NULL) {
105
352k
  while ((ch = *name3++) != 0) {
106
295k
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
295k
  }
108
56.8k
    }
109
2.84M
    return (value % table->size);
110
2.84M
}
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
15.2k
       const xmlChar *prefix3, const xmlChar *name3) {
120
15.2k
    unsigned long value = 0L;
121
15.2k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
15.2k
    if (prefix != NULL)
127
715
  value += 30 * (*prefix);
128
14.5k
    else
129
14.5k
  value += 30 * (*name);
130
131
15.2k
    if (prefix != NULL) {
132
2.96k
  while ((ch = *prefix++) != 0) {
133
2.25k
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
2.25k
  }
135
715
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
715
    }
137
15.2k
    if (name != NULL) {
138
82.6k
  while ((ch = *name++) != 0) {
139
67.3k
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
67.3k
  }
141
15.2k
    }
142
15.2k
    value = value ^ ((value << 5) + (value >> 3));
143
15.2k
    if (prefix2 != NULL) {
144
3.21k
  while ((ch = *prefix2++) != 0) {
145
2.57k
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
2.57k
  }
147
643
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
643
    }
149
15.2k
    if (name2 != NULL) {
150
53.4k
  while ((ch = *name2++) != 0) {
151
38.1k
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
38.1k
  }
153
15.2k
    }
154
15.2k
    value = value ^ ((value << 5) + (value >> 3));
155
15.2k
    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
15.2k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
15.2k
    return (value % table->size);
167
15.2k
}
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
38.4k
xmlHashCreate(int size) {
179
38.4k
    xmlHashTablePtr table;
180
181
38.4k
    if (size <= 0)
182
16.2k
        size = 256;
183
184
38.4k
    table = xmlMalloc(sizeof(xmlHashTable));
185
38.4k
    if (table) {
186
38.4k
        table->dict = NULL;
187
38.4k
        table->size = size;
188
38.4k
  table->nbElems = 0;
189
38.4k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
38.4k
        if (table->table) {
191
38.4k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
38.4k
      return(table);
196
38.4k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
38.4k
}
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
20.2k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
20.2k
    xmlHashTablePtr table;
214
215
20.2k
    table = xmlHashCreate(size);
216
20.2k
    if (table != NULL) {
217
20.2k
        table->dict = dict;
218
20.2k
  xmlDictReference(dict);
219
20.2k
    }
220
20.2k
    return(table);
221
20.2k
}
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
xmlHashGrow(xmlHashTablePtr table, int size) {
234
68
    unsigned long key;
235
68
    int oldsize, i;
236
68
    xmlHashEntryPtr iter, next;
237
68
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
68
    if (table == NULL)
243
0
  return(-1);
244
68
    if (size < 8)
245
0
        return(-1);
246
68
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
68
    oldsize = table->size;
250
68
    oldtable = table->table;
251
68
    if (oldtable == NULL)
252
0
        return(-1);
253
254
68
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
68
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
68
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
68
    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.13k
    for (i = 0; i < oldsize; i++) {
269
1.06k
  if (oldtable[i].valid == 0)
270
36
      continue;
271
1.03k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
1.03k
        oldtable[i].name3);
273
1.03k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
1.03k
  table->table[key].next = NULL;
275
1.03k
    }
276
277
1.13k
    for (i = 0; i < oldsize; i++) {
278
1.06k
  iter = oldtable[i].next;
279
5.21k
  while (iter) {
280
4.14k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
4.14k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
4.14k
                        iter->name3);
288
4.14k
      if (table->table[key].valid == 0) {
289
2.73k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
2.73k
    table->table[key].next = NULL;
291
2.73k
    xmlFree(iter);
292
2.73k
      } else {
293
1.40k
    iter->next = table->table[key].next;
294
1.40k
    table->table[key].next = iter;
295
1.40k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
4.14k
      iter = next;
302
4.14k
  }
303
1.06k
    }
304
305
68
    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
    return(0);
313
68
}
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
38.4k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
38.4k
    int i;
326
38.4k
    xmlHashEntryPtr iter;
327
38.4k
    xmlHashEntryPtr next;
328
38.4k
    int inside_table = 0;
329
38.4k
    int nbElems;
330
331
38.4k
    if (table == NULL)
332
0
  return;
333
38.4k
    if (table->table) {
334
38.4k
  nbElems = table->nbElems;
335
3.38M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
3.34M
      iter = &(table->table[i]);
337
3.34M
      if (iter->valid == 0)
338
3.26M
    continue;
339
81.7k
      inside_table = 1;
340
179k
      while (iter) {
341
97.8k
    next = iter->next;
342
97.8k
    if ((f != NULL) && (iter->payload != NULL))
343
84.2k
        f(iter->payload, iter->name);
344
97.8k
    if (table->dict == NULL) {
345
35.2k
        if (iter->name)
346
35.2k
      xmlFree(iter->name);
347
35.2k
        if (iter->name2)
348
1.50k
      xmlFree(iter->name2);
349
35.2k
        if (iter->name3)
350
3.08k
      xmlFree(iter->name3);
351
35.2k
    }
352
97.8k
    iter->payload = NULL;
353
97.8k
    if (!inside_table)
354
16.1k
        xmlFree(iter);
355
97.8k
    nbElems--;
356
97.8k
    inside_table = 0;
357
97.8k
    iter = next;
358
97.8k
      }
359
81.7k
  }
360
38.4k
  xmlFree(table->table);
361
38.4k
    }
362
38.4k
    if (table->dict)
363
14.2k
        xmlDictFree(table->dict);
364
38.4k
    xmlFree(table);
365
38.4k
}
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
24.8k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
24.8k
    xmlFree(entry);
377
24.8k
}
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
44.2k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
44.2k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
44.2k
}
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
38.4k
          const xmlChar *name2, void *userdata) {
410
38.4k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
38.4k
}
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
1.75k
       xmlHashDeallocator f) {
450
1.75k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
1.75k
}
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
2.58M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
2.58M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
2.58M
}
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
110k
        const xmlChar *name2) {
480
110k
    return(xmlHashLookup3(table, name, name2, NULL));
481
110k
}
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
15.2k
          const xmlChar *name2) {
515
15.2k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
15.2k
}
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
104k
     void *userdata) {
536
104k
    unsigned long key, len = 0;
537
104k
    xmlHashEntryPtr entry;
538
104k
    xmlHashEntryPtr insert;
539
540
104k
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
104k
    if (table->dict) {
547
68.8k
        if (!xmlDictOwns(table->dict, name)) {
548
4.84k
      name = xmlDictLookup(table->dict, name, -1);
549
4.84k
      if (name == NULL)
550
0
          return(-1);
551
4.84k
  }
552
68.8k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
1.37k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
1.37k
      if (name2 == NULL)
555
0
          return(-1);
556
1.37k
  }
557
68.8k
        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
68.8k
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
104k
    key = xmlHashComputeKey(table, name, name2, name3);
568
104k
    if (table->table[key].valid == 0) {
569
81.1k
  insert = NULL;
570
81.1k
    } else {
571
23.0k
        if (table->dict) {
572
44.1k
      for (insert = &(table->table[key]); insert->next != NULL;
573
22.8k
     insert = insert->next) {
574
22.8k
    if ((insert->name == name) &&
575
22.8k
        (insert->name2 == name2) &&
576
22.8k
        (insert->name3 == name3))
577
0
        return(-1);
578
22.8k
    len++;
579
22.8k
      }
580
21.2k
      if ((insert->name == name) &&
581
21.2k
    (insert->name2 == name2) &&
582
21.2k
    (insert->name3 == name3))
583
226
    return(-1);
584
21.2k
  } else {
585
3.59k
      for (insert = &(table->table[key]); insert->next != NULL;
586
1.80k
     insert = insert->next) {
587
1.80k
    if ((xmlStrEqual(insert->name, name)) &&
588
1.80k
        (xmlStrEqual(insert->name2, name2)) &&
589
1.80k
        (xmlStrEqual(insert->name3, name3)))
590
0
        return(-1);
591
1.80k
    len++;
592
1.80k
      }
593
1.79k
      if ((xmlStrEqual(insert->name, name)) &&
594
1.79k
    (xmlStrEqual(insert->name2, name2)) &&
595
1.79k
    (xmlStrEqual(insert->name3, name3)))
596
119
    return(-1);
597
1.79k
  }
598
23.0k
    }
599
600
103k
    if (insert == NULL) {
601
81.1k
  entry = &(table->table[key]);
602
81.1k
    } else {
603
22.7k
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
22.7k
  if (entry == NULL)
605
0
       return(-1);
606
22.7k
    }
607
608
103k
    if (table->dict != NULL) {
609
68.6k
        entry->name = (xmlChar *) name;
610
68.6k
        entry->name2 = (xmlChar *) name2;
611
68.6k
        entry->name3 = (xmlChar *) name3;
612
68.6k
    } else {
613
35.2k
  entry->name = xmlStrdup(name);
614
35.2k
  entry->name2 = xmlStrdup(name2);
615
35.2k
  entry->name3 = xmlStrdup(name3);
616
35.2k
    }
617
103k
    entry->payload = userdata;
618
103k
    entry->next = NULL;
619
103k
    entry->valid = 1;
620
621
622
103k
    if (insert != NULL)
623
22.7k
  insert->next = entry;
624
625
103k
    table->nbElems++;
626
627
103k
    if (len > MAX_HASH_LEN)
628
68
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
103k
    return(0);
631
103k
}
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
1.75k
       void *userdata, xmlHashDeallocator f) {
652
1.75k
    unsigned long key;
653
1.75k
    xmlHashEntryPtr entry;
654
1.75k
    xmlHashEntryPtr insert;
655
656
1.75k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
1.75k
    if (table->dict) {
663
1.75k
        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
1.75k
        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
1.75k
        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
1.75k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
1.75k
    key = xmlHashComputeKey(table, name, name2, name3);
684
1.75k
    if (table->table[key].valid == 0) {
685
1.56k
  insert = NULL;
686
1.56k
    } else {
687
192
        if (table ->dict) {
688
216
      for (insert = &(table->table[key]); insert->next != NULL;
689
192
     insert = insert->next) {
690
24
    if ((insert->name == name) &&
691
24
        (insert->name2 == name2) &&
692
24
        (insert->name3 == name3)) {
693
0
        if (f)
694
0
      f(insert->payload, insert->name);
695
0
        insert->payload = userdata;
696
0
        return(0);
697
0
    }
698
24
      }
699
192
      if ((insert->name == name) &&
700
192
    (insert->name2 == name2) &&
701
192
    (insert->name3 == name3)) {
702
6
    if (f)
703
0
        f(insert->payload, insert->name);
704
6
    insert->payload = userdata;
705
6
    return(0);
706
6
      }
707
192
  } 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
192
    }
729
730
1.75k
    if (insert == NULL) {
731
1.56k
  entry =  &(table->table[key]);
732
1.56k
    } else {
733
186
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
186
  if (entry == NULL)
735
0
       return(-1);
736
186
    }
737
738
1.75k
    if (table->dict != NULL) {
739
1.75k
        entry->name = (xmlChar *) name;
740
1.75k
        entry->name2 = (xmlChar *) name2;
741
1.75k
        entry->name3 = (xmlChar *) name3;
742
1.75k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
1.75k
    entry->payload = userdata;
748
1.75k
    entry->next = NULL;
749
1.75k
    entry->valid = 1;
750
1.75k
    table->nbElems++;
751
752
753
1.75k
    if (insert != NULL) {
754
186
  insert->next = entry;
755
186
    }
756
1.75k
    return(0);
757
1.75k
}
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
2.73M
         const xmlChar *name2, const xmlChar *name3) {
773
2.73M
    unsigned long key;
774
2.73M
    xmlHashEntryPtr entry;
775
776
2.73M
    if (table == NULL)
777
3.65k
  return(NULL);
778
2.72M
    if (name == NULL)
779
0
  return(NULL);
780
2.72M
    key = xmlHashComputeKey(table, name, name2, name3);
781
2.72M
    if (table->table[key].valid == 0)
782
84.5k
  return(NULL);
783
2.64M
    if (table->dict) {
784
4.17M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
2.66M
      if ((entry->name == name) &&
786
2.66M
    (entry->name2 == name2) &&
787
2.66M
    (entry->name3 == name3))
788
1.11M
    return(entry->payload);
789
2.66M
  }
790
2.61M
    }
791
1.59M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
1.56M
  if ((xmlStrEqual(entry->name, name)) &&
793
1.56M
      (xmlStrEqual(entry->name2, name2)) &&
794
1.56M
      (xmlStrEqual(entry->name3, name3)))
795
1.49M
      return(entry->payload);
796
1.56M
    }
797
30.5k
    return(NULL);
798
1.53M
}
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
15.2k
    const xmlChar *prefix3, const xmlChar *name3) {
819
15.2k
    unsigned long key;
820
15.2k
    xmlHashEntryPtr entry;
821
822
15.2k
    if (table == NULL)
823
0
  return(NULL);
824
15.2k
    if (name == NULL)
825
0
  return(NULL);
826
15.2k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
15.2k
                             name2, prefix3, name3);
828
15.2k
    if (table->table[key].valid == 0)
829
3.33k
  return(NULL);
830
31.3k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
29.1k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
29.1k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
29.1k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
9.67k
      return(entry->payload);
835
29.1k
    }
836
2.27k
    return(NULL);
837
11.9k
}
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.96k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
5.96k
    stubData *stubdata = (stubData *) data;
849
5.96k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
5.96k
}
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
2.74k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
2.74k
    stubData stubdata;
863
2.74k
    stubdata.data = data;
864
2.74k
    stubdata.hashscanner = f;
865
2.74k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
2.74k
}
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
4.94k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
4.94k
    int i, nb;
879
4.94k
    xmlHashEntryPtr iter;
880
4.94k
    xmlHashEntryPtr next;
881
882
4.94k
    if (table == NULL)
883
19
  return;
884
4.93k
    if (f == NULL)
885
0
  return;
886
887
4.93k
    if (table->table) {
888
730k
  for(i = 0; i < table->size; i++) {
889
725k
      if (table->table[i].valid == 0)
890
710k
    continue;
891
15.6k
      iter = &(table->table[i]);
892
40.8k
      while (iter) {
893
25.2k
    next = iter->next;
894
25.2k
                nb = table->nbElems;
895
25.2k
    if ((f != NULL) && (iter->payload != NULL))
896
25.2k
        f(iter->payload, data, iter->name,
897
25.2k
          iter->name2, iter->name3);
898
25.2k
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
7.70k
                    if (iter == &(table->table[i])) {
901
5.10k
                        if (table->table[i].valid == 0)
902
3.65k
                            iter = NULL;
903
5.10k
                        if (table->table[i].next != next)
904
1.44k
          iter = &(table->table[i]);
905
5.10k
                    } else
906
2.60k
            iter = next;
907
7.70k
                } else
908
17.5k
        iter = next;
909
25.2k
      }
910
15.6k
  }
911
4.93k
    }
912
4.93k
}
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
0
       xmlHashScanner f, void *data) {
931
0
    stubData stubdata;
932
0
    stubdata.data = data;
933
0
    stubdata.hashscanner = f;
934
0
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
0
                     &stubdata);
936
0
}
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
0
     xmlHashScannerFull f, void *data) {
955
0
    int i;
956
0
    xmlHashEntryPtr iter;
957
0
    xmlHashEntryPtr next;
958
959
0
    if (table == NULL)
960
0
  return;
961
0
    if (f == NULL)
962
0
  return;
963
964
0
    if (table->table) {
965
0
  for(i = 0; i < table->size; i++) {
966
0
      if (table->table[i].valid == 0)
967
0
    continue;
968
0
      iter = &(table->table[i]);
969
0
      while (iter) {
970
0
    next = iter->next;
971
0
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
0
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
0
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
0
        (iter->payload != NULL)) {
975
0
        f(iter->payload, data, iter->name,
976
0
          iter->name2, iter->name3);
977
0
    }
978
0
    iter = next;
979
0
      }
980
0
  }
981
0
    }
982
0
}
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
2.20k
xmlHashSize(xmlHashTablePtr table) {
1037
2.20k
    if (table == NULL)
1038
0
  return(-1);
1039
2.20k
    return(table->nbElems);
1040
2.20k
}
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
0
           xmlHashDeallocator f) {
1056
0
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
0
}
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
7.74k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
7.74k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
7.74k
}
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
7.74k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
7.74k
    unsigned long key;
1096
7.74k
    xmlHashEntryPtr entry;
1097
7.74k
    xmlHashEntryPtr prev = NULL;
1098
1099
7.74k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
7.74k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
7.74k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
7.74k
    } else {
1106
12.0k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
12.0k
            if (xmlStrEqual(entry->name, name) &&
1108
12.0k
                    xmlStrEqual(entry->name2, name2) &&
1109
12.0k
                    xmlStrEqual(entry->name3, name3)) {
1110
7.74k
                if ((f != NULL) && (entry->payload != NULL))
1111
0
                    f(entry->payload, entry->name);
1112
7.74k
                entry->payload = NULL;
1113
7.74k
    if (table->dict == NULL) {
1114
8
        if(entry->name)
1115
8
      xmlFree(entry->name);
1116
8
        if(entry->name2)
1117
5
      xmlFree(entry->name2);
1118
8
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
8
    }
1121
7.74k
                if(prev) {
1122
2.60k
                    prev->next = entry->next;
1123
2.60k
        xmlFree(entry);
1124
5.14k
    } else {
1125
5.14k
        if (entry->next == NULL) {
1126
3.69k
      entry->valid = 0;
1127
3.69k
        } else {
1128
1.44k
      entry = entry->next;
1129
1.44k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
1.44k
      xmlFree(entry);
1131
1.44k
        }
1132
5.14k
    }
1133
7.74k
                table->nbElems--;
1134
7.74k
                return(0);
1135
7.74k
            }
1136
4.35k
            prev = entry;
1137
4.35k
        }
1138
0
        return(-1);
1139
7.74k
    }
1140
7.74k
}
1141