From 0c9fa3de50fe7d164faf1206d33731673d539db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 16 Feb 2019 19:57:54 -0800 Subject: [PATCH] Added DirectoryReader. --- include/bx/file.h | 43 +++++++++--- src/file.cpp | 171 +++++++++++++++++++++++++++++++++++++++++++--- src/filepath.cpp | 31 +++++---- 3 files changed, 214 insertions(+), 31 deletions(-) diff --git a/include/bx/file.h b/include/bx/file.h index 07e5db4..951c297 100644 --- a/include/bx/file.h +++ b/include/bx/file.h @@ -75,23 +75,50 @@ namespace bx BX_ALIGN_DECL(16, uint8_t) m_internal[64]; }; - /// - struct FileInfo + struct FileType { enum Enum { - Regular, - Directory, + File, + Dir, Count }; - - uint64_t m_size; - Enum m_type; }; /// - bool stat(const FilePath& _filePath, FileInfo& _outFileInfo); + struct FileInfo + { + FilePath filePath; + uint64_t size; + FileType::Enum type; + }; + + /// + class DirectoryReader : public ReaderOpenI, public CloserI, public ReaderI + { + public: + /// + DirectoryReader(); + + /// + virtual ~DirectoryReader(); + + /// + virtual bool open(const FilePath& _filePath, Error* _err) override; + + /// + virtual void close() override; + + /// + virtual int32_t read(void* _data, int32_t _size, Error* _err) override; + + private: + BX_ALIGN_DECL(16, uint8_t) m_internal[sizeof(FilePath)+sizeof(FileInfo)+16]; + }; + + /// + bool stat(FileInfo& _outFileInfo, const FilePath& _filePath); } // namespace bx diff --git a/src/file.cpp b/src/file.cpp index c8bb49e..39e6180 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -9,6 +9,7 @@ #if BX_CRT_NONE # include "crt0.h" #else +# include # include # include #endif // !BX_CRT_NONE @@ -553,14 +554,168 @@ namespace bx return impl->write(_data, _size, _err); } - bool stat(const FilePath& _filePath, FileInfo& _outFileInfo) + class DirectoryReaderImpl : public ReaderOpenI, public CloserI, public ReaderI + { + public: + /// + DirectoryReaderImpl(); + + /// + virtual ~DirectoryReaderImpl(); + + /// + virtual bool open(const FilePath& _filePath, Error* _err) override; + + /// + virtual void close() override; + + /// + virtual int32_t read(void* _data, int32_t _size, Error* _err) override; + + private: + FileInfo m_cache; + DIR* m_dir; + int32_t m_pos; + }; + + DirectoryReaderImpl::DirectoryReaderImpl() + : m_dir(NULL) + , m_pos(0) + { + } + + DirectoryReaderImpl::~DirectoryReaderImpl() + { + close(); + } + + static bool fetch(FileInfo& _out, DIR* _dir) + { + for (;;) + { + const dirent* item = readdir(_dir); + + if (NULL == item) + { + return false; + } + + if (0 != (item->d_type & DT_DIR) ) + { + _out.type = FileType::Dir; + _out.size = UINT64_MAX; + _out.filePath.set(item->d_name); + return true; + } + + if (0 != (item->d_type & DT_REG) ) + { + _out.type = FileType::File; + _out.size = UINT64_MAX; + _out.filePath.set(item->d_name); + return true; + } + } + + return false; + } + + bool DirectoryReaderImpl::open(const FilePath& _filePath, Error* _err) + { + BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); + + m_dir = opendir(_filePath.get() ); + + if (NULL == m_dir) + { + BX_ERROR_SET(_err, BX_ERROR_READERWRITER_OPEN, "DirectoryReader: Failed to open directory."); + return false; + } + + m_pos = 0; + + return true; + } + + void DirectoryReaderImpl::close() + { + if (NULL != m_dir) + { + closedir(m_dir); + m_dir = NULL; + } + } + + int32_t DirectoryReaderImpl::read(void* _data, int32_t _size, Error* _err) + { + BX_CHECK(NULL != _err, "Reader/Writer interface calling functions must handle errors."); + + int32_t total = 0; + + uint8_t* out = (uint8_t*)_data; + + for (; 0 < _size;) + { + if (0 == m_pos) + { + if (!fetch(m_cache, m_dir) ) + { + BX_ERROR_SET(_err, BX_ERROR_READERWRITER_EOF, "DirectoryReader: EOF."); + return total; + } + } + + const uint8_t* src = (const uint8_t*)&m_cache; + int32_t size = min(_size, sizeof(m_cache)-m_pos); + memCopy(&out[total], &src[m_pos], size); + total += size; + _size -= size; + + m_pos += size; + m_pos %= sizeof(m_cache); + } + + return total; + } + + DirectoryReader::DirectoryReader() + { + BX_STATIC_ASSERT(sizeof(DirectoryReaderImpl) <= sizeof(m_internal) ); + BX_PLACEMENT_NEW(m_internal, DirectoryReaderImpl); + } + + DirectoryReader::~DirectoryReader() + { + DirectoryReaderImpl* impl = reinterpret_cast(m_internal); + impl->~DirectoryReaderImpl(); + } + + bool DirectoryReader::open(const FilePath& _filePath, Error* _err) + { + DirectoryReaderImpl* impl = reinterpret_cast(m_internal); + return impl->open(_filePath, _err); + } + + void DirectoryReader::close() + { + DirectoryReaderImpl* impl = reinterpret_cast(m_internal); + impl->close(); + } + + int32_t DirectoryReader::read(void* _data, int32_t _size, Error* _err) + { + DirectoryReaderImpl* impl = reinterpret_cast(m_internal); + return impl->read(_data, _size, _err); + } + + bool stat(FileInfo& _outFileInfo, const FilePath& _filePath) { #if BX_CRT_NONE BX_UNUSED(_filePath, _outFileInfo); return false; #else - _outFileInfo.m_size = 0; - _outFileInfo.m_type = FileInfo::Count; + _outFileInfo.size = 0; + _outFileInfo.type = FileType::Count; # if BX_COMPILER_MSVC struct ::_stat64 st; @@ -573,11 +728,11 @@ namespace bx if (0 != (st.st_mode & _S_IFREG) ) { - _outFileInfo.m_type = FileInfo::Regular; + _outFileInfo.type = FileType::File; } else if (0 != (st.st_mode & _S_IFDIR) ) { - _outFileInfo.m_type = FileInfo::Directory; + _outFileInfo.type = FileType::Dir; } # else struct ::stat st; @@ -589,15 +744,15 @@ namespace bx if (0 != (st.st_mode & S_IFREG) ) { - _outFileInfo.m_type = FileInfo::Regular; + _outFileInfo.type = FileType::File; } else if (0 != (st.st_mode & S_IFDIR) ) { - _outFileInfo.m_type = FileInfo::Directory; + _outFileInfo.type = FileType::Dir; } # endif // BX_COMPILER_MSVC - _outFileInfo.m_size = st.st_size; + _outFileInfo.size = st.st_size; return true; #endif // BX_CRT_NONE diff --git a/src/filepath.cpp b/src/filepath.cpp index 0e88110..7d0d597 100644 --- a/src/filepath.cpp +++ b/src/filepath.cpp @@ -154,7 +154,7 @@ namespace bx return size; } - static bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name, FileInfo::Enum _type) + static bool getEnv(char* _out, uint32_t* _inOutSize, const StringView& _name, FileType::Enum _type) { uint32_t len = *_inOutSize; *_out = '\0'; @@ -162,8 +162,8 @@ namespace bx if (getEnv(_out, &len, _name) ) { FileInfo fi; - if (stat(_out, fi) - && _type == fi.m_type) + if (stat(fi, _out) + && _type == fi.type) { *_inOutSize = len; return true; @@ -204,9 +204,9 @@ namespace bx { return false #if BX_PLATFORM_WINDOWS - || getEnv(_out, _inOutSize, "USERPROFILE", FileInfo::Directory) + || getEnv(_out, _inOutSize, "USERPROFILE", FileType::Dir) #endif // BX_PLATFORM_WINDOWS - || getEnv(_out, _inOutSize, "HOME", FileInfo::Directory) + || getEnv(_out, _inOutSize, "HOME", FileType::Dir) ; } @@ -232,7 +232,7 @@ namespace bx { uint32_t len = *_inOutSize; *_out = '\0'; - bool ok = getEnv(_out, &len, *tmp, FileInfo::Directory); + bool ok = getEnv(_out, &len, *tmp, FileType::Dir); if (ok && len != 0 @@ -244,8 +244,8 @@ namespace bx } FileInfo fi; - if (stat("/tmp", fi) - && FileInfo::Directory == fi.m_type) + if (stat(fi, "/tmp") + && FileType::Dir == fi.type) { strCopy(_out, *_inOutSize, "/tmp"); *_inOutSize = 4; @@ -385,7 +385,8 @@ namespace bx const StringView fileName = getFileName(); if (!fileName.isEmpty() ) { - return strFind(fileName, '.'); + const StringView dot = strFind(fileName, '.'); + return StringView(dot.getPtr(), fileName.getTerm() ); } return StringView(); @@ -443,9 +444,9 @@ namespace bx FileInfo fi; - if (stat(_filePath, fi) ) + if (stat(fi, _filePath) ) { - if (FileInfo::Directory == fi.m_type) + if (FileType::Dir == fi.type) { return true; } @@ -482,9 +483,9 @@ namespace bx #if BX_CRT_MSVC int32_t result = -1; FileInfo fi; - if (stat(_filePath, fi) ) + if (stat(fi, _filePath) ) { - if (FileInfo::Directory == fi.m_type) + if (FileType::Dir == fi.type) { result = ::_rmdir(_filePath.get() ); } @@ -522,13 +523,13 @@ namespace bx FileInfo fi; - if (!stat(_filePath, fi) ) + if (!stat(fi, _filePath) ) { BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process."); return false; } - if (FileInfo::Directory != fi.m_type) + if (FileType::Dir != fi.type) { BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory."); return false;