Mercurial > illumos > illumos-gate
changeset 11117:21aa1119f172
PSARC/2009/561 Pass-through iconv code conversion
5081857 iconv_open() fails if both the arguments have the same codeset
author | Ienup Sung <Ienup.Sung@Sun.COM> |
---|---|
date | Thu, 19 Nov 2009 16:13:54 -0800 |
parents | b785f10185f0 |
children | 2991ec41bd7c |
files | usr/src/lib/libc/port/gen/iconv.c |
diffstat | 1 files changed, 127 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libc/port/gen/iconv.c Thu Nov 19 22:08:32 2009 -0800 +++ b/usr/src/lib/libc/port/gen/iconv.c Thu Nov 19 16:13:54 2009 -0800 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "lint.h" #include <sys/types.h> #include <sys/stat.h> @@ -46,16 +44,43 @@ static iconv_p iconv_open_all(const char *, const char *, char *); static iconv_p iconv_open_private(const char *, const char *); static iconv_p iconv_search_alias(const char *, const char *, char *); +static size_t passthru_icv_iconv(iconv_t, const char **, size_t *, char **, + size_t *); +static void passthru_icv_close(iconv_t); + +#define PASSTHRU_MAGIC_NUMBER (0x53756e) + /* - * These functions are implemented using a shared object and the dlopen() - * functions. Then, the actual conversion algorithm for a particular - * conversion is implemented as a shared object in a separate file in - * a loadable conversion module and linked dynamically at run time. - * The loadable conversion module resides in + * These functions are mainly implemented by using a shared object and + * the dlopen() functions. The actual conversion algorithm for a particular + * conversion is implemented via a shared object as a loadable conversion + * module which is linked dynamically at run time. + * + * The loadable conversion module resides as either: + * + * /usr/lib/iconv/geniconvtbl.so + * + * if the conversion is supported through a geniconvtbl code conversion + * binary table or as a module that directly specifies the conversion at: + * * /usr/lib/iconv/fromcode%tocode.so + * * where fromcode is the source encoding and tocode is the target encoding. - * The module has 3 entries: _icv_open(), _icv_iconv(), _icv_close(). + * The modules have 3 entries: _icv_open(), _icv_iconv(), and _icv_close(). + * + * If there is no code conversion supported and if the fromcode and the tocode + * are specifying the same codeset, then, the byte-by-byte, pass-through code + * conversion that is embedded in the libc is used instead. + * + * The following are the related PSARC cases: + * + * PSARC/1993/153 iconv/iconv_open/iconv_close + * PSARC/1999/292 Addition of geniconvtbl(1) + * PSARC/2001/072 GNU gettext support + * PSARC/2009/561 Pass-through iconv code conversion + * + * The PSARC/2001/072 includes the /usr/lib/iconv/alias interface. */ iconv_t @@ -89,11 +114,37 @@ cd->_conv = iconv_search_alias(tocode, fromcode, ipath); free(ipath); if (cd->_conv == (iconv_p)-1) { - /* no valid module for this conversion found */ - free(cd); - /* errno set by iconv_search_alias */ - return ((iconv_t)-1); + /* + * As the last resort, check if the tocode and the fromcode + * are referring to the same codeset name or not. If so, + * assign the embedded pass-through code conversion. + */ + if (strcasecmp(tocode, fromcode) != 0) { + /* + * No valid conversion available. Do failure retrun + * with the errno set by iconv_search_alias(). + */ + free(cd); + return ((iconv_t)-1); + } + + /* + * For a pass-through byte-by-byte code conversion, allocate + * an internal conversion descriptor and initialize the data + * fields appropriately and we are done. + */ + cd->_conv = malloc(sizeof (struct _iconv_fields)); + if (cd->_conv == NULL) { + free(cd); + return ((iconv_t)-1); + } + + cd->_conv->_icv_handle = NULL; + cd->_conv->_icv_iconv = passthru_icv_iconv; + cd->_conv->_icv_close = passthru_icv_close; + cd->_conv->_icv_state = (void *)PASSTHRU_MAGIC_NUMBER; } + /* found a valid module for this conversion */ return (cd); } @@ -362,12 +413,23 @@ return (-1); } (*(cd->_conv)->_icv_close)(cd->_conv->_icv_state); - (void) dlclose(cd->_conv->_icv_handle); + if (cd->_conv->_icv_handle != NULL) + (void) dlclose(cd->_conv->_icv_handle); free(cd->_conv); free(cd); return (0); } +/* + * To have minimal performance impact to the existing run-time behavior, + * we supply a dummy passthru_icv_close() that will just return. + */ +static void +/*LINTED E_FUNC_ARG_UNUSED*/ +passthru_icv_close(iconv_t cd) +{ +} + size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) @@ -382,3 +444,54 @@ return ((*(cd->_conv)->_icv_iconv)(cd->_conv->_icv_state, inbuf, inbytesleft, outbuf, outbytesleft)); } + +static size_t +passthru_icv_iconv(iconv_t cd, const char **inbuf, size_t *inbufleft, + char **outbuf, size_t *outbufleft) +{ + size_t ibl; + size_t obl; + size_t len; + size_t ret_val; + + /* Check if the conversion descriptor is a valid one. */ + if (cd != (iconv_t)PASSTHRU_MAGIC_NUMBER) { + errno = EBADF; + return ((size_t)-1); + } + + /* For any state reset request, return success. */ + if (inbuf == NULL || *inbuf == NULL) + return (0); + + /* + * Initialize internally used variables for a better performance + * and prepare for a couple of the return values before the actual + * copying of the bytes. + */ + ibl = *inbufleft; + obl = *outbufleft; + + if (ibl > obl) { + len = obl; + errno = E2BIG; + ret_val = (size_t)-1; + } else { + len = ibl; + ret_val = 0; + } + + /* + * Do the copy using memmove(). There are no EILSEQ or EINVAL + * checkings since this is a simple copying. + */ + (void) memmove((void *)*outbuf, (const void *)*inbuf, len); + + /* Update the return values related to the buffers then do return. */ + *inbuf = *inbuf + len; + *outbuf = *outbuf + len; + *inbufleft = ibl - len; + *outbufleft = obl - len; + + return (ret_val); +}