Coverage Report

Created: 2023-03-26 06:13

/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
1.90M
#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
6.20M
            const xmlChar *name2, const xmlChar *name3) {
86
6.20M
    unsigned long value = 0L;
87
6.20M
    unsigned long ch;
88
89
#ifdef HASH_RANDOMIZATION
90
    value = table->random_seed;
91
#endif
92
6.20M
    if (name != NULL) {
93
6.20M
  value += 30 * (*name);
94
189M
  while ((ch = *name++) != 0) {
95
183M
      value = value ^ ((value << 5) + (value >> 3) + ch);
96
183M
  }
97
6.20M
    }
98
6.20M
    value = value ^ ((value << 5) + (value >> 3));
99
6.20M
    if (name2 != NULL) {
100
60.2M
  while ((ch = *name2++) != 0) {
101
58.1M
      value = value ^ ((value << 5) + (value >> 3) + ch);
102
58.1M
  }
103
2.09M
    }
104
6.20M
    value = value ^ ((value << 5) + (value >> 3));
105
6.20M
    if (name3 != NULL) {
106
3.12M
  while ((ch = *name3++) != 0) {
107
2.94M
      value = value ^ ((value << 5) + (value >> 3) + ch);
108
2.94M
  }
109
179k
    }
110
6.20M
    return (value % table->size);
111
6.20M
}
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
40.6k
       const xmlChar *prefix3, const xmlChar *name3) {
122
40.6k
    unsigned long value = 0L;
123
40.6k
    unsigned long ch;
124
125
#ifdef HASH_RANDOMIZATION
126
    value = table->random_seed;
127
#endif
128
40.6k
    if (prefix != NULL)
129
6.79k
  value += 30 * (*prefix);
130
33.8k
    else
131
33.8k
  value += 30 * (*name);
132
133
40.6k
    if (prefix != NULL) {
134
18.3k
  while ((ch = *prefix++) != 0) {
135
11.5k
      value = value ^ ((value << 5) + (value >> 3) + ch);
136
11.5k
  }
137
6.79k
  value = value ^ ((value << 5) + (value >> 3) + ':');
138
6.79k
    }
139
40.6k
    if (name != NULL) {
140
142k
  while ((ch = *name++) != 0) {
141
102k
      value = value ^ ((value << 5) + (value >> 3) + ch);
142
102k
  }
143
40.6k
    }
144
40.6k
    value = value ^ ((value << 5) + (value >> 3));
145
40.6k
    if (prefix2 != NULL) {
146
423k
  while ((ch = *prefix2++) != 0) {
147
418k
      value = value ^ ((value << 5) + (value >> 3) + ch);
148
418k
  }
149
5.01k
  value = value ^ ((value << 5) + (value >> 3) + ':');
150
5.01k
    }
151
40.6k
    if (name2 != NULL) {
152
23.0M
  while ((ch = *name2++) != 0) {
153
23.0M
      value = value ^ ((value << 5) + (value >> 3) + ch);
154
23.0M
  }
155
40.6k
    }
156
40.6k
    value = value ^ ((value << 5) + (value >> 3));
157
40.6k
    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
40.6k
    if (name3 != NULL) {
164
0
  while ((ch = *name3++) != 0) {
165
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
166
0
  }
167
0
    }
168
40.6k
    return (value % table->size);
169
40.6k
}
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
218k
xmlHashCreate(int size) {
181
218k
    xmlHashTablePtr table;
182
183
218k
    if (size <= 0)
184
86.9k
        size = 256;
185
186
218k
    table = xmlMalloc(sizeof(xmlHashTable));
187
218k
    if (table) {
188
217k
        table->dict = NULL;
189
217k
        table->size = size;
190
217k
  table->nbElems = 0;
191
217k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
192
217k
        if (table->table) {
193
217k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
194
#ifdef HASH_RANDOMIZATION
195
            table->random_seed = __xmlRandom();
196
#endif
197
217k
      return(table);
198
217k
        }
199
36
        xmlFree(table);
200
36
    }
201
1.04k
    return(NULL);
202
218k
}
203
204
/**
205
 * xmlHashCreateDict:
206
 * @size: the size of the hash table
207
 * @dict: a dictionary to use for the hash
208
 *
209
 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
210
 *
211
 * Returns the newly created object, or NULL if an error occurred.
212
 */
213
xmlHashTablePtr
214
80.7k
xmlHashCreateDict(int size, xmlDictPtr dict) {
215
80.7k
    xmlHashTablePtr table;
216
217
80.7k
    table = xmlHashCreate(size);
218
80.7k
    if (table != NULL) {
219
80.6k
        table->dict = dict;
220
80.6k
  xmlDictReference(dict);
221
80.6k
    }
222
80.7k
    return(table);
223
80.7k
}
224
225
/**
226
 * xmlHashGrow:
227
 * @table: the hash table
228
 * @size: the new size of the hash table
229
 *
230
 * resize the hash table
231
 *
232
 * Returns 0 in case of success, -1 in case of failure
233
 */
