Coverage Report

Created: 2023-06-07 06:50

/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
658k
#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
2.07M
            const xmlChar *name2, const xmlChar *name3) {
86
2.07M
    unsigned long value = 0L;
87
2.07M
    unsigned long ch;
88
89
#ifdef HASH_RANDOMIZATION
90
    value = table->random_seed;
91
#endif
92
2.07M
    if (name != NULL) {
93
2.07M
  value += 30 * (*name);
94
16.8M
  while ((ch = *name++) != 0) {
95
14.7M
      value = value ^ ((value << 5) + (value >> 3) + ch);
96
14.7M
  }
97
2.07M
    }
98
2.07M
    value = value ^ ((value << 5) + (value >> 3));
99
2.07M
    if (name2 != NULL) {
100
5.31M
  while ((ch = *name2++) != 0) {
101
5.11M
      value = value ^ ((value << 5) + (value >> 3) + ch);
102
5.11M
  }
103
190k
    }
104
2.07M
    value = value ^ ((value << 5) + (value >> 3));
105
2.07M
    if (name3 != NULL) {
106
526k
  while ((ch = *name3++) != 0) {
107
458k
      value = value ^ ((value << 5) + (value >> 3) + ch);
108
458k
  }
109
68.2k
    }
110
2.07M
    return (value % table->size);
111
2.07M
}
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
11.1k
       const xmlChar *prefix3, const xmlChar *name3) {
122
11.1k
    unsigned long value = 0L;
123
11.1k
    unsigned long ch;
124
125
#ifdef HASH_RANDOMIZATION
126
    value = table->random_seed;
127
#endif
128
11.1k
    if (prefix != NULL)
129
508
  value += 30 * (*prefix);
130
10.6k
    else
131
10.6k
  value += 30 * (*name);
132
133
11.1k
    if (prefix != NULL) {
134
1.32k
  while ((ch = *prefix++) != 0) {
135
819
      value = value ^ ((value << 5) + (value >> 3) + ch);
136
819
  }
137
508
  value = value ^ ((value << 5) + (value >> 3) + ':');
138
508
    }
139
11.1k
    if (name != NULL) {
140
30.5k
  while ((ch = *name++) != 0) {
141
19.3k
      value = value ^ ((value << 5) + (value >> 3) + ch);
142
19.3k
  }
143
11.1k
    }
144
11.1k
    value = value ^ ((value << 5) + (value >> 3));
145
11.1k
    if (prefix2 != NULL) {
146
9.07k
  while ((ch = *prefix2++) != 0) {
147
7.30k
      value = value ^ ((value << 5) + (value >> 3) + ch);
148
7.30k
  }
149
1.77k
  value = value ^ ((value << 5) + (value >> 3) + ':');
150
1.77k
    }
151
11.1k
    if (name2 != NULL) {
152
42.0k
  while ((ch = *name2++) != 0) {
153
30.8k
      value = value ^ ((value << 5) + (value >> 3) + ch);
154
30.8k
  }
155
11.1k
    }
156
11.1k
    value = value ^ ((value << 5) + (value >> 3));
157
11.1k
    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
11.1k
    if (name3 != NULL) {
164
0
  while ((ch = *name3++) != 0) {
165
0
      value = value ^ ((value << 5) + (value >> 3) + ch);
166
0
  }
167
0
    }
168
11.1k
    return (value % table->size);
169
11.1k
}
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
96.1k
xmlHashCreate(int size) {
181
96.1k
    xmlHashTablePtr table;
182
183
96.1k
    xmlInitParser();
184
185
96.1k
    if (size <= 0)
186
63.0k
        size = 256;
187
188
96.1k
    table = xmlMalloc(sizeof(xmlHashTable));
189
96.1k
    if (table) {
190
71.9k
        table->dict = NULL;
191
71.9k
        table->size = size;
192
71.9k
  table->nbElems = 0;
193
71.9k
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
194
71.9k
        if (table->table) {
195
71.6k
      memset(table->table, 0, size * sizeof(xmlHashEntry));
196
#ifdef HASH_RANDOMIZATION
197
            table->random_seed = __xmlRandom();
198
#endif
199
71.6k
      return(table);
200
71.6k
        }
201
379
        xmlFree(table);
202
379
    }
203
24.5k
    return(NULL);
204
96.1k
}
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
16.6k
xmlHashCreateDict(int size, xmlDictPtr dict) {
217
16.6k
    xmlHashTablePtr table;
218
219
16.6k
    table = xmlHashCreate(size);
220
16.6k
    if (table != NULL) {
221
16.6k
        table->dict = dict;
222
16.6k
  xmlDictReference(dict);
223
16.6k
    }
224
16.6k
    return(table);
225
16.6k
}
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
100
xmlHashGrow(xmlHashTablePtr table, int size) {
238
100
    unsigned long key;
239
100
    int oldsize, i;
240
100
    xmlHashEntryPtr iter, next;
241
100
    struct _xmlHashEntry *oldtable;
242
#ifdef DEBUG_GROW
243
    unsigned long nbElem = 0;
244
#endif
245
246
100
    if (table == NULL)
247
0
  return(-1);
248
100
    if (size < 8)
249
0
        return(-1);
250
100
    if (size > 8 * 2048)
251
0
  return(-1);
252
253
100
    oldsize = table->size;
254
100
    oldtable = table->table;
255
100
    if (oldtable == NULL)
256
0
        return(-1);
257
258
100
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
259
100
    if (table->table == NULL) {
260
0
  table->table = oldtable;
261
0
  return(-1);
262
0
    }
263
100
    memset(table->table, 0, size * sizeof(xmlHashEntry));
264
100
    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
2.01k
    for (i = 0; i < oldsize; i++) {
273
1.91k
  if (oldtable[i].valid == 0)
274
292
      continue;
275
1.61k
  key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
276
1.61k
        oldtable[i].name3);
277
1.61k
  memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
278
1.61k
  table->table[key].next = NULL;
279
1.61k
    }
