Coverage Report

Created: 2023-12-04 03:06

/src/libxml2/hash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * hash.c: chained hash tables
3
 *
4
 * Reference: Your favorite introductory book on algorithms
5
 *
6
 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
13
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16
 *
17
 * Author: breese@users.sourceforge.net
18
 */
19
20
#define IN_LIBXML
21
#include "libxml.h"
22
23
#include <string.h>
24
#include <stdlib.h>
25
#include <time.h>
26
27
/*
28
 * Following http://www.ocert.org/advisories/ocert-2011-003.html
29
 * it seems that having hash randomization might be a good idea
30
 * when using XML with untrusted data
31
 */
32
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
33
#define HASH_RANDOMIZATION
34
#endif
35
36
#include <libxml/parser.h>
37
#include <libxml/hash.h>
38
#include <libxml/xmlmemory.h>
39
#include <libxml/xmlerror.h>
40
#include <libxml/globals.h>
41
42
#include "private/dict.h"
43
44
4.43M
#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
64.0M
            const xmlChar *name2, const xmlChar *name3) {
85
64.0M
    unsigned long value = 0L;
86
64.0M
    unsigned long ch;
87
88
#ifdef HASH_RANDOMIZATION
89
    value = table->random_seed;
90
#endif
91
64.0M
    if (name != NULL) {
92
64.0M
  value += 30 * (*name);
93
1.05G
  while ((ch = *name++) != 0) {
94
987M
      value = value ^ ((value << 5) + (value >> 3) + ch);
95
987M
  }
96
64.0M
    }
97
64.0M
    value = value ^ ((value << 5) + (value >> 3));
98
64.0M
    if (name2 != NULL) {
99
27.6M
  while ((ch = *name2++) != 0) {
100
23.5M
      value = value ^ ((value << 5) + (value >> 3) + ch);
101
23.5M
  }
102
4.12M
    }
103
64.0M
    value = value ^ ((value << 5) + (value >> 3));
104
64.0M
    if (name3 != NULL) {
105
28.6M
  while ((ch = *name3++) != 0) {
106
24.4M
      value = value ^ ((value << 5) + (value >> 3) + ch);
107
24.4M
  }
108
4.19M
    }
109
64.0M
    return (value % table->size);
110
64.0M
}
111
112
#ifdef __clang__
113
ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
114
#endif
115
static unsigned long
116
xmlHashComputeQKey(xmlHashTablePtr table,
117
       const xmlChar *prefix, const xmlChar *name,
118
       const xmlChar *prefix2, const xmlChar *name2,
119
920k
       const xmlChar *prefix3, const xmlChar *name3) {
120
920k
    unsigned long value = 0L;
121
920k
    unsigned long ch;
122
123
#ifdef HASH_RANDOMIZATION
124
    value = table->random_seed;
125
#endif
126
920k
    if (prefix != NULL)
127
135k
  value += 30 * (*prefix);
128
784k
    else
129
784k
  value += 30 * (*name);
130
131
920k
    if (prefix != NULL) {
132
535k
  while ((ch = *prefix++) != 0) {
133
399k
      value = value ^ ((value << 5) + (value >> 3) + ch);
134
399k
  }
135
135k
  value = value ^ ((value << 5) + (value >> 3) + ':');
136
135k
    }
137
920k
    if (name != NULL) {
138
5.37M
  while ((ch = *name++) != 0) {
139
4.45M
      value = value ^ ((value << 5) + (value >> 3) + ch);
140
4.45M
  }
141
920k
    }
142
920k
    value = value ^ ((value << 5) + (value >> 3));
143
920k
    if (prefix2 != NULL) {
144
682k
  while ((ch = *prefix2++) != 0) {
145
555k
      value = value ^ ((value << 5) + (value >> 3) + ch);
146
555k
  }
147
126k
  value = value ^ ((value << 5) + (value >> 3) + ':');
148
126k
    }
149
920k
    if (name2 != NULL) {
150
4.28M
  while ((ch = *name2++) != 0) {
151
3.35M
      value = value ^ ((value << 5) + (value >> 3) + ch);
152
3.35M
  }
153
920k
    }
154
920k
    value = value ^ ((value << 5) + (value >> 3));
155
920k
    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
920k
    if (name3 != NULL) {
162
0
  while ((ch = *name3++) != 0) {
163
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
164
0
  }
165
0
    }
166
920k
    return (value % table->size);
167
920k
}
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
917k
xmlHashCreate(int size) {
179
917k
    xmlHashTablePtr table;
180
181
917k
    if (size <= 0)
182
499k
        size = 256;
183
184
917k
    table = xmlMalloc(sizeof(xmlHashTable));
185
917k
    if (table) {
186
917k
        table->dict = NULL;
187
917k
        table->size = size;
188
917k
  table->nbElems = 0;
189
917k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
190
917k
        if (table->table) {
191
917k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
192
#ifdef HASH_RANDOMIZATION
193
            table->random_seed = __xmlRandom();
194
#endif
195
917k
      return(table);
196
917k
        }
197
0
        xmlFree(table);
198
0
    }
199
0
    return(NULL);
200
917k
}
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
624k
xmlHashCreateDict(int size, xmlDictPtr dict) {
213
624k
    xmlHashTablePtr table;
214
215
624k
    table = xmlHashCreate(size);
216
624k
    if (table != NULL) {
217
624k
        table->dict = dict;
218
624k
  xmlDictReference(dict);
219
624k
    }
220
624k
    return(table);
221
624k
}
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
4.37k
xmlHashGrow(xmlHashTablePtr table, int size) {
234
4.37k
    unsigned long key;
235
4.37k
    int oldsize, i;
236
4.37k
    xmlHashEntryPtr iter, next;
237
4.37k
    struct _xmlHashEntry *oldtable;
238
#ifdef DEBUG_GROW
239
    unsigned long nbElem = 0;
240
#endif
241
242
4.37k
    if (table == NULL)
243
0
  return(-1);
244
4.37k
    if (size < 8)
245
0
        return(-1);
246
4.37k
    if (size > 8 * 2048)
247
0
  return(-1);
248
249
4.37k
    oldsize = table->size;
250
4.37k
    oldtable = table->table;
251
4.37k
    if (oldtable == NULL)
252
0
        return(-1);
253
254
4.37k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
255
4.37k
    if (table->table == NULL) {
256
0
  table->table = oldtable;
257
0
  return(-1);
258
0
    }
259
4.37k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
260
4.37k
    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
100k
    for (i = 0; i < oldsize; i++) {
269
95.6k
  if (oldtable[i].valid == 0)
270
1.56k
      continue;
271
94.1k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
272
94.1k
        oldtable[i].name3);
273
94.1k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
274
94.1k
  table->table[key].next = NULL;
275
94.1k
    }
