Coverage Report

Created: 2023-03-26 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
10.0k
#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
33.8k
            const xmlChar *name2, const xmlChar *name3) {
86
33.8k
    unsigned long value = 0L;
87
33.8k
    unsigned long ch;
88
89
#ifdef HASH_RANDOMIZATION
90
    value = table->random_seed;
91
#endif
92
33.8k
    if (name != NULL) {
93
33.8k
  value += 30 * (*name);
94
244k
  while ((ch = *name++) != 0) {
95
210k
      value = value ^ ((value << 5) + (value >> 3) + ch);
96
210k
  }
97
33.8k
    }
98
33.8k
    value = value ^ ((value << 5) + (value >> 3));
99
33.8k
    if (name2 != NULL) {
100
474k
  while ((ch = *name2++) != 0) {
101
457k
      value = value ^ ((value << 5) + (value >> 3) + ch);
102
457k
  }
103
17.1k
    }
104
33.8k
    value = value ^ ((value << 5) + (value >> 3));
105
33.8k
    if (name3 != NULL) {
106
0
  while ((ch = *name3++) != 0) {
107
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
108
0
  }
109
0
    }
110
33.8k
    return (value % table->size);
111
33.8k
}
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
0
       const xmlChar *prefix3, const xmlChar *name3) {
122
0
    unsigned long value = 0L;
123
0
    unsigned long ch;
124
125
#ifdef HASH_RANDOMIZATION
126
    value = table->random_seed;
127
#endif
128
0
    if (prefix != NULL)
129
0
  value += 30 * (*prefix);
130
0
    else
131
0
  value += 30 * (*name);
132
133
0
    if (prefix != NULL) {
134
0
  while ((ch = *prefix++) != 0) {
135
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
136
0
  }
137
0
  value = value ^ ((value << 5) + (value >> 3) + ':');
138
0
    }
139
0
    if (name != NULL) {
140
0
  while ((ch = *name++) != 0) {
141
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
142
0
  }
143
0
    }
144
0
    value = value ^ ((value << 5) + (value >> 3));
145
0
    if (prefix2 != NULL) {
146
0
  while ((ch = *prefix2++) != 0) {
147
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
148
0
  }
149
0
  value = value ^ ((value << 5) + (value >> 3) + ':');
150
0
    }
151
0
    if (name2 != NULL) {
152
0
  while ((ch = *name2++) != 0) {
153
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
154
0
  }
155
0
    }
156
0
    value = value ^ ((value << 5) + (value >> 3));
157
0
    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
0
    if (name3 != NULL) {
164
0
  while ((ch = *name3++) != 0) {
165
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
166
0
  }
167
0
    }
168
0
    return (value % table->size);
169
0
}
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
789
xmlHashCreate(int size) {
181
789
    xmlHashTablePtr table;
182
183
789
    if (size <= 0)
184
311
        size = 256;
185
186
789
    table = xmlMalloc(sizeof(xmlHashTable));
187
789
    if (table) {
188
789
        table->dict = NULL;
189
789
        table->size = size;
190
789
  table->nbElems = 0;
191
789
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
192
789
        if (table->table) {
193
789
      memset(table->table, 0, size * sizeof(xmlHashEntry));
194
#ifdef HASH_RANDOMIZATION
195
            table->random_seed = __xmlRandom();
196
#endif
197
789
      return(table);
198
789
        }
199
0
        xmlFree(table);
200
0
    }
201
0
    return(NULL);
202
789
}
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
4
xmlHashCreateDict(int size, xmlDictPtr dict) {
215
4
    xmlHashTablePtr table;
216
217
4
    table = xmlHashCreate(size);
218
4
    if (table != NULL) {
219
4
        table->dict = dict;
220
4
  xmlDictReference(dict);
221
4
    }
222
4
    return(table);
223
4
}
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
6
xmlHashGrow(xmlHashTablePtr table, int size) {
236
6
    unsigned long key;
237
6
    int oldsize, i;
238
6
    xmlHashEntryPtr iter, next;
239
6
    struct _xmlHashEntry *oldtable;
240
#ifdef DEBUG_GROW
241
    unsigned long nbElem = 0;
242
#endif
243
244
6
    if (table == NULL)
245
0
  return(-1);
246
6
    if (size < 8)
247
0
        return(-1);
248
6
    if (size > 8 * 2048)
249
0
  return(-1);
250
251
6
    oldsize = table->size;
252
6
    oldtable = table->table;
253
6
    if (oldtable == NULL)
254
0
        return(-1);
255
256
6
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
257
6
    if (table->table == NULL) {
258
0
  table->table = oldtable;
259
0
  return(-1);
260
0
    }
261
6
    memset(table->table, 0, size * sizeof(xmlHashEntry));
262
6
    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
33
    for (i = 0; i < oldsize; i++) {
271
27
  if (oldtable[i].valid == 0)
272
0
      continue;
273
27
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
274
27
        oldtable[i].name3);
275
27
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
276
27
  table->table[key].next = NULL;
277
27
    }
