Browse Source

Added walkDirectory() on Windows

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
41980f4a09

+ 3 - 21
include/anki/util/String.h

@@ -60,8 +60,6 @@ ANKI_DEPLOY_TO_STRING(F64, "%f")
 /// A wrapper on top of C strings. Used mainly for safety.
 class CString
 {
-	friend class String; // For the secret constructor
-
 public:
 	using Char = char;
 
@@ -78,7 +76,6 @@ public:
 	/// Copy constructor.
 	CString(const CString& b)
 		: m_ptr(b.m_ptr)
-		, m_length(b.m_length)
 	{
 		checkInit();
 	}
@@ -87,7 +84,6 @@ public:
 	CString& operator=(const CString& b)
 	{
 		m_ptr = b.m_ptr;
-		m_length = b.m_length;
 		return *this;
 	}
 
@@ -198,12 +194,8 @@ public:
 	/// Get the string length.
 	U getLength() const
 	{
-		if(m_length == 0 && m_ptr != nullptr)
-		{
-			m_length = std::strlen(m_ptr);
-		}
-
-		return m_length;
+		checkInit();
+		return std::strlen(m_ptr);
 	}
 
 	PtrSize find(const CString& cstr, PtrSize position = 0) const
@@ -261,16 +253,6 @@ public:
 
 private:
 	const Char* m_ptr = nullptr;
-	mutable U32 m_length = 0;
-
-	/// Constructor for friends
-	CString(const Char* ptr, U32 length)
-		: m_ptr(ptr)
-		, m_length(length)
-	{
-		checkInit();
-		ANKI_ASSERT(std::strlen(ptr) == length);
-	}
 
 	void checkInit() const
 	{
@@ -475,7 +457,7 @@ public:
 	CStringType toCString() const
 	{
 		checkInit();
-		return CStringType(&m_data[0], getLength());
+		return CStringType(&m_data[0]);
 	}
 
 	/// Append another string to this one.

+ 120 - 3
src/util/FilesystemWindows.cpp

@@ -13,6 +13,11 @@
 
 namespace anki {
 
+#if !defined(MAX_PATH)
+static const U MAX_PATH = 1024 * 4;
+#endif
+static const U MAX_PATH_LEN = MAX_PATH - 1;
+
 //==============================================================================
 Bool fileExists(const CString& filename)
 {
@@ -35,14 +40,13 @@ Bool directoryExists(const CString& filename)
 Error removeDirectory(const CString& dirname)
 {
 	// For some reason dirname should be double null terminated
-	const U PATH_SIZE = 1024 * 2;
-	if(dirname.getLength() > PATH_SIZE - 2)
+	if(dirname.getLength() > MAX_PATH - 2)
 	{
 		ANKI_LOGE("Path too big");
 		return ErrorCode::FUNCTION_FAILED;
 	}
 
-	Array<char, PATH_SIZE> dirname2;
+	Array<char, MAX_PATH> dirname2;
 	memcpy(&dirname2[0], &dirname[0], dirname.getLength() + 1);
 	dirname2[dirname.getLength() + 1] = '\0';
 
@@ -106,4 +110,117 @@ Error getHomeDirectory(GenericMemoryPoolAllocator<U8> alloc, String& out)
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+static Error walkDirectoryTreeInternal(
+	const CString& dir,
+	void* userData,
+	WalkDirectoryTreeCallback callback,
+	U baseDirLen)
+{
+	// Append something to the path
+	if(dir.getLength() > MAX_PATH_LEN - 2)
+	{
+		ANKI_LOGE("Path too long");
+		return ErrorCode::FUNCTION_FAILED;
+	}
+
+	Array<char, MAX_PATH> dir2;
+	memcpy(&dir2[0], &dir[0], dir.getLength());
+	if(dir[dir.getLength() - 1] != '/')
+	{
+		dir2[dir.getLength() + 0] = '/';
+		dir2[dir.getLength() + 1] = '*';
+		dir2[dir.getLength() + 2] = '\0';
+	}
+	else
+	{
+		dir2[dir.getLength() + 0] = '*';
+		dir2[dir.getLength() + 1] = '\0';
+	}
+
+	// Find files
+	HANDLE handle = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA find;
+
+	handle = FindFirstFile(&dir2[0], &find);
+	if(handle == INVALID_HANDLE_VALUE)
+	{
+		ANKI_LOGE("FindFirstFile() failed");
+		return ErrorCode::FUNCTION_FAILED;
+	}
+
+	// Remove '*' from dir2
+	dir2[strlen(&dir2[0]) - 1] = '\0';
+
+	do
+	{
+		CString filename(find.cFileName);
+
+		if(filename != "." && filename != "..")
+		{
+			Bool isDir = find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+
+			// Compute new path
+			U oldLen = strlen(&dir2[0]);
+			if(oldLen + filename.getLength() > MAX_PATH_LEN)
+			{
+				ANKI_LOGE("Path too long");
+				return ErrorCode::FUNCTION_FAILED;
+			}
+
+			strcat(&dir2[0], &filename[0]);
+			Error err = callback(&dir2[0] + baseDirLen, userData, isDir);
+			if(err)
+			{
+				FindClose(handle);
+				return err;
+			}
+
+			// Move to next dir
+			if(isDir)
+			{
+				Error err = walkDirectoryTreeInternal(
+					&dir2[0], userData, callback, baseDirLen);
+				if(err)
+				{
+					FindClose(handle);
+					return err;
+				}
+			}
+
+			dir2[oldLen] = '\0';
+		}
+	}while(FindNextFile(handle, &find) != 0);
+
+	if(GetLastError() != ERROR_NO_MORE_FILES)
+	{
+		ANKI_LOGE("Unknown error");
+		FindClose(handle);
+		return ErrorCode::FUNCTION_FAILED;
+	}
+
+	FindClose(handle);
+	return ErrorCode::NONE;
+}
+
+Error walkDirectoryTree(
+	const CString& dir,
+	void* userData,
+	WalkDirectoryTreeCallback callback)
+{
+	U baseDirLen = 0;
+	U len = dir.getLength();
+	if(dir[len - 1] == '/')
+	{
+		baseDirLen = len;
+	}
+	else
+	{
+		baseDirLen = len + 1;
+	}
+
+	return walkDirectoryTreeInternal(dir, userData, callback, baseDirLen);
+}
+
+
 } // end namespace anki

+ 1 - 0
tests/data/dir/subdir1/subdir2/file.txt

@@ -0,0 +1 @@
+123

+ 2 - 2
tests/util/Filesystem.cpp

@@ -78,7 +78,7 @@ ANKI_TEST(Util, WalkDir)
 			return ErrorCode::NONE;
 		}));
 
-	ANKI_TEST_EXPECT_EQ(count, 2);
+	ANKI_TEST_EXPECT_EQ(count, 3);
 
 	// Walk again
 	count = 0;
@@ -91,7 +91,7 @@ ANKI_TEST(Util, WalkDir)
 			return ErrorCode::NONE;
 		}));
 
-	ANKI_TEST_EXPECT_EQ(count, 4);
+	ANKI_TEST_EXPECT_EQ(count, 6);
 
 	// Test error
 	count = 0;