Coverage Report

Created: 2023-06-07 06:14

/src/libxml2/hash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * hash.c: chained hash tables
3
 *
4
 * Reference: Your favorite introductory book on algorithms
5
 *
6
 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
13
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16
 *
17
 * Author: breese@users.sourceforge.net
18
 */
19
20
#define IN_LIBXML
21
#include "libxml.h"
22
23
#include <string.h>
24
#include <stdlib.h>
25
#include <time.h>
26
27
/*
28
 * Following http://www.ocert.org/advisories/ocert-2011-003.html
29
 * it seems that having hash randomization might be a good idea
30
 * when using XML with untrusted data
31
 */
32
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
33
#define HASH_RANDOMIZATION
34
#endif
35
36
#include <libxml/parser.h>
37
#include <libxml/hash.h>
38
#include <libxml/xmlmemory.h>
39
#include <libxml/xmlerror.h>
40
#include <libxml/globals.h>
41
42
#include "private/dict.h"
43
44
2.55M
#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
ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
82
#endif
83
static unsigned long
84
xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
85
5.90M
            const xmlChar *name2, const xmlChar *name3) {
86
5.90M
    unsigned long value = 0L;
87
5.90M
    unsigned long ch;
88
89
#ifdef HASH_RANDOMIZATION
90
    value = table->random_seed;
91
#endif
92
5.90M
    if (name != NULL) {
93
5.90M
  value += 30 * (*name);
94
167M
  while ((ch = *name++) != 0) {
95
161M
      value = value ^ ((value << 5) + (value >> 3) + ch);
96
161M
  }
97
5.90M
    }
98
5.90M
    value = value ^ ((value << 5) + (value >> 3));
99
5.90M
    if (name2 != NULL) {
100
53.2M
  while ((ch = *name2++) != 0) {
101
51.3M
      value = value ^ ((value << 5) + (value >> 3) + ch);
102
51.3M
  }
103
1.87M
    }
104
5.90M
    value = value ^ ((value << 5) + (value >> 3));
105
5.90M
    if (name3 != NULL) {
106
1.13M
  while ((ch = *name3++) != 0) {
107
1.07M
      value = value ^ ((value << 5) + (value >> 3) + ch);
108
1.07M
  }
109
69.2k
    }
110
5.90M
    return (value % table->size);
111
5.90M
}
112
113
#ifdef __clang__
114
ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
115
ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
116
#endif
117
static unsigned long
118
xmlHashComputeQKey(xmlHashTablePtr table,
119
       const xmlChar *prefix, const xmlChar *name,
120
       const xmlChar *prefix2, const xmlChar *name2,
121
16.7k
       const xmlChar *prefix3, const xmlChar *name3) {
122
16.7k
    unsigned long value = 0L;
123
16.7k
    unsigned long ch;
124
125
#ifdef HASH_RANDOMIZATION
126
    value = table->random_seed;
127
#endif
128
16.7k
    if (prefix != NULL)
129
2.08k
  value += 30 * (*prefix);
130
14.6k
    else
131
14.6k
  value += 30 * (*name);
132
133
16.7k
    if (prefix != NULL) {
134
8.17k
  while ((ch = *prefix++) != 0) {
135
6.09k
      value = value ^ ((value << 5) + (value >> 3) + ch);
136
6.09k
  }
137
2.08k
  value = value ^ ((value << 5) + (value >> 3) + ':');
138
2.08k
    }
139
16.7k
    if (name != NULL) {
140
54.6k
  while ((ch = *name++) != 0) {
141
37.9k
      value = value ^ ((value << 5) + (value >> 3) + ch);
142
37.9k
  }
143
16.7k
    }
144
16.7k
    value = value ^ ((value << 5) + (value >> 3));
145
16.7k
    if (prefix2 != NULL) {
146
7.19k
  while ((ch = *prefix2++) != 0) {
147
5.86k
      value = value ^ ((value << 5) + (value >> 3) + ch);
148
5.86k
  }
149
1.33k
  value = value ^ ((value << 5) + (value >> 3) + ':');
150
1.33k
    }
151
16.7k
    if (name2 != NULL) {
152
86.8k
  while ((ch = *name2++) != 0) {
153
70.0k
      value = value ^ ((value << 5) + (value >> 3) + ch);
154
70.0k
  }
155
16.7k
    }
156
16.7k
    value = value ^ ((value << 5) + (value >> 3));
157
16.7k
    if (prefix3 != NULL) {
158
0
  while ((ch = *prefix3++) != 0) {
159
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
160
0
  }
161
0
  value = value ^ ((value << 5) + (value >> 3) + ':');
162
0
    }
163
16.7k
    if (name3 != NULL) {
164
0
  while ((ch = *name3++) != 0) {
165
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
166
0
  }
167
0
    }
168
16.7k
    return (value % table->size);
169
16.7k
}
170
171
/**
172
 * xmlHashCreate:
173
 * @size: the size of the hash table
174
 *
175
 * Create a new xmlHashTablePtr.
176
 *
177
 * Returns the newly created object, or NULL if an error occurred.
178
 */
