151 lines
3.6 KiB
C++
151 lines
3.6 KiB
C++
|
|
#include "fs/BufferedSource.h"
|
|
#include <algorithm>
|
|
|
|
namespace fs
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
BufferedSource<SourceType>::BufferedSource(SourceType source, size_t bufferSize)
|
|
: m_source(std::move(source))
|
|
{
|
|
if (bufferSize < 8)
|
|
bufferSize = 8;
|
|
|
|
m_buffer.reserve(bufferSize);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
tl::optional<Error> BufferedSource<SourceType>::getLastError() const
|
|
{
|
|
tl::optional<Error> error = m_optLastError;
|
|
m_optLastError = tl::nullopt;
|
|
return error;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
size_t BufferedSource<SourceType>::read(tl::span<uint8_t> data)
|
|
{
|
|
if (data.empty() || m_endOfSource)
|
|
return 0;
|
|
|
|
auto bufferPtr = data.data();
|
|
size_t totalSize = 0;
|
|
size_t pendingSize = data.size();
|
|
|
|
while (pendingSize)
|
|
{
|
|
if (m_buffer.empty() || m_bufferOffset >= m_buffer.size())
|
|
{
|
|
m_buffer.resize_uninitialized(m_buffer.capacity());
|
|
m_bufferStartOffset = m_source.tell();
|
|
m_bufferOffset = 0;
|
|
const size_t readSize = m_source.read(m_buffer);
|
|
m_buffer.resize_uninitialized(readSize);
|
|
if (readSize == 0)
|
|
{
|
|
m_optLastError = m_source.getLastError();
|
|
m_endOfSource = !m_optLastError.has_value(); //no error? then EOS
|
|
return totalSize;
|
|
}
|
|
}
|
|
|
|
TL_ASSERT(m_buffer.size());
|
|
TL_ASSERT(m_buffer.size() > m_bufferOffset);
|
|
const size_t frameSize = tl::min(m_buffer.size() - m_bufferOffset, pendingSize);
|
|
TL_ASSERT(frameSize);
|
|
|
|
memcpy(bufferPtr, m_buffer.data() + m_bufferOffset, frameSize);
|
|
bufferPtr += frameSize;
|
|
|
|
TL_ASSERT(data.size() >= frameSize);
|
|
pendingSize -= frameSize;
|
|
|
|
totalSize += frameSize;
|
|
TL_ASSERT(totalSize <= data.size());
|
|
|
|
m_bufferOffset += frameSize;
|
|
}
|
|
|
|
m_endOfSource = tell() >= getSize();
|
|
|
|
return totalSize;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
void BufferedSource<SourceType>::seekBeg(uint64_t offset)
|
|
{
|
|
offset = tl::min(offset, m_source.getSize());
|
|
if (offset < m_bufferStartOffset || offset >= m_bufferStartOffset + m_buffer.size())
|
|
{
|
|
m_source.seekBeg(offset);
|
|
m_optLastError = m_source.getLastError();
|
|
m_buffer.clear();
|
|
m_bufferOffset = 0;
|
|
m_bufferStartOffset = m_source.tell();
|
|
}
|
|
else
|
|
m_bufferOffset = offset - m_bufferStartOffset;
|
|
|
|
m_endOfSource = tell() >= getSize();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
void BufferedSource<SourceType>::seekRel(int64_t offset)
|
|
{
|
|
if (!offset)
|
|
return;
|
|
|
|
if (offset != 0)
|
|
{
|
|
int64_t newOffset = tell();
|
|
newOffset += offset;
|
|
newOffset = tl::max<int64_t>(newOffset, 0);
|
|
seekBeg(static_cast<uint64_t>(tl::min<int64_t>(newOffset, getSize())));
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
uint64_t BufferedSource<SourceType>::tell() const
|
|
{
|
|
return m_bufferStartOffset + m_bufferOffset;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
uint64_t BufferedSource<SourceType>::getSize() const
|
|
{
|
|
return m_source.getSize();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
bool BufferedSource<SourceType>::isEOS() const
|
|
{
|
|
return m_endOfSource;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template< typename SourceType>
|
|
size_t BufferedSource<SourceType>::getPreferredBufferSize() const
|
|
{
|
|
return m_buffer.size();
|
|
}
|
|
|
|
}
|
|
|