2 * Copyright (C) 2000-2002 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)) {
77 if (!wcd->parent.discard_ilseq) {
84 inleft -= sizeof(wchar_t);
87 /* Continue, append next wchar_t. */
89 /* Attempt to convert the accumulated multibyte representations
90 to the target encoding. */
91 const char* bufptr = buf;
92 size_t bufleft = bufcount;
93 char* outptr = *outbuf;
94 size_t outleft = *outbytesleft;
95 size_t res = unicode_loop_convert(&wcd->parent,
98 if (res == (size_t)(-1)) {
102 else if (errno == E2BIG)
103 /* Output buffer too small. */
105 else if (errno == EINVAL) {
106 /* Continue, append next wchar_t, but avoid buffer overrun. */
107 if (bufcount + MB_CUR_MAX > BUF_SIZE)
112 /* Successful conversion. */
114 *inbuf = (const char *) inptr;
115 *inbytesleft = inleft;
117 *outbytesleft = outleft;
127 static size_t wchar_from_loop_reset (iconv_t icd,
128 char* * outbuf, size_t *outbytesleft)
130 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
131 if (outbuf == NULL || *outbuf == NULL) {
132 /* Reset the states. */
133 memset(&wcd->state,'\0',sizeof(mbstate_t));
134 return unicode_loop_reset(&wcd->parent,NULL,NULL);
136 if (!mbsinit(&wcd->state)) {
137 mbstate_t state = wcd->state;
139 size_t bufcount = wcrtomb(buf,(wchar_t)0,&state);
140 if (bufcount == (size_t)(-1) || bufcount == 0 || buf[bufcount-1] != '\0')
143 const char* bufptr = buf;
144 size_t bufleft = bufcount-1;
145 char* outptr = *outbuf;
146 size_t outleft = *outbytesleft;
147 size_t res = unicode_loop_convert(&wcd->parent,
150 if (res == (size_t)(-1)) {
156 res = unicode_loop_reset(&wcd->parent,&outptr,&outleft);
157 if (res == (size_t)(-1))
163 *outbytesleft = outleft;
169 return unicode_loop_reset(&wcd->parent,outbuf,outbytesleft);
178 /* From anything else to wchar_t. */
180 static size_t wchar_to_loop_convert (iconv_t icd,
181 const char* * inbuf, size_t *inbytesleft,
182 char* * outbuf, size_t *outbytesleft)
184 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
186 while (*inbytesleft > 0) {
188 for (incount = 1; incount <= *inbytesleft; incount++) {
190 const char* inptr = *inbuf;
191 size_t inleft = incount;
193 size_t bufleft = BUF_SIZE;
194 size_t res = unicode_loop_convert(&wcd->parent,
197 if (res == (size_t)(-1)) {
201 else if (errno == EINVAL) {
202 /* Incomplete input. Next try with one more input byte. */
204 /* E2BIG shouldn't occur. */
207 /* Successful conversion. */
208 size_t bufcount = bufptr-buf; /* = BUF_SIZE-bufleft */
209 mbstate_t state = wcd->state;
211 res = mbrtowc(&wc,buf,bufcount,&state);
212 if (res == (size_t)(-2)) {
213 /* Next try with one more input byte. */
215 if (res == (size_t)(-1)) {
217 if (!wcd->parent.discard_ilseq)
220 if (*outbytesleft < sizeof(wchar_t)) {
224 *(wchar_t*) *outbuf = wc;
225 /* Restoring the state is not needed because it is the initial
226 state anyway: For all known locale encodings, the multibyte
227 to wchar_t conversion doesn't have shift state, and we have
228 excluded partial accumulated characters. */
229 /* wcd->state = state; */
230 *outbuf += sizeof(wchar_t);
231 *outbytesleft -= sizeof(wchar_t);
234 *inbytesleft -= incount;
244 static size_t wchar_to_loop_reset (iconv_t icd,
245 char* * outbuf, size_t *outbytesleft)
247 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
248 size_t res = unicode_loop_reset(&wcd->parent,outbuf,outbytesleft);
249 if (res == (size_t)(-1))
251 memset(&wcd->state,0,sizeof(mbstate_t));
258 /* From wchar_t to wchar_t. */
260 static size_t wchar_id_loop_convert (iconv_t icd,
261 const char* * inbuf, size_t *inbytesleft,
262 char* * outbuf, size_t *outbytesleft)
264 const wchar_t* inptr = (const wchar_t*) *inbuf;
265 size_t inleft = *inbytesleft / sizeof(wchar_t);
266 wchar_t* outptr = (wchar_t*) *outbuf;
267 size_t outleft = *outbytesleft / sizeof(wchar_t);
268 size_t count = (inleft <= outleft ? inleft : outleft);
270 *inbytesleft -= count * sizeof(wchar_t);
271 *outbytesleft -= count * sizeof(wchar_t);
273 *outptr++ = *inptr++;
275 *inbuf = (const char*) inptr;
276 *outbuf = (char*) outptr;
281 static size_t wchar_id_loop_reset (iconv_t icd,
282 char* * outbuf, size_t *outbytesleft)