234
static int
235
1.43k
xmlHashGrow(xmlHashTablePtr table, int size) {
236
1.43k
    unsigned long key;
237
1.43k
    int oldsize, i;
238
1.43k
    xmlHashEntryPtr iter, next;
239
1.43k
    struct _xmlHashEntry *oldtable;
240
#ifdef DEBUG_GROW
241
    unsigned long nbElem = 0;
242
#endif
243
244
1.43k
    if (table == NULL)
245
0
  return(-1);
246
1.43k
    if (size < 8)
247
0
        return(-1);
248
1.43k
    if (size > 8 * 2048)
249
0
  return(-1);
250
251
1.43k
    oldsize = table->size;
252
1.43k
    oldtable = table->table;
253
1.43k
    if (oldtable == NULL)
254
0
        return(-1);
255
256
1.43k
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
257
1.43k
    if (table->table == NULL) {
258
1
  table->table = oldtable;
259
1
  return(-1);
260
1
    }
261
1.43k
    memset(table->table, 0, size * sizeof(xmlHashEntry));
262
1.43k
    table->size = size;
263
264
    /*  If the two loops are merged, there would be situations where
265
  a new entry needs to allocated and data copied into it from
266
  the main table. So instead, we run through the array twice, first
267
  copying all the elements in the main array (where we can't get
268
  conflicts) and then the rest, so we only free (and don't allocate)
269
    */
270
18.4k
    for (i = 0; i < oldsize; i++) {
271
17.0k
  if (oldtable[i].valid == 0)
272
2.55k
      continue;
273
14.4k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
274
14.4k
        oldtable[i].name3);
275
14.4k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
276
14.4k
  table->table[key].next = NULL;
277
14.4k
    }
278
279
18.4k
    for (i = 0; i < oldsize; i++) {
280
17.0k
  iter = oldtable[i].next;
281
72.8k
  while (iter) {
282
55.8k
      next = iter->next;
283
284
      /*
285
       * put back the entry in the new table
286
       */
287
288
55.8k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
289
55.8k
                        iter->name3);
290
55.8k
      if (table->table[key].valid == 0) {
291
38.6k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
292
38.6k
    table->table[key].next = NULL;
293
38.6k
    xmlFree(iter);
294
38.6k
      } else {
295
17.2k
    iter->next = table->table[key].next;
296
17.2k
    table->table[key].next = iter;
297
17.2k
      }
298
299
#ifdef DEBUG_GROW
300
      nbElem++;
301
#endif
302
303
55.8k
      iter = next;
304
55.8k
  }
305
17.0k
    }
306
307
1.43k
    xmlFree(oldtable);
308
309
#ifdef DEBUG_GROW
310
    xmlGenericError(xmlGenericErrorContext,
311
      "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
312
#endif
313
314
1.43k
    return(0);
315
1.43k
}
316
317
/**
318
 * xmlHashFree:
319
 * @table: the hash table
320
 * @f:  the deallocator function for items in the hash
321
 *
322
 * Free the hash @table and its contents. The userdata is
323
 * deallocated with @f if provided.
324
 */
325
void
326
283k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
327
283k
    int i;
328
283k
    xmlHashEntryPtr iter;
329
283k
    xmlHashEntryPtr next;
330
283k
    int inside_table = 0;
331
283k
    int nbElems;
332
333
283k
    if (table == NULL)
334
66.3k
  return;
335
217k
    if (table->table) {
336
217k
  nbElems = table->nbElems;
337
27.4M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
338
27.2M
      iter = &(table->table[i]);
339
27.2M
      if (iter->valid == 0)
340
25.6M
    continue;
341
1.60M
      inside_table = 1;
342
3.53M
      while (iter) {
343
1.93M
    next = iter->next;
344
1.93M
    if ((f != NULL) && (iter->payload != NULL))
345
390k
        f(iter->payload, iter->name);
346
1.93M
    if (table->dict == NULL) {
347
1.55M
        if (iter->name)
348
1.55M
      xmlFree(iter->name);
349
1.55M
        if (iter->name2)
350
339k
      xmlFree(iter->name2);
351
1.55M
        if (iter->name3)
352
0
      xmlFree(iter->name3);
353
1.55M
    }
354
1.93M
    iter->payload = NULL;
355
1.93M
    if (!inside_table)
356
332k
        xmlFree(iter);
357
1.93M
    nbElems--;
358
1.93M
    inside_table = 0;
359
1.93M
    iter = next;
360
1.93M
      }
361
1.60M
  }
362
217k
  xmlFree(table->table);
363
217k
    }
364
217k
    if (table->dict)
365
77.3k
        xmlDictFree(table->dict);
366
217k
    xmlFree(table);
