Coverage Report

Created: 2023-06-07 06:05

/src/libxml2-2.10.3/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
18.7k
#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
106k
            const xmlChar *name2, const xmlChar *name3) {
83
106k
    unsigned long value = 0L;
84
106k
    unsigned long ch;
85
86
#ifdef HASH_RANDOMIZATION
87
    value = table->random_seed;
88
#endif
89
106k
    if (name != NULL) {
90
106k
  value += 30 * (*name);
91
1.59M
  while ((ch = *name++) != 0) {
92
1.49M
      value = value ^ ((value << 5) + (value >> 3) + ch);
93
1.49M
  }
94
106k
    }
95
106k
    value = value ^ ((value << 5) + (value >> 3));
96
106k
    if (name2 != NULL) {
97
151M
  while ((ch = *name2++) != 0) {
98
151M
      value = value ^ ((value << 5) + (value >> 3) + ch);
99
151M
  }
100
80.0k
    }
101
106k
    value = value ^ ((value << 5) + (value >> 3));
102
106k
    if (name3 != NULL) {
103
0
  while ((ch = *name3++) != 0) {
104
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
105
0
  }
106
0
    }
107
106k
    return (value % table->size);
108
106k
}
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
153k
       const xmlChar *prefix3, const xmlChar *name3) {
118
153k
    unsigned long value = 0L;
119
153k
    unsigned long ch;
120
121
#ifdef HASH_RANDOMIZATION
122
    value = table->random_seed;
123
#endif
124
153k
    if (prefix != NULL)
125
4.15k
  value += 30 * (*prefix);
126
149k
    else
127
149k
  value += 30 * (*name);
128
129
153k
    if (prefix != NULL) {
130
33.2k
  while ((ch = *prefix++) != 0) {
131
29.0k
      value = value ^ ((value << 5) + (value >> 3) + ch);
132
29.0k
  }
133
4.15k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
134
4.15k
    }
135
153k
    if (name != NULL) {
136
344k
  while ((ch = *name++) != 0) {
137
191k
      value = value ^ ((value << 5) + (value >> 3) + ch);
138
191k
  }
139
153k
    }
140
153k
    value = value ^ ((value << 5) + (value >> 3));
141
153k
    if (prefix2 != NULL) {
142
42.4k
  while ((ch = *prefix2++) != 0) {
143
35.3k
      value = value ^ ((value << 5) + (value >> 3) + ch);
144
35.3k
  }
145
7.11k
  value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
146
7.11k
    }
147
153k
    if (name2 != NULL) {
148
345k
  while ((ch = *name2++) != 0) {
149
192k
      value = value ^ ((value << 5) + (value >> 3) + ch);
150
192k
  }
151
153k
    }
152
153k
    value = value ^ ((value << 5) + (value >> 3));
153
153k
    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
153k
    if (name3 != NULL) {
160
0
  while ((ch = *name3++) != 0) {
161
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
162
0
  }
163
0
    }
164
153k
    return (value % table->size);
165
153k
}
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.36k
xmlHashCreate(int size) {
177
3.36k
    xmlHashTablePtr table;
178
179
3.36k
    if (size <= 0)
180
861
        size = 256;
181
182
3.36k
    table = xmlMalloc(sizeof(xmlHashTable));
183
3.36k
    if (table) {
184
3.36k
        table->dict = NULL;
185
3.36k
        table->size = size;
186
3.36k
  table->nbElems = 0;
187
3.36k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
188
3.36k
        if (table->table) {
189
3.36k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
190
#ifdef HASH_RANDOMIZATION
191
            table->random_seed = __xmlRandom();
192
#endif
193
3.36k
      return(table);
194
3.36k
        }
195
0
        xmlFree(table);
196
0
    }
197
0
    return(NULL);
198
3.36k
}
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.36k
xmlHashCreateDict(int size, xmlDictPtr dict) {
211
3.36k
    xmlHashTablePtr table;
212
213
3.36k
    table = xmlHashCreate(size);
214
3.36k
    if (table != NULL) {
215
3.36k
        table->dict = dict;
216
3.36k
  xmlDictReference(dict);
217
3.36k
    }
218
3.36k
    return(table);
219
3.36k
}
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
137
xmlHashGrow(xmlHashTablePtr table, int size) {
232
137
    unsigned long key;
233
137
    int oldsize, i;
234
137
    xmlHashEntryPtr iter, next;
235
137
    struct _xmlHashEntry *oldtable;
236
#ifdef DEBUG_GROW
237
    unsigned long nbElem = 0;
238
#endif
239
240
137
    if (table == NULL)
241
0
  return(-1);
242
137
    if (size < 8)
243
0
        return(-1);
244
137
    if (size > 8 * 2048)
245
0
  return(-1);
246
247
137
    oldsize = table->size;
248
137
    oldtable = table->table;
249
137
    if (oldtable == NULL)
250
0
        return(-1);
251
252
137
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
253
137
    if (table->table == NULL) {
254
0
  table->table = oldtable;
255
0
  return(-1);
256
0
    }
257
137
    memset(table->table, 0, size * sizeof(xmlHashEntry));
258
137
    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.97k
    for (i = 0; i < oldsize; i++) {
267
2.84k
  if (oldtable[i].valid == 0)
268
650
      continue;
269
2.19k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
270
2.19k
        oldtable[i].name3);
271
2.19k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
272
2.19k
  table->table[key].next = NULL;
273
2.19k
    }
