Coverage Report

Created: 2023-06-07 06:14

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