179
xmlHashTablePtr
180
257k
xmlHashCreate(int size) {
181
257k
    xmlHashTablePtr table;
182
183
257k
    xmlInitParser();
184
185
257k
    if (size <= 0)
186
119k
        size = 256;
187
188
257k
    table = xmlMalloc(sizeof(xmlHashTable));
189
257k
    if (table) {
190
255k
        table->dict = NULL;
191
255k
        table->size = size;
192
255k
  table->nbElems = 0;
193
255k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
194
255k
        if (table->table) {
195
255k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
196
#ifdef HASH_RANDOMIZATION
197
            table->random_seed = __xmlRandom();
198
#endif
199
255k
      return(table);
200
255k
        }
201
34
        xmlFree(table);
202
34
    }
203
1.98k
    return(NULL);
204
257k
}
205
206
/**
207
 * xmlHashCreateDict:
208
 * @size: the size of the hash table
209
 * @dict: a dictionary to use for the hash
210
 *
211
 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
212
 *
213
 * Returns the newly created object, or NULL if an error occurred.
214
 */
215
xmlHashTablePtr
216
82.5k
xmlHashCreateDict(int size, xmlDictPtr dict) {
217
82.5k
    xmlHashTablePtr table;
218
219
82.5k
    table = xmlHashCreate(size);
220
82.5k
    if (table != NULL) {
221
82.4k
        table->dict = dict;
222
82.4k
  xmlDictReference(dict);
223
82.4k
    }
224
82.5k
    return(table);
225
82.5k
}
226
227
/**
228
 * xmlHashGrow:
229
 * @table: the hash table
230
 * @size: the new size of the hash table
231
 *
232
 * resize the hash table
233
 *
234
 * Returns 0 in case of success, -1 in case of failure
235
 */
236
static int
237
2.24k
xmlHashGrow(xmlHashTablePtr table, int size) {
238
2.24k
    unsigned long key;
239
2.24k
    int oldsize, i;
240
2.24k
    xmlHashEntryPtr iter, next;
241
2.24k
    struct _xmlHashEntry *oldtable;
242
#ifdef DEBUG_GROW
243
    unsigned long nbElem = 0;
244
#endif
245
246
2.24k
    if (table == NULL)
247
0
  return(-1);
248
2.24k
    if (size < 8)
249
0
        return(-1);
250
2.24k
    if (size > 8 * 2048)
251
0
  return(-1);
252
253
2.24k
    oldsize = table->size;
254
2.24k
    oldtable = table->table;
255
2.24k
    if (oldtable == NULL)
256
0
        return(-1);
257
258
2.24k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
259
2.24k
    if (table->table == NULL) {
260
2
  table->table = oldtable;
261
2
  return(-1);
262
2
    }
263
2.24k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
264
2.24k
    table->size = size;
265
266
    /*  If the two loops are merged, there would be situations where
267
  a new entry needs to allocated and data copied into it from
268
  the main table. So instead, we run through the array twice, first
269
  copying all the elements in the main array (where we can't get
270
  conflicts) and then the rest, so we only free (and don't allocate)
271
    */
272
27.0k
    for (i = 0; i < oldsize; i++) {
273
24.8k
  if (oldtable[i].valid == 0)
274
5.47k
      continue;
275
19.3k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
276
19.3k
        oldtable[i].name3);
277
19.3k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
278
19.3k
  table->table[key].next = NULL;
279
19.3k
    }
280
281
27.0k
    for (i = 0; i < oldsize; i++) {
282
24.8k
  iter = oldtable[i].next;
283
75.8k
  while (iter) {
284
50.9k
      next = iter->next;
285
286
      /*
287
       * put back the entry in the new table
288
       */
289
290
50.9k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
291
50.9k
                        iter->name3);
292
50.9k
      if (table->table[key].valid == 0) {
293
29.2k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
294
29.2k
    table->table[key].next = NULL;
295
29.2k
    xmlFree(iter);
296
29.2k
      } else {
297
21.7k
    iter->next = table->table[key].next;
298
21.7k
    table->table[key].next = iter;
299
21.7k
      }
300
301
#ifdef DEBUG_GROW
302
      nbElem++;
303
#endif
304
305
50.9k
      iter = next;
306
50.9k
  }
307
24.8k
    }
308
309
2.24k
    xmlFree(oldtable);
310
311
#ifdef DEBUG_GROW
312
    xmlGenericError(xmlGenericErrorContext,
313
      "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
314
#endif
315
316
2.24k
    return(0);
317
2.24k
}
318
319
/**
320
 * xmlHashFree:
321
 * @table: the hash table
322
 * @f:  the deallocator function for items in the hash
323
 *
324
 * Free the hash @table and its contents. The userdata is
325
 * deallocated with @f if provided.
326
 */
327
void
328
375k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
329
375k
    int i;
330
375k
    xmlHashEntryPtr iter;
331
375k
    xmlHashEntryPtr next;
332
375k
    int inside_table = 0;
333
375k
    int nbElems;
334
335
375k
    if (table == NULL)
336
119k
  return;