274
275
2.97k
    for (i = 0; i < oldsize; i++) {
276
2.84k
  iter = oldtable[i].next;
277
10.4k
  while (iter) {
278
7.58k
      next = iter->next;
279
280
      /*
281
       * put back the entry in the new table
282
       */
283
284
7.58k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
285
7.58k
                        iter->name3);
286
7.58k
      if (table->table[key].valid == 0) {
287
4.78k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
288
4.78k
    table->table[key].next = NULL;
289
4.78k
    xmlFree(iter);
290
4.78k
      } else {
291
2.80k
    iter->next = table->table[key].next;
292
2.80k
    table->table[key].next = iter;
293
2.80k
      }
294
295
#ifdef DEBUG_GROW
296
      nbElem++;
297
#endif
298
299
7.58k
      iter = next;
300
7.58k
  }
301
2.84k
    }
302
303
137
    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
137
    return(0);
311
137
}
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.36k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
323
3.36k
    int i;
324
3.36k
    xmlHashEntryPtr iter;
325
3.36k
    xmlHashEntryPtr next;
326
3.36k
    int inside_table = 0;
327
3.36k
    int nbElems;
328
329
3.36k
    if (table == NULL)
330
0
  return;
331
3.36k
    if (table->table) {
332
3.36k
  nbElems = table->nbElems;
333
193k
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
334
190k
      iter = &(table->table[i]);
335
190k
      if (iter->valid == 0)
336
177k
    continue;
337
12.9k
      inside_table = 1;
338
33.1k
      while (iter) {
339
20.2k
    next = iter->next;
340
20.2k
    if ((f != NULL) && (iter->payload != NULL))
341
3.90k
        f(iter->payload, iter->name);
342
20.2k
    if (table->dict == NULL) {
343
1.39k
        if (iter->name)
344
1.39k
      xmlFree(iter->name);
345
1.39k
        if (iter->name2)
346
0
      xmlFree(iter->name2);
347
1.39k
        if (iter->name3)
348
0
      xmlFree(iter->name3);
349
1.39k
    }
350
20.2k
    iter->payload = NULL;
351
20.2k
    if (!inside_table)
352
7.35k
        xmlFree(iter);
353
20.2k
    nbElems--;
354
20.2k
    inside_table = 0;
355
20.2k
    iter = next;
356
20.2k
      }
357
12.9k
  }
358
3.36k
  xmlFree(table->table);
359
3.36k
    }
360
3.36k
    if (table->dict)
361
2.50k
        xmlDictFree(table->dict);
362
3.36k
    xmlFree(table);
363
3.36k
}
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.50k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
374
2.50k
    xmlFree(entry);
375
2.50k
}
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
7.77k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
390
7.77k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
391
7.77k
}
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
17.2k
          const xmlChar *name2, void *userdata) {
408
17.2k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
409
17.2k
}
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
4.54k
       xmlHashDeallocator f) {
448
4.54k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
449
4.54k
}
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
66.5k
        const xmlChar *name2) {
478
66.5k
    return(xmlHashLookup3(table, name, name2, NULL));
479
66.5k
}
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
153k
          const xmlChar *name2) {
513
153k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
514
153k
}
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
25.0k
     void *userdata) {
534
25.0k
    unsigned long key, len = 0;
535
25.0k
    xmlHashEntryPtr entry;
536
25.0k
    xmlHashEntryPtr insert;
537
538
25.0k
    if ((table == NULL) || (name == NULL))
539
0
  return(-1);
540
541
    /*
542
     * If using a dict internalize if needed
543
     */
544
25.0k
    if (table->dict) {
545
17.2k
        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
17.2k
        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
17.2k
        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
17.2k
    }
561
562
    /*
563
     * Check for duplicate and insertion location.
564
     */
565
25.0k
    key = xmlHashComputeKey(table, name, name2, name3);
566
25.0k
    if (table->table[key].valid == 0) {
567
6.61k
  insert = NULL;
568
18.3k
    } else {
569
18.3k
        if (table->dict) {
570
36.8k
      for (insert = &(table->table[key]); insert->next != NULL;
571
24.8k
     insert = insert->next) {
572
24.8k
    if ((insert->name == name) &&
573
24.8k
        (insert->name2 == name2) &&
574
24.8k
        (insert->name3 == name3))
575
0
        return(-1);
576
24.8k
    len++;
577
24.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
11.9k
  } else {
583
7.29k
      for (insert = &(table->table[key]); insert->next != NULL;
584
6.46k
     insert = insert->next) {
585
1.36k
    if ((xmlStrEqual(insert->name, name)) &&
586
1.36k
        (xmlStrEqual(insert->name2, name2)) &&
587
1.36k
        (xmlStrEqual(insert->name3, name3)))
588
532
        return(-1);
589
833
    len++;
590
833
      }
591
5.93k
      if ((xmlStrEqual(insert->name, name)) &&
592
5.93k
    (xmlStrEqual(insert->name2, name2)) &&
593
5.93k
    (xmlStrEqual(insert->name3, name3)))
594
5.84k
    return(-1);
595
5.93k
  }
596
18.3k
    }
597
598
18.6k
    if (insert == NULL) {
599
6.61k
  entry = &(table->table[key]);
600
12.0k
    } else {
601
12.0k
  entry = xmlMalloc(sizeof(xmlHashEntry));
602
12.0k
  if (entry == NULL)
603
0
       return(-1);
604
12.0k
    }
605
606
18.6k
    if (table->dict != NULL) {
607
17.2k
        entry->name = (xmlChar *) name;
608
17.2k
        entry->name2 = (xmlChar *) name2;
609
17.2k
        entry->name3 = (xmlChar *) name3;
610
17.2k
    } else {
611
1.39k
  entry->name = xmlStrdup(name);
612
1.39k
  entry->name2 = xmlStrdup(name2);
613
1.39k
  entry->name3 = xmlStrdup(name3);
614
1.39k
    }
615
18.6k
    entry->payload = userdata;
616
18.6k
    entry->next = NULL;
617
18.6k
    entry->valid = 1;
618
619
620
18.6k
    if (insert != NULL)
621
12.0k
  insert->next = entry;
622
623
18.6k
    table->nbElems++;
624
625
18.6k
    if (len > MAX_HASH_LEN)
626
137
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
627
628
18.6k
    return(0);
629
18.6k
}
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
4.54k
       void *userdata, xmlHashDeallocator f) {
650
4.54k
    unsigned long key;
651
4.54k
    xmlHashEntryPtr entry;
652
4.54k
    xmlHashEntryPtr insert;
653
654
4.54k
    if ((table == NULL) || name == NULL)
655
0
  return(-1);
656
657
    /*
658
     * If using a dict internalize if needed
659
     */
660
4.54k
    if (table->dict) {
661
4.54k
        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
4.54k
        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
4.54k
        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
4.54k
    }
677
678
    /*
679
     * Check for duplicate and insertion location.
680
     */
681
4.54k
    key = xmlHashComputeKey(table, name, name2, name3);
682
4.54k
    if (table->table[key].valid == 0) {
683
1.85k
  insert = NULL;
684
2.69k
    } else {
685
2.69k
        if (table ->dict) {
686
4.44k
      for (insert = &(table->table[key]); insert->next != NULL;
687
2.69k
     insert = insert->next) {
688
1.76k
    if ((insert->name == name) &&
689
1.76k
        (insert->name2 == name2) &&
690
1.76k
        (insert->name3 == name3)) {
691
10
        if (f)
692
0
      f(insert->payload, insert->name);
693
10
        insert->payload = userdata;
694
10
        return(0);
695
10
    }
696
1.76k
      }
697
2.68k
      if ((insert->name == name) &&
698
2.68k
    (insert->name2 == name2) &&
699
2.68k
    (insert->name3 == name3)) {
700
2.02k
    if (f)
701
0
        f(insert->payload, insert->name);
702
2.02k
    insert->payload = userdata;
703
2.02k
    return(0);
704
2.02k
      }
705
2.68k
  } 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
2.69k
    }
727
728
2.50k
    if (insert == NULL) {
729
1.85k
  entry =  &(table->table[key]);
730
1.85k
    } else {
731
656
  entry = xmlMalloc(sizeof(xmlHashEntry));
732
656
  if (entry == NULL)
733
0
       return(-1);
734
656
    }
735
736
2.50k
    if (table->dict != NULL) {
737
2.50k
        entry->name = (xmlChar *) name;
738
2.50k
        entry->name2 = (xmlChar *) name2;
739
2.50k
        entry->name3 = (xmlChar *) name3;
740
2.50k
    } else {
741
0
  entry->name = xmlStrdup(name);
742
0
  entry->name2 = xmlStrdup(name2);
743
0
  entry->name3 = xmlStrdup(name3);
744
0
    }
745
2.50k
    entry->payload = userdata;
746
2.50k
    entry->next = NULL;
747
2.50k
    entry->valid = 1;
748
2.50k
    table->nbElems++;
749
750
751
2.50k
    if (insert != NULL) {
752
656
  insert->next = entry;
753
656
    }
754
2.50k
    return(0);
755
2.50k
}
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
66.5k
         const xmlChar *name2, const xmlChar *name3) {
771
66.5k
    unsigned long key;
772
66.5k
    xmlHashEntryPtr entry;
773
774
66.5k
    if (table == NULL)
775
0
  return(NULL);
776
66.5k
    if (name == NULL)
777
0
  return(NULL);
778
66.5k
    key = xmlHashComputeKey(table, name, name2, name3);
779
66.5k
    if (table->table[key].valid == 0)
780
12.1k
  return(NULL);
781
54.3k
    if (table->dict) {
782
138k
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
783
113k
      if ((entry->name == name) &&
784
113k
    (entry->name2 == name2) &&
785
113k
    (entry->name3 == name3))
786
29.3k
    return(entry->payload);
787
113k
  }
788
54.3k
    }
