1 //  filesystem path_traits.hpp  --------------------------------------------------------//
2 
3 //  Copyright Beman Dawes 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 #ifndef BOOST_FILESYSTEM_PATH_TRAITS_HPP
11 #define BOOST_FILESYSTEM_PATH_TRAITS_HPP
12 
13 #include <boost/config.hpp>
14 
15 # if defined( BOOST_NO_STD_WSTRING )
16 #   error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
17 # endif
18 
19 #include <boost/filesystem/config.hpp>
20 #include <boost/utility/enable_if.hpp>
21 #include <boost/type_traits/is_array.hpp>
22 #include <boost/type_traits/decay.hpp>
23 #include <boost/system/error_code.hpp>
24 #include <cwchar>  // for mbstate_t
25 #include <string>
26 #include <vector>
27 #include <list>
28 #include <iterator>
29 #include <locale>
30 #include <boost/assert.hpp>
31 // #include <iostream>   //**** comment me out ****
32 
33 #include <boost/config/abi_prefix.hpp> // must be the last #include
34 
35 namespace boost { namespace filesystem {
36 
37   BOOST_FILESYSTEM_DECL const system::error_category& codecvt_error_category();
38   //  uses std::codecvt_base::result used for error codes:
39   //
40   //    ok:       Conversion successful.
41   //    partial:  Not all source characters converted; one or more additional source
42   //              characters are needed to produce the final target character, or the
43   //              size of the target intermediate buffer was too small to hold the result.
44   //    error:    A character in the source could not be converted to the target encoding.
45   //    noconv:   The source and target characters have the same type and encoding, so no
46   //              conversion was necessary.
47 
48   class directory_entry;
49 
50 namespace path_traits {
51 
52   typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
53 
54   //  is_pathable type trait; allows disabling over-agressive class path member templates
55 
56   template <class T>
57   struct is_pathable { static const bool value = false; };
58 
59   template<> struct is_pathable<char*>                  { static const bool value = true; };
60   template<> struct is_pathable<const char*>            { static const bool value = true; };
61   template<> struct is_pathable<wchar_t*>               { static const bool value = true; };
62   template<> struct is_pathable<const wchar_t*>         { static const bool value = true; };
63   template<> struct is_pathable<std::string>            { static const bool value = true; };
64   template<> struct is_pathable<std::wstring>           { static const bool value = true; };
65   template<> struct is_pathable<std::vector<char> >     { static const bool value = true; };
66   template<> struct is_pathable<std::vector<wchar_t> >  { static const bool value = true; };
67   template<> struct is_pathable<std::list<char> >       { static const bool value = true; };
68   template<> struct is_pathable<std::list<wchar_t> >    { static const bool value = true; };
69   template<> struct is_pathable<directory_entry>        { static const bool value = true; };
70 
71   //  Pathable empty
72 
73   template <class Container> inline
74     // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for
75     // conforming compilers. Replace by plain "bool" at some future date (2012?)
76     typename boost::disable_if<boost::is_array<Container>, bool>::type
empty(const Container & c)77       empty(const Container & c)
78         { return c.begin() == c.end(); }
79 
80   template <class T> inline
empty(T * const & c_str)81     bool empty(T * const & c_str)
82   {
83     BOOST_ASSERT(c_str);
84     return !*c_str;
85   }
86 
87   template <typename T, size_t N> inline
empty(T (& x)[N])88      bool empty(T (&x)[N])
89        { return !x[0]; }
90 
91   // value types differ  ---------------------------------------------------------------//
92   //
93   //   A from_end argument of 0 is less efficient than a known end, so use only if needed
94 
95   //  with codecvt
96 
97   BOOST_FILESYSTEM_DECL
98     void convert(const char* from,
99     const char* from_end,    // 0 for null terminated MBCS
100     std::wstring & to,
101     const codecvt_type& cvt);
102 
103   BOOST_FILESYSTEM_DECL
104     void convert(const wchar_t* from,
105     const wchar_t* from_end,  // 0 for null terminated MBCS
106     std::string & to,
107     const codecvt_type& cvt);
108 
109   inline
convert(const char * from,std::wstring & to,const codecvt_type & cvt)110     void convert(const char* from,
111     std::wstring & to,
112     const codecvt_type& cvt)
113   {
114     BOOST_ASSERT(from);
115     convert(from, 0, to, cvt);
116   }
117 
118   inline
convert(const wchar_t * from,std::string & to,const codecvt_type & cvt)119     void convert(const wchar_t* from,
120     std::string & to,
121     const codecvt_type& cvt)
122   {
123     BOOST_ASSERT(from);
124     convert(from, 0, to, cvt);
125   }
126 
127   //  without codecvt
128 
129   inline
130     void convert(const char* from,
131     const char* from_end,    // 0 for null terminated MBCS
132     std::wstring & to);
133 
134   inline
135     void convert(const wchar_t* from,
136     const wchar_t* from_end,  // 0 for null terminated MBCS
137     std::string & to);
138 
139   inline
140     void convert(const char* from,
141     std::wstring & to);
142 
143   inline
144     void convert(const wchar_t* from,
145     std::string & to);
146 
147   // value types same  -----------------------------------------------------------------//
148 
149   // char with codecvt
150 
151   inline
convert(const char * from,const char * from_end,std::string & to,const codecvt_type &)152     void convert(const char* from, const char* from_end, std::string & to,
153     const codecvt_type&)
154   {
155     BOOST_ASSERT(from);
156     BOOST_ASSERT(from_end);
157     to.append(from, from_end);
158   }
159 
160   inline
convert(const char * from,std::string & to,const codecvt_type &)161     void convert(const char* from,
162     std::string & to,
163     const codecvt_type&)
164   {
165     BOOST_ASSERT(from);
166     to += from;
167   }
168 
169   // wchar_t with codecvt
170 
171   inline
convert(const wchar_t * from,const wchar_t * from_end,std::wstring & to,const codecvt_type &)172     void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to,
173     const codecvt_type&)
174   {
175     BOOST_ASSERT(from);
176     BOOST_ASSERT(from_end);
177     to.append(from, from_end);
178   }
179 
180   inline
convert(const wchar_t * from,std::wstring & to,const codecvt_type &)181     void convert(const wchar_t* from,
182     std::wstring & to,
183     const codecvt_type&)
184   {
185     BOOST_ASSERT(from);
186     to += from;
187   }
188 
189   // char without codecvt
190 
191   inline
convert(const char * from,const char * from_end,std::string & to)192     void convert(const char* from, const char* from_end, std::string & to)
193   {
194     BOOST_ASSERT(from);
195     BOOST_ASSERT(from_end);
196     to.append(from, from_end);
197   }
198 
199   inline
convert(const char * from,std::string & to)200     void convert(const char* from, std::string & to)
201   {
202     BOOST_ASSERT(from);
203     to += from;
204   }
205 
206   // wchar_t without codecvt
207 
208   inline
convert(const wchar_t * from,const wchar_t * from_end,std::wstring & to)209     void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to)
210   {
211     BOOST_ASSERT(from);
212     BOOST_ASSERT(from_end);
213     to.append(from, from_end);
214   }
215 
216   inline
convert(const wchar_t * from,std::wstring & to)217     void convert(const wchar_t* from, std::wstring & to)
218   {
219     BOOST_ASSERT(from);
220     to += from;
221   }
222 
223   //  Source dispatch  -----------------------------------------------------------------//
224 
225   //  contiguous containers with codecvt
226   template <class U> inline
dispatch(const std::string & c,U & to,const codecvt_type & cvt)227     void dispatch(const std::string& c, U& to, const codecvt_type& cvt)
228   {
229     if (c.size())
230       convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
231   }
232   template <class U> inline
dispatch(const std::wstring & c,U & to,const codecvt_type & cvt)233     void dispatch(const std::wstring& c, U& to, const codecvt_type& cvt)
234   {
235     if (c.size())
236       convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
237   }
238   template <class U> inline
dispatch(const std::vector<char> & c,U & to,const codecvt_type & cvt)239     void dispatch(const std::vector<char>& c, U& to, const codecvt_type& cvt)
240   {
241     if (c.size())
242       convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
243   }
244   template <class U> inline
dispatch(const std::vector<wchar_t> & c,U & to,const codecvt_type & cvt)245     void dispatch(const std::vector<wchar_t>& c, U& to, const codecvt_type& cvt)
246   {
247     if (c.size())
248       convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
249   }
250 
251   //  contiguous containers without codecvt
252   template <class U> inline
dispatch(const std::string & c,U & to)253     void dispatch(const std::string& c, U& to)
254   {
255     if (c.size())
256       convert(&*c.begin(), &*c.begin() + c.size(), to);
257   }
258   template <class U> inline
dispatch(const std::wstring & c,U & to)259     void dispatch(const std::wstring& c, U& to)
260   {
261     if (c.size())
262       convert(&*c.begin(), &*c.begin() + c.size(), to);
263   }
264   template <class U> inline
dispatch(const std::vector<char> & c,U & to)265     void dispatch(const std::vector<char>& c, U& to)
266   {
267     if (c.size())
268       convert(&*c.begin(), &*c.begin() + c.size(), to);
269   }
270   template <class U> inline
dispatch(const std::vector<wchar_t> & c,U & to)271     void dispatch(const std::vector<wchar_t>& c, U& to)
272   {
273     if (c.size())
274       convert(&*c.begin(), &*c.begin() + c.size(), to);
275   }
276 
277   //  non-contiguous containers with codecvt
278   template <class Container, class U> inline
279     // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for
280     // conforming compilers. Replace by plain "void" at some future date (2012?)
281     typename boost::disable_if<boost::is_array<Container>, void>::type
dispatch(const Container & c,U & to,const codecvt_type & cvt)282     dispatch(const Container & c, U& to, const codecvt_type& cvt)
283   {
284     if (c.size())
285     {
286       std::basic_string<typename Container::value_type> s(c.begin(), c.end());
287       convert(s.c_str(), s.c_str()+s.size(), to, cvt);
288     }
289   }
290 
291   //  c_str
292   template <class T, class U> inline
dispatch(T * const & c_str,U & to,const codecvt_type & cvt)293     void dispatch(T * const & c_str, U& to, const codecvt_type& cvt)
294   {
295     //    std::cout << "dispatch() const T *\n";
296     BOOST_ASSERT(c_str);
297     convert(c_str, to, cvt);
298   }
299 
300   //  Note: there is no dispatch on C-style arrays because the array may
301   //  contain a string smaller than the array size.
302 
303   BOOST_FILESYSTEM_DECL
304     void dispatch(const directory_entry & de,
305 #                ifdef BOOST_WINDOWS_API
306     std::wstring & to,
307 #                else
308     std::string & to,
309 #                endif
310     const codecvt_type&);
311 
312   //  non-contiguous containers without codecvt
313   template <class Container, class U> inline
314     // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for
315     // conforming compilers. Replace by plain "void" at some future date (2012?)
316     typename boost::disable_if<boost::is_array<Container>, void>::type
dispatch(const Container & c,U & to)317     dispatch(const Container & c, U& to)
318   {
319     if (c.size())
320     {
321       std::basic_string<typename Container::value_type> seq(c.begin(), c.end());
322       convert(seq.c_str(), seq.c_str()+seq.size(), to);
323     }
324   }
325 
326   //  c_str
327   template <class T, class U> inline
dispatch(T * const & c_str,U & to)328     void dispatch(T * const & c_str, U& to)
329   {
330     //    std::cout << "dispatch() const T *\n";
331     BOOST_ASSERT(c_str);
332     convert(c_str, to);
333   }
334 
335   //  Note: there is no dispatch on C-style arrays because the array may
336   //  contain a string smaller than the array size.
337 
338   BOOST_FILESYSTEM_DECL
339     void dispatch(const directory_entry & de,
340 #                ifdef BOOST_WINDOWS_API
341     std::wstring & to
342 #                else
343     std::string & to
344 #                endif
345     );
346 
347 
348 }}} // namespace boost::filesystem::path_traits
349 
350 #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
351 
352 #endif  // BOOST_FILESYSTEM_PATH_TRAITS_HPP
353