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. */
32 /* Get MB_LEN_MAX, CHAR_BIT. */
37 #include "c-strcase.h"
40 # define SIZE_MAX ((size_t) -1)
47 mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
48 char **resultp, size_t *lengthp)
50 # define tmpbufsize 4096
54 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
55 # if defined _LIBICONV_VERSION \
56 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
57 /* Set to the initial state. */
58 iconv (cd, NULL, NULL, NULL, NULL);
61 /* Determine the length we need. */
64 char tmpbuf[tmpbufsize];
65 const char *inptr = src;
66 size_t insize = srclen;
70 char *outptr = tmpbuf;
71 size_t outsize = tmpbufsize;
72 size_t res = iconv (cd,
73 (ICONV_CONST char **) &inptr, &insize,
76 if (res == (size_t)(-1))
80 else if (errno == EINVAL)
85 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
86 /* Irix iconv() inserts a NUL byte if it cannot convert. */
93 count += outptr - tmpbuf;
95 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
96 # if defined _LIBICONV_VERSION \
97 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
99 char *outptr = tmpbuf;
100 size_t outsize = tmpbufsize;
101 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
103 if (res == (size_t)(-1))
105 count += outptr - tmpbuf;
116 result = (*resultp != NULL ? realloc (*resultp, length) : malloc (length));
125 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
126 # if defined _LIBICONV_VERSION \
127 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
128 /* Return to the initial state. */
129 iconv (cd, NULL, NULL, NULL, NULL);
132 /* Do the conversion for real. */
134 const char *inptr = src;
135 size_t insize = srclen;
136 char *outptr = result;
137 size_t outsize = length;
141 size_t res = iconv (cd,
142 (ICONV_CONST char **) &inptr, &insize,
145 if (res == (size_t)(-1))
152 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
153 /* Irix iconv() inserts a NUL byte if it cannot convert. */
161 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
162 # if defined _LIBICONV_VERSION \
163 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
165 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
167 if (res == (size_t)(-1))
180 str_cd_iconv (const char *src, iconv_t cd)
182 /* For most encodings, a trailing NUL byte in the input will be converted
183 to a trailing NUL byte in the output. But not for UTF-7. So that this
184 function is usable for UTF-7, we have to exclude the NUL byte from the
185 conversion and add it by hand afterwards. */
190 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
197 int saved_errno = errno;
204 /* Add the terminating NUL byte. */
206 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
207 if (final_result == NULL)
214 final_result[length] = '\0';
223 const char *inptr = src;
224 size_t inbytes_remaining = strlen (src);
226 /* Make a guess for the worst-case output size, in order to avoid a
227 realloc. It's OK if the guess is wrong as long as it is not zero and
228 doesn't lead to an integer overflow. */
229 result_size = inbytes_remaining;
231 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
232 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
233 result_size *= MB_LEN_MAX;
235 result_size += 1; /* for the terminating NUL */
237 result = (char *) malloc (result_size);
244 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
245 # if defined _LIBICONV_VERSION \
246 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
247 /* Set to the initial state. */
248 iconv (cd, NULL, NULL, NULL, NULL);
251 /* Do the conversion. */
253 char *outptr = result;
254 size_t outbytes_remaining = result_size - 1;
258 /* Here inptr + inbytes_remaining = src + strlen (src),
259 outptr + outbytes_remaining = result + result_size - 1. */
260 size_t res = iconv (cd,
261 (ICONV_CONST char **) &inptr, &inbytes_remaining,
262 &outptr, &outbytes_remaining);
264 if (res == (size_t)(-1))
268 else if (errno == E2BIG)
270 size_t used = outptr - result;
271 size_t newsize = result_size * 2;
274 if (!(newsize > result_size))
279 newresult = (char *) realloc (result, newsize);
280 if (newresult == NULL)
286 result_size = newsize;
287 outptr = result + used;
288 outbytes_remaining = result_size - 1 - used;
293 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
294 /* Irix iconv() inserts a NUL byte if it cannot convert. */
304 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
305 # if defined _LIBICONV_VERSION \
306 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
309 /* Here outptr + outbytes_remaining = result + result_size - 1. */
310 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
312 if (res == (size_t)(-1))
316 size_t used = outptr - result;
317 size_t newsize = result_size * 2;
320 if (!(newsize > result_size))
325 newresult = (char *) realloc (result, newsize);
326 if (newresult == NULL)
332 result_size = newsize;
333 outptr = result + used;
334 outbytes_remaining = result_size - 1 - used;
344 /* Add the terminating NUL byte. */
347 length = outptr - result;
350 /* Give away unused memory. */
351 if (length < result_size)
353 char *smaller_result = (char *) realloc (result, length);
355 if (smaller_result != NULL)
356 result = smaller_result;
363 int saved_errno = errno;
375 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
377 if (c_strcasecmp (from_codeset, to_codeset) == 0)
385 /* Avoid glibc-2.1 bug with EUC-KR. */
386 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
387 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
388 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
394 cd = iconv_open (to_codeset, from_codeset);
395 if (cd == (iconv_t) -1)
398 result = str_cd_iconv (src, cd);
402 /* Close cd, but preserve the errno from str_cd_iconv. */
403 int saved_errno = errno;
409 if (iconv_close (cd) < 0)
411 /* Return NULL, but free the allocated memory, and while doing
412 that, preserve the errno from iconv_close. */
413 int saved_errno = errno;
421 /* This is a different error code than if iconv_open existed but didn't
422 support from_codeset and to_codeset, so that the caller can emit
423 an error message such as
424 "iconv() is not supported. Installing GNU libiconv and
425 then reinstalling this package would fix this." */