789
100k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
790
75.7k
  if ((xmlStrEqual(entry->name, name)) &&
791
75.7k
      (xmlStrEqual(entry->name2, name2)) &&
792
75.7k
      (xmlStrEqual(entry->name3, name3)))
793
0
      return(entry->payload);
794
75.7k
    }
795
24.9k
    return(NULL);
796
24.9k
}
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
153k
    const xmlChar *prefix3, const xmlChar *name3) {
817
153k
    unsigned long key;
818
153k
    xmlHashEntryPtr entry;
819
820
153k
    if (table == NULL)
821
0
  return(NULL);
822
153k
    if (name == NULL)
823
0
  return(NULL);
824
153k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
825
153k
                             name2, prefix3, name3);
826
153k
    if (table->table[key].valid == 0)
827
131k
  return(NULL);
828
38.9k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
829
23.2k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
830
23.2k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
831
23.2k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
832
5.65k
      return(entry->payload);
833
23.2k
    }
834
15.6k
    return(NULL);
835
21.2k
}
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.31k
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
876
1.31k
    int i, nb;
877
1.31k
    xmlHashEntryPtr iter;
878
1.31k
    xmlHashEntryPtr next;
879
880
1.31k
    if (table == NULL)
881
0
  return;
882
1.31k
    if (f == NULL)
