• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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