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/ |