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.58M
#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.61M
            const xmlChar *name2, const xmlChar *name3) {
86
6.61M
    unsigned long value = 0L;
87
6.61M
    unsigned long ch;
88
89
#ifdef HASH_RANDOMIZATION
90
    value = table->random_seed;
91
#endif
92
6.61M
    if (name != NULL) {
93
6.61M
  value += 30 * (*name);
94
246M
  while ((ch = *name++) != 0) {
95
239M
      value = value ^ ((value << 5) + (value >> 3) + ch);
96
239M
  }
97
6.61M
    }
98
6.61M
    value = value ^ ((value << 5) + (value >> 3));
99
6.61M
    if (name2 != NULL) {
100
56.3M
  while ((ch = *name2++) != 0) {
101
54.4M
      value = value ^ ((value << 5) + (value >> 3) + ch);
102
54.4M
  }
103
1.88M
    }
104
6.61M
    value = value ^ ((value << 5) + (value >> 3));
105
6.61M
    if (name3 != NULL) {
106
1.15M
  while ((ch = *name3++) != 0) {
107
1.08M
      value = value ^ ((value << 5) + (value >> 3) + ch);
108
1.08M
  }
109
73.9k
    }
110
6.61M
    return (value % table->size);
111
6.61M
}
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
18.5k
       const xmlChar *prefix3, const xmlChar *name3) {
122
18.5k
    unsigned long value = 0L;
123
18.5k
    unsigned long ch;
124
125
#ifdef HASH_RANDOMIZATION
126
    value = table->random_seed;
127
#endif
128
18.5k
    if (prefix != NULL)
129
2.08k
  value += 30 * (*prefix);
130
16.4k
    else
131
16.4k
  value += 30 * (*name);
132
133
18.5k
    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
18.5k
    if (name != NULL) {
140
61.6k
  while ((ch = *name++) != 0) {
141
43.1k
      value = value ^ ((value << 5) + (value >> 3) + ch);
142
43.1k
  }
143
18.5k
    }
144
18.5k
    value = value ^ ((value << 5) + (value >> 3));
145
18.5k
    if (prefix2 != NULL) {
146
8.84k
  while ((ch = *prefix2++) != 0) {
147
7.10k
      value = value ^ ((value << 5) + (value >> 3) + ch);
148
7.10k
  }
149
1.74k
  value = value ^ ((value << 5) + (value >> 3) + ':');
150
1.74k
    }
151
18.5k
    if (name2 != NULL) {
152
91.8k
  while ((ch = *name2++) != 0) {
153
73.3k
      value = value ^ ((value << 5) + (value >> 3) + ch);
154
73.3k
  }
155
18.5k
    }
156
18.5k
    value = value ^ ((value << 5) + (value >> 3));
157
18.5k
    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
18.5k
    if (name3 != NULL) {
164
0
  while ((ch = *name3++) != 0) {
165
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
166
0
  }
167
0
    }
168
18.5k
    return (value % table->size);
169
18.5k
}
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
260k
xmlHashCreate(int size) {
181
260k
    xmlHashTablePtr table;
182
183
260k
    xmlInitParser();
184
185
260k
    if (size <= 0)
186
120k
        size = 256;
187
188
260k
    table = xmlMalloc(sizeof(xmlHashTable));
189
260k
    if (table) {
190
258k
        table->dict = NULL;
191
258k
        table->size = size;
192
258k
  table->nbElems = 0;
193
258k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
194
258k
        if (table->table) {
195
258k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
196
#ifdef HASH_RANDOMIZATION
197
            table->random_seed = __xmlRandom();
198
#endif
199
258k
      return(table);
200
258k
        }
201
34
        xmlFree(table);
202
34
    }
203
1.98k
    return(NULL);
204
260k
}
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.7k
xmlHashCreateDict(int size, xmlDictPtr dict) {
217
82.7k
    xmlHashTablePtr table;
218
219
82.7k
    table = xmlHashCreate(size);
220
82.7k
    if (table != NULL) {
221
82.6k
        table->dict = dict;
222
82.6k
  xmlDictReference(dict);
223
82.6k
    }
224
82.7k
    return(table);
225
82.7k
}
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
378k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
329
378k
    int i;
