FileStream.h#

Parent directory (stream)

Streams that are created from files.

Includes#

Included By#

Namespaces#

Classes#

Source Code#

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

namespace pvr {
class FileStream : public Stream
{
protected:
    mutable FILE* _file;
    std::string _flags;
    bool _errorOnFileNotFound;

public:
    FileStream(const std::string& filePath, const std::string& flags, bool errorOnFileNotFound = true)
        : Stream(filePath, flags.find('r') != flags.npos || flags.find('+') != flags.npos,
              flags.find('w') != flags.npos || flags.find('a') != flags.npos || flags.find('+') != flags.npos, true),
          _file(NULL), _flags(flags), _errorOnFileNotFound(errorOnFileNotFound)
    {
        open();
    }

    ~FileStream() { close(); }

    static std::unique_ptr<Stream> createFileStream(const char* filename, const char* flags, bool errorOnFileNotFound = true)
    {
        auto stream = std::make_unique<FileStream>(filename, flags, errorOnFileNotFound);
        stream->open();
        return std::move(stream);
    }

    static std::unique_ptr<Stream> createFileStream(const std::string& filename, const char* flags, bool errorOnFileNotFound = true)
    {
        return createFileStream(filename.c_str(), flags, errorOnFileNotFound);
    }

private:
    virtual uint64_t _getPosition() const override
    {
        if (_file) { return static_cast<size_t>(ftell(_file)); }
        else
        {
            return 0;
        }
    }

    virtual uint64_t _getSize() const override
    {
        if (_file)
        {
            fseek(_file, 0L, SEEK_END);
            long fileSize = ftell(_file);
            fseek(_file, 0L, SEEK_SET);
            return static_cast<size_t>(fileSize);
        }
        else
        {
            return 0;
        }
    }
    virtual void _read(size_t elementSize, size_t numElements, void* buffer, size_t& dataRead) const override
    {
        dataRead = 0;
        if (!_file) { throw FileIOError(getFileName(), "[Filestream::read] Attempted to read empty stream."); }
        if (!_isReadable) { throw FileIOError(getFileName(), "[Filestream::read] Attempted to read non-readable stream."); }

        dataRead = fread(buffer, elementSize, numElements, _file);
        if (dataRead != numElements)
        {
            if (feof(_file) != 0) { throw FileEOFError(getFileName(), "[Filestream::read] Was attempting to read past the end of stream."); }
            else
            {
                throw FileIOError(getFileName(), "[Filestream::read] Unknown Error.");
            }
        }
    }

    virtual void _write(size_t elementSize, size_t numElements, const void* buffer, size_t& dataWritten) override
    {
        dataWritten = 0;
        if (!_file) { throw FileIOError(getFileName(), "[Filestream::read] Attempted to write an empty string."); }
        if (!_isWritable) { throw FileIOError(getFileName(), "[Filestream::read] Attempted to write a non-writable stream."); }
        dataWritten = fwrite(buffer, elementSize, numElements, _file);
        if (dataWritten != numElements)
        {
            if (feof(_file) != 0) { throw FileIOError(getFileName(), "[Filestream::write] Was attempting to write past the end of stream."); }
            else
            {
                throw FileIOError(getFileName(), "[Filestream::write] Unknown error");
            }
        }
    }

    virtual void _seek(long offset, SeekOrigin origin) const override
    {
        if (!_file)
        {
            if (offset) { throw FileIOError(getFileName(), "[FileStream::seek] Attempt to seek in empty stream."); }
        }
        else
        {
            if (fseek(_file, offset, static_cast<int>(origin)) != 0) { throw FileIOError(getFileName(), "[FileStream::seek] Attempt to seek  past the end of stream."); }
        }
    }

    void open()
    {
        if (_file) // If file exists, just reset it.
        { return seek(0, SeekOriginFromStart); } // open:
        if (_fileName.length() == 0 || _flags.length() == 0) { throw InvalidOperationError("[FileStream::open] Attempted to open a nonexistent file"); }

#ifdef _WIN32
#ifdef _UNICODE
        errno_t error = _wfopen_s(&_file, _fileName.c_str(), _flags.c_str());
#else
        errno_t error = fopen_s(&_file, _fileName.c_str(), _flags.c_str());
#endif
        if (error != 0)
        {
            if (_errorOnFileNotFound) { throw FileNotFoundError(_fileName, "[FileStream::open] Failed to open file."); }
            else
            {
                _isReadable = false;
                _isWritable = false;
                _isRandomAccess = false;
                _file = nullptr;
                return;
            }
        }
#else
        _file = fopen(_fileName.c_str(), _flags.c_str());
#endif

        if (!_file)
        {
            if (_errorOnFileNotFound) { throw FileNotFoundError(_fileName, "[FileStream::open] Failed to open file."); }
            else
            {
                _isReadable = false;
                _isWritable = false;
                _isRandomAccess = false;
                _file = nullptr;
                return;
            }
        }
    }

    void close()
    {
        if (_file && fclose(_file) == EOF) { throw FileIOError(getFileName(), "[FileStream::close] Failure closing file."); }
        _file = 0;
    }
};

} // namespace pvr