280
281
2.01k
    for (i = 0; i < oldsize; i++) {
282
1.91k
  iter = oldtable[i].next;
283
6.57k
  while (iter) {
284
4.66k
      next = iter->next;
285
286
      /*
287
       * put back the entry in the new table
288
       */
289
290
4.66k
      key = xmlHashComputeKey(table, iter->name, iter->name2,
291
4.66k
                        iter->name3);
292
4.66k
      if (table->table[key].valid == 0) {
293
3.06k
    memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
294
3.06k
    table->table[key].next = NULL;
295
3.06k
    xmlFree(iter);
296
3.06k
      } else {
297
1.59k
    iter->next = table->table[key].next;
298
1.59k
    table->table[key].next = iter;
299
1.59k
      }
300
301
#ifdef DEBUG_GROW
302
      nbElem++;
303
#endif
304
305
4.66k
      iter = next;
306
4.66k
  }
307
1.91k
    }
308
309
100
    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
100
    return(0);
317
100
}
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
127k
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
329
127k
    int i;
330
127k
    xmlHashEntryPtr iter;
331
127k
    xmlHashEntryPtr next;
332
127k
    int inside_table = 0;
333
127k
    int nbElems;
334
335
127k
    if (table == NULL)
336
55.5k
  return;
337
71.6k
    if (table->table) {
338
71.6k
  nbElems = table->nbElems;
339
8.63M
  for(i = 0; (i < table->size) && (nbElems > 0); i++) {
340
8.55M
      iter = &(table->table[i]);
341
8.55M
      if (iter->valid == 0)
342
7.92M
    continue;
343
633k
      inside_table = 1;
344
1.29M
      while (iter) {
345
660k
    next = iter->next;
346
660k
    if ((f != NULL) && (iter->payload != NULL))
347
30.7k
        f(iter->payload, iter->name);
348
660k
    if (table->dict == NULL) {
349
617k
        if (iter->name)
350
617k
      xmlFree(iter->name);
351
617k
        if (iter->name2)
352
19.2k
      xmlFree(iter->name2);
353
617k
        if (iter->name3)
354
0
      xmlFree(iter->name3);
355
617k
    }
356
660k
    iter->payload = NULL;
357
660k
    if (!inside_table)
358
27.3k
        xmlFree(iter);
359
660k
    nbElems--;
360
660k
    inside_table = 0;
361
660k
    iter = next;
362
660k
      }
363
633k
  }
364
71.6k
  xmlFree(table->table);
365
71.6k
    }
