* Copyright 2011-2013, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include <BufferedDataIO.h>
#include <new>
#include <stdio.h>
#include <string.h>
#ifdef TRACE_DATA_IO
# define TRACE(x...) printf(x)
#else
# define TRACE(x...) ;
#endif
BBufferedDataIO::BBufferedDataIO(BDataIO& stream, size_t bufferSize,
bool ownsStream, bool partialReads)
:
fStream(stream),
fPosition(0),
fSize(0),
fDirty(false),
fOwnsStream(ownsStream),
fPartialReads(partialReads)
{
fBufferSize = max_c(bufferSize, 512);
fBuffer = new(std::nothrow) uint8[fBufferSize];
}
BBufferedDataIO::~BBufferedDataIO()
{
Flush();
delete[] fBuffer;
if (fOwnsStream)
delete &fStream;
}
status_t
BBufferedDataIO::InitCheck() const
{
return fBuffer == NULL ? B_NO_MEMORY : B_OK;
}
BDataIO*
BBufferedDataIO::Stream() const
{
return &fStream;
}
size_t
BBufferedDataIO::BufferSize() const
{
return fBufferSize;
}
bool
BBufferedDataIO::OwnsStream() const
{
return fOwnsStream;
}
void
BBufferedDataIO::SetOwnsStream(bool ownsStream)
{
fOwnsStream = ownsStream;
}
status_t
BBufferedDataIO::Flush()
{
if (!fDirty)
return B_OK;
ssize_t bytesWritten = fStream.Write(fBuffer + fPosition, fSize);
if ((size_t)bytesWritten == fSize) {
fDirty = false;
fPosition = 0;
fSize = 0;
return B_OK;
} else if (bytesWritten >= 0) {
fSize -= bytesWritten;
fPosition += bytesWritten;
return B_PARTIAL_WRITE;
}
return B_OK;
}
ssize_t
BBufferedDataIO::Read(void* buffer, size_t size)
{
if (buffer == NULL)
return B_BAD_VALUE;
TRACE("%p::Read(size %lu)\n", this, size);
size_t bytesRead = 0;
if (fSize > 0) {
bytesRead = min_c(size, fSize);
TRACE("%p: read %lu bytes we already have in the buffer.\n", this,
bytesRead);
memcpy(buffer, fBuffer + fPosition, bytesRead);
buffer = (void*)((uint8_t*)buffer + bytesRead);
size -= bytesRead;
fPosition += bytesRead;
fSize -= bytesRead;
if (fPartialReads)
return bytesRead;
}
if (size > fBufferSize || fBuffer == NULL) {
return fStream.Read(buffer, size);
}
if (size > 0) {
status_t status = Flush();
if (status != B_OK)
return status;
TRACE("%p: read %" B_PRIuSIZE " bytes from stream\n", this,
fBufferSize);
ssize_t nextRead = fStream.Read(fBuffer, fBufferSize);
if (nextRead < 0)
return nextRead;
fSize = nextRead;
TRACE("%p: retrieved %" B_PRIuSIZE " bytes from stream\n", this, fSize);
fPosition = 0;
size_t copy = min_c(size, fSize);
memcpy(buffer, fBuffer, copy);
TRACE("%p: copy %" B_PRIuSIZE" bytes to buffer\n", this, copy);
bytesRead += copy;
fPosition = copy;
fSize -= copy;
}
return bytesRead;
}
ssize_t
BBufferedDataIO::Write(const void* buffer, size_t size)
{
if (buffer == NULL)
return B_BAD_VALUE;
TRACE("%p::Write(size %lu)\n", this, size);
if (size > fBufferSize || fBuffer == NULL) {
status_t status = Flush();
if (status != B_OK)
return status;
return fStream.Write(buffer, size);
}
if (!fDirty) {
TRACE("%p: throw away previous buffer.\n", this);
fPosition = 0;
fSize = 0;
}
size_t bytesWritten = 0;
while (size > 0) {
size_t toCopy = min_c(size, fBufferSize - (fPosition + fSize));
TRACE("%p: write %" B_PRIuSIZE " bytes to the buffer.\n", this,
toCopy);
memcpy(fBuffer + (fPosition + fSize), buffer, toCopy);
fSize += toCopy;
bytesWritten += toCopy;
size -= toCopy;
fDirty = true;
if ((fPosition + fSize) == fBufferSize) {
status_t status = Flush();
if (status != B_OK)
return bytesWritten;
}
}
return bytesWritten;
}
status_t BBufferedDataIO::_Reserved0(void*) { return B_ERROR; }
status_t BBufferedDataIO::_Reserved1(void*) { return B_ERROR; }
status_t BBufferedDataIO::_Reserved2(void*) { return B_ERROR; }
status_t BBufferedDataIO::_Reserved3(void*) { return B_ERROR; }
status_t BBufferedDataIO::_Reserved4(void*) { return B_ERROR; }