2 Copyright (C) 2001-2007, 2009-2010 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. */
34 #include "c-strcase.h"
37 # define SIZE_MAX ((size_t) -1)
44 mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
45 char **resultp, size_t *lengthp)
47 # define tmpbufsize 4096
51 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
52 # if defined _LIBICONV_VERSION \
53 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
54 /* Set to the initial state. */
55 iconv (cd, NULL, NULL, NULL, NULL);
58 /* Determine the length we need. */
61 /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
62 libiconv's UCS-4-INTERNAL encoding. */
63 union { unsigned int align; char buf[tmpbufsize]; } tmp;
64 # define tmpbuf tmp.buf
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 __GLIBC__
86 /* Irix iconv() inserts a NUL byte if it cannot convert.
87 NetBSD iconv() inserts a question mark if it cannot convert.
88 Only GNU libiconv and GNU libc are known to prefer to fail rather
89 than doing a lossy conversion. */
96 count += outptr - tmpbuf;
98 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
99 # if defined _LIBICONV_VERSION \
100 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
102 char *outptr = tmpbuf;
103 size_t outsize = tmpbufsize;
104 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
106 if (res == (size_t)(-1))
108 count += outptr - tmpbuf;
120 if (*resultp != NULL && *lengthp >= length)
124 result = (char *) malloc (length);
132 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
133 # if defined _LIBICONV_VERSION \
134 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
135 /* Return to the initial state. */
136 iconv (cd, NULL, NULL, NULL, NULL);
139 /* Do the conversion for real. */
141 const char *inptr = src;
142 size_t insize = srclen;
143 char *outptr = result;
144 size_t outsize = length;
148 size_t res = iconv (cd,
149 (ICONV_CONST char **) &inptr, &insize,
152 if (res == (size_t)(-1))
159 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
160 /* Irix iconv() inserts a NUL byte if it cannot convert.
161 NetBSD iconv() inserts a question mark if it cannot convert.
162 Only GNU libiconv and GNU libc are known to prefer to fail rather
163 than doing a lossy conversion. */
171 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
172 # if defined _LIBICONV_VERSION \
173 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
175 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
177 if (res == (size_t)(-1))
192 if (result != *resultp)
194 int saved_errno = errno;
204 str_cd_iconv (const char *src, iconv_t cd)
206 /* For most encodings, a trailing NUL byte in the input will be converted
207 to a trailing NUL byte in the output. But not for UTF-7. So that this
208 function is usable for UTF-7, we have to exclude the NUL byte from the
209 conversion and add it by hand afterwards. */
210 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
211 /* Irix iconv() inserts a NUL byte if it cannot convert.
212 NetBSD iconv() inserts a question mark if it cannot convert.
213 Only GNU libiconv and GNU libc are known to prefer to fail rather
214 than doing a lossy conversion. For other iconv() implementations,
215 we have to look at the number of irreversible conversions returned;
216 but this information is lost when iconv() returns for an E2BIG reason.
217 Therefore we cannot use the second, faster algorithm. */
221 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
231 /* Add the terminating NUL byte. */
233 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
234 if (final_result == NULL)
240 final_result[length] = '\0';
245 /* This algorithm is likely faster than the one above. But it may produce
246 iconv() returns for an E2BIG reason, when the output size guess is too
247 small. Therefore it can only be used when we don't need the number of
248 irreversible conversions performed. */
252 const char *inptr = src;
253 size_t inbytes_remaining = strlen (src);
255 /* Make a guess for the worst-case output size, in order to avoid a
256 realloc. It's OK if the guess is wrong as long as it is not zero and
257 doesn't lead to an integer overflow. */
258 result_size = inbytes_remaining;
260 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
261 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
262 result_size *= MB_LEN_MAX;
264 result_size += 1; /* for the terminating NUL */
266 result = (char *) malloc (result_size);
273 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
274 # if defined _LIBICONV_VERSION \
275 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
276 /* Set to the initial state. */
277 iconv (cd, NULL, NULL, NULL, NULL);
280 /* Do the conversion. */
282 char *outptr = result;
283 size_t outbytes_remaining = result_size - 1;
287 /* Here inptr + inbytes_remaining = src + strlen (src),
288 outptr + outbytes_remaining = result + result_size - 1. */
289 size_t res = iconv (cd,
290 (ICONV_CONST char **) &inptr, &inbytes_remaining,
291 &outptr, &outbytes_remaining);
293 if (res == (size_t)(-1))
297 else if (errno == E2BIG)
299 size_t used = outptr - result;
300 size_t newsize = result_size * 2;
303 if (!(newsize > result_size))
308 newresult = (char *) realloc (result, newsize);
309 if (newresult == NULL)
315 result_size = newsize;
316 outptr = result + used;
317 outbytes_remaining = result_size - 1 - used;
325 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
326 # if defined _LIBICONV_VERSION \
327 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
330 /* Here outptr + outbytes_remaining = result + result_size - 1. */
331 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
333 if (res == (size_t)(-1))
337 size_t used = outptr - result;
338 size_t newsize = result_size * 2;
341 if (!(newsize > result_size))
346 newresult = (char *) realloc (result, newsize);
347 if (newresult == NULL)
353 result_size = newsize;
354 outptr = result + used;
355 outbytes_remaining = result_size - 1 - used;
365 /* Add the terminating NUL byte. */
368 length = outptr - result;
371 /* Give away unused memory. */
372 if (length < result_size)
374 char *smaller_result = (char *) realloc (result, length);
376 if (smaller_result != NULL)
377 result = smaller_result;
384 int saved_errno = errno;
396 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
398 if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0)
400 char *result = strdup (src);
412 /* Avoid glibc-2.1 bug with EUC-KR. */
413 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
414 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
415 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
421 cd = iconv_open (to_codeset, from_codeset);
422 if (cd == (iconv_t) -1)
425 result = str_cd_iconv (src, cd);
429 /* Close cd, but preserve the errno from str_cd_iconv. */
430 int saved_errno = errno;
436 if (iconv_close (cd) < 0)
438 /* Return NULL, but free the allocated memory, and while doing
439 that, preserve the errno from iconv_close. */
440 int saved_errno = errno;
448 /* This is a different error code than if iconv_open existed but didn't
449 support from_codeset and to_codeset, so that the caller can emit
450 an error message such as
451 "iconv() is not supported. Installing GNU libiconv and
452 then reinstalling this package would fix this." */