lhash.c
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:11k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* crypto/lhash/lhash.c */
  2. /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  3.  * All rights reserved.
  4.  *
  5.  * This package is an SSL implementation written
  6.  * by Eric Young (eay@cryptsoft.com).
  7.  * The implementation was written so as to conform with Netscapes SSL.
  8.  * 
  9.  * This library is free for commercial and non-commercial use as long as
  10.  * the following conditions are aheared to.  The following conditions
  11.  * apply to all code found in this distribution, be it the RC4, RSA,
  12.  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
  13.  * included with this distribution is covered by the same copyright terms
  14.  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
  15.  * 
  16.  * Copyright remains Eric Young's, and as such any Copyright notices in
  17.  * the code are not to be removed.
  18.  * If this package is used in a product, Eric Young should be given attribution
  19.  * as the author of the parts of the library used.
  20.  * This can be in the form of a textual message at program startup or
  21.  * in documentation (online or textual) provided with the package.
  22.  * 
  23.  * Redistribution and use in source and binary forms, with or without
  24.  * modification, are permitted provided that the following conditions
  25.  * are met:
  26.  * 1. Redistributions of source code must retain the copyright
  27.  *    notice, this list of conditions and the following disclaimer.
  28.  * 2. Redistributions in binary form must reproduce the above copyright
  29.  *    notice, this list of conditions and the following disclaimer in the
  30.  *    documentation and/or other materials provided with the distribution.
  31.  * 3. All advertising materials mentioning features or use of this software
  32.  *    must display the following acknowledgement:
  33.  *    "This product includes cryptographic software written by
  34.  *     Eric Young (eay@cryptsoft.com)"
  35.  *    The word 'cryptographic' can be left out if the rouines from the library
  36.  *    being used are not cryptographic related :-).
  37.  * 4. If you include any Windows specific code (or a derivative thereof) from 
  38.  *    the apps directory (application code) you must include an acknowledgement:
  39.  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
  40.  * 
  41.  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
  42.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  43.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  44.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  45.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  46.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  47.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  48.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  49.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  50.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51.  * SUCH DAMAGE.
  52.  * 
  53.  * The licence and distribution terms for any publically available version or
  54.  * derivative of this code cannot be changed.  i.e. this code cannot simply be
  55.  * copied and put under another distribution licence
  56.  * [including the GNU Public Licence.]
  57.  */
  58. /* Code for dynamic hash table routines
  59.  * Author - Eric Young v 2.0
  60.  *
  61.  * 2.2 eay - added #include "crypto.h" so the memory leak checking code is
  62.  *      present. eay 18-Jun-98
  63.  *
  64.  * 2.1 eay - Added an 'error in last operation' flag. eay 6-May-98
  65.  *
  66.  * 2.0 eay - Fixed a bug that occurred when using lh_delete
  67.  *      from inside lh_doall().  As entries were deleted,
  68.  *      the 'table' was 'contract()ed', making some entries
  69.  *      jump from the end of the table to the start, there by
  70.  *      skipping the lh_doall() processing. eay - 4/12/95
  71.  *
  72.  * 1.9 eay - Fixed a memory leak in lh_free, the LHASH_NODEs
  73.  *      were not being free()ed. 21/11/95
  74.  *
  75.  * 1.8 eay - Put the stats routines into a separate file, lh_stats.c
  76.  *      19/09/95
  77.  *
  78.  * 1.7 eay - Removed the fputs() for realloc failures - the code
  79.  *           should silently tolerate them.  I have also fixed things
  80.  *           lint complained about 04/05/95
  81.  *
  82.  * 1.6 eay - Fixed an invalid pointers in contract/expand 27/07/92
  83.  *
  84.  * 1.5 eay - Fixed a misuse of realloc in expand 02/03/1992
  85.  *
  86.  * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91
  87.  *
  88.  * 1.3 eay - Fixed a few lint problems 19/3/1991
  89.  *
  90.  * 1.2 eay - Fixed lh_doall problem 13/3/1991
  91.  *
  92.  * 1.1 eay - Added lh_doall
  93.  *
  94.  * 1.0 eay - First version
  95.  */
  96. #include <stdio.h>
  97. #include <string.h>
  98. #include <stdlib.h>
  99. #include <openssl/crypto.h>
  100. #include <openssl/lhash.h>
  101. const char *lh_version="lhash" OPENSSL_VERSION_PTEXT;
  102. #undef MIN_NODES 
  103. #define MIN_NODES 16
  104. #define UP_LOAD (2*LH_LOAD_MULT) /* load times 256  (default 2) */
  105. #define DOWN_LOAD (LH_LOAD_MULT)   /* load times 256  (default 1) */
  106. static void expand(LHASH *lh);
  107. static void contract(LHASH *lh);
  108. static LHASH_NODE **getrn(LHASH *lh, const void *data, unsigned long *rhash);
  109. LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c)
  110. {
  111. LHASH *ret;
  112. int i;
  113. if ((ret=(LHASH *)OPENSSL_malloc(sizeof(LHASH))) == NULL)
  114. goto err0;
  115. if ((ret->b=(LHASH_NODE **)OPENSSL_malloc(sizeof(LHASH_NODE *)*MIN_NODES)) == NULL)
  116. goto err1;
  117. for (i=0; i<MIN_NODES; i++)
  118. ret->b[i]=NULL;
  119. ret->comp=((c == NULL)?(LHASH_COMP_FN_TYPE)strcmp:c);
  120. ret->hash=((h == NULL)?(LHASH_HASH_FN_TYPE)lh_strhash:h);
  121. ret->num_nodes=MIN_NODES/2;
  122. ret->num_alloc_nodes=MIN_NODES;
  123. ret->p=0;
  124. ret->pmax=MIN_NODES/2;
  125. ret->up_load=UP_LOAD;
  126. ret->down_load=DOWN_LOAD;
  127. ret->num_items=0;
  128. ret->num_expands=0;
  129. ret->num_expand_reallocs=0;
  130. ret->num_contracts=0;
  131. ret->num_contract_reallocs=0;
  132. ret->num_hash_calls=0;
  133. ret->num_comp_calls=0;
  134. ret->num_insert=0;
  135. ret->num_replace=0;
  136. ret->num_delete=0;
  137. ret->num_no_delete=0;
  138. ret->num_retrieve=0;
  139. ret->num_retrieve_miss=0;
  140. ret->num_hash_comps=0;
  141. ret->error=0;
  142. return(ret);
  143. err1:
  144. OPENSSL_free(ret);
  145. err0:
  146. return(NULL);
  147. }
  148. void lh_free(LHASH *lh)
  149. {
  150. unsigned int i;
  151. LHASH_NODE *n,*nn;
  152. if (lh == NULL)
  153.     return;
  154. for (i=0; i<lh->num_nodes; i++)
  155. {
  156. n=lh->b[i];
  157. while (n != NULL)
  158. {
  159. nn=n->next;
  160. OPENSSL_free(n);
  161. n=nn;
  162. }
  163. }
  164. OPENSSL_free(lh->b);
  165. OPENSSL_free(lh);
  166. }
  167. void *lh_insert(LHASH *lh, void *data)
  168. {
  169. unsigned long hash;
  170. LHASH_NODE *nn,**rn;
  171. void *ret;
  172. lh->error=0;
  173. if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))
  174. expand(lh);
  175. rn=getrn(lh,data,&hash);
  176. if (*rn == NULL)
  177. {
  178. if ((nn=(LHASH_NODE *)OPENSSL_malloc(sizeof(LHASH_NODE))) == NULL)
  179. {
  180. lh->error++;
  181. return(NULL);
  182. }
  183. nn->data=data;
  184. nn->next=NULL;
  185. #ifndef OPENSSL_NO_HASH_COMP
  186. nn->hash=hash;
  187. #endif
  188. *rn=nn;
  189. ret=NULL;
  190. lh->num_insert++;
  191. lh->num_items++;
  192. }
  193. else /* replace same key */
  194. {
  195. ret= (*rn)->data;
  196. (*rn)->data=data;
  197. lh->num_replace++;
  198. }
  199. return(ret);
  200. }
  201. void *lh_delete(LHASH *lh, const void *data)
  202. {
  203. unsigned long hash;
  204. LHASH_NODE *nn,**rn;
  205. void *ret;
  206. lh->error=0;
  207. rn=getrn(lh,data,&hash);
  208. if (*rn == NULL)
  209. {
  210. lh->num_no_delete++;
  211. return(NULL);
  212. }
  213. else
  214. {
  215. nn= *rn;
  216. *rn=nn->next;
  217. ret=nn->data;
  218. OPENSSL_free(nn);
  219. lh->num_delete++;
  220. }
  221. lh->num_items--;
  222. if ((lh->num_nodes > MIN_NODES) &&
  223. (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)))
  224. contract(lh);
  225. return(ret);
  226. }
  227. void *lh_retrieve(LHASH *lh, const void *data)
  228. {
  229. unsigned long hash;
  230. LHASH_NODE **rn;
  231. void *ret;
  232. lh->error=0;
  233. rn=getrn(lh,data,&hash);
  234. if (*rn == NULL)
  235. {
  236. lh->num_retrieve_miss++;
  237. return(NULL);
  238. }
  239. else
  240. {
  241. ret= (*rn)->data;
  242. lh->num_retrieve++;
  243. }
  244. return(ret);
  245. }
  246. static void doall_util_fn(LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func,
  247.   LHASH_DOALL_ARG_FN_TYPE func_arg, void *arg)
  248. {
  249. int i;
  250. LHASH_NODE *a,*n;
  251. /* reverse the order so we search from 'top to bottom'
  252.  * We were having memory leaks otherwise */
  253. for (i=lh->num_nodes-1; i>=0; i--)
  254. {
  255. a=lh->b[i];
  256. while (a != NULL)
  257. {
  258. /* 28/05/91 - eay - n added so items can be deleted
  259.  * via lh_doall */
  260. n=a->next;
  261. if(use_arg)
  262. func_arg(a->data,arg);
  263. else
  264. func(a->data);
  265. a=n;
  266. }
  267. }
  268. }
  269. void lh_doall(LHASH *lh, LHASH_DOALL_FN_TYPE func)
  270. {
  271. doall_util_fn(lh, 0, func, (LHASH_DOALL_ARG_FN_TYPE)0, NULL);
  272. }
  273. void lh_doall_arg(LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg)
  274. {
  275. doall_util_fn(lh, 1, (LHASH_DOALL_FN_TYPE)0, func, arg);
  276. }
  277. static void expand(LHASH *lh)
  278. {
  279. LHASH_NODE **n,**n1,**n2,*np;
  280. unsigned int p,i,j;
  281. unsigned long hash,nni;
  282. lh->num_nodes++;
  283. lh->num_expands++;
  284. p=(int)lh->p++;
  285. n1= &(lh->b[p]);
  286. n2= &(lh->b[p+(int)lh->pmax]);
  287. *n2=NULL;        /* 27/07/92 - eay - undefined pointer bug */
  288. nni=lh->num_alloc_nodes;
  289. for (np= *n1; np != NULL; )
  290. {
  291. #ifndef OPENSSL_NO_HASH_COMP
  292. hash=np->hash;
  293. #else
  294. hash=lh->hash(np->data);
  295. lh->num_hash_calls++;
  296. #endif
  297. if ((hash%nni) != p)
  298. { /* move it */
  299. *n1= (*n1)->next;
  300. np->next= *n2;
  301. *n2=np;
  302. }
  303. else
  304. n1= &((*n1)->next);
  305. np= *n1;
  306. }
  307. if ((lh->p) >= lh->pmax)
  308. {
  309. j=(int)lh->num_alloc_nodes*2;
  310. n=(LHASH_NODE **)OPENSSL_realloc(lh->b,
  311. (int)(sizeof(LHASH_NODE *)*j));
  312. if (n == NULL)
  313. {
  314. /* fputs("realloc error in lhash",stderr); */
  315. lh->error++;
  316. lh->p=0;
  317. return;
  318. }
  319. /* else */
  320. for (i=(int)lh->num_alloc_nodes; i<j; i++)/* 26/02/92 eay */
  321. n[i]=NULL;   /* 02/03/92 eay */
  322. lh->pmax=lh->num_alloc_nodes;
  323. lh->num_alloc_nodes=j;
  324. lh->num_expand_reallocs++;
  325. lh->p=0;
  326. lh->b=n;
  327. }
  328. }
  329. static void contract(LHASH *lh)
  330. {
  331. LHASH_NODE **n,*n1,*np;
  332. np=lh->b[lh->p+lh->pmax-1];
  333. lh->b[lh->p+lh->pmax-1]=NULL; /* 24/07-92 - eay - weird but :-( */
  334. if (lh->p == 0)
  335. {
  336. n=(LHASH_NODE **)OPENSSL_realloc(lh->b,
  337. (unsigned int)(sizeof(LHASH_NODE *)*lh->pmax));
  338. if (n == NULL)
  339. {
  340. /* fputs("realloc error in lhash",stderr); */
  341. lh->error++;
  342. return;
  343. }
  344. lh->num_contract_reallocs++;
  345. lh->num_alloc_nodes/=2;
  346. lh->pmax/=2;
  347. lh->p=lh->pmax-1;
  348. lh->b=n;
  349. }
  350. else
  351. lh->p--;
  352. lh->num_nodes--;
  353. lh->num_contracts++;
  354. n1=lh->b[(int)lh->p];
  355. if (n1 == NULL)
  356. lh->b[(int)lh->p]=np;
  357. else
  358. {
  359. while (n1->next != NULL)
  360. n1=n1->next;
  361. n1->next=np;
  362. }
  363. }
  364. static LHASH_NODE **getrn(LHASH *lh, const void *data, unsigned long *rhash)
  365. {
  366. LHASH_NODE **ret,*n1;
  367. unsigned long hash,nn;
  368. LHASH_COMP_FN_TYPE cf;
  369. hash=(*(lh->hash))(data);
  370. lh->num_hash_calls++;
  371. *rhash=hash;
  372. nn=hash%lh->pmax;
  373. if (nn < lh->p)
  374. nn=hash%lh->num_alloc_nodes;
  375. cf=lh->comp;
  376. ret= &(lh->b[(int)nn]);
  377. for (n1= *ret; n1 != NULL; n1=n1->next)
  378. {
  379. #ifndef OPENSSL_NO_HASH_COMP
  380. lh->num_hash_comps++;
  381. if (n1->hash != hash)
  382. {
  383. ret= &(n1->next);
  384. continue;
  385. }
  386. #endif
  387. lh->num_comp_calls++;
  388. if(cf(n1->data,data) == 0)
  389. break;
  390. ret= &(n1->next);
  391. }
  392. return(ret);
  393. }
  394. /* The following hash seems to work very well on normal text strings
  395.  * no collisions on /usr/dict/words and it distributes on %2^n quite
  396.  * well, not as good as MD5, but still good.
  397.  */
  398. unsigned long lh_strhash(const char *c)
  399. {
  400. unsigned long ret=0;
  401. long n;
  402. unsigned long v;
  403. int r;
  404. if ((c == NULL) || (*c == ''))
  405. return(ret);
  406. /*
  407. unsigned char b[16];
  408. MD5(c,strlen(c),b);
  409. return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24)); 
  410. */
  411. n=0x100;
  412. while (*c)
  413. {
  414. v=n|(*c);
  415. n+=0x100;
  416. r= (int)((v>>2)^v)&0x0f;
  417. ret=(ret<<r)|(ret>>(32-r));
  418. ret&=0xFFFFFFFFL;
  419. ret^=v*v;
  420. c++;
  421. }
  422. return((ret>>16)^ret);
  423. }
  424. unsigned long lh_num_items(const LHASH *lh)
  425. {
  426. return lh ? lh->num_items : 0;
  427. }