| /*- |
| * Copyright (c) 2000, Boris Popov. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. All advertising materials mentioning features or use of this software |
| * must display the following acknowledgement: |
| * This product includes software developed by Boris Popov |
| * and its contributors. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * |
| */ |
| |
| #define ICONV_INTERNAL |
| |
| #include "iconv.h" |
| #include "apr_file_io.h" |
| #include "apr_file_info.h" |
| #include "apr_pools.h" |
| #include "apr_dso.h" |
| #include "apr_env.h" |
| #include "apr_strings.h" |
| #include "apr_tables.h" |
| #include "apr_lib.h" |
| |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #ifdef API_USE_BUILTIN_ALIASES |
| #include "charset_alias.h" |
| #endif |
| |
| static apr_status_t |
| iconv_getpathname(char *buffer, const char *dir, const char *name, apr_pool_t *ctx) |
| { |
| apr_status_t rv; |
| apr_finfo_t sb; |
| |
| apr_snprintf(buffer, APR_PATH_MAX, "%s/%s.so", dir, name); |
| rv = apr_stat(&sb, buffer, APR_FINFO_TYPE, ctx); |
| #ifdef API_HAVE_CHARSET_ALIAS_TABLE |
| /* If we didn't find the file, try again after looking in |
| the charset alias mapping table. */ |
| if (rv || sb.filetype != APR_REG) { |
| const char *alias = charset_alias_find(name); |
| if (alias) { |
| apr_snprintf(buffer, APR_PATH_MAX, "%s/%s.so", dir, alias); |
| rv = apr_stat(&sb, buffer, APR_FINFO_TYPE, ctx); |
| } |
| } |
| #endif /* API_HAVE_CHARSET_ALIAS_TABLE */ |
| if (!rv && sb.filetype != APR_REG) |
| rv = APR_EINVAL; |
| |
| return rv; |
| } |
| |
| static apr_status_t |
| iconv_getpath(char *buf, const char *name, apr_pool_t *ctx) |
| { |
| char buffer[APR_PATH_MAX]; |
| apr_array_header_t *pathelts; |
| apr_pool_t *subpool; |
| apr_status_t status; |
| char *ptr; |
| |
| status = apr_pool_create(&subpool, ctx); |
| if (status) |
| return status; |
| |
| if (apr_tolower(name[0]) == 'x' && name[1] == '-') |
| name += 2; |
| ptr = buffer; |
| while (0 != (*ptr++ = apr_tolower(*name++))) |
| ; |
| |
| if (!apr_env_get(&ptr, "APR_ICONV_PATH", subpool) |
| && !apr_filepath_list_split(&pathelts, ptr, subpool)) |
| { |
| int i; |
| char **elts = (char **)pathelts->elts; |
| for (i = 0; i < pathelts->nelts; ++i) |
| { |
| if (iconv_getpathname(buf, elts[i], buffer, subpool) == 0) |
| { |
| apr_pool_destroy(subpool); |
| return APR_SUCCESS; |
| } |
| } |
| } |
| |
| status = iconv_getpathname(buf, ICONV_DEFAULT_PATH, buffer, subpool); |
| apr_pool_destroy(subpool); |
| return status; |
| } |
| |
| static int |
| iconv_dlopen(const char *name, const char *symbol, void **hpp, void **dpp, apr_pool_t *ctx) |
| { |
| apr_dso_handle_t *handle; |
| void *data; |
| |
| /* dlopen */ |
| if (apr_dso_load(&handle, name, ctx) != APR_SUCCESS) { |
| return EINVAL; |
| } |
| /* dlsym */ |
| if ( apr_dso_sym(&data, handle, symbol) == APR_SUCCESS) { |
| *hpp = handle; |
| *dpp = data; |
| return 0; |
| } |
| apr_dso_unload(handle); |
| return EINVAL; |
| } |
| |
| API_DECLARE_NONSTD(int) |
| apr_iconv_mod_load(const char *modname, int modtype, const void *args, |
| struct iconv_module **modpp, apr_pool_t *ctx) |
| { |
| struct iconv_module_desc *mdesc; |
| struct iconv_module *mod, *depmod; |
| const struct iconv_module_depend *depend; |
| char buffer[APR_PATH_MAX]; |
| void *handle; |
| int error; |
| |
| if (iconv_getpath(buffer, modname, ctx) != 0) |
| return EINVAL; |
| |
| error = iconv_dlopen(buffer, "iconv_module", &handle, (void**)&mdesc, ctx); |
| if (error) |
| return error; |
| if (modtype != ICMOD_ANY && mdesc->imd_type != modtype) { |
| apr_dso_unload(handle); |
| return APR_EFTYPE; |
| } |
| mod = malloc(sizeof(*mod)); |
| if (mod == NULL) { |
| apr_dso_unload(handle); |
| return ENOMEM; |
| } |
| memset(mod, 0, sizeof(*mod)); |
| mod->im_handle = handle; |
| mod->im_desc = mdesc; |
| mod->im_args = args; |
| depend = mdesc->imd_depend; |
| if (depend) { |
| while (depend->md_name) { |
| error = apr_iconv_mod_load(depend->md_name, |
| depend->md_type, NULL, &depmod, ctx); |
| if (error) |
| goto bad; |
| depmod->im_depdata = depend->md_data; |
| depmod->im_next = mod->im_deplist; |
| mod->im_deplist = depmod; |
| depend++; |
| } |
| } |
| error = ICONV_MOD_DYN_LOAD(mod,ctx); |
| if (error) |
| goto bad; |
| depmod = mod->im_deplist; |
| while (depmod) { |
| mod->im_depcnt++; |
| depmod = depmod->im_next; |
| } |
| error = ICONV_MOD_LOAD(mod,ctx); |
| if (error) |
| goto bad; |
| mod->im_flags |= ICMODF_LOADED; |
| *modpp = mod; |
| return 0; |
| bad: |
| apr_iconv_mod_unload(mod,ctx); |
| return error; |
| } |
| |
| API_DECLARE_NONSTD(int) |
| apr_iconv_mod_unload(struct iconv_module *mod, apr_pool_t *ctx) |
| { |
| struct iconv_module *deplist, *tmp; |
| int error = 0; |
| |
| if (mod == NULL) |
| return -1; |
| if (mod->im_flags & ICMODF_LOADED) |
| error = ICONV_MOD_UNLOAD(mod,ctx); |
| error = ICONV_MOD_DYN_UNLOAD(mod,ctx); |
| deplist = mod->im_deplist; |
| while (deplist) { |
| tmp = deplist->im_next; |
| apr_iconv_mod_unload(deplist,ctx); |
| deplist = tmp; |
| } |
| if (mod->im_handle != NULL) |
| if (apr_dso_unload(mod->im_handle) != APR_SUCCESS) |
| error = APR_EINVAL; |
| free(mod); |
| return error; |
| } |
| |
| API_DECLARE_NONSTD(int) |
| apr_iconv_mod_noevent(struct iconv_module *mod, int event, apr_pool_t *ctx) |
| { |
| switch (event) { |
| case ICMODEV_LOAD: |
| case ICMODEV_UNLOAD: |
| case ICMODEV_DYN_LOAD: |
| case ICMODEV_DYN_UNLOAD: |
| break; |
| default: |
| return APR_EINVAL; |
| } |
| return 0; |
| } |