diff --git a/headers/os/support/BufferedDataIO.h b/headers/os/support/BufferedDataIO.h new file mode 100644 index 0000000000..d3f98031ae --- /dev/null +++ b/headers/os/support/BufferedDataIO.h @@ -0,0 +1,56 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _BUFFERED_DATA_IO_H +#define _BUFFERED_DATA_IO_H + + +#include + + +class BBufferedDataIO : public BDataIO { +public: + BBufferedDataIO(BDataIO& stream, + size_t bufferSize = 65536L, + bool ownsStream = true, + bool partialReads = false); + virtual ~BBufferedDataIO(); + + status_t InitCheck() const; + + BDataIO* Stream() const; + size_t BufferSize() const; + bool OwnsStream() const; + void SetOwnsStream(bool ownsStream); + status_t Flush(); + + // BDataIO interface + virtual ssize_t Read(void* buffer, size_t size); + virtual ssize_t Write(const void* buffer, size_t size); + +private: + virtual status_t _Reserved0(void*); + virtual status_t _Reserved1(void*); + virtual status_t _Reserved2(void*); + virtual status_t _Reserved3(void*); + virtual status_t _Reserved4(void*); + +private: + BDataIO& fStream; + uint8* fBuffer; + size_t fBufferSize; + size_t fPosition; + size_t fSize; + + uint32 _reserved_ints[4]; + + bool fDirty; + bool fOwnsStream; + bool fPartialReads; + + bool _reserved_bools[5]; +}; + + +#endif // _BUFFERED_DATA_IO_H diff --git a/src/kits/support/BufferedDataIO.cpp b/src/kits/support/BufferedDataIO.cpp new file mode 100644 index 0000000000..505bc2e34f --- /dev/null +++ b/src/kits/support/BufferedDataIO.cpp @@ -0,0 +1,224 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include +#include + + +//#define TRACE_DATA_IO +#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; + + size_t bytesWritten = fStream.Write(fBuffer + fPosition, fSize); + if (bytesWritten == fSize) { + fDirty = false; + fPosition = 0; + fSize = 0; + return B_OK; + } else if (bytesWritten >= 0) { + fSize -= bytesWritten; + fPosition += bytesWritten; + return B_ERROR; + } + + return bytesWritten; +} + + +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) { + // fill the part of the stream we already have + 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) { + // request is larger than our buffer, just fill it directly + return fStream.Read(buffer, size); + } + + if (size > 0) { + // retrieve next buffer + + status_t status = Flush(); + if (status != B_OK) + return status; + + TRACE("%p: read %" B_PRIuSIZE " bytes from stream\n", this, fBufferSize); + fSize = fStream.Read(fBuffer, fBufferSize); + TRACE("%p: retrieved %" B_PRIuSIZE " bytes from stream\n", this, fSize); + fPosition = 0; + + // Copy the remaining part + 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 (!fDirty) { + // Throw away a read-only buffer if necessary + TRACE("%p: throw away previous buffer.\n", this); + fPosition = 0; + fSize = 0; + } + + size_t bytesWritten = 0; + + if (size > fBufferSize || fBuffer == NULL) { + // request is larger than our buffer, just fill it directly + bytesWritten = fSize; + + status_t status = Flush(); + if (status != B_OK) + return status; + + ssize_t streamWritten = fStream.Write(buffer, size); + if (streamWritten >= 0) + return bytesWritten + streamWritten; + + return streamWritten; + } + + bytesWritten = min_c(size, fBufferSize - fSize - fPosition); + TRACE("%p: write %" B_PRIuSIZE " bytes to the buffer.\n", this, + bytesWritten); + memcpy(fBuffer + fPosition + fSize, buffer, bytesWritten); + fSize += bytesWritten; + size -= bytesWritten; + + if (size > 0) { + status_t status = Flush(); + if (status != B_OK) + return status; + + memcpy(fBuffer, (uint8*)buffer + bytesWritten, size); + fPosition = 0; + fSize = size; + fDirty = true; + bytesWritten += size; + } + + return bytesWritten; +} + + +// #pragma mark - FBC + + +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; } diff --git a/src/kits/support/Jamfile b/src/kits/support/Jamfile index 119f7cd2d2..fcdd1227a4 100644 --- a/src/kits/support/Jamfile +++ b/src/kits/support/Jamfile @@ -9,10 +9,11 @@ MergeObject support_kit.o : ArchivingManagers.cpp Beep.cpp BlockCache.cpp + BufferedDataIO.cpp + BufferIO.cpp ByteOrder.cpp DataIO.cpp DateTime.cpp - BufferIO.cpp Flattenable.cpp List.cpp Locker.cpp