366
71.6k
    if (table->dict)
367
16.6k
        xmlDictFree(table->dict);
368
71.6k
    xmlFree(table);
369
71.6k
}
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
4.85k
xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
380
4.85k
    xmlFree(entry);
381
4.85k
}
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.2k
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
396
35.2k
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
397
35.2k
}
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
760k
          const xmlChar *name2, void *userdata) {
414
760k
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
415
760k
}
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
1.67k
             void *userdata, xmlHashDeallocator f) {
433
1.67k
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
434
1.67k
}
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
4.82k
       xmlHashDeallocator f) {
454
4.82k
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
455
4.82k
}
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
1.05M
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
468
1.05M
    return(xmlHashLookup3(table, name, NULL, NULL));
469
1.05M
}
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
137k
        const xmlChar *name2) {
484
137k
    return(xmlHashLookup3(table, name, name2, NULL));
485
137k
}
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
11.1k
          const xmlChar *name2) {
519
11.1k
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
520
11.1k
}
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
841k
     void *userdata) {
540
841k
    unsigned long key, len = 0;
541
841k
    xmlHashEntryPtr entry;
542
841k
    xmlHashEntryPtr insert;
543
544
841k
    if ((table == NULL) || (name == NULL))
545
0
  return(-1);
546
547
    /*
548
     * If using a dict internalize if needed
549
     */
550
841k
    if (table->dict) {
551
98.2k
        if (!xmlDictOwns(table->dict, name)) {
552
7.55k
      name = xmlDictLookup(table->dict, name, -1);
553
7.55k
      if (name == NULL)
554
0
          return(-1);
555
7.55k
  }
556
98.2k
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
557
1.08k
      name2 = xmlDictLookup(table->dict, name2, -1);
558
1.08k
      if (name2 == NULL)
559
0
          return(-1);
560
1.08k
  }
561
98.2k
        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
98.2k
    }
567
568
    /*
569
     * Check for duplicate and insertion location.
570
     */
571
841k
    key = xmlHashComputeKey(table, name, name2, name3);
572
841k
    if (table->table[key].valid == 0) {
573
753k
  insert = NULL;
574
753k
    } else {
575
87.7k
        if (table->dict) {
576
84.0k
      for (insert = &(table->table[key]); insert->next != NULL;
577
67.2k
     insert = insert->next) {
578
18.2k
    if ((insert->name == name) &&
579
18.2k
        (insert->name2 == name2) &&
580
18.2k
        (insert->name3 == name3))
581
1.45k
        return(-1);
582
16.8k
    len++;
583
16.8k
      }
584
65.7k
      if ((insert->name == name) &&
585
65.7k
    (insert->name2 == name2) &&
586
65.7k
    (insert->name3 == name3))
587
55.6k
    return(-1);
588
65.7k
  } else {
589
20.5k
      for (insert = &(table->table[key]); insert->next != NULL;
590
20.5k
     insert = insert->next) {
591
0
    if ((xmlStrEqual(insert->name, name)) &&
592
0
        (xmlStrEqual(insert->name2, name2)) &&
593
0
        (xmlStrEqual(insert->name3, name3)))
594
0
        return(-1);
595
0
    len++;
596
0
      }
597
20.5k
      if ((xmlStrEqual(insert->name, name)) &&
598
20.5k
    (xmlStrEqual(insert->name2, name2)) &&
599
20.5k
    (xmlStrEqual(insert->name3, name3)))
600
0
    return(-1);
601
20.5k
  }
602
87.7k
    }
