dict.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. /*
  2. * dict.c: dictionary of reusable strings, just used to avoid allocation
  3. * and freeing operations.
  4. *
  5. * Copyright (C) 2003 Daniel Veillard.
  6. *
  7. * Permission to use, copy, modify, and distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  12. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  13. * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
  14. * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
  15. *
  16. * Author: daniel@veillard.com
  17. */
  18. #define IN_LIBXML
  19. #include "libxml.h"
  20. #include <string.h>
  21. #ifdef HAVE_STDINT_H
  22. #include <stdint.h>
  23. #else
  24. #ifdef HAVE_INTTYPES_H
  25. #include <inttypes.h>
  26. #elif defined(WIN32)
  27. typedef unsigned __int32 uint32_t;
  28. #endif
  29. #endif
  30. #include <libxml/tree.h>
  31. #include <libxml/dict.h>
  32. #include <libxml/xmlmemory.h>
  33. #include <libxml/xmlerror.h>
  34. #include <libxml/globals.h>
  35. /* #define DEBUG_GROW */
  36. /* #define DICT_DEBUG_PATTERNS */
  37. #define MAX_HASH_LEN 3
  38. #define MIN_DICT_SIZE 128
  39. #define MAX_DICT_HASH 8 * 2048
  40. #define WITH_BIG_KEY
  41. #ifdef WITH_BIG_KEY
  42. #define xmlDictComputeKey(dict, name, len) \
  43. (((dict)->size == MIN_DICT_SIZE) ? \
  44. xmlDictComputeFastKey(name, len) : \
  45. xmlDictComputeBigKey(name, len))
  46. #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
  47. (((prefix) == NULL) ? \
  48. (xmlDictComputeKey(dict, name, len)) : \
  49. (((dict)->size == MIN_DICT_SIZE) ? \
  50. xmlDictComputeFastQKey(prefix, plen, name, len) : \
  51. xmlDictComputeBigQKey(prefix, plen, name, len)))
  52. #else /* !WITH_BIG_KEY */
  53. #define xmlDictComputeKey(dict, name, len) \
  54. xmlDictComputeFastKey(name, len)
  55. #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
  56. xmlDictComputeFastQKey(prefix, plen, name, len)
  57. #endif /* WITH_BIG_KEY */
  58. /*
  59. * An entry in the dictionnary
  60. */
  61. typedef struct _xmlDictEntry xmlDictEntry;
  62. typedef xmlDictEntry *xmlDictEntryPtr;
  63. struct _xmlDictEntry {
  64. struct _xmlDictEntry *next;
  65. const xmlChar *name;
  66. int len;
  67. int valid;
  68. unsigned long okey;
  69. };
  70. typedef struct _xmlDictStrings xmlDictStrings;
  71. typedef xmlDictStrings *xmlDictStringsPtr;
  72. struct _xmlDictStrings {
  73. xmlDictStringsPtr next;
  74. xmlChar *free;
  75. xmlChar *end;
  76. int size;
  77. int nbStrings;
  78. xmlChar array[1];
  79. };
  80. /*
  81. * The entire dictionnary
  82. */
  83. struct _xmlDict {
  84. int ref_counter;
  85. struct _xmlDictEntry *dict;
  86. int size;
  87. int nbElems;
  88. xmlDictStringsPtr strings;
  89. struct _xmlDict *subdict;
  90. };
  91. /*
  92. * A mutex for modifying the reference counter for shared
  93. * dictionaries.
  94. */
  95. static xmlRMutexPtr xmlDictMutex = NULL;
  96. /*
  97. * Whether the dictionary mutex was initialized.
  98. */
  99. static int xmlDictInitialized = 0;
  100. /**
  101. * xmlInitializeDict:
  102. *
  103. * Do the dictionary mutex initialization.
  104. * this function is not thread safe, initialization should
  105. * preferably be done once at startup
  106. */
  107. static int xmlInitializeDict(void) {
  108. if (xmlDictInitialized)
  109. return(1);
  110. if ((xmlDictMutex = xmlNewRMutex()) == NULL)
  111. return(0);
  112. xmlDictInitialized = 1;
  113. return(1);
  114. }
  115. /**
  116. * xmlDictCleanup:
  117. *
  118. * Free the dictionary mutex.
  119. */
  120. void
  121. xmlDictCleanup(void) {
  122. if (!xmlDictInitialized)
  123. return;
  124. xmlFreeRMutex(xmlDictMutex);
  125. xmlDictInitialized = 0;
  126. }
  127. /*
  128. * xmlDictAddString:
  129. * @dict: the dictionnary
  130. * @name: the name of the userdata
  131. * @len: the length of the name, if -1 it is recomputed
  132. *
  133. * Add the string to the array[s]
  134. *
  135. * Returns the pointer of the local string, or NULL in case of error.
  136. */
  137. static const xmlChar *
  138. xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
  139. xmlDictStringsPtr pool;
  140. const xmlChar *ret;
  141. int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
  142. #ifdef DICT_DEBUG_PATTERNS
  143. fprintf(stderr, "-");
  144. #endif
  145. pool = dict->strings;
  146. while (pool != NULL) {
  147. if (pool->end - pool->free > namelen)
  148. goto found_pool;
  149. if (pool->size > size) size = pool->size;
  150. pool = pool->next;
  151. }
  152. /*
  153. * Not found, need to allocate
  154. */
  155. if (pool == NULL) {
  156. if (size == 0) size = 1000;
  157. else size *= 4; /* exponential growth */
  158. if (size < 4 * namelen)
  159. size = 4 * namelen; /* just in case ! */
  160. pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
  161. if (pool == NULL)
  162. return(NULL);
  163. pool->size = size;
  164. pool->nbStrings = 0;
  165. pool->free = &pool->array[0];
  166. pool->end = &pool->array[size];
  167. pool->next = dict->strings;
  168. dict->strings = pool;
  169. #ifdef DICT_DEBUG_PATTERNS
  170. fprintf(stderr, "+");
  171. #endif
  172. }
  173. found_pool:
  174. ret = pool->free;
  175. memcpy(pool->free, name, namelen);
  176. pool->free += namelen;
  177. *(pool->free++) = 0;
  178. pool->nbStrings++;
  179. return(ret);
  180. }
  181. /*
  182. * xmlDictAddQString:
  183. * @dict: the dictionnary
  184. * @prefix: the prefix of the userdata
  185. * @plen: the prefix length
  186. * @name: the name of the userdata
  187. * @len: the length of the name, if -1 it is recomputed
  188. *
  189. * Add the QName to the array[s]
  190. *
  191. * Returns the pointer of the local string, or NULL in case of error.
  192. */
  193. static const xmlChar *
  194. xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
  195. const xmlChar *name, int namelen)
  196. {
  197. xmlDictStringsPtr pool;
  198. const xmlChar *ret;
  199. int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
  200. if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
  201. #ifdef DICT_DEBUG_PATTERNS
  202. fprintf(stderr, "=");
  203. #endif
  204. pool = dict->strings;
  205. while (pool != NULL) {
  206. if (pool->end - pool->free > namelen + plen + 1)
  207. goto found_pool;
  208. if (pool->size > size) size = pool->size;
  209. pool = pool->next;
  210. }
  211. /*
  212. * Not found, need to allocate
  213. */
  214. if (pool == NULL) {
  215. if (size == 0) size = 1000;
  216. else size *= 4; /* exponential growth */
  217. if (size < 4 * (namelen + plen + 1))
  218. size = 4 * (namelen + plen + 1); /* just in case ! */
  219. pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
  220. if (pool == NULL)
  221. return(NULL);
  222. pool->size = size;
  223. pool->nbStrings = 0;
  224. pool->free = &pool->array[0];
  225. pool->end = &pool->array[size];
  226. pool->next = dict->strings;
  227. dict->strings = pool;
  228. #ifdef DICT_DEBUG_PATTERNS
  229. fprintf(stderr, "+");
  230. #endif
  231. }
  232. found_pool:
  233. ret = pool->free;
  234. memcpy(pool->free, prefix, plen);
  235. pool->free += plen;
  236. *(pool->free++) = ':';
  237. memcpy(pool->free, name, namelen);
  238. pool->free += namelen;
  239. *(pool->free++) = 0;
  240. pool->nbStrings++;
  241. return(ret);
  242. }
  243. #ifdef WITH_BIG_KEY
  244. /*
  245. * xmlDictComputeBigKey:
  246. *
  247. * Calculate a hash key using a good hash function that works well for
  248. * larger hash table sizes.
  249. *
  250. * Hash function by "One-at-a-Time Hash" see
  251. * http://burtleburtle.net/bob/hash/doobs.html
  252. */
  253. static uint32_t
  254. xmlDictComputeBigKey(const xmlChar* data, int namelen) {
  255. uint32_t hash;
  256. int i;
  257. if (namelen <= 0 || data == NULL) return(0);
  258. hash = 0;
  259. for (i = 0;i < namelen; i++) {
  260. hash += data[i];
  261. hash += (hash << 10);
  262. hash ^= (hash >> 6);
  263. }
  264. hash += (hash << 3);
  265. hash ^= (hash >> 11);
  266. hash += (hash << 15);
  267. return hash;
  268. }
  269. /*
  270. * xmlDictComputeBigQKey:
  271. *
  272. * Calculate a hash key for two strings using a good hash function
  273. * that works well for larger hash table sizes.
  274. *
  275. * Hash function by "One-at-a-Time Hash" see
  276. * http://burtleburtle.net/bob/hash/doobs.html
  277. *
  278. * Neither of the two strings must be NULL.
  279. */
  280. static unsigned long
  281. xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
  282. const xmlChar *name, int len)
  283. {
  284. uint32_t hash;
  285. int i;
  286. hash = 0;
  287. for (i = 0;i < plen; i++) {
  288. hash += prefix[i];
  289. hash += (hash << 10);
  290. hash ^= (hash >> 6);
  291. }
  292. hash += ':';
  293. hash += (hash << 10);
  294. hash ^= (hash >> 6);
  295. for (i = 0;i < len; i++) {
  296. hash += name[i];
  297. hash += (hash << 10);
  298. hash ^= (hash >> 6);
  299. }
  300. hash += (hash << 3);
  301. hash ^= (hash >> 11);
  302. hash += (hash << 15);
  303. return hash;
  304. }
  305. #endif /* WITH_BIG_KEY */
  306. /*
  307. * xmlDictComputeFastKey:
  308. *
  309. * Calculate a hash key using a fast hash function that works well
  310. * for low hash table fill.
  311. */
  312. static unsigned long
  313. xmlDictComputeFastKey(const xmlChar *name, int namelen) {
  314. unsigned long value = 0L;
  315. if (name == NULL) return(0);
  316. value = *name;
  317. value <<= 5;
  318. if (namelen > 10) {
  319. value += name[namelen - 1];
  320. namelen = 10;
  321. }
  322. switch (namelen) {
  323. case 10: value += name[9];
  324. case 9: value += name[8];
  325. case 8: value += name[7];
  326. case 7: value += name[6];
  327. case 6: value += name[5];
  328. case 5: value += name[4];
  329. case 4: value += name[3];
  330. case 3: value += name[2];
  331. case 2: value += name[1];
  332. default: break;
  333. }
  334. return(value);
  335. }
  336. /*
  337. * xmlDictComputeFastQKey:
  338. *
  339. * Calculate a hash key for two strings using a fast hash function
  340. * that works well for low hash table fill.
  341. *
  342. * Neither of the two strings must be NULL.
  343. */
  344. static unsigned long
  345. xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
  346. const xmlChar *name, int len)
  347. {
  348. unsigned long value = 0L;
  349. if (plen == 0)
  350. value += 30 * (unsigned long) ':';
  351. else
  352. value += 30 * (*prefix);
  353. if (len > 10) {
  354. value += name[len - (plen + 1 + 1)];
  355. len = 10;
  356. if (plen > 10)
  357. plen = 10;
  358. }
  359. switch (plen) {
  360. case 10: value += prefix[9];
  361. case 9: value += prefix[8];
  362. case 8: value += prefix[7];
  363. case 7: value += prefix[6];
  364. case 6: value += prefix[5];
  365. case 5: value += prefix[4];
  366. case 4: value += prefix[3];
  367. case 3: value += prefix[2];
  368. case 2: value += prefix[1];
  369. case 1: value += prefix[0];
  370. default: break;
  371. }
  372. len -= plen;
  373. if (len > 0) {
  374. value += (unsigned long) ':';
  375. len--;
  376. }
  377. switch (len) {
  378. case 10: value += name[9];
  379. case 9: value += name[8];
  380. case 8: value += name[7];
  381. case 7: value += name[6];
  382. case 6: value += name[5];
  383. case 5: value += name[4];
  384. case 4: value += name[3];
  385. case 3: value += name[2];
  386. case 2: value += name[1];
  387. case 1: value += name[0];
  388. default: break;
  389. }
  390. return(value);
  391. }
  392. /**
  393. * xmlDictCreate:
  394. *
  395. * Create a new dictionary
  396. *
  397. * Returns the newly created dictionnary, or NULL if an error occured.
  398. */
  399. xmlDictPtr
  400. xmlDictCreate(void) {
  401. xmlDictPtr dict;
  402. if (!xmlDictInitialized)
  403. if (!xmlInitializeDict())
  404. return(NULL);
  405. #ifdef DICT_DEBUG_PATTERNS
  406. fprintf(stderr, "C");
  407. #endif
  408. dict = xmlMalloc(sizeof(xmlDict));
  409. if (dict) {
  410. dict->ref_counter = 1;
  411. dict->size = MIN_DICT_SIZE;
  412. dict->nbElems = 0;
  413. dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
  414. dict->strings = NULL;
  415. dict->subdict = NULL;
  416. if (dict->dict) {
  417. memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
  418. return(dict);
  419. }
  420. xmlFree(dict);
  421. }
  422. return(NULL);
  423. }
  424. /**
  425. * xmlDictCreateSub:
  426. * @sub: an existing dictionnary
  427. *
  428. * Create a new dictionary, inheriting strings from the read-only
  429. * dictionnary @sub. On lookup, strings are first searched in the
  430. * new dictionnary, then in @sub, and if not found are created in the
  431. * new dictionnary.
  432. *
  433. * Returns the newly created dictionnary, or NULL if an error occured.
  434. */
  435. xmlDictPtr
  436. xmlDictCreateSub(xmlDictPtr sub) {
  437. xmlDictPtr dict = xmlDictCreate();
  438. if ((dict != NULL) && (sub != NULL)) {
  439. #ifdef DICT_DEBUG_PATTERNS
  440. fprintf(stderr, "R");
  441. #endif
  442. dict->subdict = sub;
  443. xmlDictReference(dict->subdict);
  444. }
  445. return(dict);
  446. }
  447. /**
  448. * xmlDictReference:
  449. * @dict: the dictionnary
  450. *
  451. * Increment the reference counter of a dictionary
  452. *
  453. * Returns 0 in case of success and -1 in case of error
  454. */
  455. int
  456. xmlDictReference(xmlDictPtr dict) {
  457. if (!xmlDictInitialized)
  458. if (!xmlInitializeDict())
  459. return(-1);
  460. if (dict == NULL) return -1;
  461. xmlRMutexLock(xmlDictMutex);
  462. dict->ref_counter++;
  463. xmlRMutexUnlock(xmlDictMutex);
  464. return(0);
  465. }
  466. /**
  467. * xmlDictGrow:
  468. * @dict: the dictionnary
  469. * @size: the new size of the dictionnary
  470. *
  471. * resize the dictionnary
  472. *
  473. * Returns 0 in case of success, -1 in case of failure
  474. */
  475. static int
  476. xmlDictGrow(xmlDictPtr dict, int size) {
  477. unsigned long key, okey;
  478. int oldsize, i;
  479. xmlDictEntryPtr iter, next;
  480. struct _xmlDictEntry *olddict;
  481. #ifdef DEBUG_GROW
  482. unsigned long nbElem = 0;
  483. #endif
  484. int ret = 0;
  485. int keep_keys = 1;
  486. if (dict == NULL)
  487. return(-1);
  488. if (size < 8)
  489. return(-1);
  490. if (size > 8 * 2048)
  491. return(-1);
  492. #ifdef DICT_DEBUG_PATTERNS
  493. fprintf(stderr, "*");
  494. #endif
  495. oldsize = dict->size;
  496. olddict = dict->dict;
  497. if (olddict == NULL)
  498. return(-1);
  499. if (oldsize == MIN_DICT_SIZE)
  500. keep_keys = 0;
  501. dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
  502. if (dict->dict == NULL) {
  503. dict->dict = olddict;
  504. return(-1);
  505. }
  506. memset(dict->dict, 0, size * sizeof(xmlDictEntry));
  507. dict->size = size;
  508. /* If the two loops are merged, there would be situations where
  509. a new entry needs to allocated and data copied into it from
  510. the main dict. It is nicer to run through the array twice, first
  511. copying all the elements in the main array (less probability of
  512. allocate) and then the rest, so we only free in the second loop.
  513. */
  514. for (i = 0; i < oldsize; i++) {
  515. if (olddict[i].valid == 0)
  516. continue;
  517. if (keep_keys)
  518. okey = olddict[i].okey;
  519. else
  520. okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
  521. key = okey % dict->size;
  522. if (dict->dict[key].valid == 0) {
  523. memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
  524. dict->dict[key].next = NULL;
  525. dict->dict[key].okey = okey;
  526. } else {
  527. xmlDictEntryPtr entry;
  528. entry = xmlMalloc(sizeof(xmlDictEntry));
  529. if (entry != NULL) {
  530. entry->name = olddict[i].name;
  531. entry->len = olddict[i].len;
  532. entry->okey = okey;
  533. entry->next = dict->dict[key].next;
  534. entry->valid = 1;
  535. dict->dict[key].next = entry;
  536. } else {
  537. /*
  538. * we don't have much ways to alert from herei
  539. * result is loosing an entry and unicity garantee
  540. */
  541. ret = -1;
  542. }
  543. }
  544. #ifdef DEBUG_GROW
  545. nbElem++;
  546. #endif
  547. }
  548. for (i = 0; i < oldsize; i++) {
  549. iter = olddict[i].next;
  550. while (iter) {
  551. next = iter->next;
  552. /*
  553. * put back the entry in the new dict
  554. */
  555. if (keep_keys)
  556. okey = iter->okey;
  557. else
  558. okey = xmlDictComputeKey(dict, iter->name, iter->len);
  559. key = okey % dict->size;
  560. if (dict->dict[key].valid == 0) {
  561. memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
  562. dict->dict[key].next = NULL;
  563. dict->dict[key].valid = 1;
  564. dict->dict[key].okey = okey;
  565. xmlFree(iter);
  566. } else {
  567. iter->next = dict->dict[key].next;
  568. iter->okey = okey;
  569. dict->dict[key].next = iter;
  570. }
  571. #ifdef DEBUG_GROW
  572. nbElem++;
  573. #endif
  574. iter = next;
  575. }
  576. }
  577. xmlFree(olddict);
  578. #ifdef DEBUG_GROW
  579. xmlGenericError(xmlGenericErrorContext,
  580. "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
  581. #endif
  582. return(ret);
  583. }
  584. /**
  585. * xmlDictFree:
  586. * @dict: the dictionnary
  587. *
  588. * Free the hash @dict and its contents. The userdata is
  589. * deallocated with @f if provided.
  590. */
  591. void
  592. xmlDictFree(xmlDictPtr dict) {
  593. int i;
  594. xmlDictEntryPtr iter;
  595. xmlDictEntryPtr next;
  596. int inside_dict = 0;
  597. xmlDictStringsPtr pool, nextp;
  598. if (dict == NULL)
  599. return;
  600. if (!xmlDictInitialized)
  601. if (!xmlInitializeDict())
  602. return;
  603. /* decrement the counter, it may be shared by a parser and docs */
  604. xmlRMutexLock(xmlDictMutex);
  605. dict->ref_counter--;
  606. if (dict->ref_counter > 0) {
  607. xmlRMutexUnlock(xmlDictMutex);
  608. return;
  609. }
  610. xmlRMutexUnlock(xmlDictMutex);
  611. if (dict->subdict != NULL) {
  612. xmlDictFree(dict->subdict);
  613. }
  614. if (dict->dict) {
  615. for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
  616. iter = &(dict->dict[i]);
  617. if (iter->valid == 0)
  618. continue;
  619. inside_dict = 1;
  620. while (iter) {
  621. next = iter->next;
  622. if (!inside_dict)
  623. xmlFree(iter);
  624. dict->nbElems--;
  625. inside_dict = 0;
  626. iter = next;
  627. }
  628. }
  629. xmlFree(dict->dict);
  630. }
  631. pool = dict->strings;
  632. while (pool != NULL) {
  633. nextp = pool->next;
  634. xmlFree(pool);
  635. pool = nextp;
  636. }
  637. xmlFree(dict);
  638. }
  639. /**
  640. * xmlDictLookup:
  641. * @dict: the dictionnary
  642. * @name: the name of the userdata
  643. * @len: the length of the name, if -1 it is recomputed
  644. *
  645. * Add the @name to the dictionnary @dict if not present.
  646. *
  647. * Returns the internal copy of the name or NULL in case of internal error
  648. */
  649. const xmlChar *
  650. xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
  651. unsigned long key, okey, nbi = 0;
  652. xmlDictEntryPtr entry;
  653. xmlDictEntryPtr insert;
  654. const xmlChar *ret;
  655. if ((dict == NULL) || (name == NULL))
  656. return(NULL);
  657. if (len < 0)
  658. len = strlen((const char *) name);
  659. /*
  660. * Check for duplicate and insertion location.
  661. */
  662. okey = xmlDictComputeKey(dict, name, len);
  663. key = okey % dict->size;
  664. if (dict->dict[key].valid == 0) {
  665. insert = NULL;
  666. } else {
  667. for (insert = &(dict->dict[key]); insert->next != NULL;
  668. insert = insert->next) {
  669. #ifdef __GNUC__
  670. if ((insert->okey == okey) && (insert->len == len)) {
  671. if (!memcmp(insert->name, name, len))
  672. return(insert->name);
  673. }
  674. #else
  675. if ((insert->okey == okey) && (insert->len == len) &&
  676. (!xmlStrncmp(insert->name, name, len)))
  677. return(insert->name);
  678. #endif
  679. nbi++;
  680. }
  681. #ifdef __GNUC__
  682. if ((insert->okey == okey) && (insert->len == len)) {
  683. if (!memcmp(insert->name, name, len))
  684. return(insert->name);
  685. }
  686. #else
  687. if ((insert->okey == okey) && (insert->len == len) &&
  688. (!xmlStrncmp(insert->name, name, len)))
  689. return(insert->name);
  690. #endif
  691. }
  692. if (dict->subdict) {
  693. unsigned long skey;
  694. /* we cannot always reuse the same okey for the subdict */
  695. if (((dict->size == MIN_DICT_SIZE) &&
  696. (dict->subdict->size != MIN_DICT_SIZE)) ||
  697. ((dict->size != MIN_DICT_SIZE) &&
  698. (dict->subdict->size == MIN_DICT_SIZE)))
  699. skey = xmlDictComputeKey(dict->subdict, name, len);
  700. else
  701. skey = okey;
  702. key = skey % dict->subdict->size;
  703. if (dict->subdict->dict[key].valid != 0) {
  704. xmlDictEntryPtr tmp;
  705. for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
  706. tmp = tmp->next) {
  707. #ifdef __GNUC__
  708. if ((tmp->okey == skey) && (tmp->len == len)) {
  709. if (!memcmp(tmp->name, name, len))
  710. return(tmp->name);
  711. }
  712. #else
  713. if ((tmp->okey == skey) && (tmp->len == len) &&
  714. (!xmlStrncmp(tmp->name, name, len)))
  715. return(tmp->name);
  716. #endif
  717. nbi++;
  718. }
  719. #ifdef __GNUC__
  720. if ((tmp->okey == skey) && (tmp->len == len)) {
  721. if (!memcmp(tmp->name, name, len))
  722. return(tmp->name);
  723. }
  724. #else
  725. if ((tmp->okey == skey) && (tmp->len == len) &&
  726. (!xmlStrncmp(tmp->name, name, len)))
  727. return(tmp->name);
  728. #endif
  729. }
  730. key = okey % dict->size;
  731. }
  732. ret = xmlDictAddString(dict, name, len);
  733. if (ret == NULL)
  734. return(NULL);
  735. if (insert == NULL) {
  736. entry = &(dict->dict[key]);
  737. } else {
  738. entry = xmlMalloc(sizeof(xmlDictEntry));
  739. if (entry == NULL)
  740. return(NULL);
  741. }
  742. entry->name = ret;
  743. entry->len = len;
  744. entry->next = NULL;
  745. entry->valid = 1;
  746. entry->okey = okey;
  747. if (insert != NULL)
  748. insert->next = entry;
  749. dict->nbElems++;
  750. if ((nbi > MAX_HASH_LEN) &&
  751. (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
  752. if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
  753. return(NULL);
  754. }
  755. /* Note that entry may have been freed at this point by xmlDictGrow */
  756. return(ret);
  757. }
  758. /**
  759. * xmlDictExists:
  760. * @dict: the dictionnary
  761. * @name: the name of the userdata
  762. * @len: the length of the name, if -1 it is recomputed
  763. *
  764. * Check if the @name exists in the dictionnary @dict.
  765. *
  766. * Returns the internal copy of the name or NULL if not found.
  767. */
  768. const xmlChar *
  769. xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
  770. unsigned long key, okey, nbi = 0;
  771. xmlDictEntryPtr insert;
  772. if ((dict == NULL) || (name == NULL))
  773. return(NULL);
  774. if (len < 0)
  775. len = strlen((const char *) name);
  776. /*
  777. * Check for duplicate and insertion location.
  778. */
  779. okey = xmlDictComputeKey(dict, name, len);
  780. key = okey % dict->size;
  781. if (dict->dict[key].valid == 0) {
  782. insert = NULL;
  783. } else {
  784. for (insert = &(dict->dict[key]); insert->next != NULL;
  785. insert = insert->next) {
  786. #ifdef __GNUC__
  787. if ((insert->okey == okey) && (insert->len == len)) {
  788. if (!memcmp(insert->name, name, len))
  789. return(insert->name);
  790. }
  791. #else
  792. if ((insert->okey == okey) && (insert->len == len) &&
  793. (!xmlStrncmp(insert->name, name, len)))
  794. return(insert->name);
  795. #endif
  796. nbi++;
  797. }
  798. #ifdef __GNUC__
  799. if ((insert->okey == okey) && (insert->len == len)) {
  800. if (!memcmp(insert->name, name, len))
  801. return(insert->name);
  802. }
  803. #else
  804. if ((insert->okey == okey) && (insert->len == len) &&
  805. (!xmlStrncmp(insert->name, name, len)))
  806. return(insert->name);
  807. #endif
  808. }
  809. if (dict->subdict) {
  810. unsigned long skey;
  811. /* we cannot always reuse the same okey for the subdict */
  812. if (((dict->size == MIN_DICT_SIZE) &&
  813. (dict->subdict->size != MIN_DICT_SIZE)) ||
  814. ((dict->size != MIN_DICT_SIZE) &&
  815. (dict->subdict->size == MIN_DICT_SIZE)))
  816. skey = xmlDictComputeKey(dict->subdict, name, len);
  817. else
  818. skey = okey;
  819. key = skey % dict->subdict->size;
  820. if (dict->subdict->dict[key].valid != 0) {
  821. xmlDictEntryPtr tmp;
  822. for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
  823. tmp = tmp->next) {
  824. #ifdef __GNUC__
  825. if ((tmp->okey == skey) && (tmp->len == len)) {
  826. if (!memcmp(tmp->name, name, len))
  827. return(tmp->name);
  828. }
  829. #else
  830. if ((tmp->okey == skey) && (tmp->len == len) &&
  831. (!xmlStrncmp(tmp->name, name, len)))
  832. return(tmp->name);
  833. #endif
  834. nbi++;
  835. }
  836. #ifdef __GNUC__
  837. if ((tmp->okey == skey) && (tmp->len == len)) {
  838. if (!memcmp(tmp->name, name, len))
  839. return(tmp->name);
  840. }
  841. #else
  842. if ((tmp->okey == skey) && (tmp->len == len) &&
  843. (!xmlStrncmp(tmp->name, name, len)))
  844. return(tmp->name);
  845. #endif
  846. }
  847. }
  848. /* not found */
  849. return(NULL);
  850. }
  851. /**
  852. * xmlDictQLookup:
  853. * @dict: the dictionnary
  854. * @prefix: the prefix
  855. * @name: the name
  856. *
  857. * Add the QName @prefix:@name to the hash @dict if not present.
  858. *
  859. * Returns the internal copy of the QName or NULL in case of internal error
  860. */
  861. const xmlChar *
  862. xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
  863. unsigned long okey, key, nbi = 0;
  864. xmlDictEntryPtr entry;
  865. xmlDictEntryPtr insert;
  866. const xmlChar *ret;
  867. int len, plen, l;
  868. if ((dict == NULL) || (name == NULL))
  869. return(NULL);
  870. if (prefix == NULL)
  871. return(xmlDictLookup(dict, name, -1));
  872. l = len = strlen((const char *) name);
  873. plen = strlen((const char *) prefix);
  874. len += 1 + plen;
  875. /*
  876. * Check for duplicate and insertion location.
  877. */
  878. okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
  879. key = okey % dict->size;
  880. if (dict->dict[key].valid == 0) {
  881. insert = NULL;
  882. } else {
  883. for (insert = &(dict->dict[key]); insert->next != NULL;
  884. insert = insert->next) {
  885. if ((insert->okey == okey) && (insert->len == len) &&
  886. (xmlStrQEqual(prefix, name, insert->name)))
  887. return(insert->name);
  888. nbi++;
  889. }
  890. if ((insert->okey == okey) && (insert->len == len) &&
  891. (xmlStrQEqual(prefix, name, insert->name)))
  892. return(insert->name);
  893. }
  894. if (dict->subdict) {
  895. unsigned long skey;
  896. /* we cannot always reuse the same okey for the subdict */
  897. if (((dict->size == MIN_DICT_SIZE) &&
  898. (dict->subdict->size != MIN_DICT_SIZE)) ||
  899. ((dict->size != MIN_DICT_SIZE) &&
  900. (dict->subdict->size == MIN_DICT_SIZE)))
  901. skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
  902. else
  903. skey = okey;
  904. key = skey % dict->subdict->size;
  905. if (dict->subdict->dict[key].valid != 0) {
  906. xmlDictEntryPtr tmp;
  907. for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
  908. tmp = tmp->next) {
  909. if ((tmp->okey == skey) && (tmp->len == len) &&
  910. (xmlStrQEqual(prefix, name, tmp->name)))
  911. return(tmp->name);
  912. nbi++;
  913. }
  914. if ((tmp->okey == skey) && (tmp->len == len) &&
  915. (xmlStrQEqual(prefix, name, tmp->name)))
  916. return(tmp->name);
  917. }
  918. key = okey % dict->size;
  919. }
  920. ret = xmlDictAddQString(dict, prefix, plen, name, l);
  921. if (ret == NULL)
  922. return(NULL);
  923. if (insert == NULL) {
  924. entry = &(dict->dict[key]);
  925. } else {
  926. entry = xmlMalloc(sizeof(xmlDictEntry));
  927. if (entry == NULL)
  928. return(NULL);
  929. }
  930. entry->name = ret;
  931. entry->len = len;
  932. entry->next = NULL;
  933. entry->valid = 1;
  934. entry->okey = okey;
  935. if (insert != NULL)
  936. insert->next = entry;
  937. dict->nbElems++;
  938. if ((nbi > MAX_HASH_LEN) &&
  939. (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
  940. xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
  941. /* Note that entry may have been freed at this point by xmlDictGrow */
  942. return(ret);
  943. }
  944. /**
  945. * xmlDictOwns:
  946. * @dict: the dictionnary
  947. * @str: the string
  948. *
  949. * check if a string is owned by the disctionary
  950. *
  951. * Returns 1 if true, 0 if false and -1 in case of error
  952. * -1 in case of error
  953. */
  954. int
  955. xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
  956. xmlDictStringsPtr pool;
  957. if ((dict == NULL) || (str == NULL))
  958. return(-1);
  959. pool = dict->strings;
  960. while (pool != NULL) {
  961. if ((str >= &pool->array[0]) && (str <= pool->free))
  962. return(1);
  963. pool = pool->next;
  964. }
  965. if (dict->subdict)
  966. return(xmlDictOwns(dict->subdict, str));
  967. return(0);
  968. }
  969. /**
  970. * xmlDictSize:
  971. * @dict: the dictionnary
  972. *
  973. * Query the number of elements installed in the hash @dict.
  974. *
  975. * Returns the number of elements in the dictionnary or
  976. * -1 in case of error
  977. */
  978. int
  979. xmlDictSize(xmlDictPtr dict) {
  980. if (dict == NULL)
  981. return(-1);
  982. if (dict->subdict)
  983. return(dict->nbElems + dict->subdict->nbElems);
  984. return(dict->nbElems);
  985. }
  986. #define bottom_dict
  987. #include "elfgcchack.h"