Coverage Report

Created: 2022-06-08 06:16

/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
45.4k
#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
13.4M
            const xmlChar *name2, const xmlChar *name3) {
83
13.4M
    unsigned long value = 0L;
84
13.4M
    unsigned long ch;
85
86
#ifdef HASH_RANDOMIZATION
87
    value = table->random_seed;
88
#endif
89
13.4M
    if (name != NULL) {
90
13.4M
  value += 30 * (*name);
91
118M
  while ((ch = *name++) != 0) {
92
105M
      value = value ^ ((value << 5) + (value >> 3) + ch);
93
105M
  }
94
13.4M
    }
95
13.4M
    value = value ^ ((value << 5) + (value >> 3));
96
13.4M
    if (name2 != NULL) {
97
87.0M
  while ((ch = *name2++) != 0) {
98
86.9M
      value = value ^ ((value << 5) + (value >> 3) + ch);
99
86.9M
  }
100
164k
    }
101
13.4M
    value = value ^ ((value << 5) + (value >> 3));
102
13.4M
    if (name3 != NULL) {
103
2.89M
  while ((ch = *name3++) != 0) {
104
2.85M
      value = value ^ ((value << 5) + (value >> 3) + ch);
105
2.85M
  }
106
32.3k
    }
107
13.4M
    return (value % table->size);
108
13.4M
}
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
31.3k
       const xmlChar *prefix3, const xmlChar *name3) {
118
31.3k
    unsigned long value = 0L;
119
31.3k
    unsigned long ch;
120
121
#ifdef HASH_RANDOMIZATION
122
    value = table->random_seed;
123
#endif
124
31.3k
    if (prefix != NULL)
125
360
  value += 30 * (*prefix);
126
30.9k
    else
127
30.9k
  value += 30 * (*name);
128
129
31.3k
    if (prefix != NULL) {
130
1.22k
  while ((ch = *prefix++) != 0) {
131
866
      value = value ^ ((value << 5) + (value >> 3) + ch);
132
866
  }
133
360
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
134
360
    }
135
31.3k
    if (name != NULL) {
136
267k
  while ((ch = *name++) != 0) {
137
235k
      value = value ^ ((value << 5) + (value >> 3) + ch);
138
235k
  }
139
31.3k
    }
140
31.3k
    value = value ^ ((value << 5) + (value >> 3));
141
31.3k
    if (prefix2 != NULL) {
142
39.7k
  while ((ch = *prefix2++) != 0) {
143
30.3k
      value = value ^ ((value << 5) + (value >> 3) + ch);
144
30.3k
  }
145
9.41k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
146
9.41k
    }
147
31.3k
    if (name2 != NULL) {
148
1.03M
  while ((ch = *name2++) != 0) {
149
1.00M
      value = value ^ ((value << 5) + (value >> 3) + ch);
150
1.00M
  }
151
31.3k
    }
152
31.3k
    value = value ^ ((value << 5) + (value >> 3));
153
31.3k
    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
31.3k
    if (name3 != NULL) {
160
0
  while ((ch = *name3++) != 0) {
161
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
162
0
  }
163
0
    }
164
31.3k
    return (value % table->size);
165
31.3k
}
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
13.8k
xmlHashCreate(int size) {
177
13.8k
    xmlHashTablePtr table;
178
179
13.8k
    if (size <= 0)
180
9.42k
        size = 256;
181
182
13.8k
    table = xmlMalloc(sizeof(xmlHashTable));
183
13.8k
    if (table) {
184
13.8k
        table->dict = NULL;
185
13.8k
        table->size = size;
186
13.8k
  table->nbElems = 0;
187
13.8k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
188
13.8k
        if (table->table) {
189
13.8k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
190
#ifdef HASH_RANDOMIZATION
191
            table->random_seed = __xmlRandom();
192
#endif
193
13.8k
      return(table);
194
13.8k
        }
195
0
        xmlFree(table);
196
0
    }
197
0
    return(NULL);
198
13.8k
}
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
13.8k
xmlHashCreateDict(int size, xmlDictPtr dict) {
211
13.8k
    xmlHashTablePtr table;
212
213
13.8k
    table = xmlHashCreate(size);
214
13.8k
    if (table != NULL) {
215
13.8k
        table->dict = dict;
216
13.8k
  xmlDictReference(dict);
217
13.8k
    }
218
13.8k
    return(table);
219
13.8k
}
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
104
xmlHashGrow(xmlHashTablePtr table, int size) {
232
104
    unsigned long key;
233
104
    int oldsize, i;
234
104
    xmlHashEntryPtr iter, next;
235
104
    struct _xmlHashEntry *oldtable;
236
#ifdef DEBUG_GROW
237
    unsigned long nbElem = 0;
238
#endif
239
240
104
    if (table == NULL)
241
0
  return(-1);
242
104
    if (size < 8)
243
0
        return(-1);
244
104
    if (size > 8 * 2048)
245
0
  return(-1);
246
247
104
    oldsize = table->size;
248
104
    oldtable = table->table;
249
104
    if (oldtable == NULL)
250
0
        return(-1);
251
252
104
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
253
104
    if (table->table == NULL) {
254
0
  table->table = oldtable;
255
0
  return(-1);
256
0
    }
257
104
    memset(table->table, 0, size * sizeof(xmlHashEntry));
258
104
    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
2.19k
    for (i = 0; i < oldsize; i++) {
267
2.09k
  if (oldtable[i].valid == 0)
268
166
      continue;
269
1.92k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
270
1.92k
        oldtable[i].name3);
271
1.92k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
272
1.92k
  table->table[key].next = NULL;
273
1.92k
    }