278
279
33
    for (i = 0; i < oldsize; i++) {
280
27
  iter = oldtable[i].next;
281
243
  while (iter) {
282
216
      next = iter->next;
283
284
      /*
285
       * put back the entry in the new table
286
       */
287
288
216
      key = xmlHashComputeKey(table, iter->name, iter->name2,
289
216
                        iter->name3);
290
216
      if (table->table[key].valid == 0) {
291
135
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
292
135
    table->table[key].next = NULL;
293
135
    xmlFree(iter);
294
135
      } else {
295
81
    iter->next = table->table[key].next;
296
81
    table->table[key].next = iter;
297
81
      }
298
299
#ifdef DEBUG_GROW
300
      nbElem++;
301
#endif
302
303
216
      iter = next;
304
216
  }
305
27
    }
306
307
6
    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
6
    return(0);
315
6
}
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
1.08k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
327
1.08k
    int i;
328
1.08k
    xmlHashEntryPtr iter;
329
1.08k
    xmlHashEntryPtr next;
330
1.08k
    int inside_table = 0;
331
1.08k
    int nbElems;
332
333
1.08k
    if (table == NULL)
334
306
  return;
335
779
    if (table->table) {
336
779
  nbElems = table->nbElems;
337
74.9k
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
338
74.1k
      iter = &(table->table[i]);
339
74.1k
      if (iter->valid == 0)
340
64.9k
    continue;
341
9.19k
      inside_table = 1;
342
21.4k
      while (iter) {
343
12.2k
    next = iter->next;
344
12.2k
    if ((f != NULL) && (iter->payload != NULL))
345
2.92k
        f(iter->payload, iter->name);
346
12.2k
    if (table->dict == NULL) {
347
12.2k
        if (iter->name)
348
12.2k
      xmlFree(iter->name);
349
12.2k
        if (iter->name2)
350
3.80k
      xmlFree(iter->name2);
351
12.2k
        if (iter->name3)
352
0
      xmlFree(iter->name3);
353
12.2k
    }
354
12.2k
    iter->payload = NULL;
355
12.2k
    if (!inside_table)
356
3.02k
        xmlFree(iter);
357
12.2k
    nbElems--;
358
12.2k
    inside_table = 0;
359
12.2k
    iter = next;
360
12.2k
      }
361
9.19k
  }
362
779
  xmlFree(table->table);
363
779
    }
364
779
    if (table->dict)
365
4
        xmlDictFree(table->dict);
366
779
    xmlFree(table);
367
779
}
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
1.67k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
378
1.67k
    xmlFree(entry);
379
1.67k
}
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
706
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
394
706
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
395
706
}
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
9.35k
          const xmlChar *name2, void *userdata) {
412
9.35k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
413
9.35k
}
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
1.67k
             void *userdata, xmlHashDeallocator f) {
431
1.67k
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
432
1.67k
}
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
772
       xmlHashDeallocator f) {
452
772
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
453
772
}
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
7.87k
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
466
7.87k
    return(xmlHashLookup3(table, name, NULL, NULL));
467
7.87k
}
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
13.1k
        const xmlChar *name2) {
482
13.1k
    return(xmlHashLookup3(table, name, name2, NULL));
483
13.1k
}
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
0
          const xmlChar *name2) {
517
0
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
518
0
}
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
10.0k
     void *userdata) {
538
10.0k
    unsigned long key, len = 0;
539
10.0k
    xmlHashEntryPtr entry;
540
10.0k
    xmlHashEntryPtr insert;
541
542
10.0k
    if ((table == NULL) || (name == NULL))
543
0
  return(-1);
544
545
    /*
546
     * If using a dict internalize if needed
547
     */
548
10.0k
    if (table->dict) {
549
65
        if (!xmlDictOwns(table->dict, name)) {
550
55
      name = xmlDictLookup(table->dict, name, -1);
551
55
      if (name == NULL)
552
0
          return(-1);
553
55
  }
554
65
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
555
0
      name2 = xmlDictLookup(table->dict, name2, -1);
556
0
      if (name2 == NULL)
557
0
          return(-1);
558
0
  }
559
65
        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
65
    }