337
255k
    if (table->table) {
338
255k
  nbElems = table->nbElems;
339
35.6M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
340
35.4M
      iter = &(table->table[i]);
341
35.4M
      if (iter->valid == 0)
342
33.1M
    continue;
343
2.23M
      inside_table = 1;
344
4.79M
      while (iter) {
345
2.56M
    next = iter->next;
346
2.56M
    if ((f != NULL) && (iter->payload != NULL))
347
288k
        f(iter->payload, iter->name);
348
2.56M
    if (table->dict == NULL) {
349
2.37M
        if (iter->name)
350
2.37M
      xmlFree(iter->name);
351
2.37M
        if (iter->name2)
352
411k
      xmlFree(iter->name2);
353
2.37M
        if (iter->name3)
354
236
      xmlFree(iter->name3);
355
2.37M
    }
356
2.56M
    iter->payload = NULL;
357
2.56M
    if (!inside_table)
358
330k
        xmlFree(iter);
359
2.56M
    nbElems--;
360
2.56M
    inside_table = 0;
361
2.56M
    iter = next;
362
2.56M
      }
363
2.23M
  }
364
255k
  xmlFree(table->table);
365
255k
    }
366
255k
    if (table->dict)
367
77.9k
        xmlDictFree(table->dict);
368
255k
    xmlFree(table);
369
255k
}
370
371
/**
372
 * xmlHashDefaultDeallocator:
373
 * @entry: the hash table entry
374
 * @name: the entry's name
375
 *
376
 * Free a hash table entry with xmlFree.
377
 */
378
void
379
134k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
380
134k
    xmlFree(entry);
381
134k
}
382
383
/**
384
 * xmlHashAddEntry:
385
 * @table: the hash table
386
 * @name: the name of the userdata
387
 * @userdata: a pointer to the userdata
388
 *
389
 * Add the @userdata to the hash @table. This can later be retrieved
390
 * by using the @name. Duplicate names generate errors.
391
 *
392
 * Returns 0 the addition succeeded and -1 in case of error.
393
 */
394
int
395
193k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
396
193k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
397
193k
}
398
399
/**
400
 * xmlHashAddEntry2:
401
 * @table: the hash table
402
 * @name: the name of the userdata
403
 * @name2: a second name of the userdata
404
 * @userdata: a pointer to the userdata
405
 *
406
 * Add the @userdata to the hash @table. This can later be retrieved
407
 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
408
 *
409
 * Returns 0 the addition succeeded and -1 in case of error.
410
 */
411
int
412
xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
413
2.38M
          const xmlChar *name2, void *userdata) {
414
2.38M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
415
2.38M
}
416
417
/**
418
 * xmlHashUpdateEntry:
419
 * @table: the hash table
420
 * @name: the name of the userdata
421
 * @userdata: a pointer to the userdata
422
 * @f: the deallocator function for replaced item (if any)
423
 *
424
 * Add the @userdata to the hash @table. This can later be retrieved
425
 * by using the @name. Existing entry for this @name will be removed
426
 * and freed with @f if found.
427
 *
428
 * Returns 0 the addition succeeded and -1 in case of error.
429
 */
430
int
431
xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
432
0
             void *userdata, xmlHashDeallocator f) {
433
0
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
434
0
}
435
436
/**
437
 * xmlHashUpdateEntry2:
438
 * @table: the hash table
439
 * @name: the name of the userdata
440
 * @name2: a second name of the userdata
441
 * @userdata: a pointer to the userdata
442
 * @f: the deallocator function for replaced item (if any)
443
 *
444
 * Add the @userdata to the hash @table. This can later be retrieved
445
 * by using the (@name, @name2) tuple. Existing entry for this tuple will
446
 * be removed and freed with @f if found.
447
 *
448
 * Returns 0 the addition succeeded and -1 in case of error.
449
 */
450
int
451
xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
452
             const xmlChar *name2, void *userdata,
453
32.0k
       xmlHashDeallocator f) {
454
32.0k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
455
32.0k
}
456
457
/**
458
 * xmlHashLookup:
459
 * @table: the hash table
460
 * @name: the name of the userdata
461
 *
462
 * Find the userdata specified by the @name.
463
 *
464
 * Returns the pointer to the userdata
465
 */
466
void *
467
1.01M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
468
1.01M
    return(xmlHashLookup3(table, name, NULL, NULL));
469
1.01M
}
470
471
/**
472
 * xmlHashLookup2:
473
 * @table: the hash table
474
 * @name: the name of the userdata
475
 * @name2: a second name of the userdata
476
 *
477
 * Find the userdata specified by the (@name, @name2) tuple.
478
 *
479
 * Returns the pointer to the userdata
480
 */
481
void *
482
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
483
1.57M
        const xmlChar *name2) {
484
1.57M
    return(xmlHashLookup3(table, name, name2, NULL));
485
1.57M
}
486
487
/**
488
 * xmlHashQLookup:
489
 * @table: the hash table
490
 * @prefix: the prefix of the userdata
491
 * @name: the name of the userdata
492
 *
493
 * Find the userdata specified by the QName @prefix:@name/@name.
494
 *
495
 * Returns the pointer to the userdata
496
 */
