174 lines
2.9 KiB
C++
174 lines
2.9 KiB
C++
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <system_error>
|
|
#include <Spectre/System/File.h>
|
|
|
|
namespace sp {
|
|
|
|
File::File() :
|
|
m_handle (NULL)
|
|
{
|
|
}
|
|
|
|
File::File(const std::string& filename, Access access, unsigned int mode) :
|
|
m_handle (NULL)
|
|
{
|
|
open(filename, access, mode);
|
|
}
|
|
|
|
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::readString(std::string &str)
|
|
{
|
|
if (isOpen()) {
|
|
for(;;) {
|
|
int c = ::getc(m_handle);
|
|
if (c == EOF || c == '\0') {
|
|
break;
|
|
}
|
|
str.push_back(c);
|
|
}
|
|
return str.length();
|
|
}
|
|
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
|