hash.c 30 KB

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