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. */
199 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
206 int saved_errno = errno;
213 /* Add the terminating NUL byte. */
215 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
216 if (final_result == NULL)
223 final_result[length] = '\0';
232 const char *inptr = src;
233 size_t inbytes_remaining = strlen (src);
235 /* Make a guess for the worst-case output size, in order to avoid a
236 realloc. It's OK if the guess is wrong as long as it is not zero and
237 doesn't lead to an integer overflow. */
238 result_size = inbytes_remaining;
240 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
241 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
242 result_size *= MB_LEN_MAX;
244 result_size += 1; /* for the terminating NUL */
246 result = (char *) malloc (result_size);
253 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
254 # if defined _LIBICONV_VERSION \
255 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
256 /* Set to the initial state. */
257 iconv (cd, NULL, NULL, NULL, NULL);
260 /* Do the conversion. */
262 char *outptr = result;
263 size_t outbytes_remaining = result_size - 1;
267 /* Here inptr + inbytes_remaining = src + strlen (src),
268 outptr + outbytes_remaining = result + result_size - 1. */
269 size_t res = iconv (cd,
270 (ICONV_CONST char **) &inptr, &inbytes_remaining,
271 &outptr, &outbytes_remaining);
273 if (res == (size_t)(-1))
277 else if (errno == E2BIG)
279 size_t used = outptr - result;
280 size_t newsize = result_size * 2;
283 if (!(newsize > result_size))
288 newresult = (char *) realloc (result, newsize);
289 if (newresult == NULL)
295 result_size = newsize;
296 outptr = result + used;
297 outbytes_remaining = result_size - 1 - used;
302 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
303 /* Irix iconv() inserts a NUL byte if it cannot convert.
304 NetBSD iconv() inserts a question mark if it cannot convert.
305 Only GNU libiconv and GNU libc are known to prefer to fail rather
306 than doing a lossy conversion. */
316 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
317 # if defined _LIBICONV_VERSION \
318 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
321 /* Here outptr + outbytes_remaining = result + result_size - 1. */
322 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
324 if (res == (size_t)(-1))
328 size_t used = outptr - result;
329 size_t newsize = result_size * 2;
332 if (!(newsize > result_size))
337 newresult = (char *) realloc (result, newsize);
338 if (newresult == NULL)
344 result_size = newsize;
345 outptr = result + used;
346 outbytes_remaining = result_size - 1 - used;
356 /* Add the terminating NUL byte. */
359 length = outptr - result;
362 /* Give away unused memory. */
363 if (length < result_size)
365 char *smaller_result = (char *) realloc (result, length);
367 if (smaller_result != NULL)
368 result = smaller_result;
375 int saved_errno = errno;
387 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
389 if (c_strcasecmp (from_codeset, to_codeset) == 0)
397 /* Avoid glibc-2.1 bug with EUC-KR. */
398 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
399 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
400 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
406 cd = iconv_open (to_codeset, from_codeset);
407 if (cd == (iconv_t) -1)
410 result = str_cd_iconv (src, cd);
414 /* Close cd, but preserve the errno from str_cd_iconv. */
415 int saved_errno = errno;
421 if (iconv_close (cd) < 0)
423 /* Return NULL, but free the allocated memory, and while doing
424 that, preserve the errno from iconv_close. */
425 int saved_errno = errno;
433 /* This is a different error code than if iconv_open existed but didn't
434 support from_codeset and to_codeset, so that the caller can emit
435 an error message such as
436 "iconv() is not supported. Installing GNU libiconv and
437 then reinstalling this package would fix this." */