File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / hash.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:31 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    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 occured.
  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 occured.
  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 (table->table) {
  988: 	for(i = 0; i < table->size; i++) {
  989: 	    if (table->table[i].valid == 0)
  990: 		continue;
  991: 	    iter = &(table->table[i]);
  992: 	    while (iter) {
  993: 		next = iter->next;
  994: 		xmlHashAddEntry3(ret, iter->name, iter->name2,
  995: 			         iter->name3, f(iter->payload, iter->name));
  996: 		iter = next;
  997: 	    }
  998: 	}
  999:     }
 1000:     ret->nbElems = table->nbElems;
 1001:     return(ret);
 1002: }
 1003: 
 1004: /**
 1005:  * xmlHashSize:
 1006:  * @table: the hash table
 1007:  *
 1008:  * Query the number of elements installed in the hash @table.
 1009:  *
 1010:  * Returns the number of elements in the hash table or
 1011:  * -1 in case of error
 1012:  */
 1013: int
 1014: xmlHashSize(xmlHashTablePtr table) {
 1015:     if (table == NULL)
 1016: 	return(-1);
 1017:     return(table->nbElems);
 1018: }
 1019: 
 1020: /**
 1021:  * xmlHashRemoveEntry:
 1022:  * @table: the hash table
 1023:  * @name: the name of the userdata
 1024:  * @f: the deallocator function for removed item (if any)
 1025:  *
 1026:  * Find the userdata specified by the @name and remove
 1027:  * it from the hash @table. Existing userdata for this tuple will be removed
 1028:  * and freed with @f.
 1029:  *
 1030:  * Returns 0 if the removal succeeded and -1 in case of error or not found.
 1031:  */
 1032: int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
 1033: 		       xmlHashDeallocator f) {
 1034:     return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
 1035: }
 1036: 
 1037: /**
 1038:  * xmlHashRemoveEntry2:
 1039:  * @table: the hash table
 1040:  * @name: the name of the userdata
 1041:  * @name2: a second name of the userdata
 1042:  * @f: the deallocator function for removed item (if any)
 1043:  *
 1044:  * Find the userdata specified by the (@name, @name2) tuple and remove
 1045:  * it from the hash @table. Existing userdata for this tuple will be removed
 1046:  * and freed with @f.
 1047:  *
 1048:  * Returns 0 if the removal succeeded and -1 in case of error or not found.
 1049:  */
 1050: int
 1051: xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
 1052: 			const xmlChar *name2, xmlHashDeallocator f) {
 1053:     return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
 1054: }
 1055: 
 1056: /**
 1057:  * xmlHashRemoveEntry3:
 1058:  * @table: the hash table
 1059:  * @name: the name of the userdata
 1060:  * @name2: a second name of the userdata
 1061:  * @name3: a third name of the userdata
 1062:  * @f: the deallocator function for removed item (if any)
 1063:  *
 1064:  * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
 1065:  * it from the hash @table. Existing userdata for this tuple will be removed
 1066:  * and freed with @f.
 1067:  *
 1068:  * Returns 0 if the removal succeeded and -1 in case of error or not found.
 1069:  */
 1070: int
 1071: xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
 1072:     const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
 1073:     unsigned long key;
 1074:     xmlHashEntryPtr entry;
 1075:     xmlHashEntryPtr prev = NULL;
 1076: 
 1077:     if (table == NULL || name == NULL)
 1078:         return(-1);
 1079: 
 1080:     key = xmlHashComputeKey(table, name, name2, name3);
 1081:     if (table->table[key].valid == 0) {
 1082:         return(-1);
 1083:     } else {
 1084:         for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
 1085:             if (xmlStrEqual(entry->name, name) &&
 1086:                     xmlStrEqual(entry->name2, name2) &&
 1087:                     xmlStrEqual(entry->name3, name3)) {
 1088:                 if ((f != NULL) && (entry->payload != NULL))
 1089:                     f(entry->payload, entry->name);
 1090:                 entry->payload = NULL;
 1091: 		if (table->dict == NULL) {
 1092: 		    if(entry->name)
 1093: 			xmlFree(entry->name);
 1094: 		    if(entry->name2)
 1095: 			xmlFree(entry->name2);
 1096: 		    if(entry->name3)
 1097: 			xmlFree(entry->name3);
 1098: 		}
 1099:                 if(prev) {
 1100:                     prev->next = entry->next;
 1101: 		    xmlFree(entry);
 1102: 		} else {
 1103: 		    if (entry->next == NULL) {
 1104: 			entry->valid = 0;
 1105: 		    } else {
 1106: 			entry = entry->next;
 1107: 			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
 1108: 			xmlFree(entry);
 1109: 		    }
 1110: 		}
 1111:                 table->nbElems--;
 1112:                 return(0);
 1113:             }
 1114:             prev = entry;
 1115:         }
 1116:         return(-1);
 1117:     }
 1118: }
 1119: 
 1120: #define bottom_hash
 1121: #include "elfgcchack.h"

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