367
217k
}
368
369
/**
370
 * xmlHashDefaultDeallocator:
371
 * @entry: the hash table entry
372
 * @name: the entry's name
373
 *
374
 * Free a hash table entry with xmlFree.
375
 */
376
void
377
141k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
378
141k
    xmlFree(entry);
379
141k
}
380
381
/**
382
 * xmlHashAddEntry:
383
 * @table: the hash table
384
 * @name: the name of the userdata
385
 * @userdata: a pointer to the userdata
386
 *
387
 * Add the @userdata to the hash @table. This can later be retrieved
388
 * by using the @name. Duplicate names generate errors.
389
 *
390
 * Returns 0 the addition succeeded and -1 in case of error.
391
 */
392
int
393
178k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
394
178k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
395
178k
}
396
397
/**
398
 * xmlHashAddEntry2:
399
 * @table: the hash table
400
 * @name: the name of the userdata
401
 * @name2: a second name of the userdata
402
 * @userdata: a pointer to the userdata
403
 *
404
 * Add the @userdata to the hash @table. This can later be retrieved
405
 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
406
 *
407
 * Returns 0 the addition succeeded and -1 in case of error.
408
 */
409
int
410
xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
411
1.75M
          const xmlChar *name2, void *userdata) {
412
1.75M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
413
1.75M
}
414
415
/**
416
 * xmlHashUpdateEntry:
417
 * @table: the hash table
418
 * @name: the name of the userdata
419
 * @userdata: a pointer to the userdata
420
 * @f: the deallocator function for replaced item (if any)
421
 *
422
 * Add the @userdata to the hash @table. This can later be retrieved
423
 * by using the @name. Existing entry for this @name will be removed
424
 * and freed with @f if found.
425
 *
426
 * Returns 0 the addition succeeded and -1 in case of error.
427
 */
428
int
429
xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
430
0
             void *userdata, xmlHashDeallocator f) {
431
0
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
432
0
}
433
434
/**
435
 * xmlHashUpdateEntry2:
436
 * @table: the hash table
437
 * @name: the name of the userdata
438
 * @name2: a second name of the userdata
439
 * @userdata: a pointer to the userdata
440
 * @f: the deallocator function for replaced item (if any)
441
 *
442
 * Add the @userdata to the hash @table. This can later be retrieved
443
 * by using the (@name, @name2) tuple. Existing entry for this tuple will
444
 * be removed and freed with @f if found.
445
 *
446
 * Returns 0 the addition succeeded and -1 in case of error.
447
 */
448
int
449
xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
450
             const xmlChar *name2, void *userdata,
451
55.1k
       xmlHashDeallocator f) {
452
55.1k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
453
55.1k
}
454
455
/**
456
 * xmlHashLookup:
457
 * @table: the hash table
458
 * @name: the name of the userdata
459
 *
460
 * Find the userdata specified by the @name.
461
 *
462
 * Returns the pointer to the userdata
463
 */
464
void *
465
1.14M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
466
1.14M
    return(xmlHashLookup3(table, name, NULL, NULL));
467
1.14M
}
468
469
/**
470
 * xmlHashLookup2:
471
 * @table: the hash table
472
 * @name: the name of the userdata
473
 * @name2: a second name of the userdata
474
 *
475
 * Find the userdata specified by the (@name, @name2) tuple.
476
 *
477
 * Returns the pointer to the userdata
478
 */
479
void *
480
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
481
1.83M
        const xmlChar *name2) {
482
1.83M
    return(xmlHashLookup3(table, name, name2, NULL));
483
1.83M
}
484
485
/**
486
 * xmlHashQLookup:
487
 * @table: the hash table
488
 * @prefix: the prefix of the userdata
489
 * @name: the name of the userdata
490
 *
491
 * Find the userdata specified by the QName @prefix:@name/@name.
492
 *
493
 * Returns the pointer to the userdata
494
 */
495
void *
496
xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
497
0
               const xmlChar *name) {
498
0
    return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
499
0
}
500
501
/**
502
 * xmlHashQLookup2:
503
 * @table: the hash table
504
 * @prefix: the prefix of the userdata
505
 * @name: the name of the userdata
506
 * @prefix2: the second prefix of the userdata
507
 * @name2: a second name of the userdata
508
 *
509
 * Find the userdata specified by the QNames tuple
510
 *
511
 * Returns the pointer to the userdata
512
 */
513
void *
514
xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
515
                const xmlChar *name, const xmlChar *prefix2,
516
40.6k
          const xmlChar *name2) {
517
40.6k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
518
40.6k
}
519
520
/**
521
 * xmlHashAddEntry3:
522
 * @table: the hash table
523
 * @name: the name of the userdata
524
 * @name2: a second name of the userdata
525
 * @name3: a third name of the userdata
526
 * @userdata: a pointer to the userdata
527
 *
528
 * Add the @userdata to the hash @table. This can later be retrieved
529
 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
530
 * errors.
531
 *
532
 * Returns 0 the addition succeeded and -1 in case of error.
533
 */