497
void *
498
xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
499
0
               const xmlChar *name) {
500
0
    return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
501
0
}
502
503
/**
504
 * xmlHashQLookup2:
505
 * @table: the hash table
506
 * @prefix: the prefix of the userdata
507
 * @name: the name of the userdata
508
 * @prefix2: the second prefix of the userdata
509
 * @name2: a second name of the userdata
510
 *
511
 * Find the userdata specified by the QNames tuple
512
 *
513
 * Returns the pointer to the userdata
514
 */
515
void *
516
xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
517
                const xmlChar *name, const xmlChar *prefix2,
518
16.7k
          const xmlChar *name2) {
519
16.7k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
520
16.7k
}
521
522
/**
523
 * xmlHashAddEntry3:
524
 * @table: the hash table
525
 * @name: the name of the userdata
526
 * @name2: a second name of the userdata
527
 * @name3: a third name of the userdata
528
 * @userdata: a pointer to the userdata
529
 *
530
 * Add the @userdata to the hash @table. This can later be retrieved
531
 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
532
 * errors.
533
 *
534
 * Returns 0 the addition succeeded and -1 in case of error.
535
 */
536
int
537
xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
538
           const xmlChar *name2, const xmlChar *name3,
539
2.64M
     void *userdata) {
540
2.64M
    unsigned long key, len = 0;
541
2.64M
    xmlHashEntryPtr entry;
542
2.64M
    xmlHashEntryPtr insert;
543
544
2.64M
    if ((table == NULL) || (name == NULL))
545
11.0k
  return(-1);
546
547
    /*
548
     * If using a dict internalize if needed
549
     */
550
2.62M
    if (table->dict) {
551
192k
        if (!xmlDictOwns(table->dict, name)) {
552
36.3k
      name = xmlDictLookup(table->dict, name, -1);
553
36.3k
      if (name == NULL)
554
2
          return(-1);
555
36.3k
  }
556
192k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
557
9.25k
      name2 = xmlDictLookup(table->dict, name2, -1);
558
9.25k
      if (name2 == NULL)
559
1
          return(-1);
560
9.25k
  }
561
192k
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
562
0
      name3 = xmlDictLookup(table->dict, name3, -1);
563
0
      if (name3 == NULL)
564
0
          return(-1);
565
0
  }
566
192k
    }
567
568
    /*
569
     * Check for duplicate and insertion location.
570
     */
571
2.62M
    key = xmlHashComputeKey(table, name, name2, name3);
572
2.62M
    if (table->table[key].valid == 0) {
573
2.18M
  insert = NULL;
574
2.18M
    } else {
575
441k
        if (table->dict) {
576
96.4k
      for (insert = &(table->table[key]); insert->next != NULL;
577
56.6k
     insert = insert->next) {
578
40.5k
    if ((insert->name == name) &&
579
40.5k
        (insert->name2 == name2) &&
580
40.5k
        (insert->name3 == name3))
581
854
        return(-1);
582
39.7k
    len++;
583
39.7k
      }
584
55.8k
      if ((insert->name == name) &&
585
55.8k
    (insert->name2 == name2) &&
586
55.8k
    (insert->name3 == name3))
587
23.2k
    return(-1);
588
384k
  } else {
589
752k
      for (insert = &(table->table[key]); insert->next != NULL;
590
388k
     insert = insert->next) {
591
388k
    if ((xmlStrEqual(insert->name, name)) &&
592
388k
        (xmlStrEqual(insert->name2, name2)) &&
593
388k
        (xmlStrEqual(insert->name3, name3)))
594
21.0k
        return(-1);
595
367k
    len++;
596
367k
      }
597
363k
      if ((xmlStrEqual(insert->name, name)) &&
598
363k
    (xmlStrEqual(insert->name2, name2)) &&
599
363k
    (xmlStrEqual(insert->name3, name3)))
600
35.1k
    return(-1);
601
363k
  }
602
441k
    }
603
604
2.54M
    if (insert == NULL) {
605
2.18M
  entry = &(table->table[key]);
606
2.18M
    } else {
607
360k
  entry = xmlMalloc(sizeof(xmlHashEntry));
608
360k
  if (entry == NULL)
609
319
       return(-1);
610
360k
    }
611
612
2.54M
    if (table->dict != NULL) {
613
168k
        entry->name = (xmlChar *) name;
614
168k
        entry->name2 = (xmlChar *) name2;
615
168k
        entry->name3 = (xmlChar *) name3;
616
2.38M
    } else {
617
2.38M
  entry->name = xmlStrdup(name);
618
2.38M
        if (entry->name == NULL) {
619
1.21k
            entry->name2 = NULL;
620
1.21k
            goto error;
621
1.21k
        }
622
2.38M
        if (name2 == NULL) {
623
1.96M
            entry->name2 = NULL;
624
1.96M
        } else {
625
411k
      entry->name2 = xmlStrdup(name2);
626
411k
            if (entry->name2 == NULL)
627
23
                goto error;
628
411k
        }
629
2.38M
        if (name3 == NULL) {
630
2.37M
            entry->name3 = NULL;
631
2.37M
        } else {
632
239
      entry->name3 = xmlStrdup(name3);
633
239
            if (entry->name3 == NULL)
634
3
                goto error;
635
239
        }
636
2.38M
    }