603
604
784k
    if (insert == NULL) {
605
753k
  entry = &(table->table[key]);
606
753k
    } else {
607
30.6k
  entry = xmlMalloc(sizeof(xmlHashEntry));
608
30.6k
  if (entry == NULL)
609
173
       return(-1);
610
30.6k
    }
611
612
784k
    if (table->dict != NULL) {
613
41.1k
        entry->name = (xmlChar *) name;
614
41.1k
        entry->name2 = (xmlChar *) name2;
615
41.1k
        entry->name3 = (xmlChar *) name3;
616
743k
    } else {
617
743k
  entry->name = xmlStrdup(name);
618
743k
        if (entry->name == NULL) {
619
125k
            entry->name2 = NULL;
620
125k
            goto error;
621
125k
        }
622
617k
        if (name2 == NULL) {
623
597k
            entry->name2 = NULL;
624
597k
        } else {
625
19.3k
      entry->name2 = xmlStrdup(name2);
626
19.3k
            if (entry->name2 == NULL)
627
113
                goto error;
628
19.3k
        }
629
617k
        if (name3 == NULL) {
630
617k
            entry->name3 = NULL;
631
617k
        } else {
632
0
      entry->name3 = xmlStrdup(name3);
633
0
            if (entry->name3 == NULL)
634
0
                goto error;
635
0
        }
636
617k
    }
637
658k
    entry->payload = userdata;
638
658k
    entry->next = NULL;
639
658k
    entry->valid = 1;
640
641
642
658k
    if (insert != NULL)
643
30.3k
  insert->next = entry;
644
645
658k
    table->nbElems++;
646
647
658k
    if (len > MAX_HASH_LEN)
648
100
  xmlHashGrow(table, MAX_HASH_LEN * table->size);
649
650
658k
    return(0);
651
652
125k
error:
653
125k
    xmlFree(entry->name2);
654
125k
    xmlFree(entry->name);
655
125k
    if (insert != NULL)
656
139
        xmlFree(entry);
657
125k
    return(-1);
