sl@0: /* sl@0: Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. sl@0: sl@0: Redistribution and use in source and binary forms, with or without sl@0: modification, are permitted provided that the following conditions are met: sl@0: sl@0: * Redistributions of source code must retain the above copyright notice, this sl@0: list of conditions and the following disclaimer. sl@0: * Redistributions in binary form must reproduce the above copyright notice, sl@0: this list of conditions and the following disclaimer in the documentation sl@0: and/or other materials provided with the distribution. sl@0: * Neither the name of Nokia Corporation nor the names of its contributors sl@0: may be used to endorse or promote products derived from this software sl@0: without specific prior written permission. sl@0: sl@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" sl@0: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE sl@0: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE sl@0: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR sl@0: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER sl@0: CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, sl@0: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE sl@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: sl@0: Description: sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__))) sl@0: #include "libcrypto_wsd_macros.h" sl@0: #include "libcrypto_wsd.h" sl@0: #endif sl@0: sl@0: sl@0: /* Later versions of DEC C has started to add lnkage information to certain sl@0: * functions, which makes it tricky to use them as values to regular function sl@0: * pointers. One way is to define a macro that takes care of casting them sl@0: * correctly. sl@0: */ sl@0: #ifdef OPENSSL_SYS_VMS_DECC sl@0: # define OPENSSL_strcmp (int (*)(const char *,const char *))strcmp sl@0: #else sl@0: # define OPENSSL_strcmp strcmp sl@0: #endif sl@0: sl@0: /* I use the ex_data stuff to manage the identifiers for the obj_name_types sl@0: * that applications may define. I only really use the free function field. sl@0: */ sl@0: #ifndef EMULATOR sl@0: static LHASH *names_lh=NULL; sl@0: static int names_type_num=OBJ_NAME_TYPE_NUM; sl@0: #else sl@0: GET_STATIC_VAR_FROM_TLS(names_lh,o_names,LHASH *) sl@0: #define names_lh (*GET_WSD_VAR_NAME(names_lh,o_names, s)()) sl@0: sl@0: GET_STATIC_VAR_FROM_TLS(names_type_num,o_names,int) sl@0: #define names_type_num (*GET_WSD_VAR_NAME(names_type_num,o_names, s)()) sl@0: sl@0: #endif sl@0: sl@0: typedef struct name_funcs_st sl@0: { sl@0: unsigned long (*hash_func)(const char *name); sl@0: int (*cmp_func)(const char *a,const char *b); sl@0: void (*free_func)(const char *, int, const char *); sl@0: } NAME_FUNCS; sl@0: sl@0: DECLARE_STACK_OF(NAME_FUNCS) sl@0: IMPLEMENT_STACK_OF(NAME_FUNCS) sl@0: sl@0: #ifndef EMULATOR sl@0: static STACK_OF(NAME_FUNCS) *name_funcs_stack; sl@0: #else sl@0: GET_STATIC_VAR_FROM_TLS(name_funcs_stack,o_names,STACK_OF(NAME_FUNCS)*) sl@0: #define name_funcs_stack (*GET_WSD_VAR_NAME(name_funcs_stack,o_names, s)()) sl@0: #endif sl@0: sl@0: /* The LHASH callbacks now use the raw "void *" prototypes and do per-variable sl@0: * casting in the functions. This prevents function pointer casting without the sl@0: * need for macro-generated wrapper functions. */ sl@0: sl@0: /* static unsigned long obj_name_hash(OBJ_NAME *a); */ sl@0: static unsigned long obj_name_hash(const void *a_void); sl@0: /* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */ sl@0: static int obj_name_cmp(const void *a_void,const void *b_void); sl@0: sl@0: EXPORT_C int OBJ_NAME_init(void) sl@0: { sl@0: if (names_lh != NULL) return(1); sl@0: MemCheck_off(); sl@0: names_lh=lh_new(obj_name_hash, obj_name_cmp); sl@0: MemCheck_on(); sl@0: return(names_lh != NULL); sl@0: } sl@0: sl@0: EXPORT_C int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *), sl@0: int (*cmp_func)(const char *, const char *), sl@0: void (*free_func)(const char *, int, const char *)) sl@0: { sl@0: int ret; sl@0: int i; sl@0: NAME_FUNCS *name_funcs; sl@0: sl@0: if (name_funcs_stack == NULL) sl@0: { sl@0: MemCheck_off(); sl@0: name_funcs_stack=sk_NAME_FUNCS_new_null(); sl@0: MemCheck_on(); sl@0: } sl@0: if ((name_funcs_stack == NULL)) sl@0: { sl@0: /* ERROR */ sl@0: return(0); sl@0: } sl@0: ret=names_type_num; sl@0: names_type_num++; sl@0: for (i=sk_NAME_FUNCS_num(name_funcs_stack); ihash_func = lh_strhash; sl@0: name_funcs->cmp_func = OPENSSL_strcmp; sl@0: name_funcs->free_func = 0; /* NULL is often declared to sl@0: * ((void *)0), which according sl@0: * to Compaq C is not really sl@0: * compatible with a function sl@0: * pointer. -- Richard Levitte*/ sl@0: MemCheck_off(); sl@0: sk_NAME_FUNCS_push(name_funcs_stack,name_funcs); sl@0: MemCheck_on(); sl@0: } sl@0: name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret); sl@0: if (hash_func != NULL) sl@0: name_funcs->hash_func = hash_func; sl@0: if (cmp_func != NULL) sl@0: name_funcs->cmp_func = cmp_func; sl@0: if (free_func != NULL) sl@0: name_funcs->free_func = free_func; sl@0: return(ret); sl@0: } sl@0: sl@0: /* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */ sl@0: static int obj_name_cmp(const void *a_void, const void *b_void) sl@0: { sl@0: int ret; sl@0: const OBJ_NAME *a = (const OBJ_NAME *)a_void; sl@0: const OBJ_NAME *b = (const OBJ_NAME *)b_void; sl@0: sl@0: ret=a->type-b->type; sl@0: if (ret == 0) sl@0: { sl@0: if ((name_funcs_stack != NULL) sl@0: && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) sl@0: { sl@0: ret=sk_NAME_FUNCS_value(name_funcs_stack, sl@0: a->type)->cmp_func(a->name,b->name); sl@0: } sl@0: else sl@0: ret=strcmp(a->name,b->name); sl@0: } sl@0: return(ret); sl@0: } sl@0: sl@0: /* static unsigned long obj_name_hash(OBJ_NAME *a) */ sl@0: static unsigned long obj_name_hash(const void *a_void) sl@0: { sl@0: unsigned long ret; sl@0: const OBJ_NAME *a = (const OBJ_NAME *)a_void; sl@0: sl@0: if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) sl@0: { sl@0: ret=sk_NAME_FUNCS_value(name_funcs_stack, sl@0: a->type)->hash_func(a->name); sl@0: } sl@0: else sl@0: { sl@0: ret=lh_strhash(a->name); sl@0: } sl@0: ret^=a->type; sl@0: return(ret); sl@0: } sl@0: sl@0: EXPORT_C const char *OBJ_NAME_get(const char *name, int type) sl@0: { sl@0: OBJ_NAME on,*ret; sl@0: int num=0,alias; sl@0: sl@0: if (name == NULL) return(NULL); sl@0: if ((names_lh == NULL) && !OBJ_NAME_init()) return(NULL); sl@0: sl@0: alias=type&OBJ_NAME_ALIAS; sl@0: type&= ~OBJ_NAME_ALIAS; sl@0: sl@0: on.name=name; sl@0: on.type=type; sl@0: sl@0: for (;;) sl@0: { sl@0: ret=(OBJ_NAME *)lh_retrieve(names_lh,&on); sl@0: if (ret == NULL) return(NULL); sl@0: if ((ret->alias) && !alias) sl@0: { sl@0: if (++num > 10) return(NULL); sl@0: on.name=ret->data; sl@0: } sl@0: else sl@0: { sl@0: return(ret->data); sl@0: } sl@0: } sl@0: } sl@0: sl@0: EXPORT_C int OBJ_NAME_add(const char *name, int type, const char *data) sl@0: { sl@0: OBJ_NAME *onp,*ret; sl@0: int alias; sl@0: sl@0: if ((names_lh == NULL) && !OBJ_NAME_init()) return(0); sl@0: sl@0: alias=type&OBJ_NAME_ALIAS; sl@0: type&= ~OBJ_NAME_ALIAS; sl@0: sl@0: onp=(OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME)); sl@0: if (onp == NULL) sl@0: { sl@0: /* ERROR */ sl@0: return(0); sl@0: } sl@0: sl@0: onp->name=name; sl@0: onp->alias=alias; sl@0: onp->type=type; sl@0: onp->data=data; sl@0: sl@0: ret=(OBJ_NAME *)lh_insert(names_lh,onp); sl@0: if (ret != NULL) sl@0: { sl@0: /* free things */ sl@0: if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) sl@0: { sl@0: /* XXX: I'm not sure I understand why the free sl@0: * function should get three arguments... sl@0: * -- Richard Levitte sl@0: */ sl@0: sk_NAME_FUNCS_value(name_funcs_stack, sl@0: ret->type)->free_func(ret->name,ret->type,ret->data); sl@0: } sl@0: OPENSSL_free(ret); sl@0: } sl@0: else sl@0: { sl@0: if (lh_error(names_lh)) sl@0: { sl@0: /* ERROR */ sl@0: return(0); sl@0: } sl@0: } sl@0: return(1); sl@0: } sl@0: sl@0: EXPORT_C int OBJ_NAME_remove(const char *name, int type) sl@0: { sl@0: OBJ_NAME on,*ret; sl@0: sl@0: if (names_lh == NULL) return(0); sl@0: sl@0: type&= ~OBJ_NAME_ALIAS; sl@0: on.name=name; sl@0: on.type=type; sl@0: ret=(OBJ_NAME *)lh_delete(names_lh,&on); sl@0: if (ret != NULL) sl@0: { sl@0: /* free things */ sl@0: if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) sl@0: { sl@0: /* XXX: I'm not sure I understand why the free sl@0: * function should get three arguments... sl@0: * -- Richard Levitte sl@0: */ sl@0: sk_NAME_FUNCS_value(name_funcs_stack, sl@0: ret->type)->free_func(ret->name,ret->type,ret->data); sl@0: } sl@0: OPENSSL_free(ret); sl@0: return(1); sl@0: } sl@0: else sl@0: return(0); sl@0: } sl@0: sl@0: struct doall sl@0: { sl@0: int type; sl@0: void (*fn)(const OBJ_NAME *,void *arg); sl@0: void *arg; sl@0: }; sl@0: sl@0: static void do_all_fn(const OBJ_NAME *name,struct doall *d) sl@0: { sl@0: if(name->type == d->type) sl@0: d->fn(name,d->arg); sl@0: } sl@0: sl@0: static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME *, struct doall *) sl@0: sl@0: EXPORT_C void OBJ_NAME_do_all(int type,void (*fn)(const OBJ_NAME *,void *arg),void *arg) sl@0: { sl@0: struct doall d; sl@0: sl@0: d.type=type; sl@0: d.fn=fn; sl@0: d.arg=arg; sl@0: sl@0: lh_doall_arg(names_lh,LHASH_DOALL_ARG_FN(do_all_fn),&d); sl@0: } sl@0: sl@0: struct doall_sorted sl@0: { sl@0: int type; sl@0: int n; sl@0: const OBJ_NAME **names; sl@0: }; sl@0: sl@0: static void do_all_sorted_fn(const OBJ_NAME *name,void *d_) sl@0: { sl@0: struct doall_sorted *d=d_; sl@0: sl@0: if(name->type != d->type) sl@0: return; sl@0: sl@0: d->names[d->n++]=name; sl@0: } sl@0: sl@0: static int do_all_sorted_cmp(const void *n1_,const void *n2_) sl@0: { sl@0: const OBJ_NAME * const *n1=n1_; sl@0: const OBJ_NAME * const *n2=n2_; sl@0: sl@0: return strcmp((*n1)->name,(*n2)->name); sl@0: } sl@0: sl@0: EXPORT_C void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg), sl@0: void *arg) sl@0: { sl@0: struct doall_sorted d; sl@0: int n; sl@0: sl@0: d.type=type; sl@0: d.names=OPENSSL_malloc(lh_num_items(names_lh)*sizeof *d.names); sl@0: #ifdef SYMBIAN sl@0: if(d.names==NULL) sl@0: { sl@0: return; sl@0: } sl@0: #endif sl@0: d.n=0; sl@0: OBJ_NAME_do_all(type,do_all_sorted_fn,&d); sl@0: sl@0: qsort((void *)d.names,d.n,sizeof *d.names,do_all_sorted_cmp); sl@0: sl@0: for(n=0 ; n < d.n ; ++n) sl@0: fn(d.names[n],arg); sl@0: sl@0: OPENSSL_free((void *)d.names); sl@0: } sl@0: sl@0: #ifndef EMULATOR sl@0: static int free_type; sl@0: #else sl@0: GET_STATIC_VAR_FROM_TLS(free_type,o_names,int) sl@0: #define free_type (*GET_WSD_VAR_NAME(free_type,o_names, s)()) sl@0: #endif sl@0: sl@0: static void names_lh_free(OBJ_NAME *onp) sl@0: { sl@0: if(onp == NULL) sl@0: return; sl@0: sl@0: if ((free_type < 0) || (free_type == onp->type)) sl@0: { sl@0: OBJ_NAME_remove(onp->name,onp->type); sl@0: } sl@0: } sl@0: sl@0: static IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME *) sl@0: sl@0: static void name_funcs_free(NAME_FUNCS *ptr) sl@0: { sl@0: OPENSSL_free(ptr); sl@0: } sl@0: sl@0: EXPORT_C void OBJ_NAME_cleanup(int type) sl@0: { sl@0: unsigned long down_load; sl@0: sl@0: if (names_lh == NULL) return; sl@0: sl@0: free_type=type; sl@0: down_load=names_lh->down_load; sl@0: names_lh->down_load=0; sl@0: sl@0: lh_doall(names_lh,LHASH_DOALL_FN(names_lh_free)); sl@0: if (type < 0) sl@0: { sl@0: lh_free(names_lh); sl@0: sk_NAME_FUNCS_pop_free(name_funcs_stack,name_funcs_free); sl@0: names_lh=NULL; sl@0: name_funcs_stack = NULL; sl@0: } sl@0: else sl@0: names_lh->down_load=down_load; sl@0: } sl@0: