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 sgi || defined __sgi)
84 /* Irix iconv() inserts a NUL byte if it cannot convert. */
91 count += outptr - tmpbuf;
93 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
94 # if defined _LIBICONV_VERSION \
95 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
97 char *outptr = tmpbuf;
98 size_t outsize = tmpbufsize;
99 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
101 if (res == (size_t)(-1))
103 count += outptr - tmpbuf;
114 result = (*resultp != NULL ? realloc (*resultp, length) : malloc (length));
123 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
124 # if defined _LIBICONV_VERSION \
125 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
126 /* Return to the initial state. */
127 iconv (cd, NULL, NULL, NULL, NULL);
130 /* Do the conversion for real. */
132 const char *inptr = src;
133 size_t insize = srclen;
134 char *outptr = result;
135 size_t outsize = length;
139 size_t res = iconv (cd,
140 (ICONV_CONST char **) &inptr, &insize,
143 if (res == (size_t)(-1))
150 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
151 /* Irix iconv() inserts a NUL byte if it cannot convert. */
159 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
160 # if defined _LIBICONV_VERSION \
161 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
163 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
165 if (res == (size_t)(-1))
178 str_cd_iconv (const char *src, iconv_t cd)
180 /* For most encodings, a trailing NUL byte in the input will be converted
181 to a trailing NUL byte in the output. But not for UTF-7. So that this
182 function is usable for UTF-7, we have to exclude the NUL byte from the
183 conversion and add it by hand afterwards. */
188 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
195 int saved_errno = errno;
202 /* Add the terminating NUL byte. */
204 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
205 if (final_result == NULL)
212 final_result[length] = '\0';
221 const char *inptr = src;
222 size_t inbytes_remaining = strlen (src);
224 /* Make a guess for the worst-case output size, in order to avoid a
225 realloc. It's OK if the guess is wrong as long as it is not zero and
226 doesn't lead to an integer overflow. */
227 result_size = inbytes_remaining;
229 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
230 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
231 result_size *= MB_LEN_MAX;
233 result_size += 1; /* for the terminating NUL */
235 result = (char *) malloc (result_size);
242 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
243 # if defined _LIBICONV_VERSION \
244 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
245 /* Set to the initial state. */
246 iconv (cd, NULL, NULL, NULL, NULL);
249 /* Do the conversion. */
251 char *outptr = result;
252 size_t outbytes_remaining = result_size - 1;
256 /* Here inptr + inbytes_remaining = src + strlen (src),
257 outptr + outbytes_remaining = result + result_size - 1. */
258 size_t res = iconv (cd,
259 (ICONV_CONST char **) &inptr, &inbytes_remaining,
260 &outptr, &outbytes_remaining);
262 if (res == (size_t)(-1))
266 else if (errno == E2BIG)
268 size_t used = outptr - result;
269 size_t newsize = result_size * 2;
272 if (!(newsize > result_size))
277 newresult = (char *) realloc (result, newsize);
278 if (newresult == NULL)
284 result_size = newsize;
285 outptr = result + used;
286 outbytes_remaining = result_size - 1 - used;
291 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
292 /* Irix iconv() inserts a NUL byte if it cannot convert. */
302 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
303 # if defined _LIBICONV_VERSION \
304 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
307 /* Here outptr + outbytes_remaining = result + result_size - 1. */
308 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
310 if (res == (size_t)(-1))
314 size_t used = outptr - result;
315 size_t newsize = result_size * 2;
318 if (!(newsize > result_size))
323 newresult = (char *) realloc (result, newsize);
324 if (newresult == NULL)
330 result_size = newsize;
331 outptr = result + used;
332 outbytes_remaining = result_size - 1 - used;
342 /* Add the terminating NUL byte. */
345 length = outptr - result;
348 /* Give away unused memory. */
349 if (length < result_size)
351 char *smaller_result = (char *) realloc (result, length);
353 if (smaller_result != NULL)
354 result = smaller_result;
361 int saved_errno = errno;
373 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
375 if (c_strcasecmp (from_codeset, to_codeset) == 0)
383 /* Avoid glibc-2.1 bug with EUC-KR. */
384 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
385 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
386 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
392 cd = iconv_open (to_codeset, from_codeset);
393 if (cd == (iconv_t) -1)
396 result = str_cd_iconv (src, cd);
400 /* Close cd, but preserve the errno from str_cd_iconv. */
401 int saved_errno = errno;
407 if (iconv_close (cd) < 0)
409 /* Return NULL, but free the allocated memory, and while doing
410 that, preserve the errno from iconv_close. */
411 int saved_errno = errno;
419 /* This is a different error code than if iconv_open existed but didn't
420 support from_codeset and to_codeset, so that the caller can emit
421 an error message such as
422 "iconv() is not supported. Installing GNU libiconv and
423 then reinstalling this package would fix this." */