1// std::codecvt implementation details, generic version -*- C++ -*-
2
3// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009
4// Free Software Foundation, Inc.
5//
6// This file is part of the GNU ISO C++ Library.  This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 3, or (at your option)
10// any later version.
11
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16
17// Under Section 7 of GPL version 3, you are granted additional
18// permissions described in the GCC Runtime Library Exception, version
19// 3.1, as published by the Free Software Foundation.
20
21// You should have received a copy of the GNU General Public License and
22// a copy of the GCC Runtime Library Exception along with this program;
23// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24// <http://www.gnu.org/licenses/>.
25
26//
27// ISO C++ 14882: 22.2.1.5 - Template class codecvt
28//
29
30// Written by Benjamin Kosnik <bkoz@redhat.com>
31
32#include <locale>
33#include <cstdlib>  // For MB_CUR_MAX
34#include <climits>  // For MB_LEN_MAX
35#include <cstring>
36
37_GLIBCXX_BEGIN_NAMESPACE(std)
38
39  // Specializations.
40#ifdef _GLIBCXX_USE_WCHAR_T
41  codecvt_base::result
42  codecvt<wchar_t, char, mbstate_t>::
43  do_out(state_type& __state, const intern_type* __from,
44	 const intern_type* __from_end, const intern_type*& __from_next,
45	 extern_type* __to, extern_type* __to_end,
46	 extern_type*& __to_next) const
47  {
48    result __ret = ok;
49    // The conversion must be done using a temporary destination buffer
50    // since it is not possible to pass the size of the buffer to wcrtomb
51    state_type __tmp_state(__state);
52
53    // The conversion must be done by calling wcrtomb in a loop rather
54    // than using wcsrtombs because wcsrtombs assumes that the input is
55    // zero-terminated.
56
57    // Either we can upper bound the total number of external characters to
58    // something smaller than __to_end - __to or the conversion must be done
59    // using a temporary destination buffer since it is not possible to
60    // pass the size of the buffer to wcrtomb
61    if (MB_CUR_MAX * (__from_end - __from) - (__to_end - __to) <= 0)
62      while (__from < __from_end)
63	{
64	  const size_t __conv = wcrtomb(__to, *__from, &__tmp_state);
65	  if (__conv == static_cast<size_t>(-1))
66	    {
67	      __ret = error;
68	      break;
69	    }
70	  __state = __tmp_state;
71	  __to += __conv;
72	  __from++;
73	}
74    else
75      {
76	extern_type __buf[MB_LEN_MAX];
77	while (__from < __from_end && __to < __to_end)
78	  {
79	    const size_t __conv = wcrtomb(__buf, *__from, &__tmp_state);
80	    if (__conv == static_cast<size_t>(-1))
81	      {
82		__ret = error;
83		break;
84	      }
85	    else if (__conv > static_cast<size_t>(__to_end - __to))
86	      {
87		__ret = partial;
88		break;
89	      }
90
91	    memcpy(__to, __buf, __conv);
92	    __state = __tmp_state;
93	    __to += __conv;
94	    __from++;
95	  }
96      }
97
98    if (__ret == ok && __from < __from_end)
99      __ret = partial;
100
101    __from_next = __from;
102    __to_next = __to;
103    return __ret;
104  }
105
106  codecvt_base::result
107  codecvt<wchar_t, char, mbstate_t>::
108  do_in(state_type& __state, const extern_type* __from,
109	const extern_type* __from_end, const extern_type*& __from_next,
110	intern_type* __to, intern_type* __to_end,
111	intern_type*& __to_next) const
112  {
113    result __ret = ok;
114    // This temporary state object is neccessary so __state won't be modified
115    // if [__from, __from_end) is a partial multibyte character.
116    state_type __tmp_state(__state);
117
118    // Conversion must be done by calling mbrtowc in a loop rather than
119    // by calling mbsrtowcs because mbsrtowcs assumes that the input
120    // sequence is zero-terminated.
121    while (__from < __from_end && __to < __to_end)
122      {
123	size_t __conv = mbrtowc(__to, __from, __from_end - __from,
124				&__tmp_state);
125	if (__conv == static_cast<size_t>(-1))
126	  {
127	    __ret = error;
128	    break;
129	  }
130	else if (__conv == static_cast<size_t>(-2))
131	  {
132	    // It is unclear what to return in this case (see DR 382).
133	    __ret = partial;
134	    break;
135	  }
136	else if (__conv == 0)
137	  {
138	    // XXX Probably wrong for stateful encodings
139	    __conv = 1;
140	    *__to = L'\0';
141	  }
142
143	__state = __tmp_state;
144	__to++;
145	__from += __conv;
146      }
147
148    // It is not clear that __from < __from_end implies __ret != ok
149    // (see DR 382).
150    if (__ret == ok && __from < __from_end)
151      __ret = partial;
152
153    __from_next = __from;
154    __to_next = __to;
155    return __ret;
156  }
157
158  int
159  codecvt<wchar_t, char, mbstate_t>::
160  do_encoding() const throw()
161  {
162    // XXX This implementation assumes that the encoding is
163    // stateless and is either single-byte or variable-width.
164    int __ret = 0;
165    if (MB_CUR_MAX == 1)
166      __ret = 1;
167    return __ret;
168  }
169
170  int
171  codecvt<wchar_t, char, mbstate_t>::
172  do_max_length() const throw()
173  {
174    // XXX Probably wrong for stateful encodings.
175    int __ret = MB_CUR_MAX;
176    return __ret;
177  }
178
179  int
180  codecvt<wchar_t, char, mbstate_t>::
181  do_length(state_type& __state, const extern_type* __from,
182	    const extern_type* __end, size_t __max) const
183  {
184    int __ret = 0;
185    state_type __tmp_state(__state);
186
187    while (__from < __end && __max)
188      {
189	size_t __conv = mbrtowc(NULL, __from, __end - __from, &__tmp_state);
190	if (__conv == static_cast<size_t>(-1))
191	  {
192	    // Invalid source character
193	    break;
194	  }
195	else if (__conv == static_cast<size_t>(-2))
196	  {
197	    // Remainder of input does not form a complete destination
198	    // character.
199	    break;
200	  }
201	else if (__conv == 0)
202	  {
203	    // XXX Probably wrong for stateful encodings
204	    __conv = 1;
205	  }
206
207	__state = __tmp_state;
208	__from += __conv;
209	__ret += __conv;
210	__max--;
211      }
212
213    return __ret;
214  }
215#endif
216
217_GLIBCXX_END_NAMESPACE
218