diff options
Diffstat (limited to 'Source/modules/asura-base/FileSystem/File.cpp')
-rw-r--r-- | Source/modules/asura-base/FileSystem/File.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/Source/modules/asura-base/FileSystem/File.cpp b/Source/modules/asura-base/FileSystem/File.cpp new file mode 100644 index 0000000..ec8a9bf --- /dev/null +++ b/Source/modules/asura-base/FileSystem/File.cpp @@ -0,0 +1,294 @@ +#include <physfs/physfs.h> + +#include <asura-base/Exception.h> + +#include "File.h" + +namespace AsuraEngine +{ + namespace FileSystem + { + + File::File(const std::string& filename) + : m_FileName(filename) + , m_FileHandle(nullptr) + , m_Mode(FILE_MODE_CLOSED) + , m_BufferMode(BUFFER_MODE_NONE) + , m_BufferSize(0) + { + size_t dot = filename.rfind('.'); + if (dot != std::string::npos) + { + m_Extension = filename.substr(dot + 1); + m_Name = filename.substr(0, dot); + } + else + m_Name = filename; + } + + File::~File() + { + if (m_Mode != FILE_MODE_CLOSED) + Close(); + } + + bool File::Open(FileMode mode) + { + if (!PHYSFS_isInit()) + throw Exception("Physfs is NOT initialized."); + + if (mode == FILE_MODE_CLOSED) + return false; + + if (mode == FILE_MODE_READ && !PHYSFS_exists(m_FileName.c_str())) + throw Exception("Could NOT open file %s. Does not exist.", m_FileName.c_str()); + + if (mode == FILE_MODE_APPEND || mode == FILE_MODE_WRITE) + { + if (!PHYSFS_getWriteDir()) + { + throw Exception("Could NOT set write directory."); + } + } + + // Ѿ֮ǰͲٴµhandle + if (m_FileHandle != nullptr) + return true; + + PHYSFS_getLastErrorCode(); + + PHYSFS_File* handle = nullptr; + + switch (mode) + { + case FILE_MODE_READ: + handle = PHYSFS_openRead(m_FileName.c_str()); + break; + case FILE_MODE_APPEND: + handle = PHYSFS_openAppend(m_FileName.c_str()); + break; + case FILE_MODE_WRITE: + handle = PHYSFS_openWrite(m_FileName.c_str()); + break; + } + + if (handle == nullptr) + { + const char *err = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()); + if (err == nullptr) + err = "unknown error"; + throw Exception("Could not open file %s (%s)", m_FileName.c_str(), err); + } + + m_FileHandle = handle; + m_Mode = mode; + + if (m_FileHandle && !SetBuffer(m_BufferMode,m_BufferSize)) + { + m_BufferMode = BUFFER_MODE_NONE; + m_BufferSize = 0; + } + + return m_FileHandle != nullptr; + } + + bool File::Close() + { + if (m_FileHandle == nullptr || !PHYSFS_close(m_FileHandle)) + return false; + m_Mode = FILE_MODE_CLOSED; + m_FileHandle = nullptr; + return true; + } + + bool File::IsOpen() + { + return m_Mode != FILE_MODE_CLOSED && m_FileHandle != nullptr; + } + + size_t File::GetSize() + { + if (m_FileHandle == nullptr) + { + Open(FILE_MODE_READ); + size_t size = PHYSFS_fileLength(m_FileHandle); + Close(); + return size; + } + return PHYSFS_fileLength(m_FileHandle); + } + + size_t File::Read(ASURA_OUT DataBuffer* dst, size_t length) + { + ASSERT(dst); + + if (dst->GetCapacity() < length) + throw Exception("Data buffer is too small compares to read length."); + + if (!m_FileHandle || m_Mode != FILE_MODE_READ) + throw Exception("File \"%s\" is not opened for reading", m_FileName); + + size_t max = PHYSFS_fileLength(m_FileHandle); + length = (length > max) ? max : length; + + if (length < 0) + throw Exception("Invalid read size."); + + dst->Lock(); + size_t size = PHYSFS_readBytes(m_FileHandle, dst->GetData(), length); + dst->Unlock(); + return size; + } + + size_t File::ReadAll(ASURA_OUT DataBuffer* dst) + { + ASSERT(dst); + + if (!m_FileHandle || m_Mode != FILE_MODE_READ) + throw Exception("File \"%s\" is not opened for reading", m_FileName); + + size_t length = PHYSFS_fileLength(m_FileHandle); + + if (dst->GetCapacity() < length) + throw Exception("Data buffer is too small compares to file length."); + + dst->Lock(); + byte* data = dst->GetData(); + size_t size = PHYSFS_readBytes(m_FileHandle, data, length); + dst->Move(data, length); + dst->Unlock(); + return size; + } + +#ifdef ASURA_WINDOWS + inline bool test_eof(File *that, PHYSFS_File *) + { + int64 pos = that->Tell(); + int64 size = that->GetSize(); + return pos == -1 || size == -1 || pos >= size; + } +#else + inline bool test_eof(File *, PHYSFS_File *file) + { + return PHYSFS_eof(file); + } +#endif + + bool File::IsEOF() + { + return m_FileHandle == nullptr || test_eof(this, m_FileHandle); + } + + size_t File::Tell() + { + if (!m_FileHandle) + return - 1; + + return PHYSFS_tell(m_FileHandle); + } + + bool File::Seek(size_t pos) + { + return m_FileHandle != nullptr && PHYSFS_seek(m_FileHandle, pos) != 0; + } + + bool File::Write(ASURA_REF DataBuffer* src) + { + if (!m_FileHandle || (m_Mode != FILE_MODE_APPEND && m_Mode != FILE_MODE_WRITE)) + throw Exception("File is not opened for writing."); + + byte* data = src->GetData(); + int size = src->GetSize(); + + if (size < 0) + throw Exception("Invalid write size."); + + size_t written = PHYSFS_writeBytes(m_FileHandle, data, size); + + if (written != src->GetSize()) + return false; + + // л + if (m_BufferSize == BUFFER_MODE_LINE && m_BufferSize > size) + { + if (memchr(data, '\n', size) != nullptr) + Flush(); + } + + return true; + } + + bool File::Flush() + { + if (!m_FileHandle || (m_Mode != FILE_MODE_WRITE && m_Mode != FILE_MODE_APPEND)) + throw Exception("File is not opened for writing."); + + return PHYSFS_flush(m_FileHandle) != 0; + } + + bool File::SetBuffer(BufferMode mode, size_t size) + { + if (size < 0) + return false; + + // If the file isn't open, we'll make sure the buffer values are set in + // File::open. + if (!IsOpen()) + { + m_BufferMode = mode; + m_BufferSize = size; + return true; + } + + int ret = 1; + + switch (mode) + { + case BUFFER_MODE_NONE: + default: + ret = PHYSFS_setBuffer(m_FileHandle, 0); + size = 0; + break; + case BUFFER_MODE_LINE: + case BUFFER_MODE_FULL: + ret = PHYSFS_setBuffer(m_FileHandle, size); + break; + } + + if (ret == 0) + return false; + + m_BufferMode = mode; + m_BufferSize = size; + + return true; + } + + File::BufferMode File::GetBuffer(ASURA_OUT size_t& size) + { + size = m_BufferSize; + return m_BufferMode; + } + + const std::string& File::GetFileName() + { + return m_FileName; + } + + const std::string& File::GetName() + { + return m_Name; + } + + const std::string& File::GetExtension() + { + return m_Extension; + } + + File::FileMode File::GetMode() + { + return m_Mode; + } + + } +}
\ No newline at end of file |