883
0
  return;
884
885
1.31k
    if (table->table) {
886
34.3k
  for(i = 0; i < table->size; i++) {
887
33.0k
      if (table->table[i].valid == 0)
888
22.9k
    continue;
889
10.0k
      iter = &(table->table[i]);
890
27.2k
      while (iter) {
891
17.2k
    next = iter->next;
892
17.2k
                nb = table->nbElems;
893
17.2k
    if ((f != NULL) && (iter->payload != NULL))
894
17.2k
        f(iter->payload, data, iter->name,
895
17.2k
          iter->name2, iter->name3);
896
17.2k
                if (nb != table->nbElems) {
897
                    /* table was modified by the callback, be careful */
898
874
                    if (iter == &(table->table[i])) {
899
563
                        if (table->table[i].valid == 0)
900
341
                            iter = NULL;
901
563
                        if (table->table[i].next != next)
902
222
          iter = &(table->table[i]);
903
563
                    } else
904
311
            iter = next;
905
874
                } else
906
16.3k
        iter = next;
907
17.2k
      }
908
10.0k
  }
909
1.31k
    }
910
1.31k
}
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.31k
xmlHashSize(xmlHashTablePtr table) {
1035
1.31k
    if (table == NULL)
1036
0
  return(-1);
1037
1.31k
    return(table->nbElems);
1038
1.31k
}
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
874
      const xmlChar *name2, xmlHashDeallocator f) {
1073
874
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1074
874
}
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
874
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1093
874
    unsigned long key;
1094
874
    xmlHashEntryPtr entry;
1095
874
    xmlHashEntryPtr prev = NULL;
1096
1097
874
    if (table == NULL || name == NULL)
1098
0
        return(-1);
1099
1100
874
    key = xmlHashComputeKey(table, name, name2, name3);
1101
874
    if (table->table[key].valid == 0) {
1102
0
        return(-1);
1103
874
    } else {
1104
1.38k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1105
1.38k
            if (xmlStrEqual(entry->name, name) &&
1106
1.38k
                    xmlStrEqual(entry->name2, name2) &&
1107
1.38k
                    xmlStrEqual(entry->name3, name3)) {
1108
874
                if ((f != NULL) && (entry->payload != NULL))
1109
0
                    f(entry->payload, entry->name);
1110
874
                entry->payload = NULL;
1111
874
    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
874
                if(prev) {
1120
311
                    prev->next = entry->next;
1121
311
        xmlFree(entry);
1122
563
    } else {
1123
563
        if (entry->next == NULL) {
1124
341
      entry->valid = 0;
1125
341
        } else {
1126
222
      entry = entry->next;
1127
222
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1128
222
      xmlFree(entry);
1129
222
        }
1130
563
    }
1131
874
                table->nbElems--;
1132
874
                return(0);
1133
874
            }
1134
512
            prev = entry;
1135
512
        }
1136
0
        return(-1);
1137
874
    }
1138
874
}
1139