Browse Source

Add the option to reject paths from the filesystem

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
a658f77ac0

+ 2 - 0
AnKi/Resource/ConfigDefs.h

@@ -9,4 +9,6 @@ ANKI_CONFIG_OPTION(
 	rsrc_dataPaths, ".",
 	"The engine loads assets only in from these paths. Separate them with : (it's smart enough to identify drive "
 	"letters in Windows)")
+ANKI_CONFIG_OPTION(rsrc_dataPathExcludedStrings, "build",
+				   "A list of string separated by : that will be used to exclude paths from rsrc_dataPaths")
 ANKI_CONFIG_OPTION(rsrc_transferScratchMemorySize, 256_MB, 1_MB, 4_GB)

+ 49 - 26
AnKi/Resource/ResourceFilesystem.cpp

@@ -210,6 +210,9 @@ Error ResourceFilesystem::init(const ConfigSet& config, const CString& cacheDir)
 	StringListAuto paths(m_alloc);
 	paths.splitString(config.getString("rsrc_dataPaths"), ':');
 
+	StringListAuto excludedStrings(m_alloc);
+	excludedStrings.splitString(config.getString("rsrc_dataPathExcludedStrings"), ':');
+
 	// Workaround the fact that : is used in drives in Windows
 #if ANKI_OS_WINDOWS
 	StringListAuto paths2(m_alloc);
@@ -243,12 +246,12 @@ Error ResourceFilesystem::init(const ConfigSet& config, const CString& cacheDir)
 
 #if ANKI_OS_ANDROID
 	// Add the files of the .apk
-	ANKI_CHECK(addNewPath("*special*"));
+	ANKI_CHECK(addNewPath("*special*", excludedStrings));
 #endif
 
 	for(auto& path : paths)
 	{
-		ANKI_CHECK(addNewPath(path.toCString()));
+		ANKI_CHECK(addNewPath(path.toCString(), excludedStrings));
 	}
 
 	addCachePath(cacheDir);
@@ -265,11 +268,23 @@ void ResourceFilesystem::addCachePath(const CString& path)
 	m_paths.emplaceBack(m_alloc, std::move(p));
 }
 
