Coverage Report

Created: 2025-08-04 07:15

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