/ libxml2 / hash.c
hash.c
   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  #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  	          const xmlChar *name2, const xmlChar *name3) {
  84      unsigned long value = 0L;
  85      char ch;
  86  
  87  #ifdef HASH_RANDOMIZATION
  88      value = table->random_seed;
  89  #endif
  90      if (name != NULL) {
  91  	value += 30 * (*name);
  92  	while ((ch = *name++) != 0) {
  93  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  94  	}
  95      }
  96      value = value ^ ((value << 5) + (value >> 3));
  97      if (name2 != NULL) {
  98  	while ((ch = *name2++) != 0) {
  99  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 100  	}
 101      }
 102      value = value ^ ((value << 5) + (value >> 3));
 103      if (name3 != NULL) {
 104  	while ((ch = *name3++) != 0) {
 105  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 106  	}
 107      }
 108      return (value % table->size);
 109  }
 110  
 111  static unsigned long
 112  xmlHashComputeQKey(xmlHashTablePtr table,
 113  		   const xmlChar *prefix, const xmlChar *name,
 114  		   const xmlChar *prefix2, const xmlChar *name2,
 115  		   const xmlChar *prefix3, const xmlChar *name3) {
 116      unsigned long value = 0L;
 117      char ch;
 118  
 119  #ifdef HASH_RANDOMIZATION
 120      value = table->random_seed;
 121  #endif
 122      if (prefix != NULL)
 123  	value += 30 * (*prefix);
 124      else
 125  	value += 30 * (*name);
 126  
 127      if (prefix != NULL) {
 128  	while ((ch = *prefix++) != 0) {
 129  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 130  	}
 131  	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
 132      }
 133      if (name != NULL) {
 134  	while ((ch = *name++) != 0) {
 135  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 136  	}
 137      }
 138      value = value ^ ((value << 5) + (value >> 3));
 139      if (prefix2 != NULL) {
 140  	while ((ch = *prefix2++) != 0) {
 141  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 142  	}
 143  	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
 144      }
 145      if (name2 != NULL) {
 146  	while ((ch = *name2++) != 0) {
 147  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 148  	}
 149      }
 150      value = value ^ ((value << 5) + (value >> 3));
 151      if (prefix3 != NULL) {
 152  	while ((ch = *prefix3++) != 0) {
 153  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 154  	}
 155  	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
 156      }
 157      if (name3 != NULL) {
 158  	while ((ch = *name3++) != 0) {
 159  	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 160  	}
 161      }
 162      return (value % table->size);
 163  }
 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  xmlHashCreate(int size) {
 175      xmlHashTablePtr table;
 176  
 177      if (size <= 0)
 178          size = 256;
 179  
 180      table = xmlMalloc(sizeof(xmlHashTable));
 181      if (table) {
 182          table->dict = NULL;
 183          table->size = size;
 184  	table->nbElems = 0;
 185          table->table = xmlMalloc(size * sizeof(xmlHashEntry));
 186          if (table->table) {
 187  	    memset(table->table, 0, size * sizeof(xmlHashEntry));
 188  #ifdef HASH_RANDOMIZATION
 189              table->random_seed = __xmlRandom();
 190  #endif
 191  	    return(table);
 192          }
 193          xmlFree(table);
 194      }
 195      return(NULL);
 196  }
 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  xmlHashCreateDict(int size, xmlDictPtr dict) {
 209      xmlHashTablePtr table;
 210  
 211      table = xmlHashCreate(size);
 212      if (table != NULL) {
 213          table->dict = dict;
 214  	xmlDictReference(dict);
 215      }
 216      return(table);
 217  }
 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  xmlHashGrow(xmlHashTablePtr table, int size) {
 230      unsigned long key;
 231      int oldsize, i;
 232      xmlHashEntryPtr iter, next;
 233      struct _xmlHashEntry *oldtable;
 234  #ifdef DEBUG_GROW
 235      unsigned long nbElem = 0;
 236  #endif
 237  
 238      if (table == NULL)
 239  	return(-1);
 240      if (size < 8)
 241          return(-1);
 242      if (size > 8 * 2048)
 243  	return(-1);
 244  
 245      oldsize = table->size;
 246      oldtable = table->table;
 247      if (oldtable == NULL)
 248          return(-1);
 249  
 250      table->table = xmlMalloc(size * sizeof(xmlHashEntry));
 251      if (table->table == NULL) {
 252  	table->table = oldtable;
 253  	return(-1);
 254      }
 255      memset(table->table, 0, size * sizeof(xmlHashEntry));
 256      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      for (i = 0; i < oldsize; i++) {
 265  	if (oldtable[i].valid == 0)
 266  	    continue;
 267  	key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
 268  				oldtable[i].name3);
 269  	memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
 270  	table->table[key].next = NULL;
 271      }
 272  
 273      for (i = 0; i < oldsize; i++) {
 274  	iter = oldtable[i].next;
 275  	while (iter) {
 276  	    next = iter->next;
 277  
 278  	    /*
 279  	     * put back the entry in the new table
 280  	     */
 281  
 282  	    key = xmlHashComputeKey(table, iter->name, iter->name2,
 283  		                    iter->name3);
 284  	    if (table->table[key].valid == 0) {
 285  		memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
 286  		table->table[key].next = NULL;
 287  		xmlFree(iter);
 288  	    } else {
 289  		iter->next = table->table[key].next;
 290  		table->table[key].next = iter;
 291  	    }
 292  
 293  #ifdef DEBUG_GROW
 294  	    nbElem++;
 295  #endif
 296  
 297  	    iter = next;
 298  	}
 299      }
 300  
 301      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      return(0);
 309  }
 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  xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
 321      int i;
 322      xmlHashEntryPtr iter;
 323      xmlHashEntryPtr next;
 324      int inside_table = 0;
 325      int nbElems;
 326  
 327      if (table == NULL)
 328  	return;
 329      if (table->table) {
 330  	nbElems = table->nbElems;
 331  	for(i = 0; (i < table->size) && (nbElems > 0); i++) {
 332  	    iter = &(table->table[i]);
 333  	    if (iter->valid == 0)
 334  		continue;
 335  	    inside_table = 1;
 336  	    while (iter) {
 337  		next = iter->next;
 338  		if ((f != NULL) && (iter->payload != NULL))
 339  		    f(iter->payload, iter->name);
 340  		if (table->dict == NULL) {
 341  		    if (iter->name)
 342  			xmlFree(iter->name);
 343  		    if (iter->name2)
 344  			xmlFree(iter->name2);
 345  		    if (iter->name3)
 346  			xmlFree(iter->name3);
 347  		}
 348  		iter->payload = NULL;
 349  		if (!inside_table)
 350  		    xmlFree(iter);
 351  		nbElems--;
 352  		inside_table = 0;
 353  		iter = next;
 354  	    }
 355  	}
 356  	xmlFree(table->table);
 357      }
 358      if (table->dict)
 359          xmlDictFree(table->dict);
 360      xmlFree(table);
 361  }
 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  xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
 376      return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
 377  }
 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  	        const xmlChar *name2, void *userdata) {
 394      return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
 395  }
 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  	           void *userdata, xmlHashDeallocator f) {
 413      return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
 414  }
 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  		   xmlHashDeallocator f) {
 434      return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
 435  }
 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  xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
 448      return(xmlHashLookup3(table, name, NULL, NULL));
 449  }
 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  	      const xmlChar *name2) {
 464      return(xmlHashLookup3(table, name, name2, NULL));
 465  }
 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                 const xmlChar *name) {
 480      return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
 481  }
 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  	        const xmlChar *name2) {
 499      return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
 500  }
 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  		 void *userdata) {
 520      unsigned long key, len = 0;
 521      xmlHashEntryPtr entry;
 522      xmlHashEntryPtr insert;
 523  
 524      if ((table == NULL) || (name == NULL))
 525  	return(-1);
 526  
 527      /*
 528       * If using a dict internalize if needed
 529       */
 530      if (table->dict) {
 531          if (!xmlDictOwns(table->dict, name)) {
 532  	    name = xmlDictLookup(table->dict, name, -1);
 533  	    if (name == NULL)
 534  	        return(-1);
 535  	}
 536          if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
 537  	    name2 = xmlDictLookup(table->dict, name2, -1);
 538  	    if (name2 == NULL)
 539  	        return(-1);
 540  	}
 541          if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
 542  	    name3 = xmlDictLookup(table->dict, name3, -1);
 543  	    if (name3 == NULL)
 544  	        return(-1);
 545  	}
 546      }
 547  
 548      /*
 549       * Check for duplicate and insertion location.
 550       */
 551      key = xmlHashComputeKey(table, name, name2, name3);
 552      if (table->table[key].valid == 0) {
 553  	insert = NULL;
 554      } else {
 555          if (table->dict) {
 556  	    for (insert = &(table->table[key]); insert->next != NULL;
 557  		 insert = insert->next) {
 558  		if ((insert->name == name) &&
 559  		    (insert->name2 == name2) &&
 560  		    (insert->name3 == name3))
 561  		    return(-1);
 562  		len++;
 563  	    }
 564  	    if ((insert->name == name) &&
 565  		(insert->name2 == name2) &&
 566  		(insert->name3 == name3))
 567  		return(-1);
 568  	} else {
 569  	    for (insert = &(table->table[key]); insert->next != NULL;
 570  		 insert = insert->next) {
 571  		if ((xmlStrEqual(insert->name, name)) &&
 572  		    (xmlStrEqual(insert->name2, name2)) &&
 573  		    (xmlStrEqual(insert->name3, name3)))
 574  		    return(-1);
 575  		len++;
 576  	    }
 577  	    if ((xmlStrEqual(insert->name, name)) &&
 578  		(xmlStrEqual(insert->name2, name2)) &&
 579  		(xmlStrEqual(insert->name3, name3)))
 580  		return(-1);
 581  	}
 582      }
 583  
 584      if (insert == NULL) {
 585  	entry = &(table->table[key]);
 586      } else {
 587  	entry = xmlMalloc(sizeof(xmlHashEntry));
 588  	if (entry == NULL)
 589  	     return(-1);
 590      }
 591  
 592      if (table->dict != NULL) {
 593          entry->name = (xmlChar *) name;
 594          entry->name2 = (xmlChar *) name2;
 595          entry->name3 = (xmlChar *) name3;
 596      } else {
 597  	entry->name = xmlStrdup(name);
 598  	entry->name2 = xmlStrdup(name2);
 599  	entry->name3 = xmlStrdup(name3);
 600      }
 601      entry->payload = userdata;
 602      entry->next = NULL;
 603      entry->valid = 1;
 604  
 605  
 606      if (insert != NULL)
 607  	insert->next = entry;
 608  
 609      table->nbElems++;
 610  
 611      if (len > MAX_HASH_LEN)
 612  	xmlHashGrow(table, MAX_HASH_LEN * table->size);
 613  
 614      return(0);
 615  }
 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  		   void *userdata, xmlHashDeallocator f) {
 636      unsigned long key;
 637      xmlHashEntryPtr entry;
 638      xmlHashEntryPtr insert;
 639  
 640      if ((table == NULL) || name == NULL)
 641  	return(-1);
 642  
 643      /*
 644       * If using a dict internalize if needed
 645       */
 646      if (table->dict) {
 647          if (!xmlDictOwns(table->dict, name)) {
 648  	    name = xmlDictLookup(table->dict, name, -1);
 649  	    if (name == NULL)
 650  	        return(-1);
 651  	}
 652          if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
 653  	    name2 = xmlDictLookup(table->dict, name2, -1);
 654  	    if (name2 == NULL)
 655  	        return(-1);
 656  	}
 657          if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
 658  	    name3 = xmlDictLookup(table->dict, name3, -1);
 659  	    if (name3 == NULL)
 660  	        return(-1);
 661  	}
 662      }
 663  
 664      /*
 665       * Check for duplicate and insertion location.
 666       */
 667      key = xmlHashComputeKey(table, name, name2, name3);
 668      if (table->table[key].valid == 0) {
 669  	insert = NULL;
 670      } else {
 671          if (table ->dict) {
 672  	    for (insert = &(table->table[key]); insert->next != NULL;
 673  		 insert = insert->next) {
 674  		if ((insert->name == name) &&
 675  		    (insert->name2 == name2) &&
 676  		    (insert->name3 == name3)) {
 677  		    if (f)
 678  			f(insert->payload, insert->name);
 679  		    insert->payload = userdata;
 680  		    return(0);
 681  		}
 682  	    }
 683  	    if ((insert->name == name) &&
 684  		(insert->name2 == name2) &&
 685  		(insert->name3 == name3)) {
 686  		if (f)
 687  		    f(insert->payload, insert->name);
 688  		insert->payload = userdata;
 689  		return(0);
 690  	    }
 691  	} else {
 692  	    for (insert = &(table->table[key]); insert->next != NULL;
 693  		 insert = insert->next) {
 694  		if ((xmlStrEqual(insert->name, name)) &&
 695  		    (xmlStrEqual(insert->name2, name2)) &&
 696  		    (xmlStrEqual(insert->name3, name3))) {
 697  		    if (f)
 698  			f(insert->payload, insert->name);
 699  		    insert->payload = userdata;
 700  		    return(0);
 701  		}
 702  	    }
 703  	    if ((xmlStrEqual(insert->name, name)) &&
 704  		(xmlStrEqual(insert->name2, name2)) &&
 705  		(xmlStrEqual(insert->name3, name3))) {
 706  		if (f)
 707  		    f(insert->payload, insert->name);
 708  		insert->payload = userdata;
 709  		return(0);
 710  	    }
 711  	}
 712      }
 713  
 714      if (insert == NULL) {
 715  	entry =  &(table->table[key]);
 716      } else {
 717  	entry = xmlMalloc(sizeof(xmlHashEntry));
 718  	if (entry == NULL)
 719  	     return(-1);
 720      }
 721  
 722      if (table->dict != NULL) {
 723          entry->name = (xmlChar *) name;
 724          entry->name2 = (xmlChar *) name2;
 725          entry->name3 = (xmlChar *) name3;
 726      } else {
 727  	entry->name = xmlStrdup(name);
 728  	entry->name2 = xmlStrdup(name2);
 729  	entry->name3 = xmlStrdup(name3);
 730      }
 731      entry->payload = userdata;
 732      entry->next = NULL;
 733      entry->valid = 1;
 734      table->nbElems++;
 735  
 736  
 737      if (insert != NULL) {
 738  	insert->next = entry;
 739      }
 740      return(0);
 741  }
 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  	       const xmlChar *name2, const xmlChar *name3) {
 757      unsigned long key;
 758      xmlHashEntryPtr entry;
 759  
 760      if (table == NULL)
 761  	return(NULL);
 762      if (name == NULL)
 763  	return(NULL);
 764      key = xmlHashComputeKey(table, name, name2, name3);
 765      if (table->table[key].valid == 0)
 766  	return(NULL);
 767      if (table->dict) {
 768  	for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
 769  	    if ((entry->name == name) &&
 770  		(entry->name2 == name2) &&
 771  		(entry->name3 == name3))
 772  		return(entry->payload);
 773  	}
 774      }
 775      for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
 776  	if ((xmlStrEqual(entry->name, name)) &&
 777  	    (xmlStrEqual(entry->name2, name2)) &&
 778  	    (xmlStrEqual(entry->name3, name3)))
 779  	    return(entry->payload);
 780      }
 781      return(NULL);
 782  }
 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  		const xmlChar *prefix3, const xmlChar *name3) {
 803      unsigned long key;
 804      xmlHashEntryPtr entry;
 805  
 806      if (table == NULL)
 807  	return(NULL);
 808      if (name == NULL)
 809  	return(NULL);
 810      key = xmlHashComputeQKey(table, prefix, name, prefix2,
 811                               name2, prefix3, name3);
 812      if (table->table[key].valid == 0)
 813  	return(NULL);
 814      for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
 815  	if ((xmlStrQEqual(prefix, name, entry->name)) &&
 816  	    (xmlStrQEqual(prefix2, name2, entry->name2)) &&
 817  	    (xmlStrQEqual(prefix3, name3, entry->name3)))
 818  	    return(entry->payload);
 819      }
 820      return(NULL);
 821  }
 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  		     const xmlChar *name3 ATTRIBUTE_UNUSED) {
 832      stubData *stubdata = (stubData *) data;
 833      stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
 834  }
 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  xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
 846      stubData stubdata;
 847      stubdata.data = data;
 848      stubdata.hashscanner = f;
 849      xmlHashScanFull (table, stubHashScannerFull, &stubdata);
 850  }
 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  xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
 862      int i, nb;
 863      xmlHashEntryPtr iter;
 864      xmlHashEntryPtr next;
 865  
 866      if (table == NULL)
 867  	return;
 868      if (f == NULL)
 869  	return;
 870  
 871      if (table->table) {
 872  	for(i = 0; i < table->size; i++) {
 873  	    if (table->table[i].valid == 0)
 874  		continue;
 875  	    iter = &(table->table[i]);
 876  	    while (iter) {
 877  		next = iter->next;
 878                  nb = table->nbElems;
 879  		if ((f != NULL) && (iter->payload != NULL))
 880  		    f(iter->payload, data, iter->name,
 881  		      iter->name2, iter->name3);
 882                  if (nb != table->nbElems) {
 883                      /* table was modified by the callback, be careful */
 884                      if (iter == &(table->table[i])) {
 885                          if (table->table[i].valid == 0)
 886                              iter = NULL;
 887                          if (table->table[i].next != next)
 888  			    iter = &(table->table[i]);
 889                      } else
 890  		        iter = next;
 891                  } else
 892  		    iter = next;
 893  	    }
 894  	}
 895      }
 896  }
 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  	     xmlHashScanner f, void *data) {
 915      xmlHashScanFull3 (table, name, name2, name3,
 916  		      (xmlHashScannerFull) f, data);
 917  }
 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  		 xmlHashScannerFull f, void *data) {
 936      int i;
 937      xmlHashEntryPtr iter;
 938      xmlHashEntryPtr next;
 939  
 940      if (table == NULL)
 941  	return;
 942      if (f == NULL)
 943  	return;
 944  
 945      if (table->table) {
 946  	for(i = 0; i < table->size; i++) {
 947  	    if (table->table[i].valid == 0)
 948  		continue;
 949  	    iter = &(table->table[i]);
 950  	    while (iter) {
 951  		next = iter->next;
 952  		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
 953  		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
 954  		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
 955  		    (iter->payload != NULL)) {
 956  		    f(iter->payload, data, iter->name,
 957  		      iter->name2, iter->name3);
 958  		}
 959  		iter = next;
 960  	    }
 961  	}
 962      }
 963  }
 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  xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
 976      int i;
 977      xmlHashEntryPtr iter;
 978      xmlHashEntryPtr next;
 979      xmlHashTablePtr ret;
 980  
 981      if (table == NULL)
 982  	return(NULL);
 983      if (f == NULL)
 984  	return(NULL);
 985  
 986      ret = xmlHashCreate(table->size);
 987      if (ret == NULL)
 988          return(NULL);
 989  
 990      if (table->table) {
 991  	for(i = 0; i < table->size; i++) {
 992  	    if (table->table[i].valid == 0)
 993  		continue;
 994  	    iter = &(table->table[i]);
 995  	    while (iter) {
 996  		next = iter->next;
 997  		xmlHashAddEntry3(ret, iter->name, iter->name2,
 998  			         iter->name3, f(iter->payload, iter->name));
 999  		iter = next;
1000  	    }
1001  	}
1002      }
1003      ret->nbElems = table->nbElems;
1004      return(ret);
1005  }
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  xmlHashSize(xmlHashTablePtr table) {
1018      if (table == NULL)
1019  	return(-1);
1020      return(table->nbElems);
1021  }
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  		       xmlHashDeallocator f) {
1037      return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1038  }
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  			const xmlChar *name2, xmlHashDeallocator f) {
1056      return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1057  }
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      const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1076      unsigned long key;
1077      xmlHashEntryPtr entry;
1078      xmlHashEntryPtr prev = NULL;
1079  
1080      if (table == NULL || name == NULL)
1081          return(-1);
1082  
1083      key = xmlHashComputeKey(table, name, name2, name3);
1084      if (table->table[key].valid == 0) {
1085          return(-1);
1086      } else {
1087          for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1088              if (xmlStrEqual(entry->name, name) &&
1089                      xmlStrEqual(entry->name2, name2) &&
1090                      xmlStrEqual(entry->name3, name3)) {
1091                  if ((f != NULL) && (entry->payload != NULL))
1092                      f(entry->payload, entry->name);
1093                  entry->payload = NULL;
1094  		if (table->dict == NULL) {
1095  		    if(entry->name)
1096  			xmlFree(entry->name);
1097  		    if(entry->name2)
1098  			xmlFree(entry->name2);
1099  		    if(entry->name3)
1100  			xmlFree(entry->name3);
1101  		}
1102                  if(prev) {
1103                      prev->next = entry->next;
1104  		    xmlFree(entry);
1105  		} else {
1106  		    if (entry->next == NULL) {
1107  			entry->valid = 0;
1108  		    } else {
1109  			entry = entry->next;
1110  			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1111  			xmlFree(entry);
1112  		    }
1113  		}
1114                  table->nbElems--;
1115                  return(0);
1116              }
1117              prev = entry;
1118          }
1119          return(-1);
1120      }
1121  }
1122  
1123  #define bottom_hash
1124  #include "elfgcchack.h"