276
277
100k
    for (i = 0; i < oldsize; i++) {
278
95.6k
  iter = oldtable[i].next;
279
483k
  while (iter) {
280
387k
      next = iter->next;
281
282
      /*
283
       * put back the entry in the new table
284
       */
285
286
387k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
287
387k
                        iter->name3);
288
387k
      if (table->table[key].valid == 0) {
289
259k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
290
259k
    table->table[key].next = NULL;
291
259k
    xmlFree(iter);
292
259k
      } else {
293
128k
    iter->next = table->table[key].next;
294
128k
    table->table[key].next = iter;
295
128k
      }
296
297
#ifdef DEBUG_GROW
298
      nbElem++;
299
#endif
300
301
387k
      iter = next;
302
387k
  }
303
95.6k
    }
304
305
4.37k
    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
4.37k
    return(0);
313
4.37k
}
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
917k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
325
917k
    int i;
326
917k
    xmlHashEntryPtr iter;
327
917k
    xmlHashEntryPtr next;
328
917k
    int inside_table = 0;
329
917k
    int nbElems;
330
331
917k
    if (table == NULL)
332
0
  return;
333
917k
    if (table->table) {
334
917k
  nbElems = table->nbElems;
335
99.8M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
336
98.8M
      iter = &(table->table[i]);
337
98.8M
      if (iter->valid == 0)
338
95.5M
    continue;
339
3.31M
      inside_table = 1;
340
7.53M
      while (iter) {
341
4.22M
    next = iter->next;
342
4.22M
    if ((f != NULL) && (iter->payload != NULL))
343
3.45M
        f(iter->payload, iter->name);
344
4.22M
    if (table->dict == NULL) {
345
1.47M
        if (iter->name)
346
1.47M
      xmlFree(iter->name);
347
1.47M
        if (iter->name2)
348
64.7k
      xmlFree(iter->name2);
349
1.47M
        if (iter->name3)
350
480k
      xmlFree(iter->name3);
351
1.47M
    }
352
4.22M
    iter->payload = NULL;
353
4.22M
    if (!inside_table)
354
911k
        xmlFree(iter);
355
4.22M
    nbElems--;
356
4.22M
    inside_table = 0;
357
4.22M
    iter = next;
358
4.22M
      }
359
3.31M
  }