658
784k
}
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.50k
       void *userdata, xmlHashDeallocator f) {
679
6.50k
    unsigned long key;
680
6.50k
    xmlHashEntryPtr entry;
681
6.50k
    xmlHashEntryPtr insert;
682
683
6.50k
    if ((table == NULL) || name == NULL)
684
0
  return(-1);
685
686
    /*
687
     * If using a dict internalize if needed
688
     */
689
6.50k
    if (table->dict) {
690
4.82k
        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
4.82k
        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
4.82k
        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
4.82k
    }
706
707
    /*
708
     * Check for duplicate and insertion location.
709
     */
710
6.50k
    key = xmlHashComputeKey(table, name, name2, name3);
711
6.50k
    if (table->table[key].valid == 0) {
712
2.72k
  insert = NULL;
713
3.78k
    } else {
714
3.78k
        if (table ->dict) {
715
3.84k
      for (insert = &(table->table[key]); insert->next != NULL;
716
2.21k
     insert = insert->next) {
717
1.64k
    if ((insert->name == name) &&
718
1.64k
        (insert->name2 == name2) &&
719
1.64k
        (insert->name3 == name3)) {
720
11
        if (f)
721
0
      f(insert->payload, insert->name);
722
11
        insert->payload = userdata;
723
11
        return(0);
724
11
    }
725
1.64k
      }
726
2.20k
      if ((insert->name == name) &&
727
2.20k
    (insert->name2 == name2) &&
728
2.20k
    (insert->name3 == name3)) {
729
1.63k
    if (f)
730
0
        f(insert->payload, insert->name);
731
1.63k
    insert->payload = userdata;
732
1.63k
    return(0);
733
1.63k
      }
734
2.20k
  } else {
735
2.79k
      for (insert = &(table->table[key]); insert->next != NULL;
736
1.90k
     insert = insert->next) {
737
1.90k
    if ((xmlStrEqual(insert->name, name)) &&
738
1.90k
        (xmlStrEqual(insert->name2, name2)) &&
739
1.90k
        (xmlStrEqual(insert->name3, name3))) {
740
680
        if (f)
741
680
      f(insert->payload, insert->name);
742
680
        insert->payload = userdata;
743
680
        return(0);
744
680
    }
745
1.90k
      }
746
888
      if ((xmlStrEqual(insert->name, name)) &&
747
888
    (xmlStrEqual(insert->name2, name2)) &&
748
888
    (xmlStrEqual(insert->name3, name3))) {
749
805
    if (f)
750
805
        f(insert->payload, insert->name);
751
805
    insert->payload = userdata;
752
805
    return(0);
753
805
      }
754
888
  }
755
3.78k
    }
756
757
3.37k
    if (insert == NULL) {
758
2.72k
  entry =  &(table->table[key]);
759
2.72k
    } else {
760
655
  entry = xmlMalloc(sizeof(xmlHashEntry));
761
655
  if (entry == NULL)
762
1
       return(-1);
763
655
    }
764
765
3.37k
    if (table->dict != NULL) {
766
3.18k
        entry->name = (xmlChar *) name;
767
3.18k
        entry->name2 = (xmlChar *) name2;
768
3.18k
        entry->name3 = (xmlChar *) name3;
769
3.18k
    } else {
770
192
  entry->name = xmlStrdup(name);
771
192
        if (entry->name == NULL) {
772
4
            entry->name2 = NULL;
773
4
            goto error;
774
4
        }
775
188
        if (name2 == NULL) {
776
188
            entry->name2 = NULL;
777
188
        } else {
778
0
      entry->name2 = xmlStrdup(name2);
779
0
            if (entry->name2 == NULL)
780
0
                goto error;
781
0
        }
782
188
        if (name3 == NULL) {
783
188
            entry->name3 = NULL;
784
188
        } else {
785
0
      entry->name3 = xmlStrdup(name3);
786
0
            if (entry->name3 == NULL)
787
0
                goto error;
788
0
        }
789
188
    }
790
3.37k
    entry->payload = userdata;
791
3.37k
    entry->next = NULL;
792
3.37k
    entry->valid = 1;
793
3.37k
    table->nbElems++;
794
795
796
3.37k
    if (insert != NULL) {
797
653
  insert->next = entry;
798
653
    }
799
3.37k
    return(0);
800
801
4
error:
802
4
    xmlFree(entry->name2);
803
4
    xmlFree(entry->name);
804
4
    if (insert != NULL)
805
1
        xmlFree(entry);
806
4
    return(-1);
807
3.37k
}
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
1.21M
         const xmlChar *name2, const xmlChar *name3) {
823
1.21M
    unsigned long key;
824
1.21M
    xmlHashEntryPtr entry;
825
826
1.21M
    if (table == NULL)
827
74
  return(NULL);
828
1.21M
    if (name == NULL)
829
0
  return(NULL);
830
1.21M
    key = xmlHashComputeKey(table, name, name2, name3);
831
1.21M
    if (table->table[key].valid == 0)
832
622k
  return(NULL);
833
594k
    if (table->dict) {
834
1.06M
  for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
835
643k
      if ((entry->name == name) &&
836
643k
    (entry->name2 == name2) &&
837
643k
    (entry->name3 == name3))
838
169k
    return(entry->payload);
839
643k
  }
840
592k
    }
841
473k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
842
455k
  if ((xmlStrEqual(entry->name, name)) &&
843
455k
      (xmlStrEqual(entry->name2, name2)) &&
844
455k
      (xmlStrEqual(entry->name3, name3)))
845
407k
      return(entry->payload);
846
455k
    }
847
17.8k
    return(NULL);
848
425k
}
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
11.1k
    const xmlChar *prefix3, const xmlChar *name3) {
869
11.1k
    unsigned long key;
870
11.1k
    xmlHashEntryPtr entry;
871
872
11.1k
    if (table == NULL)
873
0
  return(NULL);
874
11.1k
    if (name == NULL)
875
0
  return(NULL);
876
11.1k
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
877
11.1k
                             name2, prefix3, name3);