565
566
    /*
567
     * Check for duplicate and insertion location.
568
     */
569
10.0k
    key = xmlHashComputeKey(table, name, name2, name3);
570
10.0k
    if (table->table[key].valid == 0) {
571
7.14k
  insert = NULL;
572
7.14k
    } else {
573
2.91k
        if (table->dict) {
574
54
      for (insert = &(table->table[key]); insert->next != NULL;
575
54
     insert = insert->next) {
576
0
    if ((insert->name == name) &&
577
0
        (insert->name2 == name2) &&
578
0
        (insert->name3 == name3))
579
0
        return(-1);
580
0
    len++;
581
0
      }
582
54
      if ((insert->name == name) &&
583
54
    (insert->name2 == name2) &&
584
54
    (insert->name3 == name3))
585
54
    return(-1);
586
2.86k
  } else {
587
5.95k
      for (insert = &(table->table[key]); insert->next != NULL;
588
3.09k
     insert = insert->next) {
589
3.09k
    if ((xmlStrEqual(insert->name, name)) &&
590
3.09k
        (xmlStrEqual(insert->name2, name2)) &&
591
3.09k
        (xmlStrEqual(insert->name3, name3)))
592
0
        return(-1);
593
3.09k
    len++;
594
3.09k
      }
595
2.86k
      if ((xmlStrEqual(insert->name, name)) &&
596
2.86k
    (xmlStrEqual(insert->name2, name2)) &&
597
2.86k
    (xmlStrEqual(insert->name3, name3)))
598
0
    return(-1);
599
2.86k
  }
600
2.91k
    }
601
602
10.0k
    if (insert == NULL) {
603
7.14k
  entry = &(table->table[key]);
604
7.14k
    } else {
605
2.86k
  entry = xmlMalloc(sizeof(xmlHashEntry));
606
2.86k
  if (entry == NULL)
607
0
       return(-1);
608
2.86k
    }
609
610
10.0k
    if (table->dict != NULL) {
611
11
        entry->name = (xmlChar *) name;
612
11
        entry->name2 = (xmlChar *) name2;
613
11
        entry->name3 = (xmlChar *) name3;
614
9.99k
    } else {
615
9.99k
  entry->name = xmlStrdup(name);
616
9.99k
        if (entry->name == NULL) {
617
0
            entry->name2 = NULL;
618
0
            goto error;
619
0
        }
620
9.99k
        if (name2 == NULL) {
621
6.19k
            entry->name2 = NULL;
622
6.19k
        } else {
623
3.80k
      entry->name2 = xmlStrdup(name2);
624
3.80k
            if (entry->name2 == NULL)
625
0
                goto error;
626
3.80k
        }
627
9.99k
        if (name3 == NULL) {
628
9.99k
            entry->name3 = NULL;
629
9.99k
        } else {
630
0
      entry->name3 = xmlStrdup(name3);
631
0
            if (entry->name3 == NULL)
632
0
                goto error;
633
0
        }
634
9.99k
    }
635
10.0k
    entry->payload = userdata;
636
10.0k
    entry->next = NULL;
637
10.0k
    entry->valid = 1;
638
639
640
10.0k
    if (insert != NULL)
641
2.86k
  insert->next = entry;
642
643
10.0k
    table->nbElems++;
644
645
10.0k
    if (len > MAX_HASH_LEN)
646
6
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
647
648
10.0k
    return(0);
649
650
0
error:
651
0
    xmlFree(entry->name2);
652
0
    xmlFree(entry->name);
653
0
    if (insert != NULL)
654
0
        xmlFree(entry);
655
0
    return(-1);