360
917k
  xmlFree(table->table);
361
917k
    }
362
917k
    if (table->dict)
363
424k
        xmlDictFree(table->dict);
364
917k
    xmlFree(table);
365
917k
}
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
510k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
376
510k
    xmlFree(entry);
377
510k
}
378
379
/**
380
 * xmlHashAddEntry:
381
 * @table: the hash table
382
 * @name: the name of the userdata
383
 * @userdata: a pointer to the userdata
384
 *
385
 * Add the @userdata to the hash @table. This can later be retrieved
386
 * by using the @name. Duplicate names generate errors.
387
 *
388
 * Returns 0 the addition succeeded and -1 in case of error.
389
 */
390
int
391
1.51M
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
392
1.51M
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
393
1.51M
}
394
395
/**
396
 * xmlHashAddEntry2:
397
 * @table: the hash table
398
 * @name: the name of the userdata
399
 * @name2: a second name of the userdata
400
 * @userdata: a pointer to the userdata
401
 *
402
 * Add the @userdata to the hash @table. This can later be retrieved
403
 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
404
 *
405
 * Returns 0 the addition succeeded and -1 in case of error.
406
 */
407
int
408
xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
409
1.78M
          const xmlChar *name2, void *userdata) {
410
1.78M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
411
1.78M
}
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
67.5k
       xmlHashDeallocator f) {
450
67.5k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
451
67.5k
}
452
453
/**
454
 * xmlHashLookup:
455
 * @table: the hash table
456
 * @name: the name of the userdata
457
 *
458
 * Find the userdata specified by the @name.
459
 *
460
 * Returns the pointer to the userdata
461
 */
462
void *
463
49.0M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
464
49.0M
    return(xmlHashLookup3(table, name, NULL, NULL));
465
49.0M
}
466
467
/**
468
 * xmlHashLookup2:
469
 * @table: the hash table
470
 * @name: the name of the userdata
471
 * @name2: a second name of the userdata
472
 *
473
 * Find the userdata specified by the (@name, @name2) tuple.
474
 *
475
 * Returns the pointer to the userdata
476
 */
477
void *
478
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
479
6.88M
        const xmlChar *name2) {
480
6.88M
    return(xmlHashLookup3(table, name, name2, NULL));
481
6.88M
}
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
920k
          const xmlChar *name2) {
515
920k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
516
920k
}
517
518
/**
519
 * xmlHashAddEntry3:
520
 * @table: the hash table
521
 * @name: the name of the userdata
522
 * @name2: a second name of the userdata
523
 * @name3: a third name of the userdata
524
 * @userdata: a pointer to the userdata
525
 *
526
 * Add the @userdata to the hash @table. This can later be retrieved
527
 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
528
 * errors.
529
 *
530
 * Returns 0 the addition succeeded and -1 in case of error.
531
 */
532
int
533
xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
534
           const xmlChar *name2, const xmlChar *name3,
535
4.79M
     void *userdata) {
536
4.79M
    unsigned long key, len = 0;
537
4.79M
    xmlHashEntryPtr entry;
538
4.79M
    xmlHashEntryPtr insert;
539
540
4.79M
    if ((table == NULL) || (name == NULL))
541
0
  return(-1);
542
543
    /*
544
     * If using a dict internalize if needed
545
     */
546
4.79M
    if (table->dict) {
547
3.13M
        if (!xmlDictOwns(table->dict, name)) {
548
211k
      name = xmlDictLookup(table->dict, name, -1);
549
211k
      if (name == NULL)
550
0
          return(-1);
551
211k
  }
552
3.13M
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
553
44.5k
      name2 = xmlDictLookup(table->dict, name2, -1);
554
44.5k
      if (name2 == NULL)
555
0
          return(-1);
556
44.5k
  }
557
3.13M
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
558
0
      name3 = xmlDictLookup(table->dict, name3, -1);
559
0
      if (name3 == NULL)
560
0
          return(-1);
561
0
  }
562
3.13M
    }
563
564
    /*
565
     * Check for duplicate and insertion location.
566
     */
567
4.79M
    key = xmlHashComputeKey(table, name, name2, name3);
