summaryrefslogtreecommitdiff
path: root/source/modules/asura-utils/IO/File.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/modules/asura-utils/IO/File.cpp')
-rw-r--r--source/modules/asura-utils/IO/File.cpp294
1 files changed, 294 insertions, 0 deletions
diff --git a/source/modules/asura-utils/IO/File.cpp b/source/modules/asura-utils/IO/File.cpp
new file mode 100644
index 0000000..6d5f4eb
--- /dev/null
+++ b/source/modules/asura-utils/IO/File.cpp
@@ -0,0 +1,294 @@
+#include <physfs/physfs.h>
+
+#include <asura-utils/Exceptions/Exception.h>
+
+#include "File.h"
+
+namespace AsuraEngine
+{
+ namespace IO
+ {
+
+ 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