534
int
535
xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
536
           const xmlChar *name2, const xmlChar *name3,
537
2.10M
     void *userdata) {
538
2.10M
    unsigned long key, len = 0;
539
2.10M
    xmlHashEntryPtr entry;
540
2.10M
    xmlHashEntryPtr insert;
541
542
2.10M
    if ((table == NULL) || (name == NULL))
543
22.3k
  return(-1);
544
545
    /*
546
     * If using a dict internalize if needed
547
     */
548
2.08M
    if (table->dict) {
549
393k
        if (!xmlDictOwns(table->dict, name)) {
550
20.9k
      name = xmlDictLookup(table->dict, name, -1);
551
20.9k
      if (name == NULL)
552
2
          return(-1);
553
20.9k
  }
554
393k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
555
8.00k
      name2 = xmlDictLookup(table->dict, name2, -1);
556
8.00k
      if (name2 == NULL)
557
2
          return(-1);
558
8.00k
  }
559
393k
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
560
0
      name3 = xmlDictLookup(table->dict, name3, -1);
561
0
      if (name3 == NULL)
562
0
          return(-1);
563
0
  }
564
393k
    }
565
566
    /*
567
     * Check for duplicate and insertion location.
568
     */
569
2.08M
    key = xmlHashComputeKey(table, name, name2, name3);
570
2.08M
    if (table->table[key].valid == 0) {
571
1.54M
  insert = NULL;
572
1.54M
    } else {
573
541k
        if (table->dict) {
574
334k
      for (insert = &(table->table[key]); insert->next != NULL;
575
187k
     insert = insert->next) {
576
187k
    if ((insert->name == name) &&
577
187k
        (insert->name2 == name2) &&
578
187k
        (insert->name3 == name3))
579
1.82k
        return(-1);
580
185k
    len++;
581
185k
      }
582
146k
      if ((insert->name == name) &&
583
146k
    (insert->name2 == name2) &&
584
146k
    (insert->name3 == name3))
585
39.7k
    return(-1);
586
393k
  } else {
587
661k
      for (insert = &(table->table[key]); insert->next != NULL;
588
393k
     insert = insert->next) {
589
348k
    if ((xmlStrEqual(insert->name, name)) &&
590
348k
        (xmlStrEqual(insert->name2, name2)) &&
591
348k
        (xmlStrEqual(insert->name3, name3)))
592
79.9k
        return(-1);
593
268k
    len++;
594
268k
      }
595
313k
      if ((xmlStrEqual(insert->name, name)) &&
596
313k
    (xmlStrEqual(insert->name2, name2)) &&
597
313k
    (xmlStrEqual(insert->name3, name3)))
598
57.2k
    return(-1);
599
313k
  }
600
541k
    }
601
602
1.90M
    if (insert == NULL) {
603
1.54M
  entry = &(table->table[key]);
604
1.54M
    } else {
605
362k
  entry = xmlMalloc(sizeof(xmlHashEntry));
606
362k
  if (entry == NULL)
607
403
       return(-1);
608
362k
    }
609
610
1.90M
    if (table->dict != NULL) {
611
351k
        entry->name = (xmlChar *) name;
612
351k
        entry->name2 = (xmlChar *) name2;
613
351k
        entry->name3 = (xmlChar *) name3;
614
1.55M
    } else {
615
1.55M
  entry->name = xmlStrdup(name);
616
1.55M
        if (entry->name == NULL) {
617
524
            entry->name2 = NULL;
618
524
            goto error;
619
524
        }
620
1.55M
        if (name2 == NULL) {
621
1.21M
            entry->name2 = NULL;
622
1.21M
        } else {
623
339k
      entry->name2 = xmlStrdup(name2);
624
339k
            if (entry->name2 == NULL)
625
24
                goto error;
626
339k
        }
627
1.55M
        if (name3 == NULL) {
628
1.55M
            entry->name3 = NULL;
629
1.55M
        } else {
630
0
      entry->name3 = xmlStrdup(name3);
631
0
            if (entry->name3 == NULL)
632
0
                goto error;
633
0
        }
634
1.55M
    }
635
1.90M
    entry->payload = userdata;
636
1.90M
    entry->next = NULL;
637
1.90M
    entry->valid = 1;
638
639
640
1.90M
    if (insert != NULL)
641
362k
  insert->next = entry;
642
643
1.90M
    table->nbElems++;
644
645
1.90M
    if (len > MAX_HASH_LEN)
646
1.43k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
647
648
1.90M
    return(0);
649
650
548
error:
651
548
    xmlFree(entry->name2);
652
548
    xmlFree(entry->name);
653
548
    if (insert != NULL)
654
21
        xmlFree(entry);
