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;
118 (char *) (*resultp != NULL ? realloc (*resultp, length) : malloc (length));
127 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
128 # if defined _LIBICONV_VERSION \
129 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
130 /* Return to the initial state. */
131 iconv (cd, NULL, NULL, NULL, NULL);
134 /* Do the conversion for real. */
136 const char *inptr = src;
137 size_t insize = srclen;
138 char *outptr = result;
139 size_t outsize = length;
143 size_t res = iconv (cd,
144 (ICONV_CONST char **) &inptr, &insize,
147 if (res == (size_t)(-1))
154 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
155 /* Irix iconv() inserts a NUL byte if it cannot convert.
156 NetBSD iconv() inserts a question mark if it cannot convert.
157 Only GNU libiconv and GNU libc are known to prefer to fail rather
158 than doing a lossy conversion. */
166 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
167 # if defined _LIBICONV_VERSION \
168 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
170 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
172 if (res == (size_t)(-1))
185 str_cd_iconv (const char *src, iconv_t cd)
187 /* For most encodings, a trailing NUL byte in the input will be converted
188 to a trailing NUL byte in the output. But not for UTF-7. So that this
189 function is usable for UTF-7, we have to exclude the NUL byte from the
190 conversion and add it by hand afterwards. */
195 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
202 int saved_errno = errno;
209 /* Add the terminating NUL byte. */
211 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
212 if (final_result == NULL)
219 final_result[length] = '\0';
228 const char *inptr = src;
229 size_t inbytes_remaining = strlen (src);
231 /* Make a guess for the worst-case output size, in order to avoid a
232 realloc. It's OK if the guess is wrong as long as it is not zero and
233 doesn't lead to an integer overflow. */
234 result_size = inbytes_remaining;
236 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
237 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
238 result_size *= MB_LEN_MAX;
240 result_size += 1; /* for the terminating NUL */
242 result = (char *) malloc (result_size);
249 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
250 # if defined _LIBICONV_VERSION \
251 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
252 /* Set to the initial state. */
253 iconv (cd, NULL, NULL, NULL, NULL);
256 /* Do the conversion. */
258 char *outptr = result;
259 size_t outbytes_remaining = result_size - 1;
263 /* Here inptr + inbytes_remaining = src + strlen (src),
264 outptr + outbytes_remaining = result + result_size - 1. */
265 size_t res = iconv (cd,
266 (ICONV_CONST char **) &inptr, &inbytes_remaining,
267 &outptr, &outbytes_remaining);
269 if (res == (size_t)(-1))
273 else if (errno == E2BIG)
275 size_t used = outptr - result;
276 size_t newsize = result_size * 2;
279 if (!(newsize > result_size))
284 newresult = (char *) realloc (result, newsize);
285 if (newresult == NULL)
291 result_size = newsize;
292 outptr = result + used;
293 outbytes_remaining = result_size - 1 - used;
298 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
299 /* Irix iconv() inserts a NUL byte if it cannot convert.
300 NetBSD iconv() inserts a question mark if it cannot convert.
301 Only GNU libiconv and GNU libc are known to prefer to fail rather
302 than doing a lossy conversion. */
312 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
313 # if defined _LIBICONV_VERSION \
314 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
317 /* Here outptr + outbytes_remaining = result + result_size - 1. */
318 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
320 if (res == (size_t)(-1))
324 size_t used = outptr - result;
325 size_t newsize = result_size * 2;
328 if (!(newsize > result_size))
333 newresult = (char *) realloc (result, newsize);
334 if (newresult == NULL)
340 result_size = newsize;
341 outptr = result + used;
342 outbytes_remaining = result_size - 1 - used;
352 /* Add the terminating NUL byte. */
355 length = outptr - result;
358 /* Give away unused memory. */
359 if (length < result_size)
361 char *smaller_result = (char *) realloc (result, length);
363 if (smaller_result != NULL)
364 result = smaller_result;
371 int saved_errno = errno;
383 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
385 if (c_strcasecmp (from_codeset, to_codeset) == 0)
393 /* Avoid glibc-2.1 bug with EUC-KR. */
394 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
395 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
396 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
402 cd = iconv_open (to_codeset, from_codeset);
403 if (cd == (iconv_t) -1)
406 result = str_cd_iconv (src, cd);
410 /* Close cd, but preserve the errno from str_cd_iconv. */
411 int saved_errno = errno;
417 if (iconv_close (cd) < 0)
419 /* Return NULL, but free the allocated memory, and while doing
420 that, preserve the errno from iconv_close. */
421 int saved_errno = errno;
429 /* This is a different error code than if iconv_open existed but didn't
430 support from_codeset and to_codeset, so that the caller can emit
431 an error message such as
432 "iconv() is not supported. Installing GNU libiconv and
433 then reinstalling this package would fix this." */