2 Copyright (C) 2001-2007, 2010-2011 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__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
55 /* Set to the initial state. */
56 iconv (cd, NULL, NULL, NULL, NULL);
59 /* Determine the length we need. */
62 /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
63 libiconv's UCS-4-INTERNAL encoding. */
64 union { unsigned int align; char buf[tmpbufsize]; } tmp;
65 # define tmpbuf tmp.buf
66 const char *inptr = src;
67 size_t insize = srclen;
71 char *outptr = tmpbuf;
72 size_t outsize = tmpbufsize;
73 size_t res = iconv (cd,
74 (ICONV_CONST char **) &inptr, &insize,
77 if (res == (size_t)(-1))
81 else if (errno == EINVAL)
86 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
87 /* Irix iconv() inserts a NUL byte if it cannot convert.
88 NetBSD iconv() inserts a question mark if it cannot convert.
89 Only GNU libiconv and GNU libc are known to prefer to fail rather
90 than doing a lossy conversion. */
97 count += outptr - tmpbuf;
99 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
100 # if defined _LIBICONV_VERSION \
101 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
104 char *outptr = tmpbuf;
105 size_t outsize = tmpbufsize;
106 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
108 if (res == (size_t)(-1))
110 count += outptr - tmpbuf;
122 if (*resultp != NULL && *lengthp >= length)
126 result = (char *) malloc (length);
134 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
135 # if defined _LIBICONV_VERSION \
136 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
138 /* Return to the initial state. */
139 iconv (cd, NULL, NULL, NULL, NULL);
142 /* Do the conversion for real. */
144 const char *inptr = src;
145 size_t insize = srclen;
146 char *outptr = result;
147 size_t outsize = length;
151 size_t res = iconv (cd,
152 (ICONV_CONST char **) &inptr, &insize,
155 if (res == (size_t)(-1))
162 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
163 /* Irix iconv() inserts a NUL byte if it cannot convert.
164 NetBSD iconv() inserts a question mark if it cannot convert.
165 Only GNU libiconv and GNU libc are known to prefer to fail rather
166 than doing a lossy conversion. */
174 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
175 # if defined _LIBICONV_VERSION \
176 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
179 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
181 if (res == (size_t)(-1))
196 if (result != *resultp)
198 int saved_errno = errno;
208 str_cd_iconv (const char *src, iconv_t cd)
210 /* For most encodings, a trailing NUL byte in the input will be converted
211 to a trailing NUL byte in the output. But not for UTF-7. So that this
212 function is usable for UTF-7, we have to exclude the NUL byte from the
213 conversion and add it by hand afterwards. */
214 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
215 /* Irix iconv() inserts a NUL byte if it cannot convert.
216 NetBSD iconv() inserts a question mark if it cannot convert.
217 Only GNU libiconv and GNU libc are known to prefer to fail rather
218 than doing a lossy conversion. For other iconv() implementations,
219 we have to look at the number of irreversible conversions returned;
220 but this information is lost when iconv() returns for an E2BIG reason.
221 Therefore we cannot use the second, faster algorithm. */
225 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
235 /* Add the terminating NUL byte. */
237 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
238 if (final_result == NULL)
244 final_result[length] = '\0';
249 /* This algorithm is likely faster than the one above. But it may produce
250 iconv() returns for an E2BIG reason, when the output size guess is too
251 small. Therefore it can only be used when we don't need the number of
252 irreversible conversions performed. */
256 const char *inptr = src;
257 size_t inbytes_remaining = strlen (src);
259 /* Make a guess for the worst-case output size, in order to avoid a
260 realloc. It's OK if the guess is wrong as long as it is not zero and
261 doesn't lead to an integer overflow. */
262 result_size = inbytes_remaining;
264 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
265 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
266 result_size *= MB_LEN_MAX;
268 result_size += 1; /* for the terminating NUL */
270 result = (char *) malloc (result_size);
277 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
278 # if defined _LIBICONV_VERSION \
279 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
281 /* Set to the initial state. */
282 iconv (cd, NULL, NULL, NULL, NULL);
285 /* Do the conversion. */
287 char *outptr = result;
288 size_t outbytes_remaining = result_size - 1;
292 /* Here inptr + inbytes_remaining = src + strlen (src),
293 outptr + outbytes_remaining = result + result_size - 1. */
294 size_t res = iconv (cd,
295 (ICONV_CONST char **) &inptr, &inbytes_remaining,
296 &outptr, &outbytes_remaining);
298 if (res == (size_t)(-1))
302 else if (errno == E2BIG)
304 size_t used = outptr - result;
305 size_t newsize = result_size * 2;
308 if (!(newsize > result_size))
313 newresult = (char *) realloc (result, newsize);
314 if (newresult == NULL)
320 result_size = newsize;
321 outptr = result + used;
322 outbytes_remaining = result_size - 1 - used;
330 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
331 # if defined _LIBICONV_VERSION \
332 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
336 /* Here outptr + outbytes_remaining = result + result_size - 1. */
337 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
339 if (res == (size_t)(-1))
343 size_t used = outptr - result;
344 size_t newsize = result_size * 2;
347 if (!(newsize > result_size))
352 newresult = (char *) realloc (result, newsize);
353 if (newresult == NULL)
359 result_size = newsize;
360 outptr = result + used;
361 outbytes_remaining = result_size - 1 - used;
371 /* Add the terminating NUL byte. */
374 length = outptr - result;
377 /* Give away unused memory. */
378 if (length < result_size)
380 char *smaller_result = (char *) realloc (result, length);
382 if (smaller_result != NULL)
383 result = smaller_result;
390 int saved_errno = errno;
402 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
404 if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0)
406 char *result = strdup (src);
418 /* Avoid glibc-2.1 bug with EUC-KR. */
419 # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
420 && !defined _LIBICONV_VERSION
421 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
422 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
428 cd = iconv_open (to_codeset, from_codeset);
429 if (cd == (iconv_t) -1)
432 result = str_cd_iconv (src, cd);
436 /* Close cd, but preserve the errno from str_cd_iconv. */
437 int saved_errno = errno;
443 if (iconv_close (cd) < 0)
445 /* Return NULL, but free the allocated memory, and while doing
446 that, preserve the errno from iconv_close. */
447 int saved_errno = errno;
455 /* This is a different error code than if iconv_open existed but didn't
456 support from_codeset and to_codeset, so that the caller can emit
457 an error message such as
458 "iconv() is not supported. Installing GNU libiconv and
459 then reinstalling this package would fix this." */