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