Initial checkin. Partially abstract base class for a DataStream object

that simulates a contiguous stream out of one or more not-necessarily-
contiguous extents in another stream. Fully implemented, completely
untested.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5697 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Tyler Dauwalder 2003-12-18 09:27:54 +00:00
parent 36f786dc8f
commit 0ab79adc28
2 changed files with 364 additions and 0 deletions

View File

@ -0,0 +1,288 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
//----------------------------------------------------------------------
/*! \file SimulatedStream.cpp
*/
#include "SimulatedStream.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
SimulatedStream::SimulatedStream(DataStream &stream)
: fPosition(0)
, fStream(stream)
{
}
ssize_t
SimulatedStream::Read(void *_buffer, size_t size)
{
uint8 *buffer = reinterpret_cast<uint8*>(_buffer);
status_t error = buffer ? B_OK : B_BAD_VALUE;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(fPosition, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.ReadAt(extent.offset, buffer, extent.size);
if (bytes >= 0) {
size -= bytes;
fPosition += bytes;
buffer += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
ssize_t
SimulatedStream::ReadAt(off_t pos, void *_buffer, size_t size)
{
uint8 *buffer = reinterpret_cast<uint8*>(_buffer);
status_t error = buffer ? B_OK : B_BAD_VALUE;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(pos, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.ReadAt(extent.offset, buffer, extent.size);
if (bytes >= 0) {
size -= bytes;
pos += bytes;
buffer += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
/*! \brief Writes \a size bytes worth of data from \a buffer at the current
position in the stream, incrementing the stream's position marker as it goes.
*/
ssize_t
SimulatedStream::Write(const void *_buffer, size_t size)
{
const uint8 *buffer = reinterpret_cast<const uint8*>(_buffer);
status_t error = buffer ? B_OK : B_BAD_VALUE;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(fPosition, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.WriteAt(extent.offset, buffer, extent.size);
if (bytes >= 0) {
size -= bytes;
fPosition += bytes;
buffer += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
/*! \brief Writes \a size bytes worth of data from \a buffer at position
\a pos in the stream without incrementing the stream's position marker.
*/
ssize_t
SimulatedStream::WriteAt(off_t pos, const void *_buffer, size_t size)
{
const uint8 *buffer = reinterpret_cast<const uint8*>(_buffer);
status_t error = buffer ? B_OK : B_BAD_VALUE;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(pos, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.WriteAt(extent.offset, buffer, extent.size);
if (bytes >= 0) {
size -= bytes;
pos += bytes;
buffer += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
/*! \brief Writes \a size bytes worth of data from \a data at the current
position in the stream, incrementing the stream's position marker as it goes.
*/
ssize_t
SimulatedStream::Write(BDataIO &data, size_t size)
{
status_t error = B_OK;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(fPosition, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.WriteAt(extent.offset, data, extent.size);
if (bytes >= 0) {
size -= bytes;
fPosition += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
/*! \brief Writes \a size bytes worth of data from \a data at position
\a pos in the stream without incrementing the stream's position marker.
*/
ssize_t
SimulatedStream::WriteAt(off_t pos, BDataIO &data, size_t size)
{
status_t error = B_OK;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(pos, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.WriteAt(extent.offset, data, extent.size);
if (bytes >= 0) {
size -= bytes;
pos += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
/*! \brief Writes \a size bytes worth of zeros at the current position
in the stream, incrementing the stream's position marker as it goes.
*/
ssize_t
SimulatedStream::Zero(size_t size)
{
status_t error = B_OK;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(fPosition, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.ZeroAt(extent.offset, extent.size);
if (bytes >= 0) {
size -= bytes;
fPosition += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
/*! \brief Writes \a size bytes worth of zeros at position \a pos
in the stream without incrementing the stream's position marker.
*/
ssize_t
SimulatedStream::ZeroAt(off_t pos, size_t size)
{
status_t error = B_OK;
ssize_t bytesTotal = 0;
while (error == B_OK && size > 0) {
data_extent extent;
error = _GetExtent(pos, size, extent);
if (!error) {
if (extent.size > 0) {
ssize_t bytes = fStream.ZeroAt(extent.offset, extent.size);
if (bytes >= 0) {
size -= bytes;
pos += bytes;
bytesTotal += bytes;
} else {
error = status_t(bytes);
}
} else {
// end of simulated stream
break;
}
}
}
return !error ? bytesTotal : ssize_t(error);
}
off_t
SimulatedStream::Seek(off_t pos, uint32 seek_mode)
{
off_t size = _Size();
switch (seek_mode) {
case SEEK_SET:
fPosition = pos;
break;
case SEEK_CUR:
fPosition += pos;
break;
case SEEK_END:
fPosition = size + pos;
break;
default:
break;
}
// Range check
if (fPosition < 0)
fPosition = 0;
else if (fPosition > size && SetSize(fPosition) != B_OK)
fPosition = size;
return fPosition;
}

View File

@ -0,0 +1,76 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
//----------------------------------------------------------------------
/*! \file SimulatedStream.h
*/
#ifndef _SIMULATED_STREAM_H
#define _SIMULATED_STREAM_H
#include "DataStream.h"
/*! \brief Abstract DataStream wrapper around another DataStream and a sequence of
extents in said stream that allows for easy write access to said sequence
of extents as though they were a continuous chunk of data.
NOTE: The SimulatedStream object never modifies the data stream position
of the underlying data stream; all read/write/zero calls use the underlying
stream's ReadAt()/WriteAt()/ZeroAt() functions.
*/
class SimulatedStream : public DataStream {
public:
SimulatedStream(DataStream &stream);
virtual ssize_t Read(void *buffer, size_t size);
virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size);
virtual ssize_t Write(const void *buffer, size_t size);
virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size);
virtual ssize_t Write(BDataIO &data, size_t size);
virtual ssize_t WriteAt(off_t pos, BDataIO &data, size_t size);
virtual ssize_t Zero(size_t size);
virtual ssize_t ZeroAt(off_t pos, size_t size);
virtual off_t Seek(off_t pos, uint32 seek_mode);
virtual off_t Position() const { return fPosition; }
virtual status_t SetSize(off_t size) { return B_ERROR; }
protected:
struct data_extent {
data_extent(off_t offset = 0, size_t size = 0)
: offset(offset)
, size(size)
{
}
off_t offset;
size_t size;
};
/*! \brief Should be implemented to return (via the output parameter
\a extent) the largest extent in the underlying data stream corresponding
to the extent in the simulated data stream starting at byte position
\a pos of byte length \a size.
NOTE: If the position is at or beyond the end of the simulated stream, the
function should return B_OK, and the value of extent.size should be 0.
*/
virtual status_t _GetExtent(off_t pos, size_t size, data_extent &extent) = 0;
/*! \brief Should be implemented to return the current size of the stream.
*/
virtual off_t _Size() = 0;
private:
off_t fPosition;
DataStream &fStream;
};
#endif // _SIMULATED_STREAM_H