2 Copyright (C) 2001-2007 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 /* 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__
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__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
103 char *outptr = tmpbuf;
104 size_t outsize = tmpbufsize;
105 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
107 if (res == (size_t)(-1))
109 count += outptr - tmpbuf;
122 (char *) (*resultp != NULL ? realloc (*resultp, length) : malloc (length));
131 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
132 # if defined _LIBICONV_VERSION \
133 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
134 /* Return to the initial state. */
135 iconv (cd, NULL, NULL, NULL, NULL);
138 /* Do the conversion for real. */
140 const char *inptr = src;
141 size_t insize = srclen;
142 char *outptr = result;
143 size_t outsize = length;
147 size_t res = iconv (cd,
148 (ICONV_CONST char **) &inptr, &insize,
151 if (res == (size_t)(-1))
158 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
159 /* Irix iconv() inserts a NUL byte if it cannot convert.
160 NetBSD iconv() inserts a question mark if it cannot convert.
161 Only GNU libiconv and GNU libc are known to prefer to fail rather
162 than doing a lossy conversion. */
170 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
171 # if defined _LIBICONV_VERSION \
172 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
174 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
176 if (res == (size_t)(-1))
189 str_cd_iconv (const char *src, iconv_t cd)
191 /* For most encodings, a trailing NUL byte in the input will be converted
192 to a trailing NUL byte in the output. But not for UTF-7. So that this
193 function is usable for UTF-7, we have to exclude the NUL byte from the
194 conversion and add it by hand afterwards. */
195 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
196 /* Irix iconv() inserts a NUL byte if it cannot convert.
197 NetBSD iconv() inserts a question mark if it cannot convert.
198 Only GNU libiconv and GNU libc are known to prefer to fail rather
199 than doing a lossy conversion. For other iconv() implementations,
200 we have to look at the number of irreversible conversions returned;
201 but this information is lost when iconv() returns for an E2BIG reason.
202 Therefore we cannot use the second, faster algorithm. */
206 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
213 int saved_errno = errno;
220 /* Add the terminating NUL byte. */
222 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
223 if (final_result == NULL)
230 final_result[length] = '\0';
235 /* This algorithm is likely faster than the one above. But it may produce
236 iconv() returns for an E2BIG reason, when the output size guess is too
237 small. Therefore it can only be used when we don't need the number of
238 irreversible conversions performed. */
242 const char *inptr = src;
243 size_t inbytes_remaining = strlen (src);
245 /* Make a guess for the worst-case output size, in order to avoid a
246 realloc. It's OK if the guess is wrong as long as it is not zero and
247 doesn't lead to an integer overflow. */
248 result_size = inbytes_remaining;
250 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
251 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
252 result_size *= MB_LEN_MAX;
254 result_size += 1; /* for the terminating NUL */
256 result = (char *) malloc (result_size);
263 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
264 # if defined _LIBICONV_VERSION \
265 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
266 /* Set to the initial state. */
267 iconv (cd, NULL, NULL, NULL, NULL);
270 /* Do the conversion. */
272 char *outptr = result;
273 size_t outbytes_remaining = result_size - 1;
277 /* Here inptr + inbytes_remaining = src + strlen (src),
278 outptr + outbytes_remaining = result + result_size - 1. */
279 size_t res = iconv (cd,
280 (ICONV_CONST char **) &inptr, &inbytes_remaining,
281 &outptr, &outbytes_remaining);
283 if (res == (size_t)(-1))
287 else if (errno == E2BIG)
289 size_t used = outptr - result;
290 size_t newsize = result_size * 2;
293 if (!(newsize > result_size))
298 newresult = (char *) realloc (result, newsize);
299 if (newresult == NULL)
305 result_size = newsize;
306 outptr = result + used;
307 outbytes_remaining = result_size - 1 - used;
315 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
316 # if defined _LIBICONV_VERSION \
317 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
320 /* Here outptr + outbytes_remaining = result + result_size - 1. */
321 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
323 if (res == (size_t)(-1))
327 size_t used = outptr - result;
328 size_t newsize = result_size * 2;
331 if (!(newsize > result_size))
336 newresult = (char *) realloc (result, newsize);
337 if (newresult == NULL)
343 result_size = newsize;
344 outptr = result + used;
345 outbytes_remaining = result_size - 1 - used;
355 /* Add the terminating NUL byte. */
358 length = outptr - result;
361 /* Give away unused memory. */
362 if (length < result_size)
364 char *smaller_result = (char *) realloc (result, length);
366 if (smaller_result != NULL)
367 result = smaller_result;
374 int saved_errno = errno;
386 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
388 if (c_strcasecmp (from_codeset, to_codeset) == 0)
396 /* Avoid glibc-2.1 bug with EUC-KR. */
397 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
398 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
399 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
405 cd = iconv_open (to_codeset, from_codeset);
406 if (cd == (iconv_t) -1)
409 result = str_cd_iconv (src, cd);
413 /* Close cd, but preserve the errno from str_cd_iconv. */
414 int saved_errno = errno;
420 if (iconv_close (cd) < 0)
422 /* Return NULL, but free the allocated memory, and while doing
423 that, preserve the errno from iconv_close. */
424 int saved_errno = errno;
432 /* This is a different error code than if iconv_open existed but didn't
433 support from_codeset and to_codeset, so that the caller can emit
434 an error message such as
435 "iconv() is not supported. Installing GNU libiconv and
436 then reinstalling this package would fix this." */