330
378k
    xmlHashEntryPtr iter;
331
378k
    xmlHashEntryPtr next;
332
378k
    int inside_table = 0;
333
378k
    int nbElems;
334
335
378k
    if (table == NULL)
336
120k
  return;
337
258k
    if (table->table) {
338
258k
  nbElems = table->nbElems;
339
36.0M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
340
35.7M
      iter = &(table->table[i]);
341
35.7M
      if (iter->valid == 0)
342
33.5M
    continue;
343
2.26M
      inside_table = 1;
344
4.87M
      while (iter) {
345
2.60M
    next = iter->next;
346
2.60M
    if ((f != NULL) && (iter->payload != NULL))
347
306k
        f(iter->payload, iter->name);
348
2.60M
    if (table->dict == NULL) {
349
2.41M
        if (iter->name)
350
2.41M
      xmlFree(iter->name);
351
2.41M
        if (iter->name2)
352
421k
      xmlFree(iter->name2);
353
2.41M
        if (iter->name3)
354
236
      xmlFree(iter->name3);
355
2.41M
    }
356
2.60M
    iter->payload = NULL;
357
2.60M
    if (!inside_table)
358
337k
        xmlFree(iter);
359
2.60M
    nbElems--;
360
2.60M
    inside_table = 0;
361
2.60M
    iter = next;
362
2.60M
      }
363
2.26M
  }
364
258k
  xmlFree(table->table);
365
258k
    }
366
258k
    if (table->dict)
367
78.1k
        xmlDictFree(table->dict);
368
258k
    xmlFree(table);
369
258k
}
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
149k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
380
149k
    xmlFree(entry);
381
149k
}
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
228k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
396
228k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
397
228k
}
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.40M
          const xmlChar *name2, void *userdata) {
414
2.40M
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
415
2.40M
}
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
4.38k
             void *userdata, xmlHashDeallocator f) {
433
4.38k
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
434
4.38k
}
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
33.8k
       xmlHashDeallocator f) {
454
33.8k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
455
33.8k
}
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.65M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
468
1.65M
    return(xmlHashLookup3(table, name, NULL, NULL));