637
2.54M
    entry->payload = userdata;
638
2.54M
    entry->next = NULL;
639
2.54M
    entry->valid = 1;
640
641
642
2.54M
    if (insert != NULL)
643
360k
  insert->next = entry;
644
645
2.54M
    table->nbElems++;
646
647
2.54M
    if (len > MAX_HASH_LEN)
648
2.24k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
649
650
2.54M
    return(0);
651
652
1.24k
error:
653
1.24k
    xmlFree(entry->name2);
654
1.24k
    xmlFree(entry->name);
655
1.24k
    if (insert != NULL)
656
32
        xmlFree(entry);
657
1.24k
    return(-1);
658
2.54M
}
659
660
/**
661
 * xmlHashUpdateEntry3:
662
 * @table: the hash table
663
 * @name: the name of the userdata
664
 * @name2: a second name of the userdata
665
 * @name3: a third name of the userdata
666
 * @userdata: a pointer to the userdata
667
 * @f: the deallocator function for replaced item (if any)
668
 *
669
 * Add the @userdata to the hash @table. This can later be retrieved
670
 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
671
 * will be removed and freed with @f if found.
672
 *
673
 * Returns 0 the addition succeeded and -1 in case of error.
674
 */
675
int
676
xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
677
             const xmlChar *name2, const xmlChar *name3,
678
46.4k
       void *userdata, xmlHashDeallocator f) {
679
46.4k
    unsigned long key;
680
46.4k
    xmlHashEntryPtr entry;
681
46.4k
    xmlHashEntryPtr insert;
682
683
46.4k
    if ((table == NULL) || name == NULL)
684
0
  return(-1);
685
686
    /*
687
     * If using a dict internalize if needed
688
     */
689
46.4k
    if (table->dict) {
690
31.9k
        if (!xmlDictOwns(table->dict, name)) {
691
0
      name = xmlDictLookup(table->dict, name, -1);
692
0
      if (name == NULL)
693
0
          return(-1);
694
0
  }
695
31.9k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
696
0
      name2 = xmlDictLookup(table->dict, name2, -1);
697
0
      if (name2 == NULL)
698
0
          return(-1);
699
0
  }
700
31.9k
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
701
0
      name3 = xmlDictLookup(table->dict, name3, -1);
702
0
      if (name3 == NULL)
703
0
          return(-1);
704
0
  }
705
31.9k
    }
706
707
    /*
708
     * Check for duplicate and insertion location.
709
     */
710
46.4k
    key = xmlHashComputeKey(table, name, name2, name3);
711
46.4k
    if (table->table[key].valid == 0) {
712
21.2k
  insert = NULL;
713
25.2k
    } else {
714
25.2k
        if (table ->dict) {
715
13.7k
      for (insert = &(table->table[key]); insert->next != NULL;
716
10.6k
     insert = insert->next) {
717
3.24k
    if ((insert->name == name) &&
718
3.24k
        (insert->name2 == name2) &&
719
3.24k
        (insert->name3 == name3)) {
720
216
        if (f)
721
0
      f(insert->payload, insert->name);
722
216
        insert->payload = userdata;
723
216
        return(0);
724
216
    }
725
3.24k
      }
726
10.4k
      if ((insert->name == name) &&
727
10.4k
    (insert->name2 == name2) &&
728
10.4k
    (insert->name3 == name3)) {
729
6.48k
    if (f)
730
0
        f(insert->payload, insert->name);
731
6.48k
    insert->payload = userdata;
732
6.48k
    return(0);
733
6.48k
      }
734
14.5k
  } else {
735
16.2k
      for (insert = &(table->table[key]); insert->next != NULL;
736
14.5k
     insert = insert->next) {
737
2.58k
    if ((xmlStrEqual(insert->name, name)) &&
738
2.58k
        (xmlStrEqual(insert->name2, name2)) &&
739
2.58k
        (xmlStrEqual(insert->name3, name3))) {
740
894
        if (f)
741
0
      f(insert->payload, insert->name);
742
894
        insert->payload = userdata;
743
894
        return(0);
744
894
    }
745
2.58k
      }
746
13.6k
      if ((xmlStrEqual(insert->name, name)) &&
747
13.6k
    (xmlStrEqual(insert->name2, name2)) &&
748
13.6k
    (xmlStrEqual(insert->name3, name3))) {
749
13.5k
    if (f)
750
0
        f(insert->payload, insert->name);
751
13.5k
    insert->payload = userdata;
752
13.5k
    return(0);
753
13.5k
      }
754
13.6k
  }
755
25.2k
    }
756
757
25.3k
    if (insert == NULL) {
758
21.2k
  entry =  &(table->table[key]);
759
21.2k
    } else {
760
4.11k
  entry = xmlMalloc(sizeof(xmlHashEntry));
761
4.11k
  if (entry == NULL)
762
1
       return(-1);
763
4.11k
    }
