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
28namespace pt = boost::filesystem::path_traits;
29namespace fs = boost::filesystem;
30namespace 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
40namespace {
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
126namespace 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