+#ifdef WIN32
+#include <windows.h>
+#endif
+#include <algorithm>
+#include <msp/core/systemerror.h>
+#include "eventreader.h"
+#include "handle_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+struct EventReader::Private
+{
+#ifdef WIN32
+ OVERLAPPED *overlapped;
+ Handle event;
+ unsigned buf_size;
+ char *buffer;
+ unsigned buf_avail;
+ char *buf_next;
+#endif
+};
+
+
+EventReader::EventReader(Handle &h, unsigned size):
+ handle(h),
+ priv(0)
+{
+#ifdef WIN32
+ priv = new Private;
+
+ priv->overlapped = 0;
+ *priv->event = CreateEvent(0, true, false, 0);
+ priv->buf_size = size;
+ priv->buffer = new char[priv->buf_size];
+ priv->buf_avail = 0;
+ priv->buf_next = priv->buffer;
+
+ start();
+#else
+ (void)size;
+#endif
+}
+
+EventReader::~EventReader()
+{
+#ifdef WIN32
+ CloseHandle(*priv->event);
+ delete priv->overlapped;
+ delete[] priv->buffer;
+#endif
+ delete priv;
+}
+
+const Handle &EventReader::get_event() const
+{
+#ifdef WIN32
+ return priv->event;
+#else
+ return handle;
+#endif
+}
+
+void EventReader::start()
+{
+#ifdef WIN32
+ if(priv->buf_avail || priv->overlapped)
+ return;
+
+ priv->overlapped = new OVERLAPPED;
+ memset(priv->overlapped, 0, sizeof(OVERLAPPED));
+ priv->overlapped->hEvent = *priv->event;
+
+ DWORD ret;
+ priv->buf_next = priv->buffer;
+ if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, priv->overlapped))
+ {
+ unsigned err = GetLastError();
+ if(err!=ERROR_IO_PENDING)
+ throw system_error("ReadFile");
+ }
+ else
+ {
+ priv->buf_avail = ret;
+ delete priv->overlapped;
+ priv->overlapped = 0;
+ SetEvent(*priv->event);
+ }
+#endif
+}
+
+void EventReader::wait()
+{
+#ifdef WIN32
+ if(!priv->overlapped)
+ return;
+
+ DWORD ret;
+ if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true))
+ throw system_error("GetOverlappedResult");
+ else
+ {
+ priv->buf_avail = ret;
+ delete priv->overlapped;
+ priv->overlapped = 0;
+ }
+#endif
+}
+
+unsigned EventReader::read(char *buf, unsigned len)
+{
+#ifdef WIN32
+ if(!priv->buf_avail)
+ {
+ // No data in buffer, try to get some
+ start();
+ wait();
+ }
+
+ len = min(len, priv->buf_avail);
+ memcpy(buf, priv->buf_next, len);
+ priv->buf_next += len;
+ priv->buf_avail -= len;
+
+ if(!priv->buf_avail)
+ {
+ ResetEvent(*priv->event);
+ start();
+ }
+
+ return len;
+#else
+ return sys_read(handle, buf, len);
+#endif
+}
+
+} // namespace IO
+} // namespace Msp