568
4.79M
    if (table->table[key].valid == 0) {
569
3.11M
  insert = NULL;
570
3.11M
    } else {
571
1.67M
        if (table->dict) {
572
2.68M
      for (insert = &(table->table[key]); insert->next != NULL;
573
1.42M
     insert = insert->next) {
574
1.42M
    if ((insert->name == name) &&
575
1.42M
        (insert->name2 == name2) &&
576
1.42M
        (insert->name3 == name3))
577
13.5k
        return(-1);
578
1.41M
    len++;
579
1.41M
      }
580
1.26M
      if ((insert->name == name) &&
581
1.26M
    (insert->name2 == name2) &&
582
1.26M
    (insert->name3 == name3))
583
170k
    return(-1);
584
1.26M
  } else {
585
547k
      for (insert = &(table->table[key]); insert->next != NULL;
586
397k
     insert = insert->next) {
587
162k
    if ((xmlStrEqual(insert->name, name)) &&
588
162k
        (xmlStrEqual(insert->name2, name2)) &&
589
162k
        (xmlStrEqual(insert->name3, name3)))
590
12.3k
        return(-1);
591
150k
    len++;
592
150k
      }
593
384k
      if ((xmlStrEqual(insert->name, name)) &&
594
384k
    (xmlStrEqual(insert->name2, name2)) &&
595
384k
    (xmlStrEqual(insert->name3, name3)))
596
162k
    return(-1);
597
384k
  }
598
1.67M
    }
599
600
4.43M
    if (insert == NULL) {
601
3.11M
  entry = &(table->table[key]);
602
3.11M
    } else {
603
1.31M
  entry = xmlMalloc(sizeof(xmlHashEntry));
604
1.31M
  if (entry == NULL)
605
0
       return(-1);
606
1.31M
    }
607
608
4.43M
    if (table->dict != NULL) {
609
2.95M
        entry->name = (xmlChar *) name;
610
2.95M
        entry->name2 = (xmlChar *) name2;
611
2.95M
        entry->name3 = (xmlChar *) name3;
612
2.95M
    } else {
613
1.47M
  entry->name = xmlStrdup(name);
614
1.47M
  entry->name2 = xmlStrdup(name2);
615
1.47M
  entry->name3 = xmlStrdup(name3);
616
1.47M
    }
617
4.43M
    entry->payload = userdata;
618
4.43M
    entry->next = NULL;
619
4.43M
    entry->valid = 1;
620
621
622
4.43M
    if (insert != NULL)
623
1.31M
  insert->next = entry;
624
625
4.43M
    table->nbElems++;
626
627
4.43M
    if (len > MAX_HASH_LEN)
628
4.37k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
629
630
4.43M
    return(0);
631
4.43M
}
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
67.5k
       void *userdata, xmlHashDeallocator f) {
652
67.5k
    unsigned long key;
653
67.5k
    xmlHashEntryPtr entry;
654
67.5k
    xmlHashEntryPtr insert;
655
656
67.5k
    if ((table == NULL) || name == NULL)
657
0
  return(-1);
658
659
    /*
660
     * If using a dict internalize if needed
661
     */
662
67.5k
    if (table->dict) {
663
67.5k
        if (!xmlDictOwns(table->dict, name)) {
664
0
      name = xmlDictLookup(table->dict, name, -1);
665
0
      if (name == NULL)
666
0
          return(-1);
667
0
  }
668
67.5k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
669
0
      name2 = xmlDictLookup(table->dict, name2, -1);
670
0
      if (name2 == NULL)
671
0
          return(-1);
672
0
  }
673
67.5k
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
674
0
      name3 = xmlDictLookup(table->dict, name3, -1);
675
0
      if (name3 == NULL)
676
0
          return(-1);
677
0
  }
678
67.5k
    }
679
680
    /*
681
     * Check for duplicate and insertion location.
682
     */
683
67.5k
    key = xmlHashComputeKey(table, name, name2, name3);
