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