355 lines
10 KiB
C
355 lines
10 KiB
C
/*
|
|
* 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 <reent.h>
|
|
#include <newlib.h>
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/iconvnls.h>
|
|
#ifdef _MB_CAPABLE
|
|
#include <wchar.h>
|
|
#include <iconv.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#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))
|
|
{
|
|
_REENT_ERRNO (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)
|
|
{
|
|
_REENT_ERRNO (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 */
|
|
|