274
275
2.19k
    for (i = 0; i < oldsize; i++) {
276
2.09k
  iter = oldtable[i].next;
277
9.44k
  while (iter) {
278
7.35k
      next = iter->next;
279
280
      /*
281
       * put back the entry in the new table
282
       */
283
284
7.35k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
285
7.35k
                        iter->name3);
286
7.35k
      if (table->table[key].valid == 0) {
287
4.84k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
288
4.84k
    table->table[key].next = NULL;
289
4.84k
    xmlFree(iter);
290
4.84k
      } else {
291
2.51k
    iter->next = table->table[key].next;
292
2.51k
    table->table[key].next = iter;
293
2.51k
      }
294
295
#ifdef DEBUG_GROW
296
      nbElem++;
297
#endif
298
299
7.35k
      iter = next;
300
7.35k
  }
301
2.09k
    }
302
303
104
    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
104
    return(0);
311
104
}
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
13.8k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
323
13.8k
    int i;
324
13.8k
    xmlHashEntryPtr iter;
325
13.8k
    xmlHashEntryPtr next;
326
13.8k
    int inside_table = 0;
327
13.8k
    int nbElems;
328
329
13.8k
    if (table == NULL)
330
0
  return;
331
13.8k
    if (table->table) {
332
13.8k
  nbElems = table->nbElems;
333
1.91M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
334
1.89M
      iter = &(table->table[i]);
335
1.89M
      if (iter->valid == 0)
336
1.86M
    continue;
337
37.1k
      inside_table = 1;
338
85.0k
      while (iter) {
339
47.9k
    next = iter->next;
340
47.9k
    if ((f != NULL) && (iter->payload != NULL))
341
30.3k
        f(iter->payload, iter->name);
342
47.9k
    if (table->dict == NULL) {
343
26.9k
        if (iter->name)
344
26.9k
      xmlFree(iter->name);
345
26.9k
        if (iter->name2)
346
2.75k
      xmlFree(iter->name2);
347
26.9k
        if (iter->name3)
348
13.3k
      xmlFree(iter->name3);
349
26.9k
    }
350
47.9k
    iter->payload = NULL;
351
47.9k
    if (!inside_table)
352
10.7k
        xmlFree(iter);
353
47.9k
    nbElems--;
354
47.9k
    inside_table = 0;
355
47.9k
    iter = next;
356
47.9k
      }
357
37.1k
  }
358
13.8k
  xmlFree(table->table);
359
13.8k
    }
360
13.8k
    if (table->dict)
361
4.40k
        xmlDictFree(table->dict);
362
13.8k
    xmlFree(table);
363
13.8k
}
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
3.45k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
374
3.45k
    xmlFree(entry);