655
548
    return(-1);
656
1.90M
}
657
658
/**
659
 * xmlHashUpdateEntry3:
660
 * @table: the hash table
661
 * @name: the name of the userdata
662
 * @name2: a second name of the userdata
663
 * @name3: a third name of the userdata
664
 * @userdata: a pointer to the userdata
665
 * @f: the deallocator function for replaced item (if any)
666
 *
667
 * Add the @userdata to the hash @table. This can later be retrieved
668
 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
669
 * will be removed and freed with @f if found.
670
 *
671
 * Returns 0 the addition succeeded and -1 in case of error.
672
 */
673
int
674
xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
675
             const xmlChar *name2, const xmlChar *name3,
676
83.1k
       void *userdata, xmlHashDeallocator f) {
677
83.1k
    unsigned long key;
678
83.1k
    xmlHashEntryPtr entry;
679
83.1k
    xmlHashEntryPtr insert;
680
681
83.1k
    if ((table == NULL) || name == NULL)
682
0
  return(-1);
683
684
    /*
685
     * If using a dict internalize if needed
686
     */
687
83.1k
    if (table->dict) {
688
55.0k
        if (!xmlDictOwns(table->dict, name)) {
689
0
      name = xmlDictLookup(table->dict, name, -1);
690
0
      if (name == NULL)
691
0
          return(-1);
692
0
  }
693
55.0k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
694
0
      name2 = xmlDictLookup(table->dict, name2, -1);
695
0
      if (name2 == NULL)
696
0
          return(-1);
697
0
  }
698
55.0k
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
699
0
      name3 = xmlDictLookup(table->dict, name3, -1);
700
0
      if (name3 == NULL)
701
0
          return(-1);
702
0
  }
703
55.0k
    }
704
705
    /*
706
     * Check for duplicate and insertion location.
707
     */
708
83.1k
    key = xmlHashComputeKey(table, name, name2, name3);
709
83.1k
    if (table->table[key].valid == 0) {
710
23.1k
  insert = NULL;
711
59.9k
    } else {
712
59.9k
        if (table ->dict) {
713
57.1k
      for (insert = &(table->table[key]); insert->next != NULL;
714
31.9k
     insert = insert->next) {
715
25.5k
    if ((insert->name == name) &&
716
25.5k
        (insert->name2 == name2) &&
717
25.5k
        (insert->name3 == name3)) {
718
265
        if (f)
719
0
      f(insert->payload, insert->name);
720
265
        insert->payload = userdata;
721
265
        return(0);
722
265
    }
723
25.5k
      }
724
31.6k
      if ((insert->name == name) &&
725
31.6k
    (insert->name2 == name2) &&
726
31.6k
    (insert->name3 == name3)) {
727
21.1k
    if (f)
728
0
        f(insert->payload, insert->name);
729
21.1k
    insert->payload = userdata;
730
21.1k
    return(0);
731
21.1k
      }
732
31.6k
  } else {
733
31.3k
      for (insert = &(table->table[key]); insert->next != NULL;
734
28.0k
     insert = insert->next) {
735
8.50k
    if ((xmlStrEqual(insert->name, name)) &&
736
8.50k
        (xmlStrEqual(insert->name2, name2)) &&
737
8.50k
        (xmlStrEqual(insert->name3, name3))) {
738
5.21k
        if (f)
739
0
      f(insert->payload, insert->name);
740
5.21k
        insert->payload = userdata;
741
5.21k
        return(0);
742
5.21k
    }
743
8.50k
      }
744
22.8k
      if ((xmlStrEqual(insert->name, name)) &&
745
22.8k
    (xmlStrEqual(insert->name2, name2)) &&
746
22.8k
    (xmlStrEqual(insert->name3, name3))) {
747
22.7k
    if (f)
748
0
        f(insert->payload, insert->name);
749
22.7k
    insert->payload = userdata;
750
22.7k
    return(0);
751
22.7k
      }
752
22.8k
  }
753
59.9k
    }
754
755
33.8k
    if (insert == NULL) {
756
23.1k
  entry =  &(table->table[key]);
757
23.1k
    } else {
758
10.6k
  entry = xmlMalloc(sizeof(xmlHashEntry));
759
10.6k
  if (entry == NULL)
760
1
       return(-1);
761
10.6k
    }
762
763
33.8k
    if (table->dict != NULL) {
764
33.6k
        entry->name = (xmlChar *) name;
765
33.6k
        entry->name2 = (xmlChar *) name2;
766
33.6k
        entry->name3 = (xmlChar *) name3;
767
33.6k
    } else {
768
164
  entry->name = xmlStrdup(name);
769
164
        if (entry->name == NULL) {
770
0
            entry->name2 = NULL;
771
0
            goto error;
772
0
        }
773
164
        if (name2 == NULL) {
774
0
            entry->name2 = NULL;
775
164
        } else {
776
164
      entry->name2 = xmlStrdup(name2);
777
164
            if (entry->name2 == NULL)
778
0
                goto error;
779
164
        }
780
164
        if (name3 == NULL) {
781
164
            entry->name3 = NULL;
782
164
        } else {
783
0
      entry->name3 = xmlStrdup(name3);
784
0
            if (entry->name3 == NULL)
785
0
                goto error;
786
0
        }
787
164
    }
