2 * Copyright (C) 2000-2001 Free Software Foundation, Inc.
3 * This file is part of the GNU LIBICONV Library.
5 * The GNU LIBICONV Library is free software; you can redistribute it
6 * and/or modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * The GNU LIBICONV Library is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
17 * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
18 * Suite 330, Boston, MA 02111-1307, USA.
21 /* This file defines three conversion loops:
22 - from wchar_t to anything else,
23 - from anything else to wchar_t,
24 - from wchar_t to wchar_t.
27 #if HAVE_WCRTOMB || HAVE_MBRTOWC
29 # define BUF_SIZE 64 /* assume MB_LEN_MAX <= 64 */
30 /* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
31 extern size_t mbrtowc ();
33 # define mbrtowc(pwc, s, n, ps) (mbrtowc)(pwc, s, n, 0)
34 # define mbsinit(ps) 1
38 # define mbsinit(ps) 1
43 typedef int mbstate_t;
48 * The first two conversion loops have an extended conversion descriptor.
50 struct wchar_conv_struct
{
51 struct conv_struct parent
;
58 /* From wchar_t to anything else. */
60 static size_t wchar_from_loop_convert (iconv_t icd
,
61 const char* * inbuf
, size_t *inbytesleft
,
62 char* * outbuf
, size_t *outbytesleft
)
64 struct wchar_conv_struct
* wcd
= (struct wchar_conv_struct
*) icd
;
66 while (*inbytesleft
>= sizeof(wchar_t)) {
67 const wchar_t * inptr
= (const wchar_t *) *inbuf
;
68 size_t inleft
= *inbytesleft
;
70 mbstate_t state
= wcd
->state
;
72 while (inleft
>= sizeof(wchar_t)) {
73 /* Convert one wchar_t to multibyte representation. */
74 size_t count
= wcrtomb(buf
+bufcount
,*inptr
,&state
);
75 if (count
== (size_t)(-1)) {
81 inleft
-= sizeof(wchar_t);
84 /* Continue, append next wchar_t. */
86 /* Attempt to convert the accumulated multibyte representations
87 to the target encoding. */
88 const char* bufptr
= buf
;
89 size_t bufleft
= bufcount
;
90 char* outptr
= *outbuf
;
91 size_t outleft
= *outbytesleft
;
92 size_t res
= unicode_loop_convert(&wcd
->parent
,
95 if (res
== (size_t)(-1)) {
99 else if (errno
== E2BIG
)
100 /* Output buffer too small. */
102 else if (errno
== EINVAL
) {
103 /* Continue, append next wchar_t, but avoid buffer overrun. */
104 if (bufcount
+ MB_CUR_MAX
> BUF_SIZE
)
109 /* Successful conversion. */
111 *inbuf
= (const char *) inptr
;
112 *inbytesleft
= inleft
;
114 *outbytesleft
= outleft
;
124 static size_t wchar_from_loop_reset (iconv_t icd
,
125 char* * outbuf
, size_t *outbytesleft
)
127 struct wchar_conv_struct
* wcd
= (struct wchar_conv_struct
*) icd
;
128 if (outbuf
== NULL
|| *outbuf
== NULL
) {
129 /* Reset the states. */
130 memset(&wcd
->state
,'\0',sizeof(mbstate_t));
131 return unicode_loop_reset(&wcd
->parent
,NULL
,NULL
);
133 if (!mbsinit(&wcd
->state
)) {
134 mbstate_t state
= wcd
->state
;
136 size_t bufcount
= wcrtomb(buf
,(wchar_t)0,&state
);
137 if (bufcount
== (size_t)(-1) || bufcount
== 0 || buf
[bufcount
-1] != '\0')
140 const char* bufptr
= buf
;
141 size_t bufleft
= bufcount
-1;
142 char* outptr
= *outbuf
;
143 size_t outleft
= *outbytesleft
;
144 size_t res
= unicode_loop_convert(&wcd
->parent
,
147 if (res
== (size_t)(-1)) {
153 res
= unicode_loop_reset(&wcd
->parent
,&outptr
,&outleft
);
154 if (res
== (size_t)(-1))
160 *outbytesleft
= outleft
;
166 return unicode_loop_reset(&wcd
->parent
,outbuf
,outbytesleft
);
175 /* From anything else to wchar_t. */
177 static size_t wchar_to_loop_convert (iconv_t icd
,
178 const char* * inbuf
, size_t *inbytesleft
,
179 char* * outbuf
, size_t *outbytesleft
)
181 struct wchar_conv_struct
* wcd
= (struct wchar_conv_struct
*) icd
;
183 while (*inbytesleft
> 0) {
185 for (incount
= 1; incount
<= *inbytesleft
; incount
++) {
187 const char* inptr
= *inbuf
;
188 size_t inleft
= incount
;
190 size_t bufleft
= BUF_SIZE
;
191 size_t res
= unicode_loop_convert(&wcd
->parent
,
194 if (res
== (size_t)(-1)) {
198 else if (errno
== EINVAL
) {
199 /* Incomplete input. Next try with one more input byte. */
201 /* E2BIG shouldn't occur. */
204 /* Successful conversion. */
205 size_t bufcount
= bufptr
-buf
; /* = BUF_SIZE-bufleft */
206 mbstate_t state
= wcd
->state
;
208 res
= mbrtowc(&wc
,buf
,bufcount
,&state
);
209 if (res
== (size_t)(-2)) {
210 /* Next try with one more input byte. */
211 } else if (res
== (size_t)(-1)) {
215 if (*outbytesleft
< sizeof(wchar_t)) {
219 *(wchar_t*) *outbuf
= wc
;
220 *outbuf
+= sizeof(wchar_t);
221 *outbytesleft
-= sizeof(wchar_t);
223 *inbytesleft
-= incount
;
233 static size_t wchar_to_loop_reset (iconv_t icd
,
234 char* * outbuf
, size_t *outbytesleft
)
236 struct wchar_conv_struct
* wcd
= (struct wchar_conv_struct
*) icd
;
237 size_t res
= unicode_loop_reset(&wcd
->parent
,outbuf
,outbytesleft
);
238 if (res
== (size_t)(-1))
240 memset(&wcd
->state
,0,sizeof(mbstate_t));
247 /* From wchar_t to wchar_t. */
249 static size_t wchar_id_loop_convert (iconv_t icd
,
250 const char* * inbuf
, size_t *inbytesleft
,
251 char* * outbuf
, size_t *outbytesleft
)
253 const wchar_t* inptr
= (const wchar_t*) *inbuf
;
254 size_t inleft
= *inbytesleft
/ sizeof(wchar_t);
255 wchar_t* outptr
= (wchar_t*) *outbuf
;
256 size_t outleft
= *outbytesleft
/ sizeof(wchar_t);
257 size_t count
= (inleft
<= outleft
? inleft
: outleft
);
259 *inbytesleft
-= count
* sizeof(wchar_t);
260 *outbytesleft
-= count
* sizeof(wchar_t);
262 *outptr
++ = *inptr
++;
264 *inbuf
= (const char*) inptr
;
265 *outbuf
= (char*) outptr
;
270 static size_t wchar_id_loop_reset (iconv_t icd
,
271 char* * outbuf
, size_t *outbytesleft
)