684
67.5k
    if (table->table[key].valid == 0) {
685
57.0k
  insert = NULL;
686
57.0k
    } else {
687
10.5k
        if (table ->dict) {
688
12.2k
      for (insert = &(table->table[key]); insert->next != NULL;
689
10.5k
     insert = insert->next) {
690
1.78k
    if ((insert->name == name) &&
691
1.78k
        (insert->name2 == name2) &&
692
1.78k
        (insert->name3 == name3)) {
693
90
        if (f)
694
0
      f(insert->payload, insert->name);
695
90
        insert->payload = userdata;
696
90
        return(0);
697
90
    }
698
1.78k
      }
699
10.4k
      if ((insert->name == name) &&
700
10.4k
    (insert->name2 == name2) &&
701
10.4k
    (insert->name3 == name3)) {
702
939
    if (f)
703
0
        f(insert->payload, insert->name);
704
939
    insert->payload = userdata;
705
939
    return(0);
706
939
      }
707
10.4k
  } 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
10.5k
    }
729
730
66.5k
    if (insert == NULL) {
731
57.0k
  entry =  &(table->table[key]);
732
57.0k
    } else {
733
9.51k
  entry = xmlMalloc(sizeof(xmlHashEntry));
734
9.51k
  if (entry == NULL)
735
0
       return(-1);
736
9.51k
    }
737
738
66.5k
    if (table->dict != NULL) {
739
66.5k
        entry->name = (xmlChar *) name;
740
66.5k
        entry->name2 = (xmlChar *) name2;
741
66.5k
        entry->name3 = (xmlChar *) name3;
742
66.5k
    } else {
743
0
  entry->name = xmlStrdup(name);
744
0
  entry->name2 = xmlStrdup(name2);
745
0
  entry->name3 = xmlStrdup(name3);
746
0
    }
747
66.5k
    entry->payload = userdata;
748
66.5k
    entry->next = NULL;
749
66.5k
    entry->valid = 1;
750
66.5k
    table->nbElems++;
751
752
753
66.5k
    if (insert != NULL) {
754
9.51k
  insert->next = entry;
755
9.51k
    }
756
66.5k
    return(0);
757
66.5k
}
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
58.6M
         const xmlChar *name2, const xmlChar *name3) {
773
58.6M
    unsigned long key;
774
58.6M
    xmlHashEntryPtr entry;
775
776
58.6M
    if (table == NULL)
777
231k
  return(NULL);
778
58.3M
    if (name == NULL)
779
0
  return(NULL);
780
58.3M
    key = xmlHashComputeKey(table, name, name2, name3);
781
58.3M
    if (table->table[key].valid == 0)
782
15.9M
  return(NULL);
783
42.4M
    if (table->dict) {
784
52.8M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
785
33.6M
      if ((entry->name == name) &&
786
33.6M
    (entry->name2 == name2) &&
787
33.6M
    (entry->name3 == name3))
788
12.4M
    return(entry->payload);
789
33.6M
  }
790
31.6M
    }
791
33.2M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
792
31.8M
  if ((xmlStrEqual(entry->name, name)) &&
793
31.8M
      (xmlStrEqual(entry->name2, name2)) &&
794
31.8M
      (xmlStrEqual(entry->name3, name3)))
795
28.6M
      return(entry->payload);
796
31.8M
    }
797
1.37M
    return(NULL);
798
29.9M
}
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
920k
    const xmlChar *prefix3, const xmlChar *name3) {
819
920k
    unsigned long key;
820
920k
    xmlHashEntryPtr entry;
821
822
920k
    if (table == NULL)
823
0
  return(NULL);
824
920k
    if (name == NULL)
825
0
  return(NULL);
826
920k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
827
920k
                             name2, prefix3, name3);
828
920k
    if (table->table[key].valid == 0)
829
424k
  return(NULL);
830
1.01M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
831
873k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
832
873k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
833
873k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
834
352k
      return(entry->payload);
835
873k
    }
836
143k
    return(NULL);
837
496k
}
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
439k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
848
439k
    stubData *stubdata = (stubData *) data;
849
439k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
850
439k
}
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
98.8k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
862
98.8k
    stubData stubdata;
863
98.8k
    stubdata.data = data;
864
98.8k
    stubdata.hashscanner = f;
865
98.8k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
866
98.8k
}
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
160k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
878
160k
    int i, nb;
879
160k
    xmlHashEntryPtr iter;
880
160k
    xmlHashEntryPtr next;
881
882
160k
    if (table == NULL)
883
3.73k
  return;
884
157k
    if (f == NULL)
885
0
  return;
