a5b1aacd66831dae71aac806aef3ee7759bb29ff
[openssl.git] / crypto / objects / o_names.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include <openssl/lhash.h>
6 #include <openssl/objects.h>
7 #include <openssl/safestack.h>
8
9 /* I use the ex_data stuff to manage the identifiers for the obj_name_types
10  * that applications may define.  I only really use the free function field.
11  */
12 static LHASH *names_lh=NULL;
13 static int names_type_num=OBJ_NAME_TYPE_NUM;
14
15 typedef struct name_funcs_st
16         {
17         unsigned long (*hash_func)(const char *name);
18         int (*cmp_func)(const char *a,const char *b);
19         void (*free_func)(const char *, int, const char *);
20         } NAME_FUNCS;
21
22 DECLARE_STACK_OF(NAME_FUNCS)
23 IMPLEMENT_STACK_OF(NAME_FUNCS)
24
25 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
26
27 /* The LHASH callbacks now use the raw "void *" prototypes and do per-variable
28  * casting in the functions. This prevents function pointer casting without the
29  * need for macro-generated wrapper functions. */
30
31 /* static unsigned long obj_name_hash(OBJ_NAME *a); */
32 static unsigned long obj_name_hash(void *a_void);
33 /* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */
34 static int obj_name_cmp(void *a_void,void *b_void);
35
36 int OBJ_NAME_init(void)
37         {
38         if (names_lh != NULL) return(1);
39         MemCheck_off();
40         names_lh=lh_new(obj_name_hash, obj_name_cmp);
41         MemCheck_on();
42         return(names_lh != NULL);
43         }
44
45 int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *),
46         int (*cmp_func)(const char *, const char *),
47         void (*free_func)(const char *, int, const char *))
48         {
49         int ret;
50         int i;
51         NAME_FUNCS *name_funcs;
52
53         if (name_funcs_stack == NULL)
54                 {
55                 MemCheck_off();
56                 name_funcs_stack=sk_NAME_FUNCS_new_null();
57                 MemCheck_on();
58                 }
59         if ((name_funcs_stack == NULL))
60                 {
61                 /* ERROR */
62                 return(0);
63                 }
64         ret=names_type_num;
65         names_type_num++;
66         for (i=sk_NAME_FUNCS_num(name_funcs_stack); i<names_type_num; i++)
67                 {
68                 MemCheck_off();
69                 name_funcs = OPENSSL_malloc(sizeof(NAME_FUNCS));
70                 name_funcs->hash_func = lh_strhash;
71                 name_funcs->cmp_func = strcmp;
72                 name_funcs->free_func = 0; /* NULL is often declared to
73                                                 * ((void *)0), which according
74                                                 * to Compaq C is not really
75                                                 * compatible with a function
76                                                 * pointer.      -- Richard Levitte*/
77                 sk_NAME_FUNCS_push(name_funcs_stack,name_funcs);
78                 MemCheck_on();
79                 }
80         name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
81         if (hash_func != NULL)
82                 name_funcs->hash_func = hash_func;
83         if (cmp_func != NULL)
84                 name_funcs->cmp_func = cmp_func;
85         if (free_func != NULL)
86                 name_funcs->free_func = free_func;
87         return(ret);
88         }
89
90 /* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */
91 static int obj_name_cmp(void *a_void, void *b_void)
92         {
93         int ret;
94         OBJ_NAME *a = (OBJ_NAME *)a_void;
95         OBJ_NAME *b = (OBJ_NAME *)b_void;
96
97         ret=a->type-b->type;
98         if (ret == 0)
99                 {
100                 if ((name_funcs_stack != NULL)
101                         && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type))
102                         {
103                         ret=sk_NAME_FUNCS_value(name_funcs_stack,a->type)
104                                 ->cmp_func(a->name,b->name);
105                         }
106                 else
107                         ret=strcmp(a->name,b->name);
108                 }
109         return(ret);
110         }
111
112 /* static unsigned long obj_name_hash(OBJ_NAME *a) */
113 static unsigned long obj_name_hash(void *a_void)
114         {
115         unsigned long ret;
116         OBJ_NAME *a = (OBJ_NAME *)a_void;
117
118         if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type))
119                 {
120                 ret=sk_NAME_FUNCS_value(name_funcs_stack,a->type)
121                         ->hash_func(a->name);
122                 }
123         else
124                 {
125                 ret=lh_strhash(a->name);
126                 }
127         ret^=a->type;
128         return(ret);
129         }
130
131 const char *OBJ_NAME_get(const char *name, int type)
132         {
133         OBJ_NAME on,*ret;
134         int num=0,alias;
135
136         if (name == NULL) return(NULL);
137         if ((names_lh == NULL) && !OBJ_NAME_init()) return(NULL);
138
139         alias=type&OBJ_NAME_ALIAS;
140         type&= ~OBJ_NAME_ALIAS;
141
142         on.name=name;
143         on.type=type;
144
145         for (;;)
146         {
147                 ret=(OBJ_NAME *)lh_retrieve(names_lh,&on);
148                 if (ret == NULL) return(NULL);
149                 if ((ret->alias) && !alias)
150                         {
151                         if (++num > 10) return(NULL);
152                         on.name=ret->data;
153                         }
154                 else
155                         {
156                         return(ret->data);
157                         }
158                 }
159         }
160
161 int OBJ_NAME_add(const char *name, int type, const char *data)
162         {
163         OBJ_NAME *onp,*ret;
164         int alias;
165
166         if ((names_lh == NULL) && !OBJ_NAME_init()) return(0);
167
168         alias=type&OBJ_NAME_ALIAS;
169         type&= ~OBJ_NAME_ALIAS;
170
171         onp=(OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME));
172         if (onp == NULL)
173                 {
174                 /* ERROR */
175                 return(0);
176                 }
177
178         onp->name=name;
179         onp->alias=alias;
180         onp->type=type;
181         onp->data=data;
182
183         ret=(OBJ_NAME *)lh_insert(names_lh,onp);
184         if (ret != NULL)
185                 {
186                 /* free things */
187                 if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
188                         {
189                         /* XXX: I'm not sure I understand why the free
190                          * function should get three arguments...
191                          * -- Richard Levitte
192                          */
193                         sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
194                                 ->free_func(ret->name,ret->type,ret->data);
195                         }
196                 OPENSSL_free(ret);
197                 }
198         else
199                 {
200                 if (lh_error(names_lh))
201                         {
202                         /* ERROR */
203                         return(0);
204                         }
205                 }
206         return(1);
207         }
208
209 int OBJ_NAME_remove(const char *name, int type)
210         {
211         OBJ_NAME on,*ret;
212
213         if (names_lh == NULL) return(0);
214
215         type&= ~OBJ_NAME_ALIAS;
216         on.name=name;
217         on.type=type;
218         ret=(OBJ_NAME *)lh_delete(names_lh,&on);
219         if (ret != NULL)
220                 {
221                 /* free things */
222                 if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
223                         {
224                         /* XXX: I'm not sure I understand why the free
225                          * function should get three arguments...
226                          * -- Richard Levitte
227                          */
228                         sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
229                                 ->free_func(ret->name,ret->type,ret->data);
230                         }
231                 OPENSSL_free(ret);
232                 return(1);
233                 }
234         else
235                 return(0);
236         }
237
238 struct doall
239         {
240         int type;
241         void (*fn)(const OBJ_NAME *,void *arg);
242         void *arg;
243         };
244
245 static void do_all_fn(const OBJ_NAME *name,struct doall *d)
246         {
247         if(name->type == d->type)
248                 d->fn(name,d->arg);
249         }
250
251 void OBJ_NAME_do_all(int type,void (*fn)(const OBJ_NAME *,void *arg),void *arg)
252         {
253         struct doall d;
254
255         d.type=type;
256         d.fn=fn;
257         d.arg=arg;
258
259         lh_doall_arg(names_lh,(LHASH_DOALL_ARG_FN_TYPE)do_all_fn,&d);
260         }
261
262 struct doall_sorted
263         {
264         int type;
265         int n;
266         const OBJ_NAME **names;
267         };
268
269 static void do_all_sorted_fn(const OBJ_NAME *name,void *d_)
270         {
271         struct doall_sorted *d=d_;
272
273         if(name->type != d->type)
274                 return;
275
276         d->names[d->n++]=name;
277         }
278
279 static int do_all_sorted_cmp(const void *n1_,const void *n2_)
280         {
281         const OBJ_NAME * const *n1=n1_;
282         const OBJ_NAME * const *n2=n2_;
283
284         return strcmp((*n1)->name,(*n2)->name);
285         }
286
287 void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg),
288                                 void *arg)
289         {
290         struct doall_sorted d;
291         int n;
292
293         d.type=type;
294         d.names=OPENSSL_malloc(lh_num_items(names_lh)*sizeof *d.names);
295         d.n=0;
296         OBJ_NAME_do_all(type,do_all_sorted_fn,&d);
297
298         qsort(d.names,d.n,sizeof *d.names,do_all_sorted_cmp);
299
300         for(n=0 ; n < d.n ; ++n)
301                 fn(d.names[n],arg);
302
303         OPENSSL_free(d.names);
304         }
305
306 static int free_type;
307
308 static void names_lh_free(OBJ_NAME *onp, int type)
309 {
310         if(onp == NULL)
311                 return;
312
313         if ((free_type < 0) || (free_type == onp->type))
314                 {
315                 OBJ_NAME_remove(onp->name,onp->type);
316                 }
317         }
318
319 static void name_funcs_free(NAME_FUNCS *ptr)
320         {
321         OPENSSL_free(ptr);
322         }
323
324 void OBJ_NAME_cleanup(int type)
325         {
326         unsigned long down_load;
327
328         if (names_lh == NULL) return;
329
330         free_type=type;
331         down_load=names_lh->down_load;
332         names_lh->down_load=0;
333
334         lh_doall(names_lh,(LHASH_DOALL_FN_TYPE)names_lh_free);
335         if (type < 0)
336                 {
337                 lh_free(names_lh);
338                 sk_NAME_FUNCS_pop_free(name_funcs_stack,name_funcs_free);
339                 names_lh=NULL;
340                 name_funcs_stack = NULL;
341                 }
342         else
343                 names_lh->down_load=down_load;
344         }
345