2 Copyright (C) 2001-2007, 2010-2020 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, see <https://www.gnu.org/licenses/>. */
29 /* Get MB_LEN_MAX, CHAR_BIT. */
33 #include "c-strcase.h"
36 # define SIZE_MAX ((size_t) -1)
43 mem_cd_iconv (const char *src
, size_t srclen
, iconv_t cd
,
44 char **resultp
, size_t *lengthp
)
46 # define tmpbufsize 4096
50 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
51 # if defined _LIBICONV_VERSION \
52 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
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__ && !defined __UCLIBC__)
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__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
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
;
121 if (*resultp
!= NULL
&& *lengthp
>= length
)
125 result
= (char *) malloc (length
);
133 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
134 # if defined _LIBICONV_VERSION \
135 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
137 /* Return to the initial state. */
138 iconv (cd
, NULL
, NULL
, NULL
, NULL
);
141 /* Do the conversion for real. */
143 const char *inptr
= src
;
144 size_t insize
= srclen
;
145 char *outptr
= result
;
146 size_t outsize
= length
;
150 size_t res
= iconv (cd
,
151 (ICONV_CONST
char **) &inptr
, &insize
,
154 if (res
== (size_t)(-1))
161 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
162 /* Irix iconv() inserts a NUL byte if it cannot convert.
163 NetBSD iconv() inserts a question mark if it cannot convert.
164 Only GNU libiconv and GNU libc are known to prefer to fail rather
165 than doing a lossy conversion. */
173 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
174 # if defined _LIBICONV_VERSION \
175 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
178 size_t res
= iconv (cd
, NULL
, NULL
, &outptr
, &outsize
);
180 if (res
== (size_t)(-1))
195 if (result
!= *resultp
)
197 int saved_errno
= errno
;
207 str_cd_iconv (const char *src
, iconv_t cd
)
209 /* For most encodings, a trailing NUL byte in the input will be converted
210 to a trailing NUL byte in the output. But not for UTF-7. So that this
211 function is usable for UTF-7, we have to exclude the NUL byte from the
212 conversion and add it by hand afterwards. */
213 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
214 /* Irix iconv() inserts a NUL byte if it cannot convert.
215 NetBSD iconv() inserts a question mark if it cannot convert.
216 Only GNU libiconv and GNU libc are known to prefer to fail rather
217 than doing a lossy conversion. For other iconv() implementations,
218 we have to look at the number of irreversible conversions returned;
219 but this information is lost when iconv() returns for an E2BIG reason.
220 Therefore we cannot use the second, faster algorithm. */
224 int retval
= mem_cd_iconv (src
, strlen (src
), cd
, &result
, &length
);
234 /* Add the terminating NUL byte. */
236 (result
!= NULL
? realloc (result
, length
+ 1) : malloc (length
+ 1));
237 if (final_result
== NULL
)
243 final_result
[length
] = '\0';
248 /* This algorithm is likely faster than the one above. But it may produce
249 iconv() returns for an E2BIG reason, when the output size guess is too
250 small. Therefore it can only be used when we don't need the number of
251 irreversible conversions performed. */
255 const char *inptr
= src
;
256 size_t inbytes_remaining
= strlen (src
);
258 /* Make a guess for the worst-case output size, in order to avoid a
259 realloc. It's OK if the guess is wrong as long as it is not zero and
260 doesn't lead to an integer overflow. */
261 result_size
= inbytes_remaining
;
263 size_t approx_sqrt_SIZE_MAX
= SIZE_MAX
>> (sizeof (size_t) * CHAR_BIT
/ 2);
264 if (result_size
<= approx_sqrt_SIZE_MAX
/ MB_LEN_MAX
)
265 result_size
*= MB_LEN_MAX
;
267 result_size
+= 1; /* for the terminating NUL */
269 result
= (char *) malloc (result_size
);
276 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
277 # if defined _LIBICONV_VERSION \
278 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
280 /* Set to the initial state. */
281 iconv (cd
, NULL
, NULL
, NULL
, NULL
);
284 /* Do the conversion. */
286 char *outptr
= result
;
287 size_t outbytes_remaining
= result_size
- 1;
291 /* Here inptr + inbytes_remaining = src + strlen (src),
292 outptr + outbytes_remaining = result + result_size - 1. */
293 size_t res
= iconv (cd
,
294 (ICONV_CONST
char **) &inptr
, &inbytes_remaining
,
295 &outptr
, &outbytes_remaining
);
297 if (res
== (size_t)(-1))
301 else if (errno
== E2BIG
)
303 size_t used
= outptr
- result
;
304 size_t newsize
= result_size
* 2;
307 if (!(newsize
> result_size
))
312 newresult
= (char *) realloc (result
, newsize
);
313 if (newresult
== NULL
)
319 result_size
= newsize
;
320 outptr
= result
+ used
;
321 outbytes_remaining
= result_size
- 1 - used
;
329 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
330 # if defined _LIBICONV_VERSION \
331 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
335 /* Here outptr + outbytes_remaining = result + result_size - 1. */
336 size_t res
= iconv (cd
, NULL
, NULL
, &outptr
, &outbytes_remaining
);
338 if (res
== (size_t)(-1))
342 size_t used
= outptr
- result
;
343 size_t newsize
= result_size
* 2;
346 if (!(newsize
> result_size
))
351 newresult
= (char *) realloc (result
, newsize
);
352 if (newresult
== NULL
)
358 result_size
= newsize
;
359 outptr
= result
+ used
;
360 outbytes_remaining
= result_size
- 1 - used
;
370 /* Add the terminating NUL byte. */
373 length
= outptr
- result
;
376 /* Give away unused memory. */
377 if (length
< result_size
)
379 char *smaller_result
= (char *) realloc (result
, length
);
381 if (smaller_result
!= NULL
)
382 result
= smaller_result
;
389 int saved_errno
= errno
;
401 str_iconv (const char *src
, const char *from_codeset
, const char *to_codeset
)
403 if (*src
== '\0' || c_strcasecmp (from_codeset
, to_codeset
) == 0)
405 char *result
= strdup (src
);
417 /* Avoid glibc-2.1 bug with EUC-KR. */
418 # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
419 && !defined _LIBICONV_VERSION
420 if (c_strcasecmp (from_codeset
, "EUC-KR") == 0
421 || c_strcasecmp (to_codeset
, "EUC-KR") == 0)
427 cd
= iconv_open (to_codeset
, from_codeset
);
428 if (cd
== (iconv_t
) -1)
431 result
= str_cd_iconv (src
, cd
);
435 /* Close cd, but preserve the errno from str_cd_iconv. */
436 int saved_errno
= errno
;
442 if (iconv_close (cd
) < 0)
444 /* Return NULL, but free the allocated memory, and while doing
445 that, preserve the errno from iconv_close. */
446 int saved_errno
= errno
;
454 /* This is a different error code than if iconv_open existed but didn't
455 support from_codeset and to_codeset, so that the caller can emit
456 an error message such as
457 "iconv() is not supported. Installing GNU libiconv and
458 then reinstalling this package would fix this." */