1 // filesystem path_traits.cpp --------------------------------------------------------// 2 3 // Copyright Beman Dawes 2008, 2009 4 5 // Distributed under the Boost Software License, Version 1.0. 6 // See http://www.boost.org/LICENSE_1_0.txt 7 8 // Library home page: http://www.boost.org/libs/filesystem 9 10 //--------------------------------------------------------------------------------------// 11 12 #include "platform_config.hpp" 13 14 #include <boost/filesystem/path_traits.hpp> 15 #include <boost/system/system_error.hpp> 16 #include <boost/scoped_array.hpp> 17 #include <locale> // for codecvt_base::result 18 #include <cstring> // for strlen 19 #include <cwchar> // for wcslen 20 21 namespace pt = boost::filesystem::path_traits; 22 namespace fs = boost::filesystem; 23 namespace bs = boost::system; 24 25 //--------------------------------------------------------------------------------------// 26 // configuration // 27 //--------------------------------------------------------------------------------------// 28 29 #ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE 30 # define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256 31 #endif 32 33 namespace { 34 35 const std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE; 36 37 38 //--------------------------------------------------------------------------------------// 39 // // 40 // The public convert() functions do buffer management, and then forward to the // 41 // convert_aux() functions for the actual call to the codecvt facet. // 42 // // 43 //--------------------------------------------------------------------------------------// 44 45 //--------------------------------------------------------------------------------------// 46 // convert_aux const char* to wstring // 47 //--------------------------------------------------------------------------------------// 48 convert_aux(const char * from,const char * from_end,wchar_t * to,wchar_t * to_end,std::wstring & target,const pt::codecvt_type & cvt)49 void convert_aux( 50 const char* from, 51 const char* from_end, 52 wchar_t* to, wchar_t* to_end, 53 std::wstring & target, 54 const pt::codecvt_type & cvt) 55 { 56 //std::cout << std::hex 57 // << " from=" << std::size_t(from) 58 // << " from_end=" << std::size_t(from_end) 59 // << " to=" << std::size_t(to) 60 // << " to_end=" << std::size_t(to_end) 61 // << std::endl; 62 63 std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports 64 const char* from_next; 65 wchar_t* to_next; 66 67 std::codecvt_base::result res; 68 69 if ((res=cvt.in(state, from, from_end, from_next, 70 to, to_end, to_next)) != std::codecvt_base::ok) 71 { 72 //std::cout << " result is " << static_cast<int>(res) << std::endl; 73 BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), 74 "boost::filesystem::path codecvt to wstring")); 75 } 76 target.append(to, to_next); 77 } 78 79 //--------------------------------------------------------------------------------------// 80 // convert_aux const wchar_t* to string // 81 //--------------------------------------------------------------------------------------// 82 convert_aux(const wchar_t * from,const wchar_t * from_end,char * to,char * to_end,std::string & target,const pt::codecvt_type & cvt)83 void convert_aux( 84 const wchar_t* from, 85 const wchar_t* from_end, 86 char* to, char* to_end, 87 std::string & target, 88 const pt::codecvt_type & cvt) 89 { 90 //std::cout << std::hex 91 // << " from=" << std::size_t(from) 92 // << " from_end=" << std::size_t(from_end) 93 // << " to=" << std::size_t(to) 94 // << " to_end=" << std::size_t(to_end) 95 // << std::endl; 96 97 std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports 98 const wchar_t* from_next; 99 char* to_next; 100 101 std::codecvt_base::result res; 102 103 if ((res=cvt.out(state, from, from_end, from_next, 104 to, to_end, to_next)) != std::codecvt_base::ok) 105 { 106 //std::cout << " result is " << static_cast<int>(res) << std::endl; 107 BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), 108 "boost::filesystem::path codecvt to string")); 109 } 110 target.append(to, to_next); 111 } 112 113 } // unnamed namespace 114 115 //--------------------------------------------------------------------------------------// 116 // path_traits // 117 //--------------------------------------------------------------------------------------// 118 119 namespace boost { namespace filesystem { namespace path_traits { 120 121 //--------------------------------------------------------------------------------------// 122 // convert const char* to wstring // 123 //--------------------------------------------------------------------------------------// 124 125 BOOST_FILESYSTEM_DECL convert(const char * from,const char * from_end,std::wstring & to,const codecvt_type & cvt)126 void convert(const char* from, 127 const char* from_end, // 0 for null terminated MBCS 128 std::wstring & to, 129 const codecvt_type & cvt) 130 { 131 BOOST_ASSERT(from); 132 133 if (!from_end) // null terminated 134 { 135 from_end = from + std::strlen(from); 136 } 137 138 if (from == from_end) return; 139 140 std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK 141 142 // dynamically allocate a buffer only if source is unusually large 143 if (buf_size > default_codecvt_buf_size) 144 { 145 boost::scoped_array< wchar_t > buf(new wchar_t [buf_size]); 146 convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt); 147 } 148 else 149 { 150 wchar_t buf[default_codecvt_buf_size]; 151 convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); 152 } 153 } 154 155 //--------------------------------------------------------------------------------------// 156 // convert const wchar_t* to string // 157 //--------------------------------------------------------------------------------------// 158 159 BOOST_FILESYSTEM_DECL convert(const wchar_t * from,const wchar_t * from_end,std::string & to,const codecvt_type & cvt)160 void convert(const wchar_t* from, 161 const wchar_t* from_end, // 0 for null terminated MBCS 162 std::string & to, 163 const codecvt_type & cvt) 164 { 165 BOOST_ASSERT(from); 166 167 if (!from_end) // null terminated 168 { 169 from_end = from + std::wcslen(from); 170 } 171 172 if (from == from_end) return; 173 174 // The codecvt length functions may not be implemented, and I don't really 175 // understand them either. Thus this code is just a guess; if it turns 176 // out the buffer is too small then an error will be reported and the code 177 // will have to be fixed. 178 std::size_t buf_size = (from_end - from) * 4; // perhaps too large, but that's OK 179 buf_size += 4; // encodings like shift-JIS need some prefix space 180 181 // dynamically allocate a buffer only if source is unusually large 182 if (buf_size > default_codecvt_buf_size) 183 { 184 boost::scoped_array< char > buf(new char [buf_size]); 185 convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt); 186 } 187 else 188 { 189 char buf[default_codecvt_buf_size]; 190 convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); 191 } 192 } 193 }}} // namespace boost::filesystem::path_traits 194