aboutsummaryrefslogtreecommitdiffstats
path: root/common/alfstream.cpp
blob: 7378c678e818ea3f2736783812d03fc7eb7910c1 (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

#include "config.h"

#include "alfstream.h"

#include "strutils.h"

#ifdef _WIN32

namespace al {

auto filebuf::underflow() -> int_type
{
    if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr())
    {
        // Read in the next chunk of data, and set the pointers on success
        DWORD got{};
        if(ReadFile(mFile, mBuffer.data(), static_cast<DWORD>(mBuffer.size()), &got, nullptr))
            setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got);
    }
    if(gptr() == egptr())
        return traits_type::eof();
    return traits_type::to_int_type(*gptr());
}

auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type
{
    if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in))
        return traits_type::eof();

    LARGE_INTEGER fpos{};
    switch(whence)
    {
        case std::ios_base::beg:
            fpos.QuadPart = offset;
            if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN))
                return traits_type::eof();
            break;

        case std::ios_base::cur:
            // If the offset remains in the current buffer range, just
            // update the pointer.
            if((offset >= 0 && offset < off_type(egptr()-gptr())) ||
                (offset < 0 && -offset <= off_type(gptr()-eback())))
            {
                // Get the current file offset to report the correct read
                // offset.
                fpos.QuadPart = 0;
                if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT))
                    return traits_type::eof();
                setg(eback(), gptr()+offset, egptr());
                return fpos.QuadPart - off_type(egptr()-gptr());
            }
            // Need to offset for the file offset being at egptr() while
            // the requested offset is relative to gptr().
            offset -= off_type(egptr()-gptr());
            fpos.QuadPart = offset;
            if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT))
                return traits_type::eof();
            break;

        case std::ios_base::end:
            fpos.QuadPart = offset;
            if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END))
                return traits_type::eof();
            break;

        default:
            return traits_type::eof();
    }
    setg(nullptr, nullptr, nullptr);
    return fpos.QuadPart;
}

auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type
{
    // Simplified version of seekoff
    if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in))
        return traits_type::eof();

    LARGE_INTEGER fpos{};
    fpos.QuadPart = pos;
    if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN))
        return traits_type::eof();

    setg(nullptr, nullptr, nullptr);
    return fpos.QuadPart;
}

filebuf::~filebuf()
{
    if(mFile != INVALID_HANDLE_VALUE)
        CloseHandle(mFile);
    mFile = INVALID_HANDLE_VALUE;
}

bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode)
{
    if((mode&std::ios_base::out) || !(mode&std::ios_base::in))
        return false;
    HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, nullptr)};
    if(f == INVALID_HANDLE_VALUE) return false;

    if(mFile != INVALID_HANDLE_VALUE)
        CloseHandle(mFile);
    mFile = f;

    setg(nullptr, nullptr, nullptr);
    return true;
}
bool filebuf::open(const char *filename, std::ios_base::openmode mode)
{
    std::wstring wname{utf8_to_wstr(filename)};
    return open(wname.c_str(), mode);
}


ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode)
  : std::istream{nullptr}
{
    init(&mStreamBuf);

    // Set the failbit if the file failed to open.
    if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in))
        clear(failbit);
}

ifstream::ifstream(const char *filename, std::ios_base::openmode mode)
  : std::istream{nullptr}
{
    init(&mStreamBuf);

    // Set the failbit if the file failed to open.
    if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in))
        clear(failbit);
}

/* This is only here to ensure the compiler doesn't define an implicit
 * destructor, which it tries to automatically inline and subsequently complain
 * it can't inline without excessive code growth.
 */
ifstream::~ifstream() { }

} // namespace al

#endif