Coverage Report

Created: 2022-05-03 06:10

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