788
33.8k
    entry->payload = userdata;
789
33.8k
    entry->next = NULL;
790
33.8k
    entry->valid = 1;
791
33.8k
    table->nbElems++;
792
793
794
33.8k
    if (insert != NULL) {
795
10.6k
  insert->next = entry;
796
10.6k
    }
797
33.8k
    return(0);
798
799
0
error:
800
0
    xmlFree(entry->name2);
801
0
    xmlFree(entry->name);
802
0
    if (insert != NULL)
803
0
        xmlFree(entry);
804
0
    return(-1);
805
33.8k
}
806
807
/**
808
 * xmlHashLookup3:
809
 * @table: the hash table
810
 * @name: the name of the userdata
811
 * @name2: a second name of the userdata
812
 * @name3: a third name of the userdata
813
 *
814
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
815
 *
816
 * Returns the a pointer to the userdata
817
 */
818
void *
819
xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
820
4.00M
         const xmlChar *name2, const xmlChar *name3) {
821
4.00M
    unsigned long key;
822
4.00M
    xmlHashEntryPtr entry;
823
824
4.00M
    if (table == NULL)
825
45.6k
  return(NULL);
826
3.96M
    if (name == NULL)
827
10
  return(NULL);
828
3.96M
    key = xmlHashComputeKey(table, name, name2, name3);
829
3.96M
    if (table->table[key].valid == 0)
830
1.28M
  return(NULL);
831
2.67M
    if (table->dict) {
832
1.56M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
833
1.32M
      if ((entry->name == name) &&
834
1.32M
    (entry->name2 == name2) &&
835
1.32M
    (entry->name3 == name3))
836
503k
    return(entry->payload);
837
1.32M
  }
838
750k
    }
839
5.06M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
840
4.25M
  if ((xmlStrEqual(entry->name, name)) &&
841
4.25M
      (xmlStrEqual(entry->name2, name2)) &&
842
4.25M
      (xmlStrEqual(entry->name3, name3)))
843
1.35M
      return(entry->payload);
844
4.25M
    }
845
813k
    return(NULL);
846
2.16M
}
847
848
/**
849
 * xmlHashQLookup3:
850
 * @table: the hash table
851
 * @prefix: the prefix of the userdata
852
 * @name: the name of the userdata
853
 * @prefix2: the second prefix of the userdata
854
 * @name2: a second name of the userdata
855
 * @prefix3: the third prefix of the userdata
856
 * @name3: a third name of the userdata
857
 *
858
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
859
 *
860
 * Returns the a pointer to the userdata
861
 */
862
void *
863
xmlHashQLookup3(xmlHashTablePtr table,
864
                const xmlChar *prefix, const xmlChar *name,
865
    const xmlChar *prefix2, const xmlChar *name2,
866
40.6k
    const xmlChar *prefix3, const xmlChar *name3) {
867
40.6k
    unsigned long key;
868
40.6k
    xmlHashEntryPtr entry;
869
870
40.6k
    if (table == NULL)
871
0
  return(NULL);
872
40.6k
    if (name == NULL)
873
0
  return(NULL);
874
40.6k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
875
40.6k
                             name2, prefix3, name3);
876
40.6k
    if (table->table[key].valid == 0)
877
17.5k
  return(NULL);
878
35.2k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
879
28.5k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
880
28.5k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
881
28.5k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
882
16.3k
      return(entry->payload);
883
28.5k
    }
884
6.72k
    return(NULL);
885
23.1k
}
886
887
typedef struct {
888
    xmlHashScanner hashscanner;
889
    void *data;
890
} stubData;
891
892
static void
893
stubHashScannerFull (void *payload, void *data, const xmlChar *name,
894
                     const xmlChar *name2 ATTRIBUTE_UNUSED,
895
12.1k
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
896
12.1k
    stubData *stubdata = (stubData *) data;
897
12.1k
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
898
12.1k
}
899
900
/**
901
 * xmlHashScan:
902
 * @table: the hash table
903
 * @f:  the scanner function for items in the hash
904
 * @data:  extra data passed to f
905
 *
906
 * Scan the hash @table and applied @f to each value.
907
 */
908
void
909
24.4k
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
910
24.4k
    stubData stubdata;
911
24.4k
    stubdata.data = data;
912
24.4k
    stubdata.hashscanner = f;