764
765
25.3k
    if (table->dict != NULL) {
766
25.2k
        entry->name = (xmlChar *) name;
767
25.2k
        entry->name2 = (xmlChar *) name2;
768
25.2k
        entry->name3 = (xmlChar *) name3;
769
25.2k
    } else {
770
164
  entry->name = xmlStrdup(name);
771
164
        if (entry->name == NULL) {
772
0
            entry->name2 = NULL;
773
0
            goto error;
774
0
        }
775
164
        if (name2 == NULL) {
776
0
            entry->name2 = NULL;
777
164
        } else {
778
164
      entry->name2 = xmlStrdup(name2);
779
164
            if (entry->name2 == NULL)
780
0
                goto error;
781
164
        }
782
164
        if (name3 == NULL) {
783
164
            entry->name3 = NULL;
784
164
        } else {
785
0
      entry->name3 = xmlStrdup(name3);
786
0
            if (entry->name3 == NULL)
787
0
                goto error;
788
0
        }
789
164
    }
790
25.3k
    entry->payload = userdata;
791
25.3k
    entry->next = NULL;
792
25.3k
    entry->valid = 1;
793
25.3k
    table->nbElems++;
794
795
796
25.3k
    if (insert != NULL) {
797
4.11k
  insert->next = entry;
798
4.11k
    }
799
25.3k
    return(0);
800
801
0
error:
802
0
    xmlFree(entry->name2);
803
0
    xmlFree(entry->name);
804
0
    if (insert != NULL)
805
0
        xmlFree(entry);
806
0
    return(-1);
807
25.3k
}
808
809
/**
810
 * xmlHashLookup3:
811
 * @table: the hash table
812
 * @name: the name of the userdata
813
 * @name2: a second name of the userdata
814
 * @name3: a third name of the userdata
815
 *
816
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
817
 *
818
 * Returns the a pointer to the userdata
819
 */
820
void *
821
xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
822
3.28M
         const xmlChar *name2, const xmlChar *name3) {
823
3.28M
    unsigned long key;
824
3.28M
    xmlHashEntryPtr entry;
825
826
3.28M
    if (table == NULL)
827
134k
  return(NULL);
828
3.14M
    if (name == NULL)
829
7
  return(NULL);
830
3.14M
    key = xmlHashComputeKey(table, name, name2, name3);
831
3.14M
    if (table->table[key].valid == 0)
832
1.02M
  return(NULL);
833
2.11M
    if (table->dict) {
834
532k
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
835
442k
      if ((entry->name == name) &&
836
442k
    (entry->name2 == name2) &&
837
442k
    (entry->name3 == name3))
838
228k
    return(entry->payload);
839
442k
  }
840
319k
    }
841
4.21M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
842
3.56M
  if ((xmlStrEqual(entry->name, name)) &&
843
3.56M
      (xmlStrEqual(entry->name2, name2)) &&
844
3.56M
      (xmlStrEqual(entry->name3, name3)))
845
1.24M
      return(entry->payload);
846
3.56M
    }
847
647k
    return(NULL);
848
1.88M
}
849
850
/**
851
 * xmlHashQLookup3:
852
 * @table: the hash table
853
 * @prefix: the prefix of the userdata
854
 * @name: the name of the userdata
855
 * @prefix2: the second prefix of the userdata
856
 * @name2: a second name of the userdata
857
 * @prefix3: the third prefix of the userdata
858
 * @name3: a third name of the userdata
859
 *
860
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
861
 *
862
 * Returns the a pointer to the userdata
863
 */
864
void *
865
xmlHashQLookup3(xmlHashTablePtr table,
866
                const xmlChar *prefix, const xmlChar *name,
867
    const xmlChar *prefix2, const xmlChar *name2,
868
16.7k
    const xmlChar *prefix3, const xmlChar *name3) {
869
16.7k
    unsigned long key;
870
16.7k
    xmlHashEntryPtr entry;
871
872
16.7k
    if (table == NULL)
873
0
  return(NULL);
874
16.7k
    if (name == NULL)
875
0
  return(NULL);
876
16.7k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
877
16.7k
                             name2, prefix3, name3);
878
16.7k
    if (table->table[key].valid == 0)
879
6.46k
  return(NULL);
880
13.3k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
881
11.4k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
882
11.4k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
883
11.4k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
884
8.36k
      return(entry->payload);
885
11.4k
    }
886
1.90k
    return(NULL);
887
10.2k
}
888
889
typedef struct {
890
    xmlHashScanner hashscanner;
891
    void *data;
892
} stubData;
893
894
static void
895
stubHashScannerFull (void *payload, void *data, const xmlChar *name,
896
                     const xmlChar *name2 ATTRIBUTE_UNUSED,
897
12.2k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
898
12.2k
    stubData *stubdata = (stubData *) data;
899
12.2k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
900
12.2k
}
901
902
/**
903
 * xmlHashScan:
904
 * @table: the hash table
905
 * @f:  the scanner function for items in the hash
906
 * @data:  extra data passed to f
907
 *
908
 * Scan the hash @table and applied @f to each value.
909
 */
