File: TestUtilFStream.h

package info (click to toggle)
openexr 2.5.4-2%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 46,108 kB
  • sloc: cpp: 216,939; makefile: 937; sh: 380
file content (135 lines) | stat: -rw-r--r-- 3,925 bytes parent folder | download | duplicates (2)
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_