375
3.45k
}
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
40.2k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
390
40.2k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
391
40.2k
}
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
21.0k
          const xmlChar *name2, void *userdata) {
408
21.0k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
409
21.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.75k
       xmlHashDeallocator f) {
448
5.75k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
449
5.75k
}
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
8.95M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
462
8.95M
    return(xmlHashLookup3(table, name, NULL, NULL));
463
8.95M
}
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
4.35M
        const xmlChar *name2) {
478
4.35M
    return(xmlHashLookup3(table, name, name2, NULL));
479
4.35M
}
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
31.3k
          const xmlChar *name2) {
513
31.3k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
514
31.3k
}
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
91.1k
     void *userdata) {
534
91.1k
    unsigned long key, len = 0;
535
91.1k
    xmlHashEntryPtr entry;
536
91.1k
    xmlHashEntryPtr insert;
537
538
91.1k
    if ((table == NULL) || (name == NULL))
539
0
  return(-1);
540
541
    /*
542
     * If using a dict internalize if needed
543
     */
544
91.1k
    if (table->dict) {
545
18.3k
        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
18.3k
        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
18.3k
        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
18.3k
    }
561
562
    /*
563
     * Check for duplicate and insertion location.
564
     */
565
91.1k
    key = xmlHashComputeKey(table, name, name2, name3);
566
91.1k
    if (table->table[key].valid == 0) {
567
30.1k
  insert = NULL;
568
61.0k
    } else {
569
61.0k
        if (table->dict) {
570
35.7k
      for (insert = &(table->table[key]); insert->next != NULL;
571
23.8k
     insert = insert->next) {
572
23.8k
    if ((insert->name == name) &&
573
23.8k
        (insert->name2 == name2) &&
574
23.8k
        (insert->name3 == name3))
575
0
        return(-1);
576
23.8k
    len++;
577
23.8k
      }
578
11.9k
      if ((insert->name == name) &&
579
11.9k
    (insert->name2 == name2) &&
580
11.9k
    (insert->name3 == name3))
581
0
    return(-1);
582
49.0k
  } else {
583
52.8k
      for (insert = &(table->table[key]); insert->next != NULL;
584
49.0k
     insert = insert->next) {
585
5.87k
    if ((xmlStrEqual(insert->name, name)) &&
586
5.87k
        (xmlStrEqual(insert->name2, name2)) &&
587
5.87k
        (xmlStrEqual(insert->name3, name3)))
588
2.15k
        return(-1);
589
3.72k
    len++;
590
3.72k
      }
591
46.9k
      if ((xmlStrEqual(insert->name, name)) &&
592
46.9k
    (xmlStrEqual(insert->name2, name2)) &&
593
46.9k
    (xmlStrEqual(insert->name3, name3)))
594
43.5k
    return(-1);
595
46.9k
  }
596
61.0k
    }
597
598
45.3k
    if (insert == NULL) {
599
30.1k
  entry = &(table->table[key]);
600
30.1k
    } else {
601
15.2k
  entry = xmlMalloc(sizeof(xmlHashEntry));
602
15.2k
  if (entry == NULL)
603
0
       return(-1);
604
15.2k
    }
605
606
45.3k
    if (table->dict != NULL) {
607
18.3k
        entry->name = (xmlChar *) name;
608
18.3k
        entry->name2 = (xmlChar *) name2;
609
18.3k
        entry->name3 = (xmlChar *) name3;
610
27.0k
    } else {
611
27.0k
  entry->name = xmlStrdup(name);
612
27.0k
  entry->name2 = xmlStrdup(name2);
613
27.0k
  entry->name3 = xmlStrdup(name3);
614
27.0k
    }
615
45.3k
    entry->payload = userdata;
616
45.3k
    entry->next = NULL;
617
45.3k
    entry->valid = 1;
618
619
620
45.3k
    if (insert != NULL)
621
15.2k
  insert->next = entry;
622
623
45.3k
    table->nbElems++;
624
625
45.3k
    if (len > MAX_HASH_LEN)
626
104
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
627
628
45.3k
    return(0);
629
45.3k
}
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.75k
       void *userdata, xmlHashDeallocator f) {
650
5.75k
    unsigned long key;
651
5.75k
    xmlHashEntryPtr entry;
652
5.75k
    xmlHashEntryPtr insert;
653
654
5.75k
    if ((table == NULL) || name == NULL)
655
0
  return(-1);
656
657
    /*
658
     * If using a dict internalize if needed
659
     */
660
5.75k
    if (table->dict) {
661
5.75k
        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.75k
        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.75k
        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.75k
    }
677
678
    /*
679
     * Check for duplicate and insertion location.
680
     */
681
5.75k
    key = xmlHashComputeKey(table, name, name2, name3);
682
5.75k
    if (table->table[key].valid == 0) {
683
2.62k
  insert = NULL;
684
3.12k
    } else {
685
3.12k
        if (table ->dict) {
686
7.18k
      for (insert = &(table->table[key]); insert->next != NULL;
687
4.07k
     insert = insert->next) {
688
4.07k
    if ((insert->name == name) &&
689
4.07k
        (insert->name2 == name2) &&
690
4.07k
        (insert->name3 == name3)) {
691
21
        if (f)
692
0
      f(insert->payload, insert->name);
693
21
        insert->payload = userdata;
694
21
        return(0);
695
21
    }
696
4.07k
      }
697
3.10k
      if ((insert->name == name) &&
698
3.10k
    (insert->name2 == name2) &&
699
3.10k
    (insert->name3 == name3)) {
700
2.27k
    if (f)
701
0
        f(insert->payload, insert->name);
702
2.27k
    insert->payload = userdata;
703
2.27k
    return(0);
704
2.27k
      }
705
3.10k
  } 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.12k
    }
727
728
3.45k
    if (insert == NULL) {
729
2.62k
  entry =  &(table->table[key]);
730
2.62k
    } else {
731
829
  entry = xmlMalloc(sizeof(xmlHashEntry));
732
829
  if (entry == NULL)
733
0
       return(-1);
734
829
    }
735
736
3.45k
    if (table->dict != NULL) {
737
3.45k
        entry->name = (xmlChar *) name;
738
3.45k
        entry->name2 = (xmlChar *) name2;
739
3.45k
        entry->name3 = (xmlChar *) name3;
740
3.45k
    } else {
741
0
  entry->name = xmlStrdup(name);
742
0
  entry->name2 = xmlStrdup(name2);
743
0
  entry->name3 = xmlStrdup(name3);
744
0
    }
745
3.45k
    entry->payload = userdata;
746
3.45k
    entry->next = NULL;
747
3.45k
    entry->valid = 1;
748
3.45k
    table->nbElems++;
749
750
751
3.45k
    if (insert != NULL) {
752
829
  insert->next = entry;
753
829
    }
754
3.45k
    return(0);
755
3.45k
}
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
13.3M
         const xmlChar *name2, const xmlChar *name3) {
771
13.3M
    unsigned long key;
772
13.3M
    xmlHashEntryPtr entry;
773
774
13.3M
    if (table == NULL)
775
0
  return(NULL);
776
13.3M
    if (name == NULL)
777
0
  return(NULL);
778
13.3M
    key = xmlHashComputeKey(table, name, name2, name3);
779
13.3M
    if (table->table[key].valid == 0)
780
675k
  return(NULL);
781
12.6M
    if (table->dict) {
782
4.34M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
783
4.31M
      if ((entry->name == name) &&
784
4.31M
    (entry->name2 == name2) &&
785
4.31M
    (entry->name3 == name3))
786
4.18M
    return(entry->payload);
787
4.31M
  }
788
4.22M
    }
