]> git.tdb.fi Git - libs/core.git/blob - source/io/windows/eventreader.cpp
8c4102067854eb0c9096ff92ab4277c1e3cf6441
[libs/core.git] / source / io / windows / eventreader.cpp
1 #include <windows.h>
2 #include <algorithm>
3 #include <msp/core/systemerror.h>
4 #include "eventreader.h"
5 #include "handle_private.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace IO {
11
12 struct EventReader::Private
13 {
14         OVERLAPPED overlapped;
15         Handle event;
16         size_t buf_size = 0;
17         char *buffer = 0;
18         size_t buf_avail = 0;
19         char *buf_next = 0;
20         bool pending = false;
21         bool eof = false;
22 };
23
24
25 EventReader::EventReader(Handle &h, unsigned size):
26         handle(h),
27         priv(new Private)
28 {
29         memset(&priv->overlapped, 0, sizeof(OVERLAPPED));
30         *priv->event = CreateEvent(0, true, false, 0);
31         priv->overlapped.hEvent = *priv->event;
32         priv->buf_size = size;
33         priv->buffer = new char[priv->buf_size];
34         priv->buf_next = priv->buffer;
35 }
36
37 EventReader::~EventReader()
38 {
39         CloseHandle(*priv->event);
40         delete[] priv->buffer;
41         delete priv;
42 }
43
44 const Handle &EventReader::get_event()
45 {
46         start();
47         return priv->event;
48 }
49
50 void EventReader::start()
51 {
52         if(priv->buf_avail || priv->pending)
53                 return;
54
55         DWORD ret;
56         priv->buf_next = priv->buffer;
57         if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, &priv->overlapped))
58         {
59                 unsigned err = GetLastError();
60                 if(err==ERROR_BROKEN_PIPE)
61                         priv->eof = true;
62                 else if(err==ERROR_IO_PENDING)
63                         priv->pending = true;
64                 else
65                         throw system_error("ReadFile");
66         }
67         else
68         {
69                 priv->buf_avail = ret;
70                 SetEvent(*priv->event);
71         }
72 }
73
74 void EventReader::wait()
75 {
76         if(!priv->pending)
77                 return;
78
79         DWORD ret;
80         if(!GetOverlappedResult(*handle, &priv->overlapped, &ret, true))
81         {
82                 DWORD err = GetLastError();
83                 if(err==ERROR_BROKEN_PIPE)
84                         priv->eof = true;
85                 else
86                         throw system_error("GetOverlappedResult");
87         }
88         else
89         {
90                 priv->buf_avail = ret;
91                 priv->pending = false;
92         }
93 }
94
95 unsigned EventReader::read(char *buf, unsigned len)
96 {
97         if(!priv->buf_avail)
98         {
99                 if(priv->eof)
100                         return 0;
101
102                 // No data in buffer, try to get some
103                 start();
104                 wait();
105         }
106
107         len = min(len, priv->buf_avail);
108         memcpy(buf, priv->buf_next, len);
109         priv->buf_next += len;
110         priv->buf_avail -= len;
111
112         if(!priv->buf_avail)
113         {
114                 ResetEvent(*priv->event);
115                 start();
116         }
117
118         return len;
119 }
120
121 } // namespace IO
122 } // namespace Msp