878
11.1k
    if (table->table[key].valid == 0)
879
4.03k
  return(NULL);
880
8.70k
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
881
7.78k
  if ((xmlStrQEqual(prefix, name, entry->name)) &&
882
7.78k
      (xmlStrQEqual(prefix2, name2, entry->name2)) &&
883
7.78k
      (xmlStrQEqual(prefix3, name3, entry->name3)))
884
6.23k
      return(entry->payload);
885
7.78k
    }
886
923
    return(NULL);
887
7.16k
}
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
905
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
928
905
    int i, nb;
929
905
    xmlHashEntryPtr iter;
930
905
    xmlHashEntryPtr next;
931
932
905
    if (table == NULL)
933
0
  return;
934
905
    if (f == NULL)
935
0
  return;
936
937
905
    if (table->table) {
938
11.5k
  for(i = 0; i < table->size; i++) {
939
10.6k
      if (table->table[i].valid == 0)
940
8.58k
    continue;
941
2.07k
      iter = &(table->table[i]);
942
5.21k
      while (iter) {
943
3.14k
    next = iter->next;
944
3.14k
                nb = table->nbElems;
945
3.14k
    if ((f != NULL) && (iter->payload != NULL))
946
3.14k
        f(iter->payload, data, iter->name,
947
3.14k
          iter->name2, iter->name3);
948
3.14k
                if (nb != table->nbElems) {
949
                    /* table was modified by the callback, be careful */
950
844
                    if (iter == &(table->table[i])) {
951
549
                        if (table->table[i].valid == 0)
952
270
                            iter = NULL;
953
549
                        if (table->table[i].next != next)
954
279
          iter = &(table->table[i]);
955
549
                    } else
956
295
            iter = next;
957
844
                } else
958
2.29k
        iter = next;
959
3.14k
      }
960
2.07k
  }
961
905
    }
962
905
}
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
905
xmlHashSize(xmlHashTablePtr table) {
1087
905
    if (table == NULL)
1088
0
  return(-1);
1089
905
    return(table->nbElems);
1090
905
}
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
26
           xmlHashDeallocator f) {
1106
26
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1107
26
}
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
995
      const xmlChar *name2, xmlHashDeallocator f) {
1125
995
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1126
995
}
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
1.02k
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1145
1.02k
    unsigned long key;
1146
1.02k
    xmlHashEntryPtr entry;
1147
1.02k
    xmlHashEntryPtr prev = NULL;
1148
1149
1.02k
    if (table == NULL || name == NULL)
1150
0
        return(-1);
1151
1152
1.02k
    key = xmlHashComputeKey(table, name, name2, name3);
1153
1.02k
    if (table->table[key].valid == 0) {
1154
0
        return(-1);
1155
1.02k
    } else {
1156
1.46k
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1157
1.46k
            if (xmlStrEqual(entry->name, name) &&
1158
1.46k
                    xmlStrEqual(entry->name2, name2) &&
1159
1.46k
                    xmlStrEqual(entry->name3, name3)) {
1160
1.02k
                if ((f != NULL) && (entry->payload != NULL))
1161
26
                    f(entry->payload, entry->name);
1162
1.02k
                entry->payload = NULL;
1163
1.02k
    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
1.02k
                if(prev) {
1172
295
                    prev->next = entry->next;
1173
295
        xmlFree(entry);
1174
726
    } else {
1175
726
        if (entry->next == NULL) {
1176
447
      entry->valid = 0;
1177
447
        } else {
1178
279
      entry = entry->next;
1179
279
      memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1180
279
      xmlFree(entry);
1181
279
        }
1182
726
    }
1183
1.02k
                table->nbElems--;
1184
1.02k
                return(0);
1185
1.02k
            }
1186
440
            prev = entry;
1187
440
        }
1188
0
        return(-1);
1189
1.02k
    }
1190
1.02k
}
1191