/************************************************
*
* Chunked Data Source
* Copyright (C) 2020
* John Ryland
* All rights reserved
*
************************************************/
#include <cassert>
#include "ChunkedDataSource.hpp"
namespace
{
std::string removeCRLF(std::string aLine)
{
if (aLine[aLine.size()-1] == '\n')
return aLine.substr(0, aLine.size()-1);
return aLine;
}
}
ChunkedDataSource::ChunkedDataSource(size_t aChunkSize, unsigned aRetryAttempts)
: mChunkSize(aChunkSize)
, mRetryAttempts(aRetryAttempts)
{
}
ChunkedReaderProxy::ChunkedReaderProxy(ChunkedDataSource& aProxiedSource)
: OpenedDataSource()
, mProxiedSource(aProxiedSource)
, mBufferIndex(0)
{
mBufferedData.reserve(mProxiedSource.ChunkSize() * 2);
}
ChunkedReaderProxy::~ChunkedReaderProxy()
{
// delete mProxiedSource;
}
bool ChunkedReaderProxy::ReadBytes(size_t aNumberOfBytes, ReadCompletionCallback aCallback)
{
ssize_t availableBytes = mBufferedData.size() - mBufferIndex;
// Refill buffers a chunk at a time to meet the read request
while (availableBytes < static_cast<ssize_t>(aNumberOfBytes))
{
ChunkedDataSource::ReadResult result = mProxiedSource.ReadChunk(mBufferedData);
if (result == ChunkedDataSource::ReadResult::eError)
{
return false;
}
availableBytes = mBufferedData.size() - mBufferIndex;
}
// Fulfill the request
assert(availableBytes > static_cast<ssize_t>(aNumberOfBytes));
const auto start = mBufferedData.begin() + mBufferIndex;
aCallback(ReadResult::eSuccess, VectorSlice<uint8_t>(start, start + aNumberOfBytes));
mBufferIndex += aNumberOfBytes;
// Fix up the buffer to contain up to a chunk of data with space for a 2nd chunk
const size_t chunkSize = mProxiedSource.ChunkSize();
assert(chunkSize != 0);
if (mBufferIndex > chunkSize)
{
// Copy last chunk to start of buffer
const size_t numberOfChunks = mBufferedData.size() / chunkSize;
const size_t lastChunk = numberOfChunks - 1;
const size_t lastChunkOffset = lastChunk * chunkSize;
assert(mBufferIndex >= lastChunkOffset);
const auto start = mBufferedData.begin() + lastChunkOffset;
const auto end = start + chunkSize;
mBufferedData.resize(chunkSize);
std::copy(start, end, mBufferedData.begin());
mBufferIndex -= lastChunkOffset;
}
return true;
}
bool ChunkedReaderProxy::ReadLine(ReadCompletionCallback aCallback)
{
uint8_t ch = -1;
std::vector<uint8_t> line;
line.reserve(64);
while (ch && ch != '\n')
{
ReadBytes(1, [&ch](ReadResult aResult, VectorSlice<uint8_t> aBytesRead)
{
ch = *aBytesRead.begin();
});
line.push_back(ch);
}
//line = removeCRLF(line);
aCallback(ReadResult::eSuccess, VectorSlice<uint8_t>(line.begin(), line.end()));
}
bool ChunkedReaderProxy::ReadAll(ReadCompletionCallback aCallback)
{
return ReadBytes(mProxiedSource.GetDataSize(), aCallback);
}