2 Copyright (C) 2001-2006 Free Software Foundation, Inc.
3 Written by Bruno Haible and Simon Josefsson.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
30 /* Get MB_LEN_MAX, CHAR_BIT. */
35 #include "c-strcase.h"
38 # define SIZE_MAX ((size_t) -1)
45 mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
46 char **resultp, size_t *lengthp)
48 # define tmpbufsize 4096
52 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
53 # if defined _LIBICONV_VERSION \
54 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
55 /* Set to the initial state. */
56 iconv (cd, NULL, NULL, NULL, NULL);
59 /* Determine the length we need. */
62 char tmpbuf[tmpbufsize];
63 const char *inptr = src;
64 size_t insize = srclen;
68 char *outptr = tmpbuf;
69 size_t outsize = tmpbufsize;
70 size_t res = iconv (cd,
71 (ICONV_CONST char **) &inptr, &insize,
74 if (res == (size_t)(-1))
78 else if (errno == EINVAL)
83 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
84 /* Irix iconv() inserts a NUL byte if it cannot convert.
85 NetBSD iconv() inserts a question mark if it cannot convert.
86 Only GNU libiconv and GNU libc are known to prefer to fail rather
87 than doing a lossy conversion. */
94 count += outptr - tmpbuf;
96 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
97 # if defined _LIBICONV_VERSION \
98 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
100 char *outptr = tmpbuf;
101 size_t outsize = tmpbufsize;
102 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
104 if (res == (size_t)(-1))
106 count += outptr - tmpbuf;
117 result = (*resultp != NULL ? realloc (*resultp, length) : malloc (length));
126 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
127 # if defined _LIBICONV_VERSION \
128 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
129 /* Return to the initial state. */
130 iconv (cd, NULL, NULL, NULL, NULL);
133 /* Do the conversion for real. */
135 const char *inptr = src;
136 size_t insize = srclen;
137 char *outptr = result;
138 size_t outsize = length;
142 size_t res = iconv (cd,
143 (ICONV_CONST char **) &inptr, &insize,
146 if (res == (size_t)(-1))
153 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
154 /* Irix iconv() inserts a NUL byte if it cannot convert.
155 NetBSD iconv() inserts a question mark if it cannot convert.
156 Only GNU libiconv and GNU libc are known to prefer to fail rather
157 than doing a lossy conversion. */
165 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
166 # if defined _LIBICONV_VERSION \
167 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
169 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
171 if (res == (size_t)(-1))
184 str_cd_iconv (const char *src, iconv_t cd)
186 /* For most encodings, a trailing NUL byte in the input will be converted
187 to a trailing NUL byte in the output. But not for UTF-7. So that this
188 function is usable for UTF-7, we have to exclude the NUL byte from the
189 conversion and add it by hand afterwards. */
194 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
201 int saved_errno = errno;
208 /* Add the terminating NUL byte. */
210 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
211 if (final_result == NULL)
218 final_result[length] = '\0';
227 const char *inptr = src;
228 size_t inbytes_remaining = strlen (src);
230 /* Make a guess for the worst-case output size, in order to avoid a
231 realloc. It's OK if the guess is wrong as long as it is not zero and
232 doesn't lead to an integer overflow. */
233 result_size = inbytes_remaining;
235 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
236 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
237 result_size *= MB_LEN_MAX;
239 result_size += 1; /* for the terminating NUL */
241 result = (char *) malloc (result_size);
248 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
249 # if defined _LIBICONV_VERSION \
250 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
251 /* Set to the initial state. */
252 iconv (cd, NULL, NULL, NULL, NULL);
255 /* Do the conversion. */
257 char *outptr = result;
258 size_t outbytes_remaining = result_size - 1;
262 /* Here inptr + inbytes_remaining = src + strlen (src),
263 outptr + outbytes_remaining = result + result_size - 1. */
264 size_t res = iconv (cd,
265 (ICONV_CONST char **) &inptr, &inbytes_remaining,
266 &outptr, &outbytes_remaining);
268 if (res == (size_t)(-1))
272 else if (errno == E2BIG)
274 size_t used = outptr - result;
275 size_t newsize = result_size * 2;
278 if (!(newsize > result_size))
283 newresult = (char *) realloc (result, newsize);
284 if (newresult == NULL)
290 result_size = newsize;
291 outptr = result + used;
292 outbytes_remaining = result_size - 1 - used;
297 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
298 /* Irix iconv() inserts a NUL byte if it cannot convert.
299 NetBSD iconv() inserts a question mark if it cannot convert.
300 Only GNU libiconv and GNU libc are known to prefer to fail rather
301 than doing a lossy conversion. */
311 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
312 # if defined _LIBICONV_VERSION \
313 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
316 /* Here outptr + outbytes_remaining = result + result_size - 1. */
317 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
319 if (res == (size_t)(-1))
323 size_t used = outptr - result;
324 size_t newsize = result_size * 2;
327 if (!(newsize > result_size))
332 newresult = (char *) realloc (result, newsize);
333 if (newresult == NULL)
339 result_size = newsize;
340 outptr = result + used;
341 outbytes_remaining = result_size - 1 - used;
351 /* Add the terminating NUL byte. */
354 length = outptr - result;
357 /* Give away unused memory. */
358 if (length < result_size)
360 char *smaller_result = (char *) realloc (result, length);
362 if (smaller_result != NULL)
363 result = smaller_result;
370 int saved_errno = errno;
382 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
384 if (c_strcasecmp (from_codeset, to_codeset) == 0)
392 /* Avoid glibc-2.1 bug with EUC-KR. */
393 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
394 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
395 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
401 cd = iconv_open (to_codeset, from_codeset);
402 if (cd == (iconv_t) -1)
405 result = str_cd_iconv (src, cd);
409 /* Close cd, but preserve the errno from str_cd_iconv. */
410 int saved_errno = errno;
416 if (iconv_close (cd) < 0)
418 /* Return NULL, but free the allocated memory, and while doing
419 that, preserve the errno from iconv_close. */
420 int saved_errno = errno;
428 /* This is a different error code than if iconv_open existed but didn't
429 support from_codeset and to_codeset, so that the caller can emit
430 an error message such as
431 "iconv() is not supported. Installing GNU libiconv and
432 then reinstalling this package would fix this." */