Browse Source

Added DirectoryReader.

Бранимир Караџић 6 years ago
parent
commit
0c9fa3de50
3 changed files with 213 additions and 30 deletions
  1. 34 7
      include/bx/file.h
  2. 163 8
      src/file.cpp
  3. 16 15
      src/filepath.cpp

+ 34 - 7
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
 		};
+	};
+
+	///
+	struct FileInfo
+	{
+		FilePath filePath;
+		uint64_t size;
+		FileType::Enum type;
+	};
+
+	///
+	class DirectoryReader : public ReaderOpenI, public CloserI, public ReaderI
+	{
+	public:
+		///
+		DirectoryReader();
 
-		uint64_t m_size;
-		Enum m_type;
+		///
+		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(const FilePath& _filePath, FileInfo& _outFileInfo);
+	bool stat(FileInfo& _outFileInfo, const FilePath& _filePath);
 
 } // namespace bx
 

+ 163 - 8
src/file.cpp

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

+ 16 - 15
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;