diff options
Diffstat (limited to 'src/lib/io')
| -rw-r--r-- | src/lib/io/CMakeLists.txt | 24 | ||||
| -rw-r--r-- | src/lib/io/IStream.h | 120 | ||||
| -rw-r--r-- | src/lib/io/StreamBuffer.cpp | 146 | ||||
| -rw-r--r-- | src/lib/io/StreamBuffer.h | 79 | ||||
| -rw-r--r-- | src/lib/io/StreamFilter.cpp | 118 | ||||
| -rw-r--r-- | src/lib/io/StreamFilter.h | 73 | ||||
| -rw-r--r-- | src/lib/io/XIO.cpp | 51 | ||||
| -rw-r--r-- | src/lib/io/XIO.h | 49 |
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); |
