hash.c 28 KB

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