1
0
Fork 0

Spectre/System/File: implement File class.

This commit is contained in:
Henrik Hautakoski 2020-01-15 19:49:44 +01:00
parent 1a218532c0
commit 624a979356
No known key found for this signature in database
GPG key ID: 96765B12FEAC4745
2 changed files with 236 additions and 16 deletions

View file

@ -2,12 +2,109 @@
#ifndef SPECTRE_SYSTEM_FILE_H
#define SPECTRE_SYSTEM_FILE_H
#include <vector>
#include <stdio.h>
#include <string>
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();
// 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;
};
} //namespace sp
#endif /* SPECTRE_SYSTEM_FILE_H */

View file

@ -3,20 +3,143 @@
#include <stdio.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");
File::File(const std::string& filename, Access access, unsigned int mode) :
m_handle (NULL)
{
open(filename, access, mode);
}
if (fd) {
fseek(fd, 0, SEEK_END);
buf.resize(ftell(fd));
rewind(fd);
fread(&buf[0], 1, buf.size(), fd);
fclose(fd);
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";
}
return buf;
}
} } // namespace sp::file
// 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) {
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;
}
return false;
}
bool File::isOpen() const
{
return m_handle != NULL;
}
void File::close()
{
if (m_handle) {
fclose(m_handle);
m_handle = NULL;
}
}
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