910
void
911
30.6k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
912
30.6k
    stubData stubdata;
913
30.6k
    stubdata.data = data;
914
30.6k
    stubdata.hashscanner = f;
915
30.6k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
916
30.6k
}
917
918
/**
919
 * xmlHashScanFull:
920
 * @table: the hash table
921
 * @f:  the scanner function for items in the hash
922
 * @data:  extra data passed to f
923
 *
924
 * Scan the hash @table and applied @f to each value.
925
 */
926
void
927
38.7k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
928
38.7k
    int i, nb;
929
38.7k
    xmlHashEntryPtr iter;
930
38.7k
    xmlHashEntryPtr next;
931
932
38.7k
    if (table == NULL)
933
6.61k
  return;
934
32.1k
    if (f == NULL)
935
0
  return;
936
937
32.1k
    if (table->table) {
938
3.42M
  for(i = 0; i < table->size; i++) {
939
3.39M
      if (table->table[i].valid == 0)
940
3.37M
    continue;
941
26.4k
      iter = &(table->table[i]);
942
62.2k
      while (iter) {
943
35.7k
    next = iter->next;
944
35.7k
                nb = table->nbElems;
945
35.7k
    if ((f != NULL) && (iter->payload != NULL))
946
35.7k
        f(iter->payload, data, iter->name,
947
35.7k
          iter->name2, iter->name3);
948
35.7k
                if (nb != table->nbElems) {
949
                    /* table was modified by the callback, be careful */
950
6.73k
                    if (iter == &(table->table[i])) {
951
4.54k
                        if (table->table[i].valid == 0)
952
1.53k
                            iter = NULL;
953
4.54k
                        if (table->table[i].next != next)
954
3.00k
          iter = &(table->table[i]);
955
4.54k
                    } else
956
2.19k
            iter = next;
957
6.73k
                } else
958
29.0k
        iter = next;
959
35.7k
      }
960
26.4k
  }
961
32.1k
    }
962
32.1k
}
963
964
/**
965
 * xmlHashScan3:
966
 * @table: the hash table
967
 * @name: the name of the userdata or NULL
968
 * @name2: a second name of the userdata or NULL
969
 * @name3: a third name of the userdata or NULL
970
 * @f:  the scanner function for items in the hash
971
 * @data:  extra data passed to f
972
 *
973
 * Scan the hash @table and applied @f to each value matching
974
 * (@name, @name2, @name3) tuple. If one of the names is null,
975
 * the comparison is considered to match.
976
 */
977
void
978
xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
979
       const xmlChar *name2, const xmlChar *name3,
980
0
       xmlHashScanner f, void *data) {
981
0
    stubData stubdata;
982
0
    stubdata.data = data;
983
0
    stubdata.hashscanner = f;
984
0
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
985
0
                     &stubdata);
986
0
}
987
988
/**
989
 * xmlHashScanFull3:
990
 * @table: the hash table
991
 * @name: the name of the userdata or NULL
992
 * @name2: a second name of the userdata or NULL
993
 * @name3: a third name of the userdata or NULL
994
 * @f:  the scanner function for items in the hash
995
 * @data:  extra data passed to f
996
 *
997
 * Scan the hash @table and applied @f to each value matching
998
 * (@name, @name2, @name3) tuple. If one of the names is null,
999
 * the comparison is considered to match.
1000
 */
1001
void
1002
xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
1003
     const xmlChar *name2, const xmlChar *name3,
1004
0
     xmlHashScannerFull f, void *data) {
1005
0
    int i;
1006
0
    xmlHashEntryPtr iter;
1007
0
    xmlHashEntryPtr next;
1008
1009
0
    if (table == NULL)
1010
0
  return;
1011
0
    if (f == NULL)
1012
0
  return;
1013
1014
0
    if (table->table) {
1015
0
  for(i = 0; i < table->size; i++) {
1016
0
      if (table->table[i].valid == 0)
1017
0
    continue;
1018
0
      iter = &(table->table[i]);
1019
0
      while (iter) {
1020
0
    next = iter->next;
1021
0
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
1022
0
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
1023
0
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
1024
0
        (iter->payload != NULL)) {
1025
0
        f(iter->payload, data, iter->name,
1026
0
          iter->name2, iter->name3);
1027
0
    }
1028
0
    iter = next;
1029
0
      }
1030
0
  }
1031
0
    }
1032
0
}
1033
1034
/**
1035
 * xmlHashCopy:
1036
 * @table: the hash table
1037
 * @f:  the copier function for items in the hash
1038
 *
1039
 * Scan the hash @table and applied @f to each value.
1040
 *
1041
 * Returns the new table or NULL in case of error.
1042
 */
1043
xmlHashTablePtr
1044
0
xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
1045
0
    int i;
1046
0
    xmlHashEntryPtr iter;
1047
0
    xmlHashEntryPtr next;
1048
0
    xmlHashTablePtr ret;
1049
1050
0
    if (table == NULL)
