Merge branch '6-abstract-filesystem' into dev
This commit is contained in:
commit
afc1491718
4 changed files with 275 additions and 40 deletions
|
|
@ -2,12 +2,115 @@
|
||||||
#ifndef SPECTRE_SYSTEM_FILE_H
|
#ifndef SPECTRE_SYSTEM_FILE_H
|
||||||
#define SPECTRE_SYSTEM_FILE_H
|
#define SPECTRE_SYSTEM_FILE_H
|
||||||
|
|
||||||
#include <vector>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
namespace sp { namespace file
|
namespace sp {
|
||||||
|
|
||||||
|
class File
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> read(const std::string& path);
|
public :
|
||||||
} }
|
|
||||||
|
enum struct Access {
|
||||||
|
READ = 1 << 0,
|
||||||
|
WRITE = 1 << 1,
|
||||||
|
READ_WRITE = READ | WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: These are ignored atm. as implementation uses stdio.h
|
||||||
|
enum OpenMode {
|
||||||
|
// Only open if file exists and
|
||||||
|
// in overwrite mode if write is enabled.
|
||||||
|
DEFAULT = 0,
|
||||||
|
// Create file if it does not exist (ignored in read-only mode)
|
||||||
|
CREATE = 1 << 0,
|
||||||
|
// If file exists any write calls will
|
||||||
|
// append to the file. (ignored in read-only mode)
|
||||||
|
APPEND = 1 << 1,
|
||||||
|
// If file exists it's content are discarded
|
||||||
|
// resulting in an empty file. (ignored in read-only mode)
|
||||||
|
TRUNCATE = 1 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Methods.
|
||||||
|
public :
|
||||||
|
File();
|
||||||
|
|
||||||
|
// see `open()`
|
||||||
|
File(const std::string& filename,
|
||||||
|
Access access = Access::READ,
|
||||||
|
unsigned int mode = DEFAULT);
|
||||||
|
|
||||||
|
~File();
|
||||||
|
|
||||||
|
// Opens a file (default in read-only)
|
||||||
|
bool open(const std::string& filename,
|
||||||
|
Access access = Access::READ,
|
||||||
|
unsigned int mode = DEFAULT);
|
||||||
|
|
||||||
|
// Returns true if the file is open, false otherwise.
|
||||||
|
bool isOpen() const;
|
||||||
|
|
||||||
|
// Close the file.
|
||||||
|
void close();
|
||||||
|
|
||||||
|
std::string getErrorMessage() const;
|
||||||
|
|
||||||
|
// Get the current position in the file.
|
||||||
|
size_t pos();
|
||||||
|
|
||||||
|
// Set the file stream position.
|
||||||
|
// if `from_end` is true. `offset` will be applied from the end of file, otherwise from beginning.
|
||||||
|
// Returns true if the position was updated, false otherwise.
|
||||||
|
bool set(long int pos = 0, bool from_end = false);
|
||||||
|
|
||||||
|
// Move the current file stream position with `offset` bytes.
|
||||||
|
// This is equivalent to calling set(pos() + offset)
|
||||||
|
// Returns true if the position was updated, false otherwise.
|
||||||
|
bool seek(long int offset);
|
||||||
|
|
||||||
|
// Get the size of the file (in bytes)
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
// Read `size` data from file at the current position.
|
||||||
|
// Content is stored in `ptr` and must be alteast `size` bytes.
|
||||||
|
// Returns -1 if an error occured. Otherwice the number of bytes read is returned.
|
||||||
|
size_t read(void *ptr, size_t size);
|
||||||
|
|
||||||
|
// Read all remaining data from file at the current position. Content is stored in `buffer`.
|
||||||
|
// Returns true if exactly all data could be read from file. false otherwise.
|
||||||
|
template <typename buffer_t>
|
||||||
|
inline bool read(buffer_t& buffer)
|
||||||
|
{
|
||||||
|
size_t s = size();
|
||||||
|
buffer.resize(s);
|
||||||
|
return read((void*) &buffer[0], s) == s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data to file at the current position.
|
||||||
|
// Returns -1 if an error occured. Otherwice the number of bytes written is returned.
|
||||||
|
size_t write(const void *ptr, size_t size);
|
||||||
|
|
||||||
|
// Write data to file at the current position.
|
||||||
|
// Returns true if exactly all data could be written from `buffer`. false otherwise.
|
||||||
|
template <typename buffer_t>
|
||||||
|
inline bool write(const buffer_t& buffer)
|
||||||
|
{
|
||||||
|
return write((const void*) &buffer[0], buffer.size()) == buffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush any buffered data to the file.
|
||||||
|
bool flush();
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
FILE *m_handle;
|
||||||
|
|
||||||
|
// Error
|
||||||
|
mutable std::error_condition m_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace sp
|
||||||
|
|
||||||
#endif /* SPECTRE_SYSTEM_FILE_H */
|
#endif /* SPECTRE_SYSTEM_FILE_H */
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
|
|
||||||
|
#include <Spectre/System/File.h>
|
||||||
#include <Spectre/System/Path.h>
|
#include <Spectre/System/Path.h>
|
||||||
#include <Spectre/System/Log.h>
|
#include <Spectre/System/Log.h>
|
||||||
#include <Spectre/Graphics/Image.h>
|
#include <Spectre/Graphics/Image.h>
|
||||||
|
|
@ -18,22 +19,17 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace sp {
|
namespace sp {
|
||||||
|
|
||||||
bool ImageLoader::loadFromFile(const char *filename, Image& img)
|
bool ImageLoader::loadFromFile(const char *filename, Image& img)
|
||||||
{
|
{
|
||||||
FILE *fd = fopen(filename, "rb");
|
File file(filename);
|
||||||
|
|
||||||
if (fd) {
|
if (file.isOpen()) {
|
||||||
std::vector<unsigned char> buf;
|
std::vector<unsigned char> buf;
|
||||||
fseek(fd, 0, SEEK_END);
|
file.read(buf);
|
||||||
buf.resize(ftell(fd));
|
|
||||||
rewind(fd);
|
|
||||||
fread(&buf[0], 1, buf.size(), fd);
|
|
||||||
fclose(fd);
|
|
||||||
|
|
||||||
if (loadFromMemory(&buf[0], buf.size(), img) == false) {
|
if (loadFromMemory(&buf[0], buf.size(), img) == false) {
|
||||||
Log::warn("ImageLoader: could not load file '%s'. Reason: %s",
|
Log::warn("ImageLoader: could not load file '%s'. Reason: %s",
|
||||||
|
|
@ -44,7 +40,7 @@ bool ImageLoader::loadFromFile(const char *filename, Image& img)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::warn("ImageLoader: could not open file '%s'. Reason: %s",
|
Log::warn("ImageLoader: could not open file '%s'. Reason: %s",
|
||||||
filename, strerror(errno));
|
filename, file.getErrorMessage().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,10 +87,9 @@ bool ImageLoader::saveToFile(const Image& img, const char *filename)
|
||||||
|
|
||||||
if (encoded_data.size() > 0) {
|
if (encoded_data.size() > 0) {
|
||||||
|
|
||||||
FILE *fd = fopen(filename, "wb");
|
File file(filename, File::Access::WRITE);
|
||||||
if (fd) {
|
if (file.isOpen()) {
|
||||||
fwrite(&encoded_data[0], 1, encoded_data.size(), fd);
|
file.write(encoded_data);
|
||||||
fclose(fd);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <Spectre/System/Path.h>
|
#include <Spectre/System/Path.h>
|
||||||
|
#include <Spectre/System/File.h>
|
||||||
#include <Spectre/Graphics/Shader.h>
|
#include <Spectre/Graphics/Shader.h>
|
||||||
#include <Graphics/GL/gl.h>
|
#include <Graphics/GL/gl.h>
|
||||||
|
|
||||||
|
|
@ -30,26 +30,26 @@ const std::string& Shader::getName() const
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::loadFromFile(const std::string& file)
|
bool Shader::loadFromFile(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::string src;
|
std::string src;
|
||||||
std::ifstream strm;
|
File file;
|
||||||
|
|
||||||
// If this shader does not have a name, pick the filename.
|
// If this shader does not have a name, pick the filename.
|
||||||
if (m_name.length() < 1) {
|
if (m_name.length() < 1) {
|
||||||
m_name = Path::getBasename(file);
|
m_name = Path::getBasename(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load file into memory.
|
if (!file.open(filename)) {
|
||||||
strm.open(file.c_str(), std::fstream::in);
|
m_error = "Can't open file: " + filename;
|
||||||
if (!strm.is_open()) {
|
|
||||||
m_error = "Can't open file: " + file;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
src.assign(std::istreambuf_iterator<char>(strm), std::istreambuf_iterator<char>());
|
// Load file into memory.
|
||||||
|
if (!file.read(src)) {
|
||||||
strm.close();
|
m_error = "Could not read file: " + filename;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return loadFromMemory(src);
|
return loadFromMemory(src);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,159 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <system_error>
|
||||||
#include <Spectre/System/File.h>
|
#include <Spectre/System/File.h>
|
||||||
|
|
||||||
namespace sp { namespace file
|
namespace sp {
|
||||||
|
|
||||||
|
File::File() :
|
||||||
|
m_handle (NULL)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> read(const std::string& path) {
|
|
||||||
|
|
||||||
std::vector<unsigned char> buf;
|
|
||||||
FILE *fd = fopen(path.c_str(), "rb");
|
|
||||||
|
|
||||||
if (fd) {
|
|
||||||
fseek(fd, 0, SEEK_END);
|
|
||||||
buf.resize(ftell(fd));
|
|
||||||
rewind(fd);
|
|
||||||
fread(&buf[0], 1, buf.size(), fd);
|
|
||||||
fclose(fd);
|
|
||||||
}
|
}
|
||||||
return buf;
|
|
||||||
|
File::File(const std::string& filename, Access access, unsigned int mode) :
|
||||||
|
m_handle (NULL)
|
||||||
|
{
|
||||||
|
open(filename, access, mode);
|
||||||
}
|
}
|
||||||
} } // namespace sp::file
|
|
||||||
|
File::~File()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::open(const std::string& filename, Access access, unsigned int mode)
|
||||||
|
{
|
||||||
|
std::string m;
|
||||||
|
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (access == Access::READ) {
|
||||||
|
m = "rb";
|
||||||
|
} else if (access == Access::WRITE) {
|
||||||
|
if (mode & TRUNCATE) {
|
||||||
|
m = "wb";
|
||||||
|
} else {
|
||||||
|
// NOTE: this is append mode. but stdio does only
|
||||||
|
// have "a" and "w". and "w" will truncate.
|
||||||
|
// So we need to handle append with fseek() later.
|
||||||
|
m = "ab";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read + Write
|
||||||
|
else if (mode & TRUNCATE) {
|
||||||
|
m = "wb+";
|
||||||
|
} else if (mode & APPEND) {
|
||||||
|
m = "ab+";
|
||||||
|
} else {
|
||||||
|
m = "rb+";
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK. stdio does not have a mode for strictly create new files
|
||||||
|
// independant of access (read/write). So we will fake it by open the
|
||||||
|
// file in append mode and close it. creating the file if did not exist.
|
||||||
|
if (mode & CREATE && (access == Access::WRITE || access == Access::READ_WRITE)) {
|
||||||
|
m_handle = fopen(filename.c_str(), "a");
|
||||||
|
if (!m_handle) {
|
||||||
|
m_error.assign(errno, std::generic_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fclose(m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_handle = fopen(filename.c_str(), m.c_str());
|
||||||
|
|
||||||
|
if (m_handle) {
|
||||||
|
|
||||||
|
// Hack, if we opened the file in "a" mode, but did not
|
||||||
|
// have the append flag. seek to the beginning.
|
||||||
|
if (m == "ab" && mode & ~APPEND) {
|
||||||
|
fseek(m_handle, 0, SEEK_SET);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_error.assign(errno, std::generic_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOpen() const
|
||||||
|
{
|
||||||
|
if (m_handle == NULL) {
|
||||||
|
m_error = std::errc::bad_file_descriptor;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::close()
|
||||||
|
{
|
||||||
|
if (m_handle) {
|
||||||
|
fclose(m_handle);
|
||||||
|
m_handle = NULL;
|
||||||
|
}
|
||||||
|
m_error.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string File::getErrorMessage() const
|
||||||
|
{
|
||||||
|
return m_error.message();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::pos()
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
return ftell(m_handle);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::set(long int offset, bool from_end)
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
return fseek(m_handle, offset, from_end ? SEEK_END : SEEK_SET) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::seek(long int offset)
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
return fseek(m_handle, offset, SEEK_CUR) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::size() const
|
||||||
|
{
|
||||||
|
size_t s = 0;
|
||||||
|
while(::getc(m_handle) != EOF) s++;
|
||||||
|
::rewind(m_handle);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::read(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
return fread(ptr, 1, size, m_handle);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::write(const void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
return fwrite(ptr, 1, size, m_handle);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::flush()
|
||||||
|
{
|
||||||
|
if (isOpen()) {
|
||||||
|
return fflush(m_handle) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sp
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue