8 #define WIN32_LEAN_AND_MEAN
15 inline std::string
wstr_to_utf8(const WCHAR
*wstr
)
19 int len
= WideCharToMultiByte(CP_UTF8
, 0, wstr
, -1, nullptr, 0, nullptr, nullptr);
23 WideCharToMultiByte(CP_UTF8
, 0, wstr
, -1, &ret
[0], len
, nullptr, nullptr);
30 inline std::wstring
utf8_to_wstr(const char *str
)
34 int len
= MultiByteToWideChar(CP_UTF8
, 0, str
, -1, NULL
, 0);
38 MultiByteToWideChar(CP_UTF8
, 0, str
, -1, &ret
[0], len
);
48 // Windows' std::ifstream fails with non-ANSI paths since the standard only
49 // specifies names using const char* (or std::string). MSVC has a non-standard
50 // extension using const wchar_t* (or std::wstring?) to handle Unicode paths,
51 // but not all Windows compilers support it. So we have to make our own istream
52 // that accepts UTF-8 paths and forwards to Unicode-aware I/O functions.
53 class filebuf final
: public std::streambuf
{
54 std::array
<char_type
,4096> mBuffer
;
55 HANDLE mFile
{INVALID_HANDLE_VALUE
};
57 int_type
underflow() override
59 if(mFile
!= INVALID_HANDLE_VALUE
&& gptr() == egptr())
61 // Read in the next chunk of data, and set the pointers on success
63 if(ReadFile(mFile
, mBuffer
.data(), (DWORD
)mBuffer
.size(), &got
, nullptr))
64 setg(mBuffer
.data(), mBuffer
.data(), mBuffer
.data()+got
);
67 return traits_type::eof();
68 return traits_type::to_int_type(*gptr());
71 pos_type
seekoff(off_type offset
, std::ios_base::seekdir whence
, std::ios_base::openmode mode
) override
73 if(mFile
== INVALID_HANDLE_VALUE
|| (mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
74 return traits_type::eof();
79 case std::ios_base::beg
:
80 fpos
.QuadPart
= offset
;
81 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_BEGIN
))
82 return traits_type::eof();
85 case std::ios_base::cur
:
86 // If the offset remains in the current buffer range, just
87 // update the pointer.
88 if((offset
>= 0 && offset
< off_type(egptr()-gptr())) ||
89 (offset
< 0 && -offset
<= off_type(gptr()-eback())))
91 // Get the current file offset to report the correct read
94 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_CURRENT
))
95 return traits_type::eof();
96 setg(eback(), gptr()+offset
, egptr());
97 return fpos
.QuadPart
- off_type(egptr()-gptr());
99 // Need to offset for the file offset being at egptr() while
100 // the requested offset is relative to gptr().
101 offset
-= off_type(egptr()-gptr());
102 fpos
.QuadPart
= offset
;
103 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_CURRENT
))
104 return traits_type::eof();
107 case std::ios_base::end
:
108 fpos
.QuadPart
= offset
;
109 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_END
))
110 return traits_type::eof();
114 return traits_type::eof();
116 setg(nullptr, nullptr, nullptr);
117 return fpos
.QuadPart
;
120 pos_type
seekpos(pos_type pos
, std::ios_base::openmode mode
) override
122 // Simplified version of seekoff
123 if(mFile
== INVALID_HANDLE_VALUE
|| (mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
124 return traits_type::eof();
128 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_BEGIN
))
129 return traits_type::eof();
131 setg(nullptr, nullptr, nullptr);
132 return fpos
.QuadPart
;
136 bool open(const wchar_t *filename
, std::ios_base::openmode mode
)
138 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
140 HANDLE f
{CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, nullptr,
141 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr)};
142 if(f
== INVALID_HANDLE_VALUE
) return false;
144 if(mFile
!= INVALID_HANDLE_VALUE
)
148 setg(nullptr, nullptr, nullptr);
151 bool open(const char *filename
, std::ios_base::openmode mode
)
153 std::wstring wname
{utf8_to_wstr(filename
)};
154 return open(wname
.c_str(), mode
);
157 bool is_open() const noexcept
{ return mFile
!= INVALID_HANDLE_VALUE
; }
162 if(mFile
!= INVALID_HANDLE_VALUE
)
164 mFile
= INVALID_HANDLE_VALUE
;
168 // Inherit from std::istream to use our custom streambuf
169 class ifstream final
: public std::istream
{
173 ifstream(const std::wstring
&filename
, std::ios_base::openmode mode
= std::ios_base::in
)
174 : ifstream(filename
.c_str(), mode
) { }
175 ifstream(const wchar_t *filename
, std::ios_base::openmode mode
= std::ios_base::in
)
176 : std::istream
{nullptr}
180 // Set the failbit if the file failed to open.
181 if((mode
&std::ios_base::out
) ||
182 !mStreamBuf
.open(filename
, mode
|std::ios_base::in
))
186 ifstream(const std::string
&filename
, std::ios_base::openmode mode
= std::ios_base::in
)
187 : ifstream(filename
.c_str(), mode
) { }
188 ifstream(const char *filename
, std::ios_base::openmode mode
= std::ios_base::in
)
189 : std::istream
{nullptr}
193 // Set the failbit if the file failed to open.
194 if((mode
&std::ios_base::out
) ||
195 !mStreamBuf
.open(filename
, mode
|std::ios_base::in
))
199 bool is_open() const noexcept
{ return mStreamBuf
.is_open(); }
204 #define HAVE_DYNLOAD 1
212 using filebuf
= std::filebuf
;
213 using ifstream
= std::ifstream
;
217 #if defined(HAVE_DLFCN_H)
218 #define HAVE_DYNLOAD 1
225 struct PathNamePair
{ std::string path
, fname
; };
226 PathNamePair
GetProcBinary(void);
229 void *LoadLib(const char *name
);
230 void CloseLib(void *handle
);
231 void *GetSymbol(void *handle
, const char *name
);
234 #endif /* __cplusplus */
236 #endif /* AL_COMPAT_H */