-Error ResourceFilesystem::addNewPath(const CString& path)
+Error ResourceFilesystem::addNewPath(const CString& path, const StringListAuto& excludedStrings)
 {
 	U32 fileCount = 0;
 	static const CString extension(".ankizip");
 
+	auto rejectPath = [&](CString p) -> Bool {
+		for(const String& s : excludedStrings)
+		{
+			if(p.find(s) != CString::NPOS)
+			{
+				return true;
+			}
+		}
+
+		return false;
+	};
+
 	auto pos = path.find(extension);
 	if(pos != CString::NPOS && pos == path.getLength() - extension.getLength())
 	{
@@ -307,8 +322,8 @@ Error ResourceFilesystem::addNewPath(const CString& path)
 				return Error::FILE_ACCESS;
 			}
 
-			// If compressed size is zero then it's a dir
-			if(info.uncompressed_size > 0)
+			const Bool itsADir = info.uncompressed_size == 0;
+			if(!itsADir && !rejectPath(&filename[0]))
 			{
 				p.m_files.pushBackSprintf(m_alloc, "%s", &filename[0]);
 				++fileCount;
@@ -322,25 +337,37 @@ Error ResourceFilesystem::addNewPath(const CString& path)
 	{
 		// Android apk, read the file that contains the directory structure
 
+		// Read the file
 		File dirStructure;
 		ANKI_CHECK(dirStructure.open("DirStructure.txt", FileOpenFlag::READ | FileOpenFlag::SPECIAL));
-
 		StringAuto txt(m_alloc);
 		ANKI_CHECK(dirStructure.readAllText(txt));
 
-		m_paths.emplaceFront(m_alloc, Path());
-		Path& p = m_paths.getFront();
-		p.m_path.sprintf(m_alloc, "%s", &path[0]);
-		p.m_isArchive = false;
-		p.m_isSpecial = true;
-
-		p.m_files.splitString(m_alloc, txt, '\n');
+		StringListAuto filenames(m_alloc);
+		filenames.splitString(txt, '\n');
 
-		if(p.m_files.getSize() < 1)
+		if(filenames.isEmpty())
 		{
 			ANKI_RESOURCE_LOGE("DirStructure.txt is empty");
 			return Error::USER_DATA;
 		}
+
+		// Create the Path
+		m_paths.emplaceFront(m_alloc, Path());
+		Path& p = m_paths.getFront();
+		while(!filenames.isEmpty())
+		{
+			const String& filename = filenames.getFront();
+			if(!rejectPath(filename))
+			{
+				p.m_files.pushBack(m_alloc, filename);
+				++fileCount;
+			}
+		}
+
+		p.m_path.sprintf(m_alloc, "%s", &path[0]);
+		p.m_isArchive = false;
+		p.m_isSpecial = true;
 	}
 	else
 	{
@@ -351,25 +378,21 @@ Error ResourceFilesystem::addNewPath(const CString& path)
 		p.m_path.sprintf(m_alloc, "%s", &path[0]);
 		p.m_isArchive = false;
 
-		struct UserData
-		{
-			ResourceFilesystem* m_sys;
-			U32* m_fileCount;
-		} ud{this, &fileCount};
-
-		ANKI_CHECK(walkDirectoryTree(path, &ud, [](const CString& fname, void* ud, Bool isDir) -> Error {
+		ANKI_CHECK(walkDirectoryTree(path, m_alloc, [&, this](const CString& fname, Bool isDir) -> Error {
 			if(isDir)
 			{
 				return Error::NONE;
 			}
 
-			UserData* udd = static_cast<UserData*>(ud);
-			ResourceFilesystem* self = udd->m_sys;
+			if(rejectPath(fname))
+			{
+				return Error::NONE;
+			}
 
-			Path& p = self->m_paths.getFront();
-			p.m_files.pushBackSprintf(self->m_alloc, "%s", fname.cstr());
+			Path& p = m_paths.getFront();
+			p.m_files.pushBackSprintf(m_alloc, "%s", fname.cstr());
 
-			++(*udd->m_fileCount);
+			++fileCount;
 			return Error::NONE;
 		}));
 

+ 1 - 1
AnKi/Resource/ResourceFilesystem.h

@@ -138,7 +138,7 @@ private:
 	String m_cacheDir;
 
 	/// Add a filesystem path or an archive. The path is read-only.
-	ANKI_USE_RESULT Error addNewPath(const CString& path);
+	ANKI_USE_RESULT Error addNewPath(const CString& path, const StringListAuto& excludedStrings);
 
 	void addCachePath(const CString& path);
 };

+ 21 - 7
AnKi/Util/Filesystem.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <AnKi/Util/String.h>
+#include <AnKi/Util/Function.h>
 
 namespace anki
 {
@@ -30,14 +31,27 @@ void getParentFilepath(const CString& filename, StringAuto& out);
 /// Return true if directory exists?
 Bool directoryExists(const CString& dir);
 
-/// Callback for the @ref walkDirectoryTree.
-/// @param filename The file or directory name.
-/// @param userData User data passed to walkDirectoryTree.
-/// @param isDirectory True if it's directory, false if it's regular file.
-using WalkDirectoryTreeCallback = Error (*)(const CString& filename, void* userData, Bool isDirectory);
+/// Walk a directory tree.
+/// @param dir The dir to walk.
+/// @param alloc An allocator for temp allocations.
+/// @param func A lambda. See code example on how to use it.
+/// Example:
+/// @code
+/// walkDirectoryTree("./path/to", alloc, [&, this](CString path, Bool isDir) {
+/// 	...
+/// 	return Error::NONE;
+/// });
+/// @endcode
+template<typename TFunc>
+ANKI_USE_RESULT Error walkDirectoryTree(const CString& dir, GenericMemoryPoolAllocator<U8> alloc, TFunc func)
+{
+	Error walkDirectoryTreeInternal(const CString& dir, const Function<Error(const CString&, Bool)>& callback);
 
-/// Walk a directory and it's subdirectories. Will walk and list all directories and files of a directory.
-ANKI_USE_RESULT Error walkDirectoryTree(const CString& dir, void* userData, WalkDirectoryTreeCallback callback);
+	Function<Error(const CString&, Bool)> f(alloc, func);
+	const Error err = walkDirectoryTreeInternal(dir, f);
+	f.destroy(alloc);
+	return err;
+}
 
 /// Equivalent to: rm -rf dir
 /// @param dir The directory to remove.

+ 4 - 7
AnKi/Util/FilesystemPosix.cpp

@@ -61,8 +61,7 @@ Bool directoryExists(const CString& filename)
 class WalkDirectoryTreeCallbackContext
 {
 public:
-	WalkDirectoryTreeCallback m_callback = nullptr;
-	void* m_userData = nullptr;
+	const Function<Error(const CString&, Bool)>* m_callback = nullptr;
 	U32 m_prefixLen;
 	Error m_err = {Error::NONE};
 };
@@ -95,15 +94,14 @@ static int walkDirectoryTreeCallback(const char* filepath, const struct stat* in
 			return 0;
 		}
 
-		ctx.m_err = ctx.m_callback(filepath + ctx.m_prefixLen, ctx.m_userData, isDir);
+		ctx.m_err = (*ctx.m_callback)(filepath + ctx.m_prefixLen, isDir);
 	}
 
 	return 0;
 }
 
-Error walkDirectoryTree(const CString& dir, void* userData, WalkDirectoryTreeCallback callback)
+Error walkDirectoryTreeInternal(const CString& dir, const Function<Error(const CString&, Bool)>& callback)
 {
-	ANKI_ASSERT(callback != nullptr);
 	ANKI_ASSERT(dir.getLength() > 0);
 	Error err = Error::NONE;
 
@@ -115,8 +113,7 @@ Error walkDirectoryTree(const CString& dir, void* userData, WalkDirectoryTreeCal
 	}
 
 	WalkDirectoryTreeCallbackContext& ctx = g_walkDirectoryTreeContext;
-	ctx.m_callback = callback;
-	ctx.m_userData = userData;
+	ctx.m_callback = &callback;
 	ctx.m_prefixLen = prefixLen;
 	ctx.m_err = Error::NONE;
 

+ 2 - 2
Tests/Resource/ResourceFilesystem.cpp

@@ -17,7 +17,7 @@ ANKI_TEST(Resource, ResourceFilesystem)
 	ResourceFilesystem fs(alloc);
 
 	{
-		ANKI_TEST_EXPECT_NO_ERR(fs.addNewPath("Tests/Data/Dir/../Dir/"));
+		ANKI_TEST_EXPECT_NO_ERR(fs.addNewPath("Tests/Data/Dir/../Dir/", StringListAuto(alloc)));
 		ResourceFilePtr file;
 		ANKI_TEST_EXPECT_NO_ERR(fs.openFile("subdir0/hello.txt", file));
 		StringAuto txt(alloc);
@@ -26,7 +26,7 @@ ANKI_TEST(Resource, ResourceFilesystem)
 	}
 
 	{
-		ANKI_TEST_EXPECT_NO_ERR(fs.addNewPath("./Tests/Data/Dir.AnKiZLibip"));
+		ANKI_TEST_EXPECT_NO_ERR(fs.addNewPath("./Tests/Data/Dir.AnKiZLibip", StringListAuto(alloc)));
 		ResourceFilePtr file;
 		ANKI_TEST_EXPECT_NO_ERR(fs.openFile("subdir0/hello.txt", file));
 		StringAuto txt(alloc);

+ 4 - 5
Tests/Util/Filesystem.cpp

@@ -102,8 +102,7 @@ ANKI_TEST(Util, WalkDir)
 	}
 
 	// Walk crnt dir
-	ANKI_TEST_EXPECT_NO_ERR(walkDirectoryTree("./data", &ctx, [](const CString& fname, void* ud, Bool isDir) -> Error {
-		Ctx& ctx = *static_cast<Ctx*>(ud);
+	ANKI_TEST_EXPECT_NO_ERR(walkDirectoryTree("./data", alloc, [&](const CString& fname, Bool isDir) -> Error {
 		for(U32 i = 0; i < ctx.m_paths.getSize(); ++i)
 		{
 			StringAuto p(ctx.m_alloc);
@@ -122,9 +121,9 @@ ANKI_TEST(Util, WalkDir)
 
 	// Test error
 	U32 count = 0;
-	ANKI_TEST_EXPECT_ERR(walkDirectoryTree("./data///dir////", &count,
-										   [](const CString& fname, void* pCount, Bool isDir) -> Error {
-											   ++(*static_cast<U32*>(pCount));
+	ANKI_TEST_EXPECT_ERR(walkDirectoryTree("./data///dir////", alloc,
+										   [&count](const CString& fname, Bool isDir) -> Error {
+											   ++count;
 											   return Error::FUNCTION_FAILED;
 										   }),
 						 Error::FUNCTION_FAILED);

+ 25 - 0
Tests/Util/Function.cpp

@@ -7,6 +7,16 @@
 #include <Tests/Util/Foo.h>
 #include <AnKi/Util/Function.h>
 
+namespace anki
+{
+
+static I32 functionAcceptingFunction(const Function<I32(F32)>& f)
+{
+	return f(1.0f) + f(2.0f);
+}
+
+} // end namespace anki
+
 ANKI_TEST(Util, Function)
 {
 	HeapAllocator<U8> alloc(allocAligned, nullptr);
@@ -29,6 +39,21 @@ ANKI_TEST(Util, Function)
 		f.destroy(alloc);
 	}
 
+	// No templates
+	{
+		F32 f = 1.1f;
+
+		Function<I32(F32)> func(alloc, [&f](F32 ff) {
+			f += 2.0f;
+			return I32(f) + I32(ff);
+		});
+
+		const I32 o = functionAcceptingFunction(func);
+		func.destroy(alloc);
+
+		ANKI_TEST_EXPECT_EQ(o, 11);
+	}
+
 	// Allocated
 	{
 		const Vec4 a(1.9f);