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
|
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenEXR Project.
#pragma once
#ifndef INCLUDE_TestUtilFStream_h_
#define INCLUDE_TestUtilFStream_h_ 1
#include <fstream>
#include <string>
#ifdef _WIN32
# define VC_EXTRALEAN
# include <string.h>
# include <windows.h>
# include <io.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <share.h>
#endif
namespace testutil
{
#ifdef _WIN32
inline std::wstring
WidenFilename (const char* filename)
{
std::wstring ret;
int fnlen = static_cast<int> (strlen (filename));
int len = MultiByteToWideChar (CP_UTF8, 0, filename, fnlen, NULL, 0);
if (len > 0)
{
ret.resize (len);
MultiByteToWideChar (CP_UTF8, 0, filename, fnlen, &ret[0], len);
}
return ret;
}
// This is a big work around mechanism for compiling using mingw / gcc under windows
// until mingw 9 where they add the wide filename version of open
# if (defined(__GLIBCXX__) && !(defined(_GLIBCXX_HAVE_WFOPEN) && defined(_GLIBCXX_USE_WCHAR_T)))
# define USE_WIDEN_FILEBUF 1
template <typename CharT, typename TraitsT>
class WidenFilebuf : public std::basic_filebuf<CharT, TraitsT>
{
inline int mode_to_flags (std::ios_base::openmode mode)
{
int flags = 0;
if (mode & std::ios_base::in) flags |= _O_RDONLY;
if (mode & std::ios_base::out)
{
flags |= _O_WRONLY;
flags |= _O_CREAT;
if (mode & std::ios_base::app) flags |= _O_APPEND;
if (mode & std::ios_base::trunc) flags |= _O_TRUNC;
}
if (mode & std::ios_base::binary)
flags |= _O_BINARY;
else
flags |= _O_TEXT;
return flags;
}
public:
using base_filebuf = std::basic_filebuf<CharT, TraitsT>;
inline base_filebuf* wide_open (std::wstring& fn, std::ios_base::openmode m)
{
if (this->is_open () || fn.empty ())
return nullptr;
int fd;
errno_t e = _wsopen_s (
&fd,
fn.c_str (),
mode_to_flags (m),
_SH_DENYNO,
_S_IREAD | _S_IWRITE);
if (e != 0)
return nullptr;
// sys_open will do an fdopen internally which will then clean up the fd upon close
this->_M_file.sys_open (fd, m);
if (this->is_open ())
{
// reset the internal state, these members are consistent between gcc versions 4.3 - 9
// but at 9, the wfopen stuff should become available, such that this will no longer be
// active
this->_M_allocate_internal_buffer ();
this->_M_mode = m;
this->_M_reading = false;
this->_M_writing = false;
this->_M_set_buffer (-1);
this->_M_state_last = this->_M_state_cur = this->_M_state_beg;
if ((m & std::ios_base::ate) &&
this->seekoff (0, std::ios_base::end, m) ==
static_cast<typename base_filebuf::pos_type> (-1))
{
this->close ();
return nullptr;
}
}
return this;
}
};
# endif // __GLIBCXX__
#endif // _WIN32
template <typename StreamType>
inline void
OpenStreamWithUTF8Name (
StreamType& is, const char* filename, std::ios_base::openmode mode)
{
#ifdef _WIN32
std::wstring wfn = WidenFilename (filename);
# ifdef USE_WIDEN_FILEBUF
using CharT = typename StreamType::char_type;
using TraitsT = typename StreamType::traits_type;
using wbuf = WidenFilebuf<CharT, TraitsT>;
if (!static_cast<wbuf*> (is.rdbuf ())->wide_open (wfn, mode))
is.setstate (std::ios_base::failbit);
else
is.clear ();
# else
is.rdbuf ()->open (wfn.c_str (), mode);
# endif
#else
is.rdbuf ()->open (filename, mode);
#endif
}
} // namespace testutil
#endif // INCLUDE_TestUtilFStream_h_
|