summaryrefslogtreecommitdiffstats
blob: 16f65833b03907bb5f6a2f54f85259eeeaba3237 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//  path.cpp  ----------------------------------------------------------------//

//  Copyright 2005 Beman Dawes

//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//  See library home page at http://www.boost.org/libs/filesystem

//----------------------------------------------------------------------------// 

// define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_FILESYSTEM_SOURCE 

#ifndef BOOST_SYSTEM_NO_DEPRECATED 
# define BOOST_SYSTEM_NO_DEPRECATED
#endif

#include <boost/filesystem/v2/config.hpp>

#ifndef BOOST_FILESYSTEM2_NARROW_ONLY

#include <boost/filesystem/v2/path.hpp>
#include <boost/scoped_array.hpp>

#include <locale>
#include <boost/cerrno.hpp>
#include <boost/system/error_code.hpp>

#include <cwchar>     // for std::mbstate_t

#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) 
# include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
#endif


namespace
{
  // std::locale construction can throw (if LC_MESSAGES is wrong, for example),
  // so a static at function scope is used to ensure that exceptions can be
  // caught. (A previous version was at namespace scope, so initialization
  // occurred before main(), preventing exceptions from being caught.)
  std::locale & loc()
  {
#if !defined(macintosh) && !defined(__APPLE__) && !defined(__APPLE_CC__) 
    // ISO C calls this "the locale-specific native environment":
    static std::locale lc("");
#else  // Mac OS
    // "All BSD system functions expect their string parameters to be in UTF-8 encoding
    // and nothing else."
    // See http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
    std::locale global_loc = std::locale();  // Mac OS doesn't support locale("")
    static std::locale lc(global_loc,
        new boost::filesystem::detail::utf8_codecvt_facet);  
#endif
    return lc;
  }

  const std::codecvt<wchar_t, char, std::mbstate_t> *&
  converter()
  {
   static const std::codecvt<wchar_t, char, std::mbstate_t> *
     cvtr(
       &std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >
        ( loc() ) );
   return cvtr;
  }

  bool locked(false);
} // unnamed namespace

namespace boost
{
  namespace filesystem2
  {
    bool wpath_traits::imbue( const std::locale & new_loc, const std::nothrow_t & )
    {
      if ( locked ) return false;
      locked = true;
      loc() = new_loc;
      converter() = &std::use_facet
        <std::codecvt<wchar_t, char, std::mbstate_t> >( loc() );
      return true;
    }

    void wpath_traits::imbue( const std::locale & new_loc )
    {
      if ( locked ) BOOST_FILESYSTEM_THROW(
        wfilesystem_error(
          "boost::filesystem::wpath_traits::imbue() after lockdown",
          make_error_code( system::errc::not_supported ) ) );
      imbue( new_loc, std::nothrow );
    }

    //namespace detail
    //{
    //  BOOST_FILESYSTEM_DECL
    //  const char * what( const char * sys_err_what,
    //    const path & path1, const path & path2, std::string & target)
    //  {
    //    try
    //    {
    //      if ( target.empty() )
    //      {
    //        target = sys_err_what;
    //        if ( !path1.empty() )
    //        {
    //          target += ": \"";
    //          target += path1.file_string();
    //          target += "\"";
    //        }
    //        if ( !path2.empty() )
    //        {
    //          target += ", \"";
    //          target += path2.file_string();
    //          target += "\"";
    //        }
    //      }
    //      return target.c_str();
    //    }
    //    catch (...)
    //    {
    //      return sys_err_what;
    //    }
    //  }
    //}
    
# ifdef BOOST_POSIX_API

//  Because this is POSIX only code, we don't have to worry about ABI issues
//  described in http://www.boost.org/more/separate_compilation.html

    wpath_traits::external_string_type
    wpath_traits::to_external( const wpath & ph, 
      const internal_string_type & src )
    {
      locked = true;
      std::size_t work_size( converter()->max_length() * (src.size()+1) );
      boost::scoped_array<char> work( new char[ work_size ] );
      std::mbstate_t state = std::mbstate_t();  // perhaps unneeded, but cuts bug reports
      const internal_string_type::value_type * from_next;
      external_string_type::value_type * to_next;
      if ( converter()->out( 
        state, src.c_str(), src.c_str()+src.size(), from_next, work.get(),
        work.get()+work_size, to_next ) != std::codecvt_base::ok )
        BOOST_FILESYSTEM_THROW( boost::filesystem::wfilesystem_error(
          "boost::filesystem::wpath::to_external conversion error",
          ph, system::error_code( system::errc::invalid_argument, system::system_category() ) ) );
      *to_next = '\0';
      return external_string_type( work.get() );
    }

    wpath_traits::internal_string_type
    wpath_traits::to_internal( const external_string_type & src )
    {
      locked = true;
      std::size_t work_size( src.size()+1 );
      boost::scoped_array<wchar_t> work( new wchar_t[ work_size ] );
      std::mbstate_t state  = std::mbstate_t();  // perhaps unneeded, but cuts bug reports
      const external_string_type::value_type * from_next;
      internal_string_type::value_type * to_next;
      if ( converter()->in( 
        state, src.c_str(), src.c_str()+src.size(), from_next, work.get(),
        work.get()+work_size, to_next ) != std::codecvt_base::ok )
        BOOST_FILESYSTEM_THROW( boost::filesystem::wfilesystem_error(
          "boost::filesystem::wpath::to_internal conversion error",
          system::error_code( system::errc::invalid_argument, system::system_category() ) ) );
      *to_next = L'\0';
      return internal_string_type( work.get() );
    }
# endif // BOOST_POSIX_API

  } // namespace filesystem2
} // namespace boost

#endif // ifndef BOOST_FILESYSTEM2_NARROW_ONLY