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