1 /*
2  * Distributed under the Boost Software License, Version 1.0.(See accompanying
3  * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4  *
5  * See http://www.boost.org/libs/iostreams for documentation.
6  *
7  * File:        boost/iostreams/detail/path.hpp
8  * Date:        Sat Jun 21 21:24:05 MDT 2008
9  * Copyright:   2008 CodeRage, LLC
10  * Author:      Jonathan Turkanis
11  * Contact:     turkanis at coderage dot com
12  *
13  * Defines the class boost::iostreams::detail::path, for storing a
14  * a std::string or std::wstring.
15  *
16  * This class allows interoperability with Boost.Filesystem without
17  * creating a dependence on Boost.Filesystem headers or implementation.
18  */
19 
20 #ifndef BOOST_IOSTREAMS_DETAIL_PATH_HPP_INCLUDED
21 #define BOOST_IOSTREAMS_DETAIL_PATH_HPP_INCLUDED
22 
23 #include <cstring>
24 #include <string>
25 #include <boost/iostreams/detail/config/wide_streams.hpp>
26 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS
27 # include <cwchar>
28 #endif
29 #include <boost/static_assert.hpp>
30 #include <boost/type.hpp>
31 #include <boost/type_traits/is_same.hpp>
32 
33 namespace boost { namespace iostreams { namespace detail {
34 
35 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS //------------------------------------//
36 
37 class path {
38     template<typename T, typename V>
39     struct sfinae
40     {
41         typedef V type;
42     };
43 public:
44 
45     // Default constructor
path()46     path() : narrow_(), wide_(), is_wide_(false) { }
47 
48     // Constructor taking a std::string
path(const std::string & p)49     path(const std::string& p) : narrow_(p), wide_(), is_wide_(false) { }
50 
51     // Constructor taking a C-style string
path(const char * p)52     path(const char* p) : narrow_(p), wide_(), is_wide_(false) { }
53 
54     // Constructor taking a boost::filesystem2::path or
55     // boost::filesystem2::wpath
56     template<typename Path>
path(const Path & p,typename Path::external_string_type * =0)57     explicit path(const Path& p, typename Path::external_string_type* = 0)
58     {
59         init(p.external_file_string());
60     }
61 
62     // Constructor taking a boost::filesystem3::path (boost filesystem v3)
63     template<typename Path>
path(const Path & p,typename Path::codecvt_type * =0)64     explicit path(const Path& p, typename Path::codecvt_type* = 0)
65     {
66         init(p.native());
67     }
68 
69     // Copy constructor
path(const path & p)70     path(const path& p)
71         : narrow_(p.narrow_), wide_(p.wide_), is_wide_(p.is_wide_)
72         { }
73 
74     // Assignment operator taking another path
operator =(const path & p)75     path& operator=(const path& p)
76     {
77         narrow_ = p.narrow_;
78         wide_ = p.wide_;
79         is_wide_ = p.is_wide_;
80         return *this;
81     }
82 
83     // Assignment operator taking a std::string
operator =(const std::string & p)84     path& operator=(const std::string& p)
85     {
86         narrow_ = p;
87         wide_.clear();
88         is_wide_ = false;
89         return *this;
90     }
91 
92     // Assignment operator taking a C-style string
operator =(const char * p)93     path& operator=(const char* p)
94     {
95         narrow_.assign(p);
96         wide_.clear();
97         is_wide_ = false;
98         return *this;
99     }
100 
101 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
102     // Assignment operator taking a boost::filesystem2::path or
103     // boost::filesystem2::wpath
104     // (not on Visual C++ 7.1/8.0, as it seems to have problems with
105     // SFINAE functions with the same parameters, doesn't seem
106     // worth working around).
107     template<typename Path>
108     typename sfinae<typename Path::external_string_type, path&>::type
operator =(const Path & p)109         operator=(const Path& p)
110     {
111         init(p.external_file_string());
112         return *this;
113     }
114 #endif
115 
116     // Assignment operator taking a boost::filesystem3::path
117     template<typename Path>
118     typename sfinae<typename Path::codecvt_type, path&>::type
operator =(const Path & p)119         operator=(const Path& p)
120     {
121         init(p.native());
122         return *this;
123     }
124 
is_wide() const125     bool is_wide() const { return is_wide_; }
126 
127     // Returns a representation of the underlying path as a std::string
128     // Requires: is_wide() returns false
c_str() const129     const char* c_str() const { return narrow_.c_str(); }
130 
131     // Returns a representation of the underlying path as a std::wstring
132     // Requires: is_wide() returns true
c_wstr() const133     const wchar_t* c_wstr() const { return wide_.c_str(); }
134 private:
135 
136     // For wide-character paths, use a boost::filesystem::wpath instead of a
137     // std::wstring
138     path(const std::wstring&);
139     path& operator=(const std::wstring&);
140 
init(std::string const & file_path)141     void init(std::string const& file_path)
142     {
143         narrow_ = file_path;
144         wide_.clear();
145         is_wide_ = false;
146     }
147 
init(std::wstring const & file_path)148     void init(std::wstring const& file_path)
149     {
150         narrow_.clear();
151         wide_ = file_path;
152         is_wide_ = true;
153     }
154 
155     std::string   narrow_;
156     std::wstring  wide_;
157     bool          is_wide_;
158 };
159 
operator ==(const path & lhs,const path & rhs)160 inline bool operator==(const path& lhs, const path& rhs)
161 {
162     return lhs.is_wide() ?
163         rhs.is_wide() && std::wcscmp(lhs.c_wstr(), rhs.c_wstr()) == 0 :
164         !rhs.is_wide() && std::strcmp(lhs.c_str(), rhs.c_str()) == 0;
165 }
166 
167 #else // #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS //---------------------------//
168 
169 class path {
170 public:
171     path() { }
172     path(const std::string& p) : path_(p) { }
173     path(const char* p) : path_(p) { }
174     template<typename Path>
175         path(const Path& p) : path_(p.external_file_string()) { }
176     path(const path& p) : path_(p.path_) { }
177     path& operator=(const path& other)
178     {
179         path_ = other.path_;
180         return *this;
181     }
182     path& operator=(const std::string& p)
183     {
184         path_ = p;
185         return *this;
186     }
187     path& operator=(const char* p)
188     {
189         path_ = p;
190         return *this;
191     }
192     template<typename Path>
193         path& operator=(const Path& p)
194         {
195             path_ = p.external_file_string();
196             return *this;
197         }
198     bool is_wide() const { return false; }
199     const char* c_str() const { return path_.c_str(); }
200     const wchar_t* c_wstr() const { return 0; }
201 private:
202     std::string path_;
203 };
204 
205 inline bool operator==(const path& lhs, const path& rhs)
206 {
207     return std::strcmp(lhs.c_str(), rhs.c_str()) == 0 ;
208 }
209 
210 #endif // #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS //--------------------------//
211 
212 } } } // End namespaces detail, iostreams, boost.
213 
214 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_PATH_HPP_INCLUDED
215