8a4c862d3eb7a9d846af590322fffed6d73b1ccb
[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         unsigned buf_size;
17         char *buffer;
18         unsigned buf_avail;
19         char *buf_next;
20         bool pending;
21 };
22
23
24 EventReader::EventReader(Handle &h, unsigned size):
25         handle(h),
26         priv(new Private)
27 {
28         memset(&priv->overlapped, 0, sizeof(OVERLAPPED));
29         *priv->event = CreateEvent(0, true, false, 0);
30         priv->overlapped.hEvent = *priv->event;
31         priv->buf_size = size;
32         priv->buffer = new char[priv->buf_size];
33         priv->buf_avail = 0;
34         priv->buf_next = priv->buffer;
35         priv->pending = false;
36 }
37
38 EventReader::~EventReader()
39 {
40         CloseHandle(*priv->event);
41         delete[] priv->buffer;
42         delete priv;
43 }
44
45 const Handle &EventReader::get_event()
46 {
47         start();
48         return priv->event;
49 }
50
51 void EventReader::start()
52 {
53         if(priv->buf_avail || priv->pending)
54                 return;
55
56         DWORD ret;
57         priv->buf_next = priv->buffer;
58         if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, &priv->overlapped))
59         {
60                 unsigned err = GetLastError();
61                 if(err==ERROR_IO_PENDING)
62                         priv->pending = true;
63                 else
64                         throw system_error("ReadFile");
65         }
66         else
67         {
68                 priv->buf_avail = ret;
69                 SetEvent(*priv->event);
70         }
71 }
72
73 void EventReader::wait()
74 {
75         if(!priv->pending)
76                 return;
77
78         DWORD ret;
79         if(!GetOverlappedResult(*handle, &priv->overlapped, &ret, true))
80                 throw system_error("GetOverlappedResult");
81         else
82         {
83                 priv->buf_avail = ret;
84                 priv->pending = false;
85         }
86 }
87
88 unsigned EventReader::read(char *buf, unsigned len)
89 {
90         if(!priv->buf_avail)
91         {
92                 // No data in buffer, try to get some
93                 start();
94                 wait();
95         }
96
97         len = min(len, priv->buf_avail);
98         memcpy(buf, priv->buf_next, len);
99         priv->buf_next += len;
100         priv->buf_avail -= len;
101
102         if(!priv->buf_avail)
103         {
104                 ResetEvent(*priv->event);
105                 start();
106         }
107
108         return len;
109 }
110
111 } // namespace IO
112 } // namespace Msp