789
8.53M
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
790
8.49M
  if ((xmlStrEqual(entry->name, name)) &&
791
8.49M
      (xmlStrEqual(entry->name2, name2)) &&
792
8.49M
      (xmlStrEqual(entry->name3, name3)))
793
8.41M
      return(entry->payload);
794
8.49M
    }
795
39.0k
    return(NULL);
796
8.44M
}
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
31.3k
    const xmlChar *prefix3, const xmlChar *name3) {
817
31.3k
    unsigned long key;
818
31.3k
    xmlHashEntryPtr entry;
819
820
31.3k
    if (table == NULL)
821
0
  return(NULL);
822
31.3k
    if (name == NULL)
823
0
  return(NULL);
824
31.3k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
825
31.3k
                             name2, prefix3, name3);
826
31.3k
    if (table->table[key].valid == 0)
827
15.0k
  return(NULL);
828
27.9k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
829
17.8k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
830
17.8k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
831
17.8k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
832
6.20k
      return(entry->payload);
833
17.8k
    }
834
10.0k
    return(NULL);
835
16.3k
}
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
2.32k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
876
2.32k
    int i, nb;
877
2.32k
    xmlHashEntryPtr iter;
878
2.32k
    xmlHashEntryPtr next;
879
880
2.32k
    if (table == NULL)
