1 /* Copyright (C) 1999-2001, 2003, 2011 Bruno Haible.
2 This file is not part of the GNU LIBICONV Library.
3 This file is put into the public domain. */
5 #include "iconv_string.h"
11 #define tmpbufsize 4096
13 int iconv_string (const char* tocode
, const char* fromcode
,
14 const char* start
, const char* end
,
15 char** resultp
, size_t* lengthp
)
17 iconv_t cd
= iconv_open(tocode
,fromcode
);
20 if (cd
== (iconv_t
)(-1)) {
23 /* Unsupported fromcode or tocode. Check whether the caller requested
25 if (!strcmp(fromcode
,"autodetect_utf8")) {
27 /* Try UTF-8 first. There are very few ISO-8859-1 inputs that would
28 be valid UTF-8, but many UTF-8 inputs are valid ISO-8859-1. */
29 ret
= iconv_string(tocode
,"UTF-8",start
,end
,resultp
,lengthp
);
30 if (!(ret
< 0 && errno
== EILSEQ
))
32 ret
= iconv_string(tocode
,"ISO-8859-1",start
,end
,resultp
,lengthp
);
35 if (!strcmp(fromcode
,"autodetect_jp")) {
37 /* Try 7-bit encoding first. If the input contains bytes >= 0x80,
39 ret
= iconv_string(tocode
,"ISO-2022-JP-2",start
,end
,resultp
,lengthp
);
40 if (!(ret
< 0 && errno
== EILSEQ
))
42 /* Try EUC-JP next. Short SHIFT_JIS inputs may come out wrong. This
43 is unavoidable. People will condemn SHIFT_JIS.
44 If we tried SHIFT_JIS first, then some short EUC-JP inputs would
45 come out wrong, and people would condemn EUC-JP and Unix, which
47 ret
= iconv_string(tocode
,"EUC-JP",start
,end
,resultp
,lengthp
);
48 if (!(ret
< 0 && errno
== EILSEQ
))
50 /* Finally try SHIFT_JIS. */
51 ret
= iconv_string(tocode
,"SHIFT_JIS",start
,end
,resultp
,lengthp
);
54 if (!strcmp(fromcode
,"autodetect_kr")) {
56 /* Try 7-bit encoding first. If the input contains bytes >= 0x80,
58 ret
= iconv_string(tocode
,"ISO-2022-KR",start
,end
,resultp
,lengthp
);
59 if (!(ret
< 0 && errno
== EILSEQ
))
61 /* Finally try EUC-KR. */
62 ret
= iconv_string(tocode
,"EUC-KR",start
,end
,resultp
,lengthp
);
68 /* Determine the length we need. */
71 char tmpbuf
[tmpbufsize
];
72 const char* inptr
= start
;
73 size_t insize
= end
-start
;
75 char* outptr
= tmpbuf
;
76 size_t outsize
= tmpbufsize
;
77 size_t res
= iconv(cd
,&inptr
,&insize
,&outptr
,&outsize
);
78 if (res
== (size_t)(-1) && errno
!= E2BIG
) {
79 int saved_errno
= (errno
== EINVAL
? EILSEQ
: errno
);
84 count
+= outptr
-tmpbuf
;
87 char* outptr
= tmpbuf
;
88 size_t outsize
= tmpbufsize
;
89 size_t res
= iconv(cd
,NULL
,NULL
,&outptr
,&outsize
);
90 if (res
== (size_t)(-1)) {
91 int saved_errno
= errno
;
96 count
+= outptr
-tmpbuf
;
102 if (resultp
== NULL
) {
106 result
= (*resultp
== NULL
? malloc(length
) : realloc(*resultp
,length
));
112 if (result
== NULL
) {
117 iconv(cd
,NULL
,NULL
,NULL
,NULL
); /* return to the initial state */
118 /* Do the conversion for real. */
120 const char* inptr
= start
;
121 size_t insize
= end
-start
;
122 char* outptr
= result
;
123 size_t outsize
= length
;
125 size_t res
= iconv(cd
,&inptr
,&insize
,&outptr
,&outsize
);
126 if (res
== (size_t)(-1)) {
130 int saved_errno
= errno
;
138 size_t res
= iconv(cd
,NULL
,NULL
,&outptr
,&outsize
);
139 if (res
== (size_t)(-1)) {
140 int saved_errno
= errno
;
146 if (outsize
!= 0) abort();