886
887
157k
    if (table->table) {
888
25.5M
  for(i = 0; i < table->size; i++) {
889
25.4M
      if (table->table[i].valid == 0)
890
24.6M
    continue;
891
786k
      iter = &(table->table[i]);
892
1.97M
      while (iter) {
893
1.19M
    next = iter->next;
894
1.19M
                nb = table->nbElems;
895
1.19M
    if ((f != NULL) && (iter->payload != NULL))
896
1.19M
        f(iter->payload, data, iter->name,
897
1.19M
          iter->name2, iter->name3);
898
1.19M
                if (nb != table->nbElems) {
899
                    /* table was modified by the callback, be careful */
900
272k
                    if (iter == &(table->table[i])) {
901
189k
                        if (table->table[i].valid == 0)
902
120k
                            iter = NULL;
903
189k
                        if (table->table[i].next != next)
904
68.7k
          iter = &(table->table[i]);
905
189k
                    } else
906
83.7k
            iter = next;
907
272k
                } else
908
919k
        iter = next;
909
1.19M
      }
910
786k
  }
911
157k
    }
912
157k
}
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
60.7k
       xmlHashScanner f, void *data) {
931
60.7k
    stubData stubdata;
932
60.7k
    stubdata.data = data;
933
60.7k
    stubdata.hashscanner = f;
934
60.7k
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
935
60.7k
                     &stubdata);
936
60.7k
}
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
60.7k
     xmlHashScannerFull f, void *data) {
955
60.7k
    int i;
956
60.7k
    xmlHashEntryPtr iter;
957
60.7k
    xmlHashEntryPtr next;
958
959
60.7k
    if (table == NULL)
960
58.5k
  return;
961
2.19k
    if (f == NULL)
962
0
  return;
963
964
2.19k
    if (table->table) {
965
564k
  for(i = 0; i < table->size; i++) {
966
562k
      if (table->table[i].valid == 0)
967
180k
    continue;
968
382k
      iter = &(table->table[i]);
969
1.25M
      while (iter) {
970
875k
    next = iter->next;
971
875k
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
972
875k
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
973
875k
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
974
875k
        (iter->payload != NULL)) {
975
45
        f(iter->payload, data, iter->name,
976
45
          iter->name2, iter->name3);
977
45
    }
978
875k
    iter = next;
979
875k
      }
980
382k
  }
981
2.19k
    }
982
2.19k
}
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
62.0k
xmlHashSize(xmlHashTablePtr table) {
1037
62.0k
    if (table == NULL)
1038
0
  return(-1);
1039
62.0k
    return(table->nbElems);
1040
62.0k
}
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
318
           xmlHashDeallocator f) {
1056
318
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1057
318
}
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
274k
      const xmlChar *name2, xmlHashDeallocator f) {
1075
274k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1076
274k
}
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
274k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1095
274k
    unsigned long key;
1096
274k
    xmlHashEntryPtr entry;
1097
274k
    xmlHashEntryPtr prev = NULL;
1098
1099
274k
    if (table == NULL || name == NULL)
1100
0
        return(-1);
1101
1102
274k
    key = xmlHashComputeKey(table, name, name2, name3);
1103
274k
    if (table->table[key].valid == 0) {
1104
0
        return(-1);
1105
274k
    } else {
1106
398k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1107
398k
            if (xmlStrEqual(entry->name, name) &&
1108
398k
                    xmlStrEqual(entry->name2, name2) &&
1109
398k
                    xmlStrEqual(entry->name3, name3)) {
1110
274k
                if ((f != NULL) && (entry->payload != NULL))
1111
318
                    f(entry->payload, entry->name);
1112
274k
                entry->payload = NULL;
1113
274k
    if (table->dict == NULL) {
1114
797
        if(entry->name)
1115
797
      xmlFree(entry->name);
1116
797
        if(entry->name2)
1117
151
      xmlFree(entry->name2);
1118
797
        if(entry->name3)
1119
0
      xmlFree(entry->name3);
1120
797
    }
1121
274k
                if(prev) {
1122
83.7k
                    prev->next = entry->next;
1123
83.7k
        xmlFree(entry);
1124
190k
    } else {
1125
190k
        if (entry->next == NULL) {
1126
122k
      entry->valid = 0;
1127
122k
        } else {
1128
68.7k
      entry = entry->next;
1129
68.7k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1130
68.7k
      xmlFree(entry);
1131
68.7k
        }
1132
190k
    }
1133
274k
                table->nbElems--;
1134
274k
                return(0);
1135
274k
            }
1136
123k
            prev = entry;
1137
123k
        }
1138
0
        return(-1);
1139
274k
    }
1140
274k
}
1141