913
24.4k
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
914
24.4k
}
915
916
/**
917
 * xmlHashScanFull:
918
 * @table: the hash table
919
 * @f:  the scanner function for items in the hash
920
 * @data:  extra data passed to f
921
 *
922
 * Scan the hash @table and applied @f to each value.
923
 */
924
void
925
36.4k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
926
36.4k
    int i, nb;
927
36.4k
    xmlHashEntryPtr iter;
928
36.4k
    xmlHashEntryPtr next;
929
930
36.4k
    if (table == NULL)
931
2.82k
  return;
932
33.5k
    if (f == NULL)
933
0
  return;
934
935
33.5k
    if (table->table) {
936
3.60M
  for(i = 0; i < table->size; i++) {
937
3.57M
      if (table->table[i].valid == 0)
938
3.53M
    continue;
939
40.9k
      iter = &(table->table[i]);
940
89.9k
      while (iter) {
941
48.9k
    next = iter->next;
942
48.9k
                nb = table->nbElems;
943
48.9k
    if ((f != NULL) && (iter->payload != NULL))
944
48.9k
        f(iter->payload, data, iter->name,
945
48.9k
          iter->name2, iter->name3);
946
48.9k
                if (nb != table->nbElems) {
947
                    /* table was modified by the callback, be careful */
948
3.33k
                    if (iter == &(table->table[i])) {
949
2.05k
                        if (table->table[i].valid == 0)
950
1.23k
                            iter = NULL;
951
2.05k
                        if (table->table[i].next != next)
952
823
          iter = &(table->table[i]);
953
2.05k
                    } else
954
1.27k
            iter = next;
955
3.33k
                } else
956
45.6k
        iter = next;
957
48.9k
      }
958
40.9k
  }
959
33.5k
    }
960
33.5k
}
961
962
/**
963
 * xmlHashScan3:
964
 * @table: the hash table
965
 * @name: the name of the userdata or NULL
966
 * @name2: a second name of the userdata or NULL
967
 * @name3: a third name of the userdata or NULL
968
 * @f:  the scanner function for items in the hash
969
 * @data:  extra data passed to f
970
 *
971
 * Scan the hash @table and applied @f to each value matching
972
 * (@name, @name2, @name3) tuple. If one of the names is null,
973
 * the comparison is considered to match.
974
 */
975
void
976
xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
977
       const xmlChar *name2, const xmlChar *name3,
978
0
       xmlHashScanner f, void *data) {
979
0
    stubData stubdata;
980
0
    stubdata.data = data;
981
0
    stubdata.hashscanner = f;
982
0
    xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
983
0
                     &stubdata);
984
0
}
985
986
/**
987
 * xmlHashScanFull3:
988
 * @table: the hash table
989
 * @name: the name of the userdata or NULL
990
 * @name2: a second name of the userdata or NULL
991
 * @name3: a third name of the userdata or NULL
992
 * @f:  the scanner function for items in the hash
993
 * @data:  extra data passed to f
994
 *
995
 * Scan the hash @table and applied @f to each value matching
996
 * (@name, @name2, @name3) tuple. If one of the names is null,
997
 * the comparison is considered to match.
998
 */
999
void
1000
xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
1001
     const xmlChar *name2, const xmlChar *name3,
1002
0
     xmlHashScannerFull f, void *data) {
1003
0
    int i;
1004
0
    xmlHashEntryPtr iter;
1005
0
    xmlHashEntryPtr next;
1006
1007
0
    if (table == NULL)
1008
0
  return;
1009
0
    if (f == NULL)
1010
0
  return;
1011
1012
0
    if (table->table) {
1013
0
  for(i = 0; i < table->size; i++) {
1014
0
      if (table->table[i].valid == 0)
1015
0
    continue;
1016
0
      iter = &(table->table[i]);
1017
0
      while (iter) {
1018
0
    next = iter->next;
1019
0
    if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
1020
0
        ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
1021
0
        ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
1022
0
        (iter->payload != NULL)) {
1023
0
        f(iter->payload, data, iter->name,
1024
0
          iter->name2, iter->name3);
1025
0
    }
1026
0
    iter = next;
1027
0
      }
1028
0
  }
1029
0
    }
1030
0
}
1031
1032
/**
1033
 * xmlHashCopy:
1034
 * @table: the hash table
1035
 * @f:  the copier function for items in the hash
1036
 *
1037
 * Scan the hash @table and applied @f to each value.
1038
 *
1039
 * Returns the new table or NULL in case of error.
1040
 */
1041
xmlHashTablePtr
1042
0
xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
1043
0
    int i;
1044
0
    xmlHashEntryPtr iter;
1045
0
    xmlHashEntryPtr next;
1046
0
    xmlHashTablePtr ret;
1047
1048
0
    if (table == NULL)
1049
0
  return(NULL);
1050
0
    if (f == NULL)
1051
0
  return(NULL);
1052
1053
0
    ret = xmlHashCreate(table->size);
1054
0
    if (ret == NULL)