469
1.65M
}
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.58M
        const xmlChar *name2) {
484
1.58M
    return(xmlHashLookup3(table, name, name2, NULL));
485
1.58M
}
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
18.5k
          const xmlChar *name2) {
519
18.5k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
520
18.5k
}
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.70M
     void *userdata) {
540
2.70M
    unsigned long key, len = 0;
541
2.70M
    xmlHashEntryPtr entry;
542
2.70M
    xmlHashEntryPtr insert;
543
544
2.70M
    if ((table == NULL) || (name == NULL))
545
11.0k
  return(-1);
546
547
    /*
548
     * If using a dict internalize if needed
549
     */
550
2.69M
    if (table->dict) {
551
218k
        if (!xmlDictOwns(table->dict, name)) {
552
37.7k
      name = xmlDictLookup(table->dict, name, -1);
553
37.7k
      if (name == NULL)
554
2
          return(-1);
555
37.7k
  }
556
218k
        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
218k
        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
218k
    }
567
568
    /*
569
     * Check for duplicate and insertion location.
570
     */
571
2.69M
    key = xmlHashComputeKey(table, name, name2, name3);
572
2.69M
    if (table->table[key].valid == 0) {
573
2.21M
  insert = NULL;
574
2.21M
    } else {
575
472k
        if (table->dict) {
576
122k
      for (insert = &(table->table[key]); insert->next != NULL;
577
82.1k
     insert = insert->next) {
578
40.7k
    if ((insert->name == name) &&
579
40.7k
        (insert->name2 == name2) &&
580
40.7k
        (insert->name3 == name3))
581
861
        return(-1);
582
39.8k
    len++;
583
39.8k
      }
584
81.2k
      if ((insert->name == name) &&
585
81.2k
    (insert->name2 == name2) &&
586
81.2k
    (insert->name3 == name3))
587
48.4k
    return(-1);
588
390k
  } else {
589
763k
      for (insert = &(table->table[key]); insert->next != NULL;
590
393k
     insert = insert->next) {
591
393k
    if ((xmlStrEqual(insert->name, name)) &&
592
393k
        (xmlStrEqual(insert->name2, name2)) &&
593
393k
        (xmlStrEqual(insert->name3, name3)))
594
21.0k
        return(-1);
595
372k
    len++;
596
372k
      }
597
369k
      if ((xmlStrEqual(insert->name, name)) &&
598
369k
    (xmlStrEqual(insert->name2, name2)) &&
599
369k
    (xmlStrEqual(insert->name3, name3)))
600
35.1k
    return(-1);
601
369k
  }
602
472k
    }
603
604
2.58M
    if (insert == NULL) {
605
2.21M
  entry = &(table->table[key]);
606
2.21M
    } else {
607
367k
  entry = xmlMalloc(sizeof(xmlHashEntry));
608
367k
  if (entry == NULL)
609
319
       return(-1);
610
367k
    }
611
612
2.58M
    if (table->dict != NULL) {
613
168k
        entry->name = (xmlChar *) name;
614
168k
        entry->name2 = (xmlChar *) name2;
615
168k
        entry->name3 = (xmlChar *) name3;
616
2.41M
    } else {
617
2.41M
  entry->name = xmlStrdup(name);
618
2.41M
        if (entry->name == NULL) {
619
1.21k
            entry->name2 = NULL;
620
1.21k
            goto error;
621
1.21k
        }
622
2.41M
        if (name2 == NULL) {
623
1.99M
            entry->name2 = NULL;
624
1.99M
        } else {
625
421k
      entry->name2 = xmlStrdup(name2);
626
421k
            if (entry->name2 == NULL)
627
23
                goto error;
628
421k
        }
629
2.41M
        if (name3 == NULL) {
630
2.41M
            entry->name3 = NULL;
631
2.41M
        } else {
632
239
      entry->name3 = xmlStrdup(name3);
633
239
            if (entry->name3 == NULL)
634
3
                goto error;
635
239
        }
636
2.41M
    }
637
2.58M
    entry->payload = userdata;
638
2.58M
    entry->next = NULL;
639
2.58M
    entry->valid = 1;
640
641
642
2.58M
    if (insert != NULL)
643
367k
  insert->next = entry;
644
645
2.58M
    table->nbElems++;
646
647
2.58M
    if (len > MAX_HASH_LEN)
648
2.24k
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
649
650
2.58M
    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.58M
}
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
52.6k
       void *userdata, xmlHashDeallocator f) {
679
52.6k
    unsigned long key;
680
52.6k
    xmlHashEntryPtr entry;
681
52.6k
    xmlHashEntryPtr insert;
682
683
52.6k
    if ((table == NULL) || name == NULL)
684
0
  return(-1);
685
686
    /*
687
     * If using a dict internalize if needed
688
     */
689
52.6k
    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
52.6k
    key = xmlHashComputeKey(table, name, name2, name3);
711
52.6k
    if (table->table[key].valid == 0) {
712
26.4k
  insert = NULL;
713
26.4k
    } else {
714
26.1k
        if (table ->dict) {
715
13.7k
      for (insert = &(table->table[key]); insert->next != NULL;
716
10.7k
     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.51k
    if (f)
730
0
        f(insert->payload, insert->name);
731
6.51k
    insert->payload = userdata;
732
6.51k
    return(0);
733
6.51k
      }
734
15.4k
  } else {
735
17.5k
      for (insert = &(table->table[key]); insert->next != NULL;
736
15.4k
     insert = insert->next) {
737
3.01k
    if ((xmlStrEqual(insert->name, name)) &&
738
3.01k
        (xmlStrEqual(insert->name2, name2)) &&
739
3.01k
        (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
3.01k
      }
746
14.5k
      if ((xmlStrEqual(insert->name, name)) &&
747
14.5k
    (xmlStrEqual(insert->name2, name2)) &&
748
14.5k
    (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
14.5k
  }
755
26.1k
    }
756
757
31.5k
    if (insert == NULL) {
758
26.4k
  entry =  &(table->table[key]);
759
26.4k
    } else {
760
5.04k
  entry = xmlMalloc(sizeof(xmlHashEntry));
761
5.04k
  if (entry == NULL)
762
1
       return(-1);
763
5.04k
    }
764
765
31.5k
    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
6.31k
  entry->name = xmlStrdup(name);
771
6.31k
        if (entry->name == NULL) {
772
0
            entry->name2 = NULL;
773
0
            goto error;
774
0
        }
775
6.31k
        if (name2 == NULL) {
776
5.98k
            entry->name2 = NULL;
777
5.98k
        } else {
778
328
      entry->name2 = xmlStrdup(name2);
779
328
            if (entry->name2 == NULL)
780
0
                goto error;
781
328
        }
782
6.31k
        if (name3 == NULL) {
783
6.31k
            entry->name3 = NULL;
784
6.31k
        } else {
785
0
      entry->name3 = xmlStrdup(name3);
786
0
            if (entry->name3 == NULL)
787
0
                goto error;
788
0
        }
789
6.31k
    }
790
31.5k
    entry->payload = userdata;
791
31.5k
    entry->next = NULL;
792
31.5k
    entry->valid = 1;
793
31.5k
    table->nbElems++;
794
795
796
31.5k
    if (insert != NULL) {
797
5.03k
  insert->next = entry;
798
5.03k
    }
799
31.5k
    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
31.5k
}
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.92M
         const xmlChar *name2, const xmlChar *name3) {
823
3.92M
    unsigned long key;
824
3.92M
    xmlHashEntryPtr entry;
825
826
3.92M
    if (table == NULL)
827
134k
  return(NULL);
828
3.79M
    if (name == NULL)
829
9
  return(NULL);
830
3.79M
    key = xmlHashComputeKey(table, name, name2, name3);
831
3.79M
    if (table->table[key].valid == 0)
832
1.11M
  return(NULL);
833
2.68M
    if (table->dict) {
834
1.15M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
835
772k
      if ((entry->name == name) &&
836
772k
    (entry->name2 == name2) &&
837
772k
    (entry->name3 == name3))
838
264k
    return(entry->payload);
839
772k
  }
840
647k
    }
841
4.74M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
842
4.09M
  if ((xmlStrEqual(entry->name, name)) &&
843
4.09M
      (xmlStrEqual(entry->name2, name2)) &&
844
4.09M
      (xmlStrEqual(entry->name3, name3)))
845
1.76M
      return(entry->payload);
846
4.09M
    }
847
648k
    return(NULL);
848
2.41M
}
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
18.5k
    const xmlChar *prefix3, const xmlChar *name3) {
869
18.5k
    unsigned long key;
870
18.5k
    xmlHashEntryPtr entry;
871
872
18.5k
    if (table == NULL)
873
0
  return(NULL);
874
18.5k
    if (name == NULL)
875
0
  return(NULL);
876
18.5k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
877
18.5k
                             name2, prefix3, name3);
878
18.5k
    if (table->table[key].valid == 0)
879
6.98k
  return(NULL);
880
14.6k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
881
12.7k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
882
12.7k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
883
12.7k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
884
9.63k
      return(entry->payload);
885
12.7k
    }
886
1.90k
    return(NULL);
887
11.5k
}
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.55k
xmlHashSize(xmlHashTablePtr table) {
1087
4.55k
    if (table == NULL)
1088
0
  return(-1);
1089
4.55k
    return(table->nbElems);
1090
4.55k
}
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.41k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1145
9.41k
    unsigned long key;
1146
9.41k
    xmlHashEntryPtr entry;
1147
9.41k
    xmlHashEntryPtr prev = NULL;
1148
1149
9.41k
    if (table == NULL || name == NULL)
1150
0
        return(-1);
1151
1152
9.41k
    key = xmlHashComputeKey(table, name, name2, name3);
1153
9.41k
    if (table->table[key].valid == 0) {
1154
3
        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.41k
}
1191