striconveh.c   striconveh.c 
/* Character set conversion with error handling. /* Character set conversion with error handling.
Copyright (C) 2001-2010 Free Software Foundation, Inc. Copyright (C) 2001-2014 Free Software Foundation, Inc.
Written by Bruno Haible and Simon Josefsson. Written by Bruno Haible and Simon Josefsson.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
skipping to change at line 54 skipping to change at line 54
of the inconvertible character. */ of the inconvertible character. */
int int
iconveh_open (const char *to_codeset, const char *from_codeset, iconveh_t * cdp) iconveh_open (const char *to_codeset, const char *from_codeset, iconveh_t * cdp)
{ {
iconv_t cd; iconv_t cd;
iconv_t cd1; iconv_t cd1;
iconv_t cd2; iconv_t cd2;
/* Avoid glibc-2.1 bug with EUC-KR. */ /* Avoid glibc-2.1 bug with EUC-KR. */
# if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
_VERSION && !defined _LIBICONV_VERSION
if (c_strcasecmp (from_codeset, "EUC-KR") == 0 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
|| c_strcasecmp (to_codeset, "EUC-KR") == 0) || c_strcasecmp (to_codeset, "EUC-KR") == 0)
{ {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
# endif # endif
cd = iconv_open (to_codeset, from_codeset); cd = iconv_open (to_codeset, from_codeset);
skipping to change at line 81 skipping to change at line 82
{ {
int saved_errno = errno; int saved_errno = errno;
if (cd != (iconv_t)(-1)) if (cd != (iconv_t)(-1))
iconv_close (cdp->cd); iconv_close (cdp->cd);
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} }
} }
if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0) if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0)
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV # if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \
_VERSION >= 0x0105 && !defined __UCLIBC__) \
|| _LIBICONV_VERSION >= 0x0105
|| c_strcasecmp (to_codeset, "UTF-8//TRANSLIT") == 0 || c_strcasecmp (to_codeset, "UTF-8//TRANSLIT") == 0
# endif # endif
) )
cd2 = (iconv_t)(-1); cd2 = (iconv_t)(-1);
else else
{ {
cd2 = iconv_open (to_codeset, "UTF-8"); cd2 = iconv_open (to_codeset, "UTF-8");
if (cd2 == (iconv_t)(-1)) if (cd2 == (iconv_t)(-1))
{ {
int saved_errno = errno; int saved_errno = errno;
skipping to change at line 138 skipping to change at line 141
return -1; return -1;
} }
if (cd->cd != (iconv_t)(-1) && iconv_close (cd->cd) < 0) if (cd->cd != (iconv_t)(-1) && iconv_close (cd->cd) < 0)
return -1; return -1;
return 0; return 0;
} }
/* iconv_carefully is like iconv, except that it stops as soon as it encoun ters /* iconv_carefully is like iconv, except that it stops as soon as it encoun ters
a conversion error, and it returns in *INCREMENTED a boolean telling whe ther a conversion error, and it returns in *INCREMENTED a boolean telling whe ther
it has incremented the input pointers past the error location. */ it has incremented the input pointers past the error location. */
# if !defined _LIBICONV_VERSION && !defined __GLIBC__ # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC __)
/* Irix iconv() inserts a NUL byte if it cannot convert. /* Irix iconv() inserts a NUL byte if it cannot convert.
NetBSD iconv() inserts a question mark if it cannot convert. NetBSD iconv() inserts a question mark if it cannot convert.
Only GNU libiconv and GNU libc are known to prefer to fail rather Only GNU libiconv and GNU libc are known to prefer to fail rather
than doing a lossy conversion. */ than doing a lossy conversion. */
static size_t static size_t
iconv_carefully (iconv_t cd, iconv_carefully (iconv_t cd,
const char **inbuf, size_t *inbytesleft, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, char **outbuf, size_t *outbytesleft,
bool *incremented) bool *incremented)
{ {
skipping to change at line 246 skipping to change at line 249
to convert the first character. E.g. libiconv does this. */ to convert the first character. E.g. libiconv does this. */
if (inptr > inptr_before) if (inptr > inptr_before)
{ {
res = 0; res = 0;
break; break;
} }
} }
*inbuf = inptr; *inbuf = inptr;
*inbytesleft = inptr_end - inptr; *inbytesleft = inptr_end - inptr;
# if !defined _LIBICONV_VERSION && !defined __GLIBC__ # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC __)
/* Irix iconv() inserts a NUL byte if it cannot convert. /* Irix iconv() inserts a NUL byte if it cannot convert.
NetBSD iconv() inserts a question mark if it cannot convert. NetBSD iconv() inserts a question mark if it cannot convert.
Only GNU libiconv and GNU libc are known to prefer to fail rather Only GNU libiconv and GNU libc are known to prefer to fail rather
than doing a lossy conversion. */ than doing a lossy conversion. */
if (res != (size_t)(-1) && res > 0) if (res != (size_t)(-1) && res > 0)
{ {
/* iconv() has already incremented INPTR. We cannot go back to a /* iconv() has already incremented INPTR. We cannot go back to a
previous INPTR, otherwise the state inside CD would become invalid , previous INPTR, otherwise the state inside CD would become invalid ,
if FROM_CODESET is a stateful encoding. So, tell the caller that if FROM_CODESET is a stateful encoding. So, tell the caller that
*INBUF has already been incremented. */ *INBUF has already been incremented. */
skipping to change at line 405 skipping to change at line 408
length = 0; length = 0;
/* First, try a direct conversion, and see whether a conversion error /* First, try a direct conversion, and see whether a conversion error
occurs at all. */ occurs at all. */
{ {
const char *inptr = src; const char *inptr = src;
size_t insize = srclen; size_t insize = srclen;
/* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */ /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
# if defined _LIBICONV_VERSION \ # if defined _LIBICONV_VERSION \
|| !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__)
) \
|| defined __sun)
/* Set to the initial state. */ /* Set to the initial state. */
iconv (cd, NULL, NULL, NULL, NULL); iconv (cd, NULL, NULL, NULL, NULL);
# endif # endif
while (insize > 0) while (insize > 0)
{ {
char *outptr = result + length; char *outptr = result + length;
size_t outsize = allocated - extra_alloc - length; size_t outsize = allocated - extra_alloc - length;
bool incremented; bool incremented;
size_t res; size_t res;
skipping to change at line 533 skipping to change at line 537
if (result == initial_result) if (result == initial_result)
memcpy (memory, initial_result, length); memcpy (memory, initial_result, length);
result = memory; result = memory;
} }
} }
} }
/* Now get the conversion state back to the initial state. /* Now get the conversion state back to the initial state.
But avoid glibc-2.1 bug and Solaris 2.7 bug. */ But avoid glibc-2.1 bug and Solaris 2.7 bug. */
#if defined _LIBICONV_VERSION \ #if defined _LIBICONV_VERSION \
|| !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun) || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__)
\
|| defined __sun)
for (;;) for (;;)
{ {
char *outptr = result + length; char *outptr = result + length;
size_t outsize = allocated - extra_alloc - length; size_t outsize = allocated - extra_alloc - length;
size_t res; size_t res;
res = iconv (cd, NULL, NULL, &outptr, &outsize); res = iconv (cd, NULL, NULL, &outptr, &outsize);
length = outptr - result; length = outptr - result;
if (res == (size_t)(-1)) if (res == (size_t)(-1))
{ {
skipping to change at line 608 skipping to change at line 613
# define utf8bufsize 4096 /* may also be smaller or larger than tmpbufsize */ # define utf8bufsize 4096 /* may also be smaller or larger than tmpbufsize */
char utf8buf[utf8bufsize + 1]; char utf8buf[utf8bufsize + 1];
size_t utf8len = 0; size_t utf8len = 0;
const char *in1ptr = src; const char *in1ptr = src;
size_t in1size = srclen; size_t in1size = srclen;
bool do_final_flush1 = true; bool do_final_flush1 = true;
bool do_final_flush2 = true; bool do_final_flush2 = true;
/* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */ /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
# if defined _LIBICONV_VERSION \ # if defined _LIBICONV_VERSION \
|| !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__)
) \
|| defined __sun)
/* Set to the initial state. */ /* Set to the initial state. */
if (cd1 != (iconv_t)(-1)) if (cd1 != (iconv_t)(-1))
iconv (cd1, NULL, NULL, NULL, NULL); iconv (cd1, NULL, NULL, NULL, NULL);
if (cd2 != (iconv_t)(-1)) if (cd2 != (iconv_t)(-1))
iconv (cd2, NULL, NULL, NULL, NULL); iconv (cd2, NULL, NULL, NULL, NULL);
# endif # endif
while (in1size > 0 || do_final_flush1 || utf8len > 0 || do_final_flush2 ) while (in1size > 0 || do_final_flush1 || utf8len > 0 || do_final_flush2 )
{ {
char *out1ptr = utf8buf + utf8len; char *out1ptr = utf8buf + utf8len;
skipping to change at line 660 skipping to change at line 666
&in1ptr, &in1size, &in1ptr, &in1size,
&out1ptr, &out1size, &out1ptr, &out1size,
&incremented1); &incremented1);
} }
} }
else if (do_final_flush1) else if (do_final_flush1)
{ {
/* Now get the conversion state of CD1 back to the initial stat e. /* Now get the conversion state of CD1 back to the initial stat e.
But avoid glibc-2.1 bug and Solaris 2.7 bug. */ But avoid glibc-2.1 bug and Solaris 2.7 bug. */
# if defined _LIBICONV_VERSION \ # if defined _LIBICONV_VERSION \
|| !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun) || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__)
\
|| defined __sun)
if (cd1 != (iconv_t)(-1)) if (cd1 != (iconv_t)(-1))
res1 = iconv (cd1, NULL, NULL, &out1ptr, &out1size); res1 = iconv (cd1, NULL, NULL, &out1ptr, &out1size);
else else
# endif # endif
res1 = 0; res1 = 0;
do_final_flush1 = false; do_final_flush1 = false;
incremented1 = true; incremented1 = true;
} }
else else
{ {
skipping to change at line 742 skipping to change at line 749
&in2ptr, &in2size, &in2ptr, &in2size,
&out2ptr, &out2size, &out2ptr, &out2size,
&incremented2); &incremented2);
} }
else /* in1size == 0 && !do_final_flush1 else /* in1size == 0 && !do_final_flush1
&& in2size == 0 && do_final_flush2 */ && in2size == 0 && do_final_flush2 */
{ {
/* Now get the conversion state of CD1 back to the init ial /* Now get the conversion state of CD1 back to the init ial
state. But avoid glibc-2.1 bug and Solaris 2.7 bug. */ state. But avoid glibc-2.1 bug and Solaris 2.7 bug. */
# if defined _LIBICONV_VERSION \ # if defined _LIBICONV_VERSION \
|| !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun) || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__)
\
|| defined __sun)
if (cd2 != (iconv_t)(-1)) if (cd2 != (iconv_t)(-1))
res2 = iconv (cd2, NULL, NULL, &out2ptr, &out2size); res2 = iconv (cd2, NULL, NULL, &out2ptr, &out2size);
else else
# endif # endif
res2 = 0; res2 = 0;
do_final_flush2 = false; do_final_flush2 = false;
incremented2 = true; incremented2 = true;
} }
length = out2ptr - result; length = out2ptr - result;
skipping to change at line 885 skipping to change at line 893
abort (); abort ();
memcpy (out2ptr, inptr, insize); memcpy (out2ptr, inptr, insize);
out2ptr += insize; out2ptr += insize;
out2size -= insize; out2size -= insize;
inptr += insize; inptr += insize;
insize = 0; insize = 0;
res = 0; res = 0;
} }
length = out2ptr - result; length = out2ptr - result;
} }
# if !defined _LIBICONV_VERSION && !defined __GLIBC__ # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC __)
/* Irix iconv() inserts a NUL byte if it cannot con vert. /* Irix iconv() inserts a NUL byte if it cannot con vert.
NetBSD iconv() inserts a question mark if it can not NetBSD iconv() inserts a question mark if it can not
convert. convert.
Only GNU libiconv and GNU libc are known to pref er Only GNU libiconv and GNU libc are known to pref er
to fail rather than doing a lossy conversion. * / to fail rather than doing a lossy conversion. * /
if (res != (size_t)(-1) && res > 0) if (res != (size_t)(-1) && res > 0)
{ {
errno = EILSEQ; errno = EILSEQ;
res = (size_t)(-1); res = (size_t)(-1);
} }
skipping to change at line 972 skipping to change at line 980
} }
} }
# undef utf8bufsize # undef utf8bufsize
} }
done: done:
/* Now the final memory allocation. */ /* Now the final memory allocation. */
if (result == tmpbuf) if (result == tmpbuf)
{ {
size_t memsize = length + extra_alloc; size_t memsize = length + extra_alloc;
char *memory;
memory = (char *) malloc (memsize > 0 ? memsize : 1); if (*resultp != NULL && *lengthp >= memsize)
if (memory != NULL) result = *resultp;
{
memcpy (memory, tmpbuf, length);
result = memory;
}
else else
{ {
errno = ENOMEM; char *memory;
return -1;
memory = (char *) malloc (memsize > 0 ? memsize : 1);
if (memory != NULL)
result = memory;
else
{
errno = ENOMEM;
return -1;
}
} }
memcpy (result, tmpbuf, length);
} }
else if (result != *resultp && length + extra_alloc < allocated) else if (result != *resultp && length + extra_alloc < allocated)
{ {
/* Shrink the allocated memory if possible. */ /* Shrink the allocated memory if possible. */
size_t memsize = length + extra_alloc; size_t memsize = length + extra_alloc;
char *memory; char *memory;
memory = (char *) realloc (result, memsize > 0 ? memsize : 1); memory = (char *) realloc (result, memsize > 0 ? memsize : 1);
if (memory != NULL) if (memory != NULL)
result = memory; result = memory;
 End of changes. 15 change blocks. 
24 lines changed or deleted 37 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/