1055
0
        return(NULL);
1056
1057
0
    if (table->table) {
1058
0
  for(i = 0; i < table->size; i++) {
1059
0
      if (table->table[i].valid == 0)
1060
0
    continue;
1061
0
      iter = &(table->table[i]);
1062
0
      while (iter) {
1063
0
    next = iter->next;
1064
0
    xmlHashAddEntry3(ret, iter->name, iter->name2,
1065
0
               iter->name3, f(iter->payload, iter->name));
1066
0
    iter = next;
1067
0
      }
1068
0
  }
1069
0
    }
1070
0
    ret->nbElems = table->nbElems;
1071
0
    return(ret);
1072
0
}
1073
1074
/**
1075
 * xmlHashSize:
1076
 * @table: the hash table
1077
 *
1078
 * Query the number of elements installed in the hash @table.
1079
 *
1080
 * Returns the number of elements in the hash table or
1081
 * -1 in case of error
1082
 */
1083
int
1084
8.56k
xmlHashSize(xmlHashTablePtr table) {
1085
8.56k
    if (table == NULL)
1086
0
  return(-1);
1087
8.56k
    return(table->nbElems);
1088
8.56k
}
1089
1090
/**
1091
 * xmlHashRemoveEntry:
1092
 * @table: the hash table
1093
 * @name: the name of the userdata
1094
 * @f: the deallocator function for removed item (if any)
1095
 *
1096
 * Find the userdata specified by the @name and remove
1097
 * it from the hash @table. Existing userdata for this tuple will be removed
1098
 * and freed with @f.
1099
 *
1100
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1101
 */
1102
int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
1103
106
           xmlHashDeallocator f) {
1104
106
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1105
106
}
1106
1107
/**
1108
 * xmlHashRemoveEntry2:
1109
 * @table: the hash table
1110
 * @name: the name of the userdata
1111
 * @name2: a second name of the userdata
1112
 * @f: the deallocator function for removed item (if any)
1113
 *
1114
 * Find the userdata specified by the (@name, @name2) tuple and remove
1115
 * it from the hash @table. Existing userdata for this tuple will be removed
1116
 * and freed with @f.
1117
 *
1118
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1119
 */
1120
int
1121
xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
1122
4.86k
      const xmlChar *name2, xmlHashDeallocator f) {
1123
4.86k
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1124
4.86k
}
1125
1126
/**
1127
 * xmlHashRemoveEntry3:
1128
 * @table: the hash table
1129
 * @name: the name of the userdata
1130
 * @name2: a second name of the userdata
1131
 * @name3: a third name of the userdata
1132
 * @f: the deallocator function for removed item (if any)
1133
 *
1134
 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1135
 * it from the hash @table. Existing userdata for this tuple will be removed
1136
 * and freed with @f.
1137
 *
1138
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1139
 */
1140
int
1141
xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
1142
4.97k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1143
4.97k
    unsigned long key;
1144
4.97k
    xmlHashEntryPtr entry;
1145
4.97k
    xmlHashEntryPtr prev = NULL;
1146
1147
4.97k
    if (table == NULL || name == NULL)
1148
0
        return(-1);
1149
1150
4.97k
    key = xmlHashComputeKey(table, name, name2, name3);
1151
4.97k
    if (table->table[key].valid == 0) {
1152
0
        return(-1);
1153
4.97k
    } else {
1154
6.73k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1155
6.73k
            if (xmlStrEqual(entry->name, name) &&
1156
6.73k
                    xmlStrEqual(entry->name2, name2) &&
1157
6.73k
                    xmlStrEqual(entry->name3, name3)) {
1158
4.97k
                if ((f != NULL) && (entry->payload != NULL))
1159
106
                    f(entry->payload, entry->name);
1160
4.97k
                entry->payload = NULL;
1161
4.97k
    if (table->dict == NULL) {
1162
1.53k
        if(entry->name)
1163
1.53k
      xmlFree(entry->name);
1164
1.53k
        if(entry->name2)
1165
0
      xmlFree(entry->name2);
1166
1.53k
        if(entry->name3)
1167
0
      xmlFree(entry->name3);
1168
1.53k
    }
1169
4.97k
                if(prev) {
1170
1.27k
                    prev->next = entry->next;
1171
1.27k
        xmlFree(entry);
1172
3.70k
    } else {
1173
3.70k
        if (entry->next == NULL) {
1174
2.87k
      entry->valid = 0;
1175
2.87k
        } else {
1176
823
      entry = entry->next;
1177
823
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1178
823
      xmlFree(entry);
1179
823
        }
1180
3.70k
    }
1181
4.97k
                table->nbElems--;
1182
4.97k
                return(0);
1183
4.97k
            }
1184
1.76k
            prev = entry;
1185
1.76k
        }
1186
0
        return(-1);
1187
4.97k
    }
1188
4.97k
}
1189