Stream.h#
↰ Parent directory (stream
)
Contains a class used to abstract streams of data (files, blocks of memory, resources etc.).
Includes#
PVRCore/Errors.h
PVRCore/strings/StringFunctions.h
memory
string
(CompileTimeHash.h)vector
Included By#
Namespaces#
Classes#
Source Code#
#pragma once
#include "PVRCore/Errors.h"
#include "PVRCore/strings/StringFunctions.h"
#include <memory>
#include <vector>
#include <string>
namespace pvr {
class Stream;
class FileIOError : public PvrError
{
public:
explicit FileIOError(const Stream& stream);
FileIOError(const Stream& stream, std::string message);
explicit FileIOError(std::string filenameOrMessage) : PvrError("[" + filenameOrMessage + "]: File IO operation failed") {}
FileIOError(std::string filename, std::string message) : PvrError("[" + filename + "]: File IO operation failed - " + message) {}
};
class FileEOFError : public PvrError
{
public:
explicit FileEOFError(const Stream& stream);
FileEOFError(const Stream& stream, std::string message);
explicit FileEOFError(std::string filenameOrMessage) : PvrError("[" + filenameOrMessage + "]: Attempted to read past the end of file.") {}
FileEOFError(std::string filename, std::string message) : PvrError("[" + filename + "]: Attempted to read past the end of file - " + message) {}
};
class FileNotFoundError : public std::runtime_error
{
public:
explicit FileNotFoundError(const Stream& stream);
FileNotFoundError(const Stream& stream, std::string message);
explicit FileNotFoundError(std::string filenameOrMessage) : std::runtime_error("[" + filenameOrMessage + "]: File not found") {}
FileNotFoundError(std::string filename, std::string message) : std::runtime_error("[" + filename + "]: File not found - " + message) {}
};
class Stream
{
public:
enum SeekOrigin
{
SeekOriginFromStart,
SeekOriginFromCurrent,
SeekOriginFromEnd
};
virtual ~Stream() = default;
bool isReadable() const { return _isReadable; }
bool isWritable() const { return _isWritable; }
const std::string& getFileName() const { return _fileName; }
public:
void read(size_t elementSize, size_t numElements, void* buffer, size_t& dataRead) const
{
dataRead = 0;
if (!_isReadable) { throw InvalidOperationError("[Stream::read]: Attempted to read non readable stream"); }
_read(elementSize, numElements, buffer, dataRead);
}
void readExact(size_t elementSize, size_t numElements, void* buffer) const
{
size_t dataRead;
read(elementSize, numElements, buffer, dataRead);
if (dataRead != numElements)
{
throw FileEOFError(*this,
std::string("[Stream::readExact]: Failed to read specified number of elements. Size of element: [" + std::to_string(elementSize) + "]. Attempted to read [" +
std::to_string(numElements) + "] but got [" + std::to_string(dataRead) + "]"));
}
}
void write(size_t elementSize, size_t numElements, const void* buffer, size_t& dataWritten)
{
dataWritten = 0;
if (!_isWritable) { throw InvalidOperationError("[Stream::write]: Attempt to write to non-writable stream"); }
_write(elementSize, numElements, buffer, dataWritten);
}
void writeExact(size_t elementSize, size_t numElements, const void* buffer)
{
size_t dataWritten;
write(elementSize, numElements, buffer, dataWritten);
if (dataWritten != numElements) { throw FileIOError(*this, std::string("Stream::writeExact: Failed to write specified number of elements.")); }
}
void seek(long offset, SeekOrigin origin) const
{
if (!isRandomAccess()) { throw InvalidOperationError(pvr::strings::createFormatted("[pvr::Stream] Attempted to seek on non-seekable stream '%s'", getFileName().c_str())); }
_seek(offset, origin);
}
bool isSeekable() const { return isRandomAccess(); }
bool isRandomAccess() const { return _isRandomAccess; }
size_t getPosition() const { return size_t(_getPosition()); }
uint64_t getPosition64() const { return _getPosition(); }
size_t getSize() const { return size_t(_getSize()); }
uint64_t getSize64() const { return _getSize(); }
template<typename Type_>
std::vector<Type_> readToEnd() const
{
std::vector<Type_> ret;
uint64_t mySize = getSize() - getPosition();
uint64_t numElements = mySize / sizeof(Type_);
ret.resize(size_t(numElements));
size_t actuallyRead;
read(sizeof(Type_), size_t(numElements), ret.data(), actuallyRead);
return ret;
}
void readIntoCharBuffer(std::vector<char>& outString) const
{
outString.resize((size_t)getSize() + 1);
size_t dataRead;
read(1, (size_t)getSize(), outString.data(), dataRead);
}
template<typename T_>
void readIntoBuffer(std::vector<T_>& outString) const
{
size_t initial_size = outString.size();
outString.resize(size_t(initial_size + getSize()));
size_t dataRead;
return read(sizeof(T_), size_t(getSize()), outString.data() + initial_size, dataRead);
}
std::vector<char> readChars() const
{
std::vector<char> pData;
readIntoCharBuffer(pData);
return pData;
}
void readIntoString(std::string& outString) const
{
uint64_t sz = getSize();
outString.resize((size_t)sz);
if (sz > 0) { readExact(1, (size_t)getSize(), &outString[0]); }
}
std::string readString() const
{
uint64_t sz = getSize();
std::string outString;
outString.resize((size_t)sz);
if (sz > 0) { readExact(1, (size_t)getSize(), &outString[0]); }
return outString;
}
protected:
explicit Stream(const std::string& fileName, bool readable, bool writable, bool seekable)
: _isReadable(readable), _isWritable(writable), _isRandomAccess(seekable), _fileName(fileName)
{}
bool _isReadable;
bool _isWritable;
bool _isRandomAccess;
std::string _fileName;
private:
virtual void _seek(long offset, SeekOrigin origin) const = 0;
virtual void _write(size_t elementSize, size_t numElements, const void* buffer, size_t& dataWritten) = 0;
virtual void _read(size_t elementSize, size_t numElements, void* buffer, size_t& dataRead) const = 0;
virtual uint64_t _getPosition() const = 0;
virtual uint64_t _getSize() const = 0;
// Disable copying and assign.
Stream& operator=(const Stream&) = delete;
Stream(const Stream&) = delete;
};
inline FileIOError::FileIOError(const Stream& stream) : PvrError("[" + stream.getFileName() + "]: File IO operation failed") {}
inline FileIOError::FileIOError(const Stream& stream, std::string message) : PvrError("[" + stream.getFileName() + "] : File IO operation failed - " + message) {}
inline FileEOFError::FileEOFError(const Stream& stream) : PvrError("[" + stream.getFileName() + "]: File IO operation failed") {}
inline FileEOFError::FileEOFError(const Stream& stream, std::string message) : PvrError("[" + stream.getFileName() + "] : File IO operation failed - " + message) {}
inline FileNotFoundError::FileNotFoundError(const Stream& stream) : std::runtime_error("[" + stream.getFileName() + "]: File not found.") {}
inline FileNotFoundError::FileNotFoundError(const Stream& stream, std::string message) : std::runtime_error("[" + stream.getFileName() + "] : File not found - " + message) {}
} // namespace pvr