forked from CobaltFusion/DebugViewPP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhstream.h
106 lines (85 loc) · 3.19 KB
/
hstream.h
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
// (C) Copyright Gert-Jan de Vos and Jan Wilmans 2013.
// 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)
// Repository at: https://github.com/djeedjay/DebugViewPP/
#pragma once
#include <streambuf>
#include <vector>
namespace fusion {
template <class Elem, class Tr = std::char_traits<Elem>, class Alloc = std::allocator<Elem>>
class basic_handlebuf : public std::basic_streambuf<Elem, Tr>
{
public:
using _int_type = typename std::basic_streambuf<Elem, Tr>::int_type;
explicit basic_handlebuf(HANDLE handle, std::size_t buff_sz = 256, std::size_t put_back = 8) :
m_handle(handle),
m_put_back(std::max<std::size_t>(put_back, 1)),
m_readBuffer(std::max(buff_sz, m_put_back) + m_put_back)
{
Elem* end = &m_readBuffer.front() + m_readBuffer.size();
this->setg(end, end, end);
}
protected:
int sync() override
{
if (!m_writeBuffer.empty())
{
DWORD written;
if (!WriteFile(m_handle, m_writeBuffer.data(), static_cast<DWORD>(m_writeBuffer.size()), &written, nullptr))
return std::basic_streambuf<Elem, Tr>::traits_type::eof();
m_writeBuffer.clear();
}
return 0;
}
_int_type overflow(_int_type c) override
{
if (c == std::basic_streambuf<Elem, Tr>::traits_type::eof())
return c;
m_writeBuffer.push_back(std::basic_streambuf<Elem, Tr>::traits_type::to_char_type(c));
if (c == '\n')
sync();
return c;
}
_int_type underflow() override
{
if (this->gptr() < this->egptr()) // buffer not exhausted
return std::basic_streambuf<Elem, Tr>::traits_type::to_int_type(*this->gptr());
Elem* base = &m_readBuffer.front();
Elem* start = base;
if (this->eback() == base) // true when this isn't the first fill
{
// Make arrangements for putback characters
std::memmove(base, this->egptr() - m_put_back, m_put_back);
start += m_put_back;
}
// start is now the start of the buffer, proper.
// Read from m_handle in to the provided buffer
DWORD read;
if (!ReadFile(m_handle, start, static_cast<DWORD>((m_readBuffer.size() - (start - base)) * sizeof(Elem)), &read, nullptr) || read == 0)
return std::basic_streambuf<Elem, Tr>::traits_type::eof();
// Set buffer pointers
this->setg(base, start, start + read / sizeof(Elem));
return std::basic_streambuf<Elem, Tr>::traits_type::to_int_type(*this->gptr());
}
private:
HANDLE m_handle;
const std::size_t m_put_back;
std::vector<Elem> m_readBuffer;
std::vector<Elem> m_writeBuffer;
};
template <class Elem, class Tr = std::char_traits<Elem>>
class basic_handlestream : public std::basic_iostream<Elem, Tr>
{
public:
explicit basic_handlestream(HANDLE handle) :
std::basic_iostream<Elem, Tr>(&m_buf),
m_buf(handle)
{
}
private:
basic_handlebuf<Elem, Tr> m_buf;
};
typedef basic_handlestream<char> hstream;
typedef basic_handlestream<wchar_t> whstream;
} // namespace fusion