/* * Copyright (c) 2003-2004, Artem B. Bityuckiy * * 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. * * 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. */ #include <_ansi.h> #include #include #include #include #include #include #ifdef _MB_CAPABLE #include #include #include #include #include #include "local.h" #include "conv.h" #include "ucsconv.h" #include "iconvnls.h" #endif /* * _iconv_nls_construct_filename -- constructs full file name. * * PARAMETERS: * struct _reent *rptr - reent structure of current thread/process. * const char *file - the name of file. * const char *dir - the name of subdirectory; * const char *ext - file extension. * * DESCRIPTION: * Function constructs patch to icionv-related file. * 'file' shouldn't be NULL. Doesn't use extension if 'ext' is NULL. * * RETURN: * The pointer to file name if success, In case of error returns NULL * and sets current thread's/process's errno. */ const char * _iconv_nls_construct_filename (struct _reent *rptr, const char *file, const char *dir, const char *ext) { int len1, len2, len3; char *path; char *p; int dirlen = strlen (dir); if ((path = _getenv_r (rptr, NLS_ENVVAR_NAME)) == NULL || *path == '\0') path = ICONV_DEFAULT_NLSPATH; len1 = strlen (path); len2 = strlen (file); len3 = strlen (ext); if ((p = _malloc_r (rptr, len1 + dirlen + len2 + len3 + 3)) == NULL) return (const char *)NULL; memcpy (p, path, len1); if (p[len1 - 1] != '/') p[len1++] = '/'; memcpy (p + len1, dir, dirlen); len1 += dirlen; p[len1++] = '/'; memcpy (p + len1, file, len2); len1 += len2; if (ext != NULL) { memcpy (p + len1, ext, len3); len1 += len3; } p[len1] = '\0'; return (const char *)p; } #ifdef _MB_CAPABLE /* * _iconv_nls_get_mb_cur_max -- return encoding's maximum length * of a multi-byte character. * * PARAMETERS: * iconv_t cd - opened iconv conversion descriptor; * int direction - "from encoding" or "to encoding" direction. * * DESCRIPTION: * Return maximum length of a multi-byte character in one of 'cd's * encoding. Return "from" encoding's value if 'direction' is 0 and * "to" encoding's value if 'direction' isn't 0. */ int _iconv_nls_get_mb_cur_max (iconv_t cd, int direction) { iconv_conversion_t *ic = (iconv_conversion_t *)cd; return ic->handlers->get_mb_cur_max (ic->data, direction); } /* * _iconv_nls_is_stateful -- is encoding stateful? * * PARAMETERS: * iconv_t cd - opened iconv conversion descriptor; * int direction - "from encoding" or "to encoding" direction. * * DESCRIPTION: * Returns 0 if encoding is stateless or 1 if stateful. * Tests "from" encoding if 'direction' is 0 and * "to" encoding's value if 'direction' isn't 0. */ int _iconv_nls_is_stateful (iconv_t cd, int direction) { iconv_conversion_t *ic = (iconv_conversion_t *)cd; return ic->handlers->is_stateful (ic->data, direction); } /* * _iconv_nls_conv - special version of iconv for NLS. * * PARAMETERS: * Same as _iconv_r. * * DESCRIPTION: * Function behaves as _iconv_r but: * 1. Don't handle reset/return shift states queries * (like iconv does when 'inbuf' == NULL, etc); * 2. Don't save result if 'outbuf' == NULL or * '*outbuf' == NULL; * 3. Don't perform default conversion if there is no character * in "to" encoding that corresponds to character from "from" * encoding. * * RETURN: * Same as _iconv_r. */ size_t _iconv_nls_conv (struct _reent *rptr, iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { iconv_conversion_t *ic = (iconv_conversion_t *)cd; int flags = ICONV_FAIL_BIT; if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL || (ic->handlers != &_iconv_null_conversion_handlers && ic->handlers != &_iconv_ucs_conversion_handlers)) { __errno_r (rptr) = EBADF; return (size_t)-1; } if (inbytesleft == NULL || *inbytesleft == 0) return (size_t)0; if (outbuf == NULL || *outbuf == NULL) flags |= ICONV_DONT_SAVE_BIT; if (outbytesleft == NULL || *outbytesleft == 0) { __errno_r (rptr) = E2BIG; return (size_t)-1; } return ic->handlers->convert (rptr, ic->data, (const unsigned char**)inbuf, inbytesleft, (unsigned char**)outbuf, outbytesleft, flags); } /* * _iconv_nls_get_state -- get encoding's current shift state value. * * PARAMETERS: * iconv_t cd - iconv descriptor; * mbstate_t *ps - where to save shift state; * int direction - "from" encoding if 0, "to" encoding if 1. * * DESCRIPTION: * Save encoding's current shift state to 'ps'. Save "from" encoding's * shift state if 'direction' is 0 and "to" encodings's shift state * if 'direction' isn't 0. */ void _iconv_nls_get_state (iconv_t cd, mbstate_t *ps, int direction) { iconv_conversion_t *ic = (iconv_conversion_t *)cd; ic->handlers->get_state (ic->data, ps, direction); return; } /* * _iconv_nls_set_state -- set encoding's current shift state value. * * PARAMETERS: * iconv_t cd - iconv descriptor; * mbstate_t *ps - where to save shift state. * int direction - "from" encoding if 0, "to" encoding if 1. * * DESCRIPTION: * Set encoding's current shift state. * * RETURN: * 0 if success, -1 if failure. */ int _iconv_nls_set_state (iconv_t cd, mbstate_t *ps, int direction) { iconv_conversion_t *ic = (iconv_conversion_t *)cd; return ic->handlers->set_state (ic->data, ps, direction); } /* Same as iconv_open() but don't perform name resolving */ static iconv_t iconv_open1 (struct _reent *rptr, const char *to, const char *from) { iconv_conversion_t *ic; if (to == NULL || from == NULL || *to == '\0' || *from == '\0') return (iconv_t)-1; ic = (iconv_conversion_t *)_malloc_r (rptr, sizeof (iconv_conversion_t)); if (ic == NULL) return (iconv_t)-1; /* Select which conversion type to use */ if (strcmp (from, to) == 0) { /* Use null conversion */ ic->handlers = &_iconv_null_conversion_handlers; ic->data = ic->handlers->open (rptr, to, from); } else { /* Use UCS-based conversion */ ic->handlers = &_iconv_ucs_conversion_handlers; ic->data = ic->handlers->open (rptr, to, from); } if (ic->data == NULL) { _free_r (rptr, (void *)ic); return (iconv_t)-1; } return (void *)ic; } /* * _iconv_nls_open - open iconv descriptors for NLS. * * PARAMETERS: * struct _reent *rptr - process's reent structure; * const char *encoding - encoding name; * iconv_t *tomb - wchar -> encoding iconv descriptor pointer; * iconv_t *towc - encoding -> wchar iconv descriptor pointer; * int flag - perform encoding name resolving flag. * * DESCRIPTION: * Opens two iconv descriptors for 'encoding' -> wchar and * wchar -> 'encoding' iconv conversions. Function is used when locale or * wide-oriented stream is opened. If 'flag' is 0, don't perform encoding * name resolving ('encoding' must not be alias in this case). * * RETURN: * If successful - return 0, else set errno and return -1. */ int _iconv_nls_open (struct _reent *rptr, const char *encoding, iconv_t *tomb, iconv_t *towc, int flag) { const char *wchar_encoding; if (sizeof (wchar_t) > 2 && WCHAR_MAX > 0xFFFF) wchar_encoding = "ucs_4_internal"; else if (sizeof (wchar_t) > 1 && WCHAR_MAX > 0xFF) wchar_encoding = "ucs_2_internal"; else wchar_encoding = ""; /* This shuldn't happen */ if (flag) { if ((*towc = _iconv_open_r (rptr, wchar_encoding, encoding)) == (iconv_t)-1) return -1; if ((*tomb = _iconv_open_r (rptr, encoding, wchar_encoding)) == (iconv_t)-1) { _iconv_close_r (rptr, *towc); return -1; } } else { if ((*towc = iconv_open1 (rptr, wchar_encoding, encoding)) == (iconv_t)-1) return -1; if ((*tomb = iconv_open1 (rptr, encoding, wchar_encoding)) == (iconv_t)-1) { _iconv_close_r (rptr, *towc); return -1; } } return 0; } #endif /* _MB_CAPABLE */