]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/lhash/lhash.c
This commit was generated by cvs2svn to track changes on a CVS vendor
[thirdparty/openssl.git] / crypto / lhash / lhash.c
1 /* crypto/lhash/lhash.c */
2 /* Copyright (C) 1995-1997 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
59 char *lh_version="lhash part of SSLeay 0.8.1b 29-Jun-1998";
60
61 /* Code for dynamic hash table routines
62 * Author - Eric Young v 2.0
63 *
64 * 2.0 eay - Fixed a bug that occured when using lh_delete
65 * from inside lh_doall(). As entries were deleted,
66 * the 'table' was 'contract()ed', making some entries
67 * jump from the end of the table to the start, there by
68 * skiping the lh_doall() processing. eay - 4/12/95
69 *
70 * 1.9 eay - Fixed a memory leak in lh_free, the LHASH_NODEs
71 * were not being free()ed. 21/11/95
72 *
73 * 1.8 eay - Put the stats routines into a separate file, lh_stats.c
74 * 19/09/95
75 *
76 * 1.7 eay - Removed the fputs() for realloc failures - the code
77 * should silently tolerate them. I have also fixed things
78 * lint complained about 04/05/95
79 *
80 * 1.6 eay - Fixed an invalid pointers in contract/expand 27/07/92
81 *
82 * 1.5 eay - Fixed a misuse of realloc in expand 02/03/1992
83 *
84 * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91
85 *
86 * 1.3 eay - Fixed a few lint problems 19/3/1991
87 *
88 * 1.2 eay - Fixed lh_doall problem 13/3/1991
89 *
90 * 1.1 eay - Added lh_doall
91 *
92 * 1.0 eay - First version
93 */
94 #include <stdio.h>
95 #include <string.h>
96 #include <stdlib.h>
97 #include "lhash.h"
98
99 #undef MIN_NODES
100 #define MIN_NODES 16
101 #define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */
102 #define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */
103
104 #ifndef NOPROTO
105
106 #define P_CP char *
107 #define P_CPP char *,char *
108 static void expand(LHASH *lh);
109 static void contract(LHASH *lh);
110 static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash);
111
112 #else
113
114 #define P_CP
115 #define P_CPP
116 static void expand();
117 static void contract();
118 static LHASH_NODE **getrn();
119
120 #endif
121
122 LHASH *lh_new(h, c)
123 unsigned long (*h)();
124 int (*c)();
125 {
126 LHASH *ret;
127 int i;
128
129 if ((ret=(LHASH *)malloc(sizeof(LHASH))) == NULL)
130 goto err0;
131 if ((ret->b=(LHASH_NODE **)malloc(sizeof(LHASH_NODE *)*MIN_NODES)) == NULL)
132 goto err1;
133 for (i=0; i<MIN_NODES; i++)
134 ret->b[i]=NULL;
135 ret->comp=((c == NULL)?(int (*)())strcmp:c);
136 ret->hash=((h == NULL)?(unsigned long (*)())lh_strhash:h);
137 ret->num_nodes=MIN_NODES/2;
138 ret->num_alloc_nodes=MIN_NODES;
139 ret->p=0;
140 ret->pmax=MIN_NODES/2;
141 ret->up_load=UP_LOAD;
142 ret->down_load=DOWN_LOAD;
143 ret->num_items=0;
144
145 ret->num_expands=0;
146 ret->num_expand_reallocs=0;
147 ret->num_contracts=0;
148 ret->num_contract_reallocs=0;
149 ret->num_hash_calls=0;
150 ret->num_comp_calls=0;
151 ret->num_insert=0;
152 ret->num_replace=0;
153 ret->num_delete=0;
154 ret->num_no_delete=0;
155 ret->num_retrieve=0;
156 ret->num_retrieve_miss=0;
157 ret->num_hash_comps=0;
158
159 return(ret);
160 err1:
161 free((char *)ret);
162 err0:
163 return(NULL);
164 }
165
166 void lh_free(lh)
167 LHASH *lh;
168 {
169 unsigned int i;
170 LHASH_NODE *n,*nn;
171
172 for (i=0; i<lh->num_nodes; i++)
173 {
174 n=lh->b[i];
175 while (n != NULL)
176 {
177 nn=n->next;
178 free(n);
179 n=nn;
180 }
181 }
182 free((char *)lh->b);
183 free((char *)lh);
184 }
185
186 char *lh_insert(lh, data)
187 LHASH *lh;
188 char *data;
189 {
190 unsigned long hash;
191 LHASH_NODE *nn,**rn;
192 char *ret;
193
194 if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))
195 expand(lh);
196
197 rn=getrn(lh,data,&hash);
198
199 if (*rn == NULL)
200 {
201 if ((nn=(LHASH_NODE *)malloc(sizeof(LHASH_NODE))) == NULL)
202 return(NULL);
203 nn->data=data;
204 nn->next=NULL;
205 #ifndef NO_HASH_COMP
206 nn->hash=hash;
207 #endif
208 *rn=nn;
209 ret=NULL;
210 lh->num_insert++;
211 lh->num_items++;
212 }
213 else /* replace same key */
214 {
215 ret= (*rn)->data;
216 (*rn)->data=data;
217 lh->num_replace++;
218 }
219 return(ret);
220 }
221
222 char *lh_delete(lh, data)
223 LHASH *lh;
224 char *data;
225 {
226 unsigned long hash;
227 LHASH_NODE *nn,**rn;
228 char *ret;
229
230 rn=getrn(lh,data,&hash);
231
232 if (*rn == NULL)
233 {
234 lh->num_no_delete++;
235 return(NULL);
236 }
237 else
238 {
239 nn= *rn;
240 *rn=nn->next;
241 ret=nn->data;
242 free((char *)nn);
243 lh->num_delete++;
244 }
245
246 lh->num_items--;
247 if ((lh->num_nodes > MIN_NODES) &&
248 (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)))
249 contract(lh);
250
251 return(ret);
252 }
253
254 char *lh_retrieve(lh, data)
255 LHASH *lh;
256 char *data;
257 {
258 unsigned long hash;
259 LHASH_NODE **rn;
260 char *ret;
261
262 rn=getrn(lh,data,&hash);
263
264 if (*rn == NULL)
265 {
266 lh->num_retrieve_miss++;
267 return(NULL);
268 }
269 else
270 {
271 ret= (*rn)->data;
272 lh->num_retrieve++;
273 }
274 return(ret);
275 }
276
277 void lh_doall(lh, func)
278 LHASH *lh;
279 void (*func)();
280 {
281 lh_doall_arg(lh,func,NULL);
282 }
283
284 void lh_doall_arg(lh, func, arg)
285 LHASH *lh;
286 void (*func)();
287 char *arg;
288 {
289 int i;
290 LHASH_NODE *a,*n;
291
292 /* reverse the order so we search from 'top to bottom'
293 * We were having memory leaks otherwise */
294 for (i=lh->num_nodes-1; i>=0; i--)
295 {
296 a=lh->b[i];
297 while (a != NULL)
298 {
299 /* 28/05/91 - eay - n added so items can be deleted
300 * via lh_doall */
301 n=a->next;
302 func(a->data,arg);
303 a=n;
304 }
305 }
306 }
307
308 static void expand(lh)
309 LHASH *lh;
310 {
311 LHASH_NODE **n,**n1,**n2,*np;
312 unsigned int p,i,j;
313 unsigned long hash,nni;
314
315 lh->num_nodes++;
316 lh->num_expands++;
317 p=(int)lh->p++;
318 n1= &(lh->b[p]);
319 n2= &(lh->b[p+(int)lh->pmax]);
320 *n2=NULL; /* 27/07/92 - eay - undefined pointer bug */
321 nni=lh->num_alloc_nodes;
322
323 for (np= *n1; np != NULL; )
324 {
325 #ifndef NO_HASH_COMP
326 hash=np->hash;
327 #else
328 hash=(*(lh->hash))(np->data);
329 lh->num_hash_calls++;
330 #endif
331 if ((hash%nni) != p)
332 { /* move it */
333 *n1= (*n1)->next;
334 np->next= *n2;
335 *n2=np;
336 }
337 else
338 n1= &((*n1)->next);
339 np= *n1;
340 }
341
342 if ((lh->p) >= lh->pmax)
343 {
344 j=(int)lh->num_alloc_nodes*2;
345 n=(LHASH_NODE **)realloc((char *)lh->b,
346 (unsigned int)sizeof(LHASH_NODE *)*j);
347 if (n == NULL)
348 {
349 /* fputs("realloc error in lhash",stderr); */
350 lh->p=0;
351 return;
352 }
353 /* else */
354 for (i=(int)lh->num_alloc_nodes; i<j; i++)/* 26/02/92 eay */
355 n[i]=NULL; /* 02/03/92 eay */
356 lh->pmax=lh->num_alloc_nodes;
357 lh->num_alloc_nodes=j;
358 lh->num_expand_reallocs++;
359 lh->p=0;
360 lh->b=n;
361 }
362 }
363
364 static void contract(lh)
365 LHASH *lh;
366 {
367 LHASH_NODE **n,*n1,*np;
368
369 np=lh->b[lh->p+lh->pmax-1];
370 lh->b[lh->p+lh->pmax-1]=NULL; /* 24/07-92 - eay - weird but :-( */
371 if (lh->p == 0)
372 {
373 n=(LHASH_NODE **)realloc((char *)lh->b,
374 (unsigned int)(sizeof(LHASH_NODE *)*lh->pmax));
375 if (n == NULL)
376 {
377 /* fputs("realloc error in lhash",stderr); */
378 return;
379 }
380 lh->num_contract_reallocs++;
381 lh->num_alloc_nodes/=2;
382 lh->pmax/=2;
383 lh->p=lh->pmax-1;
384 lh->b=n;
385 }
386 else
387 lh->p--;
388
389 lh->num_nodes--;
390 lh->num_contracts++;
391
392 n1=lh->b[(int)lh->p];
393 if (n1 == NULL)
394 lh->b[(int)lh->p]=np;
395 else
396 {
397 while (n1->next != NULL)
398 n1=n1->next;
399 n1->next=np;
400 }
401 }
402
403 static LHASH_NODE **getrn(lh, data, rhash)
404 LHASH *lh;
405 char *data;
406 unsigned long *rhash;
407 {
408 LHASH_NODE **ret,*n1;
409 unsigned long hash,nn;
410 int (*cf)();
411
412 hash=(*(lh->hash))(data);
413 lh->num_hash_calls++;
414 *rhash=hash;
415
416 nn=hash%lh->pmax;
417 if (nn < lh->p)
418 nn=hash%lh->num_alloc_nodes;
419
420 cf=lh->comp;
421 ret= &(lh->b[(int)nn]);
422 for (n1= *ret; n1 != NULL; n1=n1->next)
423 {
424 #ifndef NO_HASH_COMP
425 lh->num_hash_comps++;
426 if (n1->hash != hash)
427 {
428 ret= &(n1->next);
429 continue;
430 }
431 #endif
432 lh->num_comp_calls++;
433 if ((*cf)(n1->data,data) == 0)
434 break;
435 ret= &(n1->next);
436 }
437 return(ret);
438 }
439
440 /*
441 static unsigned long lh_strhash(str)
442 char *str;
443 {
444 int i,l;
445 unsigned long ret=0;
446 unsigned short *s;
447
448 if (str == NULL) return(0);
449 l=(strlen(str)+1)/2;
450 s=(unsigned short *)str;
451 for (i=0; i<l; i++)
452 ret^=(s[i]<<(i&0x0f));
453 return(ret);
454 } */
455
456 /* The following hash seems to work very well on normal text strings
457 * no collisions on /usr/dict/words and it distributes on %2^n quite
458 * well, not as good as MD5, but still good.
459 */
460 unsigned long lh_strhash(c)
461 char *c;
462 {
463 unsigned long ret=0;
464 long n;
465 unsigned long v;
466 int r;
467
468 if ((c == NULL) || (*c == '\0'))
469 return(ret);
470 /*
471 unsigned char b[16];
472 MD5(c,strlen(c),b);
473 return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
474 */
475
476 n=0x100;
477 while (*c)
478 {
479 v=n|(*c);
480 n+=0x100;
481 r= (int)((v>>2)^v)&0x0f;
482 ret=(ret<<r)|(ret>>(32-r));
483 ret&=0xFFFFFFFFL;
484 ret^=v*v;
485 c++;
486 }
487 return((ret>>16)^ret);
488 }
489