aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/io')
-rw-r--r--src/lib/io/CMakeLists.txt24
-rw-r--r--src/lib/io/IStream.h120
-rw-r--r--src/lib/io/StreamBuffer.cpp146
-rw-r--r--src/lib/io/StreamBuffer.h79
-rw-r--r--src/lib/io/StreamFilter.cpp118
-rw-r--r--src/lib/io/StreamFilter.h73
-rw-r--r--src/lib/io/XIO.cpp51
-rw-r--r--src/lib/io/XIO.h49
8 files changed, 660 insertions, 0 deletions
diff --git a/src/lib/io/CMakeLists.txt b/src/lib/io/CMakeLists.txt
new file mode 100644
index 0000000..32ae7ec
--- /dev/null
+++ b/src/lib/io/CMakeLists.txt
@@ -0,0 +1,24 @@
+# barrier -- mouse and keyboard sharing utility
+# Copyright (C) 2012-2016 Symless Ltd.
+# Copyright (C) 2009 Nick Bolton
+#
+# This package is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# found in the file LICENSE that should have accompanied this file.
+#
+# This package is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+file(GLOB headers "*.h")
+file(GLOB sources "*.cpp")
+
+if (BARRIER_ADD_HEADERS)
+ list(APPEND sources ${headers})
+endif()
+
+add_library(io STATIC ${sources})
diff --git a/src/lib/io/IStream.h b/src/lib/io/IStream.h
new file mode 100644
index 0000000..cf93ac4
--- /dev/null
+++ b/src/lib/io/IStream.h
@@ -0,0 +1,120 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/IInterface.h"
+#include "base/Event.h"
+#include "base/IEventQueue.h"
+#include "base/EventTypes.h"
+
+class IEventQueue;
+
+namespace barrier {
+
+//! Bidirectional stream interface
+/*!
+Defines the interface for all streams.
+*/
+class IStream : public IInterface {
+public:
+ IStream() { }
+
+ //! @name manipulators
+ //@{
+
+ //! Close the stream
+ /*!
+ Closes the stream. Pending input data and buffered output data
+ are discarded. Use \c flush() before \c close() to send buffered
+ output data. Attempts to \c read() after a close return 0,
+ attempts to \c write() generate output error events, and attempts
+ to \c flush() return immediately.
+ */
+ virtual void close() = 0;
+
+ //! Read from stream
+ /*!
+ Read up to \p n bytes into \p buffer, returning the number read
+ (zero if no data is available or input is shutdown). \p buffer
+ may be NULL in which case the data is discarded.
+ */
+ virtual UInt32 read(void* buffer, UInt32 n) = 0;
+
+ //! Write to stream
+ /*!
+ Write \c n bytes from \c buffer to the stream. If this can't
+ complete immediately it will block. Data may be buffered in
+ order to return more quickly. A output error event is generated
+ when writing fails.
+ */
+ virtual void write(const void* buffer, UInt32 n) = 0;
+
+ //! Flush the stream
+ /*!
+ Waits until all buffered data has been written to the stream.
+ */
+ virtual void flush() = 0;
+
+ //! Shutdown input
+ /*!
+ Shutdown the input side of the stream. Any pending input data is
+ discarded and further reads immediately return 0.
+ */
+ virtual void shutdownInput() = 0;
+
+ //! Shutdown output
+ /*!
+ Shutdown the output side of the stream. Any buffered output data
+ is discarded and further writes generate output error events. Use
+ \c flush() before \c shutdownOutput() to send buffered output data.
+ */
+ virtual void shutdownOutput() = 0;
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Get event target
+ /*!
+ Returns the event target for events generated by this stream. It
+ should be the source stream in a chain of stream filters.
+ */
+ virtual void* getEventTarget() const = 0;
+
+ //! Test if \c read() will succeed
+ /*!
+ Returns true iff an immediate \c read() will return data. This
+ may or may not be the same as \c getSize() > 0, depending on the
+ stream type.
+ */
+ virtual bool isReady() const = 0;
+
+ //! Get bytes available to read
+ /*!
+ Returns a conservative estimate of the available bytes to read
+ (i.e. a number not greater than the actual number of bytes).
+ Some streams may not be able to determine this and will always
+ return zero.
+ */
+ virtual UInt32 getSize() const = 0;
+
+ //@}
+};
+
+}
diff --git a/src/lib/io/StreamBuffer.cpp b/src/lib/io/StreamBuffer.cpp
new file mode 100644
index 0000000..61f05ba
--- /dev/null
+++ b/src/lib/io/StreamBuffer.cpp
@@ -0,0 +1,146 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "io/StreamBuffer.h"
+
+//
+// StreamBuffer
+//
+
+const UInt32 StreamBuffer::kChunkSize = 4096;
+
+StreamBuffer::StreamBuffer() :
+ m_size(0),
+ m_headUsed(0)
+{
+ // do nothing
+}
+
+StreamBuffer::~StreamBuffer()
+{
+ // do nothing
+}
+
+const void*
+StreamBuffer::peek(UInt32 n)
+{
+ assert(n <= m_size);
+
+ // if requesting no data then return NULL so we don't try to access
+ // an empty list.
+ if (n == 0) {
+ return NULL;
+ }
+
+ // reserve space in first chunk
+ ChunkList::iterator head = m_chunks.begin();
+ head->reserve(n + m_headUsed);
+
+ // consolidate chunks into the first chunk until it has n bytes
+ ChunkList::iterator scan = head;
+ ++scan;
+ while (head->size() - m_headUsed < n && scan != m_chunks.end()) {
+ head->insert(head->end(), scan->begin(), scan->end());
+ scan = m_chunks.erase(scan);
+ }
+
+ return static_cast<const void*>(&(head->begin()[m_headUsed]));
+}
+
+void
+StreamBuffer::pop(UInt32 n)
+{
+ // discard all chunks if n is greater than or equal to m_size
+ if (n >= m_size) {
+ m_size = 0;
+ m_headUsed = 0;
+ m_chunks.clear();
+ return;
+ }
+
+ // update size
+ m_size -= n;
+
+ // discard chunks until more than n bytes would've been discarded
+ ChunkList::iterator scan = m_chunks.begin();
+ assert(scan != m_chunks.end());
+ while (scan->size() - m_headUsed <= n) {
+ n -= (UInt32)scan->size() - m_headUsed;
+ m_headUsed = 0;
+ scan = m_chunks.erase(scan);
+ assert(scan != m_chunks.end());
+ }
+
+ // remove left over bytes from the head chunk
+ if (n > 0) {
+ m_headUsed += n;
+ }
+}
+
+void
+StreamBuffer::write(const void* vdata, UInt32 n)
+{
+ assert(vdata != NULL);
+
+ // ignore if no data, otherwise update size
+ if (n == 0) {
+ return;
+ }
+ m_size += n;
+
+ // cast data to bytes
+ const UInt8* data = static_cast<const UInt8*>(vdata);
+
+ // point to last chunk if it has space, otherwise append an empty chunk
+ ChunkList::iterator scan = m_chunks.end();
+ if (scan != m_chunks.begin()) {
+ --scan;
+ if (scan->size() >= kChunkSize) {
+ ++scan;
+ }
+ }
+ if (scan == m_chunks.end()) {
+ scan = m_chunks.insert(scan, Chunk());
+ }
+
+ // append data in chunks
+ while (n > 0) {
+ // choose number of bytes for next chunk
+ assert(scan->size() <= kChunkSize);
+ UInt32 count = kChunkSize - (UInt32)scan->size();
+ if (count > n)
+ count = n;
+
+ // transfer data
+ scan->insert(scan->end(), data, data + count);
+ n -= count;
+ data += count;
+
+ // append another empty chunk if we're not done yet
+ if (n > 0) {
+ ++scan;
+ scan = m_chunks.insert(scan, Chunk());
+ }
+ }
+}
+
+UInt32
+StreamBuffer::getSize() const
+{
+ return m_size;
+}
diff --git a/src/lib/io/StreamBuffer.h b/src/lib/io/StreamBuffer.h
new file mode 100644
index 0000000..49b666b
--- /dev/null
+++ b/src/lib/io/StreamBuffer.h
@@ -0,0 +1,79 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "base/EventTypes.h"
+#include "common/stdlist.h"
+#include "common/stdvector.h"
+
+//! FIFO of bytes
+/*!
+This class maintains a FIFO (first-in, last-out) buffer of bytes.
+*/
+class StreamBuffer {
+public:
+ StreamBuffer();
+ ~StreamBuffer();
+
+ //! @name manipulators
+ //@{
+
+ //! Read data without removing from buffer
+ /*!
+ Return a pointer to memory with the next \c n bytes in the buffer
+ (which must be <= getSize()). The caller must not modify the returned
+ memory nor delete it.
+ */
+ const void* peek(UInt32 n);
+
+ //! Discard data
+ /*!
+ Discards the next \c n bytes. If \c n >= getSize() then the buffer
+ is cleared.
+ */
+ void pop(UInt32 n);
+
+ //! Write data to buffer
+ /*!
+ Appends \c n bytes from \c data to the buffer.
+ */
+ void write(const void* data, UInt32 n);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Get size of buffer
+ /*!
+ Returns the number of bytes in the buffer.
+ */
+ UInt32 getSize() const;
+
+ //@}
+
+private:
+ static const UInt32 kChunkSize;
+
+ typedef std::vector<UInt8> Chunk;
+ typedef std::list<Chunk> ChunkList;
+
+ ChunkList m_chunks;
+ UInt32 m_size;
+ UInt32 m_headUsed;
+};
diff --git a/src/lib/io/StreamFilter.cpp b/src/lib/io/StreamFilter.cpp
new file mode 100644
index 0000000..170e237
--- /dev/null
+++ b/src/lib/io/StreamFilter.cpp
@@ -0,0 +1,118 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "io/StreamFilter.h"
+#include "base/IEventQueue.h"
+#include "base/TMethodEventJob.h"
+
+//
+// StreamFilter
+//
+
+StreamFilter::StreamFilter(IEventQueue* events, barrier::IStream* stream, bool adoptStream) :
+ m_stream(stream),
+ m_adopted(adoptStream),
+ m_events(events)
+{
+ // replace handlers for m_stream
+ m_events->removeHandlers(m_stream->getEventTarget());
+ m_events->adoptHandler(Event::kUnknown, m_stream->getEventTarget(),
+ new TMethodEventJob<StreamFilter>(this,
+ &StreamFilter::handleUpstreamEvent));
+}
+
+StreamFilter::~StreamFilter()
+{
+ m_events->removeHandler(Event::kUnknown, m_stream->getEventTarget());
+ if (m_adopted) {
+ delete m_stream;
+ }
+}
+
+void
+StreamFilter::close()
+{
+ getStream()->close();
+}
+
+UInt32
+StreamFilter::read(void* buffer, UInt32 n)
+{
+ return getStream()->read(buffer, n);
+}
+
+void
+StreamFilter::write(const void* buffer, UInt32 n)
+{
+ getStream()->write(buffer, n);
+}
+
+void
+StreamFilter::flush()
+{
+ getStream()->flush();
+}
+
+void
+StreamFilter::shutdownInput()
+{
+ getStream()->shutdownInput();
+}
+
+void
+StreamFilter::shutdownOutput()
+{
+ getStream()->shutdownOutput();
+}
+
+void*
+StreamFilter::getEventTarget() const
+{
+ return const_cast<void*>(static_cast<const void*>(this));
+}
+
+bool
+StreamFilter::isReady() const
+{
+ return getStream()->isReady();
+}
+
+UInt32
+StreamFilter::getSize() const
+{
+ return getStream()->getSize();
+}
+
+barrier::IStream*
+StreamFilter::getStream() const
+{
+ return m_stream;
+}
+
+void
+StreamFilter::filterEvent(const Event& event)
+{
+ m_events->dispatchEvent(Event(event.getType(),
+ getEventTarget(), event.getData()));
+}
+
+void
+StreamFilter::handleUpstreamEvent(const Event& event, void*)
+{
+ filterEvent(event);
+}
diff --git a/src/lib/io/StreamFilter.h b/src/lib/io/StreamFilter.h
new file mode 100644
index 0000000..e578e0c
--- /dev/null
+++ b/src/lib/io/StreamFilter.h
@@ -0,0 +1,73 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "io/IStream.h"
+#include "base/IEventQueue.h"
+
+//! A stream filter
+/*!
+This class wraps a stream. Subclasses provide indirect access
+to the wrapped stream, typically performing some filtering.
+*/
+class StreamFilter : public barrier::IStream {
+public:
+ /*!
+ Create a wrapper around \c stream. Iff \c adoptStream is true then
+ this object takes ownership of the stream and will delete it in the
+ d'tor.
+ */
+ StreamFilter(IEventQueue* events, barrier::IStream* stream, bool adoptStream = true);
+ virtual ~StreamFilter();
+
+ // IStream overrides
+ // These all just forward to the underlying stream except getEventTarget.
+ // Override as necessary. getEventTarget returns a pointer to this.
+ virtual void close();
+ virtual UInt32 read(void* buffer, UInt32 n);
+ virtual void write(const void* buffer, UInt32 n);
+ virtual void flush();
+ virtual void shutdownInput();
+ virtual void shutdownOutput();
+ virtual void* getEventTarget() const;
+ virtual bool isReady() const;
+ virtual UInt32 getSize() const;
+
+ //! Get the stream
+ /*!
+ Returns the stream passed to the c'tor.
+ */
+ barrier::IStream* getStream() const;
+
+protected:
+ //! Handle events from source stream
+ /*!
+ Does the event filtering. The default simply dispatches an event
+ identical except using this object as the event target.
+ */
+ virtual void filterEvent(const Event&);
+
+private:
+ void handleUpstreamEvent(const Event&, void*);
+
+private:
+ barrier::IStream* m_stream;
+ bool m_adopted;
+ IEventQueue* m_events;
+};
diff --git a/src/lib/io/XIO.cpp b/src/lib/io/XIO.cpp
new file mode 100644
index 0000000..1299d23
--- /dev/null
+++ b/src/lib/io/XIO.cpp
@@ -0,0 +1,51 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "io/XIO.h"
+
+//
+// XIOClosed
+//
+
+String
+XIOClosed::getWhat() const throw()
+{
+ return format("XIOClosed", "already closed");
+}
+
+
+//
+// XIOEndOfStream
+//
+
+String
+XIOEndOfStream::getWhat() const throw()
+{
+ return format("XIOEndOfStream", "reached end of stream");
+}
+
+
+//
+// XIOWouldBlock
+//
+
+String
+XIOWouldBlock::getWhat() const throw()
+{
+ return format("XIOWouldBlock", "stream operation would block");
+}
diff --git a/src/lib/io/XIO.h b/src/lib/io/XIO.h
new file mode 100644
index 0000000..4964441
--- /dev/null
+++ b/src/lib/io/XIO.h
@@ -0,0 +1,49 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "base/XBase.h"
+
+//! Generic I/O exception
+XBASE_SUBCLASS(XIO, XBase);
+
+//! I/O closing exception
+/*!
+Thrown if a stream cannot be closed.
+*/
+XBASE_SUBCLASS(XIOClose, XIO);
+
+//! I/O already closed exception
+/*!
+Thrown when attempting to close or perform I/O on an already closed.
+stream.
+*/
+XBASE_SUBCLASS_WHAT(XIOClosed, XIO);
+
+//! I/O end of stream exception
+/*!
+Thrown when attempting to read beyond the end of a stream.
+*/
+XBASE_SUBCLASS_WHAT(XIOEndOfStream, XIO);
+
+//! I/O would block exception
+/*!
+Thrown if an operation on a stream would block.
+*/
+XBASE_SUBCLASS_WHAT(XIOWouldBlock, XIO);