BufferStream.h#

Parent directory (stream)

A Stream wrapping a block of memory.

Includes#

  • PVRCore/stream/Stream.h

  • algorithm

Included By#

Namespaces#

Classes#

Defines#

Source Code#

#pragma once
#include "PVRCore/stream/Stream.h"
#include <algorithm>

namespace pvr {
class BufferStream : public Stream
{
protected:
    const void* _originalData;
    mutable const void* _currentPointer;
    mutable size_t _bufferSize;
    mutable size_t _bufferPosition;

    explicit BufferStream(const std::string& resourceName) : Stream(resourceName, false, false, false), _originalData(0), _currentPointer(0), _bufferSize(0), _bufferPosition(0) {}

public:
    BufferStream(const std::string& fileName, void* buffer, size_t bufferSize)
        : Stream(fileName, buffer != nullptr, buffer != nullptr, buffer != nullptr), _originalData(buffer), _currentPointer(buffer), _bufferSize(bufferSize), _bufferPosition(0)
    {}

    BufferStream(const std::string& fileName, const void* buffer, size_t bufferSize)
        : Stream(fileName, buffer != nullptr, false, buffer != nullptr), _originalData(buffer), _currentPointer(buffer), _bufferSize(bufferSize), _bufferPosition(0)
    {}

private:
    virtual void _read(size_t elementSize, size_t numElements, void* buffer, size_t& dataRead) const override
    {
        if (!buffer || !_currentPointer) { throw InvalidOperationError("Attempted to read a null BufferStream"); }
        char* dataCurrent = static_cast<char*>(buffer);
        // Make sure we don't read too much
        for(size_t realcount = 0; realcount < numElements; ++realcount)
        {
            size_t realsize = static_cast<size_t>(std::min(elementSize, _bufferSize - _bufferPosition));
            memcpy(dataCurrent, _currentPointer, realsize);

            _bufferPosition += realsize;
            _currentPointer = static_cast<const void*>(static_cast<const char*>(_currentPointer) + realsize);
            dataCurrent += realsize;

            if (realsize == elementSize) { ++dataRead; }
        }
        if (dataRead != numElements && _bufferPosition != _bufferSize) { throw FileIOError("[BufferStream::read]: Unknown error while reading BufferStream."); }
    }

    virtual void _write(size_t elementSize, size_t numElements, const void* buffer, size_t& dataWritten) override
    {
        if (!buffer || !_currentPointer) { throw FileIOError("[BufferStream::write]: UnknownError: No data / Memory Pointer was NULL"); }
        const unsigned char* dataCurrent = static_cast<const unsigned char*>(buffer);
        // Make sure we don't read too much
        for(size_t realcount = 0; realcount < numElements; ++realcount)
        {
            size_t realsize = static_cast<size_t>(std::min<uint64_t>(static_cast<uint64_t>(elementSize), _bufferSize - _bufferPosition));
            memcpy(const_cast<void*>(_currentPointer), dataCurrent, realsize);

            _bufferPosition += realsize;
            _currentPointer = static_cast<const void*>(static_cast<const char*>(_currentPointer) + realsize);
            dataCurrent += realsize;

            if (realsize == elementSize) { ++dataWritten; }
        }
        if (dataWritten != numElements) { throw FileIOError("[BufferStream::write]: Unknown error trying to write stream"); }
    }

#define CLAMP(val, minim, maxim) ((val < minim) ? minim : ((val > maxim) ? maxim : val))

    virtual void _seek(long offset, SeekOrigin origin) const override
    {
        long newOffset = 0;

        if (!_currentPointer || !_originalData)
        {
            if (offset) { throw FileIOError("BufferStream::seek: Attempt to seek from empty stream"); }
        }
        else
        {
            switch (origin)
            {
            case Stream::SeekOriginFromStart:
            {
                newOffset = static_cast<long>(CLAMP(static_cast<int64_t>(offset), 0, static_cast<int64_t>(_bufferSize)));

                _bufferPosition = static_cast<size_t>(newOffset);
                _currentPointer = static_cast<const unsigned char*>(_originalData) + _bufferPosition;
                break;
            }
            case Stream::SeekOriginFromCurrent:
            {
                int64_t maxOffset = static_cast<int64_t>(_bufferSize - _bufferPosition);
                int64_t minOffset = -1 * static_cast<int64_t>(_bufferPosition);

                newOffset = static_cast<long>(CLAMP(offset, static_cast<long>(minOffset), static_cast<long>(maxOffset)));

                _bufferPosition += newOffset;
                _currentPointer = static_cast<const char*>(_currentPointer) + newOffset;
                break;
            }
            case Stream::SeekOriginFromEnd:
            {
                newOffset = static_cast<long>(CLAMP(offset, static_cast<long>(-1 * (static_cast<int64_t>(_bufferPosition))), 0));

                _bufferPosition = _bufferSize + newOffset;
                _currentPointer = static_cast<const unsigned char*>(_originalData) + _bufferPosition;
                break;
            }
            }
        }

        if (newOffset != offset) { throw FileIOError("[BufferStream::seek] Attempted to seek past the end of stream"); }
    }
#undef CLAMP

    virtual uint64_t _getPosition() const override { return _bufferPosition; }

    virtual uint64_t _getSize() const override { return _bufferSize; }

private:
    // Disable copy and assign.
    void operator=(const BufferStream&);
    BufferStream(const BufferStream&);
};
} // namespace pvr