656
10.0k
}
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
2.44k
       void *userdata, xmlHashDeallocator f) {
677
2.44k
    unsigned long key;
678
2.44k
    xmlHashEntryPtr entry;
679
2.44k
    xmlHashEntryPtr insert;
680
681
2.44k
    if ((table == NULL) || name == NULL)
682
0
  return(-1);
683
684
    /*
685
     * If using a dict internalize if needed
686
     */
687
2.44k
    if (table->dict) {
688
0
        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
0
        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
0
        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
0
    }
704
705
    /*
706
     * Check for duplicate and insertion location.
707
     */
708
2.44k
    key = xmlHashComputeKey(table, name, name2, name3);
709
2.44k
    if (table->table[key].valid == 0) {
710
2.01k
  insert = NULL;
711
2.01k
    } else {
712
432
        if (table ->dict) {
713
0
      for (insert = &(table->table[key]); insert->next != NULL;
714
0
     insert = insert->next) {
715
0
    if ((insert->name == name) &&
716
0
        (insert->name2 == name2) &&
717
0
        (insert->name3 == name3)) {
718
0
        if (f)
719
0
      f(insert->payload, insert->name);
720
0
        insert->payload = userdata;
721
0
        return(0);
722
0
    }
723
0
      }
724
0
      if ((insert->name == name) &&
725
0
    (insert->name2 == name2) &&
726
0
    (insert->name3 == name3)) {
727
0
    if (f)
728
0
        f(insert->payload, insert->name);
729
0
    insert->payload = userdata;
730
0
    return(0);
731
0
      }
732
432
  } else {
733
862
      for (insert = &(table->table[key]); insert->next != NULL;
734
432
     insert = insert->next) {
735
430
    if ((xmlStrEqual(insert->name, name)) &&
736
430
        (xmlStrEqual(insert->name2, name2)) &&
737
430
        (xmlStrEqual(insert->name3, name3))) {
738
0
        if (f)
739
0
      f(insert->payload, insert->name);
740
0
        insert->payload = userdata;
741
0
        return(0);
742
0
    }
743
430
      }
744
432
      if ((xmlStrEqual(insert->name, name)) &&
745
432
    (xmlStrEqual(insert->name2, name2)) &&
746
432
    (xmlStrEqual(insert->name3, name3))) {
747
0
    if (f)
748
0
        f(insert->payload, insert->name);
749
0
    insert->payload = userdata;
750
0
    return(0);
751
0
      }
752
432
  }
753
432
    }
754
755
2.44k
    if (insert == NULL) {
756
2.01k
  entry =  &(table->table[key]);
757
2.01k
    } else {
758
432
  entry = xmlMalloc(sizeof(xmlHashEntry));
759
432
  if (entry == NULL)
760
0
       return(-1);
761
432
    }
762
763
2.44k
    if (table->dict != NULL) {
764
0
        entry->name = (xmlChar *) name;
765
0
        entry->name2 = (xmlChar *) name2;
766
0
        entry->name3 = (xmlChar *) name3;
767
2.44k
    } else {
768
2.44k
  entry->name = xmlStrdup(name);
769
2.44k
        if (entry->name == NULL) {
770
0
            entry->name2 = NULL;
771
0
            goto error;
772
0
        }
773
2.44k
        if (name2 == NULL) {
774
2.28k
            entry->name2 = NULL;
775
2.28k
        } else {
776
164
      entry->name2 = xmlStrdup(name2);
777
164
            if (entry->name2 == NULL)
778
0
                goto error;
779
164
        }
780
2.44k
        if (name3 == NULL) {
781
2.44k
            entry->name3 = NULL;
782
2.44k
        } else {
783
0
      entry->name3 = xmlStrdup(name3);
784
0
            if (entry->name3 == NULL)
785
0
                goto error;
786
0
        }
787
2.44k
    }
788
2.44k
    entry->payload = userdata;
789
2.44k
    entry->next = NULL;
790
2.44k
    entry->valid = 1;
791
2.44k
    table->nbElems++;
792
793
794
2.44k
    if (insert != NULL) {
795
432
  insert->next = entry;
796
432
    }
797
2.44k
    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
2.44k
}
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
21.0k
         const xmlChar *name2, const xmlChar *name3) {
821
21.0k
    unsigned long key;
822
21.0k
    xmlHashEntryPtr entry;
823
824
21.0k
    if (table == NULL)
825
0
  return(NULL);
826
21.0k
    if (name == NULL)
827
0
  return(NULL);
828
21.0k
    key = xmlHashComputeKey(table, name, name2, name3);
829
21.0k
    if (table->table[key].valid == 0)
830
109
  return(NULL);
831
20.9k
    if (table->dict) {
832
0
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
833
0
      if ((entry->name == name) &&
834
0
    (entry->name2 == name2) &&
835
0
    (entry->name3 == name3))
836
0
    return(entry->payload);
837
0
  }
838
0
    }
839
49.1k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
840
42.0k
  if ((xmlStrEqual(entry->name, name)) &&
841
42.0k
      (xmlStrEqual(entry->name2, name2)) &&
842
42.0k
      (xmlStrEqual(entry->name3, name3)))
