diff options
Diffstat (limited to 'src/lib/io/StreamBuffer.cpp')
| -rw-r--r-- | src/lib/io/StreamBuffer.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
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; +} |
