File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / hash.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:18 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>