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
27namespace pt = boost::filesystem::detail::path_traits;
28namespace fs = boost::filesystem;
29namespace 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
39namespace {
40
41BOOST_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
54void 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
81void 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
110namespace boost {
111namespace filesystem {
112namespace detail {
113namespace path_traits {
114
115//--------------------------------------------------------------------------------------//
116// convert const char* to wstring //
117//--------------------------------------------------------------------------------------//
118
119BOOST_FILESYSTEM_DECL
120void 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
150BOOST_FILESYSTEM_DECL
151void 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

source code of boost/libs/filesystem/src/path_traits.cpp