Added DirectoryReader.

This commit is contained in:
Бранимир Караџић
2019-02-16 19:57:54 -08:00
parent 8397b518d6
commit 0c9fa3de50
3 changed files with 214 additions and 31 deletions

View File

@@ -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

View File

@@ -9,6 +9,7 @@
#if BX_CRT_NONE
# include "crt0.h"
#else
# include <dirent.h>
# include <stdio.h>
# include <sys/stat.h>
#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<int32_t>(_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<DirectoryReaderImpl*>(m_internal);
impl->~DirectoryReaderImpl();
}
bool DirectoryReader::open(const FilePath& _filePath, Error* _err)
{
DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
return impl->open(_filePath, _err);
}
void DirectoryReader::close()
{
DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(m_internal);
impl->close();
}
int32_t DirectoryReader::read(void* _data, int32_t _size, Error* _err)
{
DirectoryReaderImpl* impl = reinterpret_cast<DirectoryReaderImpl*>(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

View File

@@ -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;