1051
0
  return(NULL);
1052
0
    if (f == NULL)
1053
0
  return(NULL);
1054
1055
0
    ret = xmlHashCreate(table->size);
1056
0
    if (ret == NULL)
1057
0
        return(NULL);
1058
1059
0
    if (table->table) {
1060
0
  for(i = 0; i < table->size; i++) {
1061
0
      if (table->table[i].valid == 0)
1062
0
    continue;
1063
0
      iter = &(table->table[i]);
1064
0
      while (iter) {
1065
0
    next = iter->next;
1066
0
    xmlHashAddEntry3(ret, iter->name, iter->name2,
1067
0
               iter->name3, f(iter->payload, iter->name));
1068
0
    iter = next;
1069
0
      }
1070
0
  }
1071
0
    }
1072
0
    ret->nbElems = table->nbElems;
1073
0
    return(ret);
1074
0
}
1075
1076
/**
1077
 * xmlHashSize:
1078
 * @table: the hash table
1079
 *
1080
 * Query the number of elements installed in the hash @table.
1081
 *
1082
 * Returns the number of elements in the hash table or
1083
 * -1 in case of error
1084
 */
1085
int
1086
4.54k
xmlHashSize(xmlHashTablePtr table) {
1087
4.54k
    if (table == NULL)
1088
0
  return(-1);
1089
4.54k
    return(table->nbElems);
1090
4.54k
}
1091
1092
/**
1093
 * xmlHashRemoveEntry:
1094
 * @table: the hash table
1095
 * @name: the name of the userdata
1096
 * @f: the deallocator function for removed item (if any)
1097
 *
1098
 * Find the userdata specified by the @name and remove
1099
 * it from the hash @table. Existing userdata for this tuple will be removed
1100
 * and freed with @f.
1101
 *
1102
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1103
 */
1104
int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
1105
317
           xmlHashDeallocator f) {
1106
317
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1107
317
}
1108
1109
/**
1110
 * xmlHashRemoveEntry2:
1111
 * @table: the hash table
1112
 * @name: the name of the userdata
1113
 * @name2: a second name of the userdata
1114
 * @f: the deallocator function for removed item (if any)
1115
 *
1116
 * Find the userdata specified by the (@name, @name2) tuple and remove
1117
 * it from the hash @table. Existing userdata for this tuple will be removed
1118
 * and freed with @f.
1119
 *
1120
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1121
 */
1122
int
1123
xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
1124
9.09k
      const xmlChar *name2, xmlHashDeallocator f) {
1125
9.09k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1126
9.09k
}
1127
1128
/**
1129
 * xmlHashRemoveEntry3:
1130
 * @table: the hash table
1131
 * @name: the name of the userdata
1132
 * @name2: a second name of the userdata
1133
 * @name3: a third name of the userdata
1134
 * @f: the deallocator function for removed item (if any)
1135
 *
1136
 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1137
 * it from the hash @table. Existing userdata for this tuple will be removed
1138
 * and freed with @f.
1139
 *
1140
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1141
 */
1142
int
1143
xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
1144
9.40k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1145
9.40k
    unsigned long key;
1146
9.40k
    xmlHashEntryPtr entry;
1147
9.40k
    xmlHashEntryPtr prev = NULL;
1148
1149
9.40k
    if (table == NULL || name == NULL)
1150
0
        return(-1);
1151
1152
9.40k
    key = xmlHashComputeKey(table, name, name2, name3);
1153
9.40k
    if (table->table[key].valid == 0) {
1154
0
        return(-1);
1155
9.40k
    } else {
1156
12.1k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1157
12.1k
            if (xmlStrEqual(entry->name, name) &&
1158
12.1k
                    xmlStrEqual(entry->name2, name2) &&
1159
12.1k
                    xmlStrEqual(entry->name3, name3)) {
1160
9.40k
                if ((f != NULL) && (entry->payload != NULL))
1161
317
                    f(entry->payload, entry->name);
1162
9.40k
                entry->payload = NULL;
1163
9.40k
    if (table->dict == NULL) {
1164
2.35k
        if(entry->name)
1165
2.35k
      xmlFree(entry->name);
1166
2.35k
        if(entry->name2)
1167
51
      xmlFree(entry->name2);
1168
2.35k
        if(entry->name3)
1169
0
      xmlFree(entry->name3);
1170
2.35k
    }
1171
9.40k
                if(prev) {
1172
2.20k
                    prev->next = entry->next;
1173
2.20k
        xmlFree(entry);
1174
7.20k
    } else {
1175
7.20k
        if (entry->next == NULL) {
1176
4.19k
      entry->valid = 0;
1177
4.19k
        } else {
1178
3.00k
      entry = entry->next;
1179
3.00k
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1180
3.00k
      xmlFree(entry);
1181
3.00k
        }
1182
7.20k
    }
1183
9.40k
                table->nbElems--;
1184
9.40k
                return(0);
1185
9.40k
            }
1186
2.78k
            prev = entry;
1187
2.78k
        }
1188
0
        return(-1);
1189
9.40k
    }
1190
9.40k
}
1191