843
13.8k
      return(entry->payload);
844
42.0k
    }
845
7.13k
    return(NULL);
846
20.9k
}
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
0
    const xmlChar *prefix3, const xmlChar *name3) {
867
0
    unsigned long key;
868
0
    xmlHashEntryPtr entry;
869
870
0
    if (table == NULL)
871
0
  return(NULL);
872
0
    if (name == NULL)
873
0
  return(NULL);
874
0
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
875
0
                             name2, prefix3, name3);
876
0
    if (table->table[key].valid == 0)
877
0
  return(NULL);
878
0
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
879
0
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
880
0
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
881
0
      (xmlStrQEqual(prefix3, name3, entry->name3)))
882
0
      return(entry->payload);
883
0
    }
884
0
    return(NULL);
885
0
}
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
3
         const xmlChar *name3 ATTRIBUTE_UNUSED) {
896
3
    stubData *stubdata = (stubData *) data;
897
3
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
898
3
}
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
3
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
910
3
    stubData stubdata;
911
3
    stubdata.data = data;
912
3
    stubdata.hashscanner = f;
913
3
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
914
3
}
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
3
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
926
3
    int i, nb;
927
3
    xmlHashEntryPtr iter;
928
3
    xmlHashEntryPtr next;
929
930
3
    if (table == NULL)
931
0
  return;
932
3
    if (f == NULL)
933
0
  return;
934
935
3
    if (table->table) {
936
33
  for(i = 0; i < table->size; i++) {
937
30
      if (table->table[i].valid == 0)
938
27
    continue;
939
3
      iter = &(table->table[i]);
940
6
      while (iter) {
941
3
    next = iter->next;
942
3
                nb = table->nbElems;
943
3
    if ((f != NULL) && (iter->payload != NULL))
944
3
        f(iter->payload, data, iter->name,
945
3
          iter->name2, iter->name3);
946
3
                if (nb != table->nbElems) {
947
                    /* table was modified by the callback, be careful */
948
0
                    if (iter == &(table->table[i])) {
949
0
                        if (table->table[i].valid == 0)
950
0
                            iter = NULL;
951
0
                        if (table->table[i].next != next)
952
0
          iter = &(table->table[i]);
953
0
                    } else
954
0
            iter = next;
955
0
                } else
956
3
        iter = next;
957
3
      }
958
3
  }
959
3
    }
960
3
}
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
0
xmlHashSize(xmlHashTablePtr table) {
1085
0
    if (table == NULL)
1086
0
  return(-1);
1087
0
    return(table->nbElems);
1088
0
}
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
0
           xmlHashDeallocator f) {
1104
0
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1105
0
}
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
0
      const xmlChar *name2, xmlHashDeallocator f) {
1123
0
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1124
0
}
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
0
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1143
0
    unsigned long key;
1144
0
    xmlHashEntryPtr entry;
1145
0
    xmlHashEntryPtr prev = NULL;
1146
1147
0
    if (table == NULL || name == NULL)
1148
0
        return(-1);
1149
1150
0
    key = xmlHashComputeKey(table, name, name2, name3);
1151
0
    if (table->table[key].valid == 0) {
1152
0
        return(-1);
1153
0
    } else {
1154
0
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1155
0
            if (xmlStrEqual(entry->name, name) &&
1156
0
                    xmlStrEqual(entry->name2, name2) &&
1157
0
                    xmlStrEqual(entry->name3, name3)) {
1158
0
                if ((f != NULL) && (entry->payload != NULL))
1159
0
                    f(entry->payload, entry->name);
1160
0
                entry->payload = NULL;
1161
0
    if (table->dict == NULL) {
1162
0
        if(entry->name)
1163
0
      xmlFree(entry->name);
1164
0
        if(entry->name2)
1165
0
      xmlFree(entry->name2);
1166
0
        if(entry->name3)
1167
0
      xmlFree(entry->name3);
1168
0
    }
1169
0
                if(prev) {
1170
0
                    prev->next = entry->next;
1171
0
        xmlFree(entry);
1172
0
    } else {
1173
0
        if (entry->next == NULL) {
1174
0
      entry->valid = 0;
1175
0
        } else {
1176
0
      entry = entry->next;
1177
0
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1178
0
      xmlFree(entry);
1179
0
        }
1180
0
    }
1181
0
                table->nbElems--;
1182
0
                return(0);
1183
0
            }
1184
0
            prev = entry;
1185
0
        }
1186
0
        return(-1);
1187
0
    }
1188
0
}
1189