#include "StarBuffer.hpp" #include "StarMathCommon.hpp" #include "StarIODevice.hpp" #include "StarFormat.hpp" namespace Star { Buffer::Buffer() : m_pos(0) { setMode(IOMode::ReadWrite); } Buffer::Buffer(size_t initialSize) : Buffer() { reset(initialSize); } Buffer::Buffer(ByteArray b) : Buffer() { reset(move(b)); } Buffer::Buffer(Buffer const& buffer) : Buffer() { operator=(buffer); } Buffer::Buffer(Buffer&& buffer) : Buffer() { operator=(move(buffer)); } StreamOffset Buffer::pos() { return m_pos; } void Buffer::seek(StreamOffset pos, IOSeek mode) { StreamOffset newPos = m_pos; if (mode == IOSeek::Absolute) newPos = pos; else if (mode == IOSeek::Relative) newPos += pos; else if (mode == IOSeek::End) newPos = m_bytes.size() - pos; m_pos = newPos; } void Buffer::resize(StreamOffset size) { data().resize((size_t)size); } bool Buffer::atEnd() { return m_pos >= m_bytes.size(); } size_t Buffer::read(char* data, size_t len) { size_t l = doRead(m_pos, data, len); m_pos += l; return l; } size_t Buffer::write(char const* data, size_t len) { size_t l = doWrite(m_pos, data, len); m_pos += l; return l; } size_t Buffer::readAbsolute(StreamOffset readPosition, char* data, size_t len) { size_t rpos = readPosition; if ((StreamOffset)rpos != readPosition) throw IOException("Error, readPosition out of range"); return doRead(rpos, data, len); } size_t Buffer::writeAbsolute(StreamOffset writePosition, char const* data, size_t len) { size_t wpos = writePosition; if ((StreamOffset)wpos != writePosition) throw IOException("Error, writePosition out of range"); return doWrite(wpos, data, len); } void Buffer::open(IOMode mode) { setMode(mode); if (mode & IOMode::Write && mode & IOMode::Truncate) resize(0); if (mode & IOMode::Append) seek(0, IOSeek::End); } String Buffer::deviceName() const { return strf("Buffer <%s>", (void*)this); } StreamOffset Buffer::size() { return m_bytes.size(); } ByteArray& Buffer::data() { return m_bytes; } ByteArray const& Buffer::data() const { return m_bytes; } ByteArray Buffer::takeData() { ByteArray ret = move(m_bytes); reset(0); return ret; } char* Buffer::ptr() { return data().ptr(); } char const* Buffer::ptr() const { return m_bytes.ptr(); } size_t Buffer::dataSize() const { return m_bytes.size(); } void Buffer::reserve(size_t size) { data().reserve(size); } void Buffer::clear() { m_pos = 0; m_bytes.clear(); } bool Buffer::empty() const { return m_bytes.empty(); } void Buffer::reset(size_t newSize) { m_pos = 0; m_bytes.fill(newSize, 0); } void Buffer::reset(ByteArray b) { m_pos = 0; m_bytes = move(b); } Buffer& Buffer::operator=(Buffer const& buffer) { IODevice::operator=(buffer); m_pos = buffer.m_pos; m_bytes = buffer.m_bytes; return *this; } Buffer& Buffer::operator=(Buffer&& buffer) { IODevice::operator=(buffer); m_pos = buffer.m_pos; m_bytes = move(buffer.m_bytes); buffer.m_pos = 0; buffer.m_bytes = ByteArray(); return *this; } size_t Buffer::doRead(size_t pos, char* data, size_t len) { if (len == 0) return 0; if (!isReadable()) throw IOException("Error, read called on non-readable Buffer"); if (pos >= m_bytes.size()) return 0; size_t l = min(m_bytes.size() - pos, len); memcpy(data, m_bytes.ptr() + pos, l); return l; } size_t Buffer::doWrite(size_t pos, char const* data, size_t len) { if (len == 0) return 0; if (!isWritable()) throw EofException("Error, write called on non-writable Buffer"); if (pos + len > m_bytes.size()) m_bytes.resize(pos + len); memcpy(m_bytes.ptr() + pos, data, len); return len; } ExternalBuffer::ExternalBuffer() : m_pos(0), m_bytes(nullptr), m_size(0) { setMode(IOMode::Read); } ExternalBuffer::ExternalBuffer(char const* externalData, size_t len) : ExternalBuffer() { reset(externalData, len); } StreamOffset ExternalBuffer::pos() { return m_pos; } void ExternalBuffer::seek(StreamOffset pos, IOSeek mode) { StreamOffset newPos = m_pos; if (mode == IOSeek::Absolute) newPos = pos; else if (mode == IOSeek::Relative) newPos += pos; else if (mode == IOSeek::End) newPos = m_size - pos; m_pos = newPos; } bool ExternalBuffer::atEnd() { return m_pos >= m_size; } size_t ExternalBuffer::read(char* data, size_t len) { size_t l = doRead(m_pos, data, len); m_pos += l; return l; } size_t ExternalBuffer::write(char const*, size_t) { throw IOException("Error, ExternalBuffer is not writable"); } size_t ExternalBuffer::readAbsolute(StreamOffset readPosition, char* data, size_t len) { size_t rpos = readPosition; if ((StreamOffset)rpos != readPosition) throw IOException("Error, readPosition out of range"); return doRead(rpos, data, len); } size_t ExternalBuffer::writeAbsolute(StreamOffset, char const*, size_t) { throw IOException("Error, ExternalBuffer is not writable"); } String ExternalBuffer::deviceName() const { return strf("ExternalBuffer <%s>", (void*)this); } StreamOffset ExternalBuffer::size() { return m_size; } char const* ExternalBuffer::ptr() const { return m_bytes; } size_t ExternalBuffer::dataSize() const { return m_size; } bool ExternalBuffer::empty() const { return m_size == 0; } void ExternalBuffer::reset(char const* externalData, size_t len) { m_pos = 0; m_bytes = externalData; m_size = len; } size_t ExternalBuffer::doRead(size_t pos, char* data, size_t len) { if (len == 0) return 0; if (!isReadable()) throw IOException("Error, read called on non-readable Buffer"); if (pos >= m_size) return 0; size_t l = min(m_size - pos, len); memcpy(data, m_bytes + pos, l); return l; } }