881
0
  return;
882
2.32k
    if (f == NULL)
883
0
  return;
884
885
2.32k
    if (table->table) {
886
40.2k
  for(i = 0; i < table->size; i++) {
887
37.8k
      if (table->table[i].valid == 0)
888
26.6k
    continue;
889
11.2k
      iter = &(table->table[i]);
890
29.5k
      while (iter) {
891
18.2k
    next = iter->next;
892
18.2k
                nb = table->nbElems;
893
18.2k
    if ((f != NULL) && (iter->payload != NULL))
894
18.2k
        f(iter->payload, data, iter->name,
895
18.2k
          iter->name2, iter->name3);
896
18.2k
                if (nb != table->nbElems) {
897
                    /* table was modified by the callback, be careful */
898
760
                    if (iter == &(table->table[i])) {
899
487
                        if (table->table[i].valid == 0)
900
255
                            iter = NULL;
901
487
                        if (table->table[i].next != next)
902
232
          iter = &(table->table[i]);
903
487
                    } else
904
273
            iter = next;
905
760
                } else
906
17.5k
        iter = next;
907
18.2k
      }
908
11.2k
  }
909
2.32k
    }
910
2.32k
}
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
2.32k
xmlHashSize(xmlHashTablePtr table) {
1035
2.32k
    if (table == NULL)
1036
0
  return(-1);
1037
2.32k
    return(table->nbElems);
1038
2.32k
}
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
159
           xmlHashDeallocator f) {
1054
159
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1055
159
}
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
760
      const xmlChar *name2, xmlHashDeallocator f) {
1073
760
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1074
760
}
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
919
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1093
919
    unsigned long key;
1094
919
    xmlHashEntryPtr entry;
1095
919
    xmlHashEntryPtr prev = NULL;
1096
1097
919
    if (table == NULL || name == NULL)
1098
0
        return(-1);
1099
1100
919
    key = xmlHashComputeKey(table, name, name2, name3);
1101
919
    if (table->table[key].valid == 0) {
1102
0
        return(-1);
1103
919
    } else {
1104
1.55k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1105
1.55k
            if (xmlStrEqual(entry->name, name) &&
1106
1.55k
                    xmlStrEqual(entry->name2, name2) &&
1107
1.55k
                    xmlStrEqual(entry->name3, name3)) {
1108
919
                if ((f != NULL) && (entry->payload != NULL))
1109
159
                    f(entry->payload, entry->name);
1110
919
                entry->payload = NULL;
1111
919
    if (table->dict == NULL) {
1112
159
        if(entry->name)
1113
159
      xmlFree(entry->name);
1114
159
        if(entry->name2)
1115
0
      xmlFree(entry->name2);
1116
159
        if(entry->name3)
1117
0
      xmlFree(entry->name3);
1118
159
    }
1119
919
                if(prev) {
1120
274
                    prev->next = entry->next;
1121
274
        xmlFree(entry);
1122
645
    } else {
1123
645
        if (entry->next == NULL) {
1124
411
      entry->valid = 0;
1125
411
        } else {
1126
234
      entry = entry->next;
1127
234
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1128
234
      xmlFree(entry);
1129
234
        }
1130
645
    }
1131
919
                table->nbElems--;
1132
919
                return(0);
1133
919
            }
1134
633
            prev = entry;
1135
633
        }
1136
0
        return(-1);
1137
919
    }
1138
919
}
1139