Jelajahi Sumber

Custom FileSystem class, removed boost dependency on filesystem

Marko Pintera 11 tahun lalu
induk
melakukan
902e9bc4eb

+ 1 - 1
CamelotUtility/CamelotUtility.vcxproj

@@ -264,6 +264,7 @@
     <ClCompile Include="Source\CmSphere.cpp" />
     <ClCompile Include="Source\CmSphere.cpp" />
     <ClCompile Include="Source\CmStringTable.cpp" />
     <ClCompile Include="Source\CmStringTable.cpp" />
     <ClCompile Include="Source\CmTexAtlasGenerator.cpp" />
     <ClCompile Include="Source\CmTexAtlasGenerator.cpp" />
+    <ClCompile Include="Source\Win32\CmFileSystem.cpp" />
     <ClCompile Include="Source\Win32\CmTimer.cpp" />
     <ClCompile Include="Source\Win32\CmTimer.cpp" />
     <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsEvent.h" />
     <ClInclude Include="Include\BsEvent.h" />
@@ -329,7 +330,6 @@
     <ClInclude Include="Include\CmDataStream.h" />
     <ClInclude Include="Include\CmDataStream.h" />
     <ClCompile Include="Source\CmBinarySerializer.cpp" />
     <ClCompile Include="Source\CmBinarySerializer.cpp" />
     <ClCompile Include="Source\CmFileSerializer.cpp" />
     <ClCompile Include="Source\CmFileSerializer.cpp" />
-    <ClCompile Include="Source\CmFileSystem.cpp" />
     <ClCompile Include="Source\CmIReflectable.cpp" />
     <ClCompile Include="Source\CmIReflectable.cpp" />
     <ClCompile Include="Source\CmRTTIField.cpp" />
     <ClCompile Include="Source\CmRTTIField.cpp" />
     <ClCompile Include="Source\CmRTTIType.cpp" />
     <ClCompile Include="Source\CmRTTIType.cpp" />

+ 3 - 3
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -305,9 +305,6 @@
     <ClCompile Include="Source\CmIReflectable.cpp">
     <ClCompile Include="Source\CmIReflectable.cpp">
       <Filter>Source Files\RTTI</Filter>
       <Filter>Source Files\RTTI</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="Source\CmFileSystem.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="Source\CmTime.cpp">
     <ClCompile Include="Source\CmTime.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
@@ -377,5 +374,8 @@
     <ClCompile Include="Source\BsTaskScheduler.cpp">
     <ClCompile Include="Source\BsTaskScheduler.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\Win32\CmFileSystem.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 1 - 2
CamelotUtility/Include/CmTimer.h

@@ -2,7 +2,6 @@
 
 
 #include "CmPrerequisitesUtil.h"
 #include "CmPrerequisitesUtil.h"
 
 
-//Bring in the specific platform's header file
 #if CM_PLATFORM == CM_PLATFORM_WIN32
 #if CM_PLATFORM == CM_PLATFORM_WIN32
-# include "Win32/CmTimerImp.h"
+#include "Win32/CmTimerImp.h"
 #endif
 #endif

+ 0 - 178
CamelotUtility/Source/CmFileSystem.cpp

@@ -1,178 +0,0 @@
-#include "CmFileSystem.h"
-#include "CmDataStream.h"
-#include "CmPath.h"
-#include "CmException.h"
-#include "CmDebug.h"
-
-#include <boost/filesystem.hpp>
-
-using namespace boost::filesystem3;
-
-namespace BansheeEngine
-{
-	DataStreamPtr FileSystem::openFile(const Path& fullPath, bool readOnly)
-	{
-		UINT64 fileSize = getFileSize(fullPath);
-
-		// Always open in binary mode
-		// Also, always include reading
-		std::ios::openmode mode = std::ios::in | std::ios::binary;
-		std::shared_ptr<std::istream> baseStream = 0;
-		std::shared_ptr<std::ifstream> roStream = 0;
-		std::shared_ptr<std::fstream> rwStream = 0;
-
-		if (!readOnly)
-		{
-			mode |= std::ios::out;
-			rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
-			rwStream->open(fullPath.toWString().c_str(), mode);
-			baseStream = rwStream;
-		}
-		else
-		{
-			roStream = cm_shared_ptr<std::ifstream, ScratchAlloc>();
-			roStream->open(fullPath.toWString().c_str(), mode);
-			baseStream = roStream;
-		}
-
-		// Should check ensure open succeeded, in case fail for some reason.
-		if (baseStream->fail())
-			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + fullPath.toString());
-
-		/// Construct return stream, tell it to delete on destroy
-		FileDataStream* stream = 0;
-		if (rwStream)
-		{
-			// use the writeable stream 
-			stream = cm_new<FileDataStream, ScratchAlloc>(rwStream, (size_t)fileSize, true);
-		}
-		else
-		{
-			// read-only stream
-			stream = cm_new<FileDataStream, ScratchAlloc>(roStream, (size_t)fileSize, true);
-		}
-		return cm_shared_ptr<FileDataStream, ScratchAlloc>(stream);
-	}
-
-	DataStreamPtr FileSystem::createAndOpenFile(const Path& fullPath)
-	{
-		// Always open in binary mode
-		// Also, always include reading
-		std::ios::openmode mode = std::ios::out | std::ios::binary;
-		std::shared_ptr<std::fstream> rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
-		rwStream->open(fullPath.toWString().c_str(), mode);
-
-		// Should check ensure open succeeded, in case fail for some reason.
-		if (rwStream->fail())
-			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + fullPath.toString());
-
-		/// Construct return stream, tell it to delete on destroy
-		return cm_shared_ptr<FileDataStream, ScratchAlloc>(rwStream, 0, true);
-	}
-
-	UINT64 FileSystem::getFileSize(const Path& fullPath)
-	{
-		return file_size(fullPath.toWString().c_str());
-	}
-
-	void FileSystem::remove(const Path& fullPath, bool recursively)
-	{
-		if(recursively)
-			boost::filesystem3::remove_all(fullPath.toWString().c_str());
-		else
-			boost::filesystem3::remove(fullPath.toWString().c_str());
-	}
-
-	void FileSystem::move(const Path& oldPath, const Path& newPath, bool overwriteExisting)
-	{
-		boost::filesystem3::path oldPathInternal = oldPath.toWString().c_str();
-		boost::filesystem3::path newPathInternal = newPath.toWString().c_str();
-
-		if(boost::filesystem3::exists(newPathInternal))
-		{
-			if(overwriteExisting)
-				boost::filesystem3::remove_all(newPathInternal);
-			else
-			{
-				CM_EXCEPT(InvalidStateException, "Move operation failed because another file already exists at the new path: \"" + toString(WString(newPathInternal.c_str())) + "\"");
-			}
-		}
-
-		boost::filesystem3::rename(oldPathInternal, newPathInternal);
-	}
-
-	bool FileSystem::exists(const Path& fullPath)
-	{
-		return boost::filesystem3::exists(fullPath.toWString().c_str());
-	}
-
-	bool FileSystem::isFile(const Path& fullPath)
-	{
-		if (boost::filesystem3::exists(fullPath.toWString().c_str()) && !is_directory(fullPath.toWString().c_str()))
-			return true;
-
-		return false;
-	}
-
-	bool FileSystem::isDirectory(const Path& fullPath)
-	{
-		if (boost::filesystem3::exists(fullPath.toWString().c_str()) && is_directory(fullPath.toWString().c_str()))
-			return true;
-
-		return false;
-	}
-
-	void FileSystem::createDir(const Path& fullPath)
-	{
-		boost::filesystem3::path fullPathInternal = fullPath.toWString().c_str();
-		if(fullPathInternal.empty())
-			return;
-
-		boost::filesystem3::path parentPath = fullPathInternal;
-		auto pathEnd = fullPathInternal.end();
-
-		while(!boost::filesystem3::exists(parentPath))
-		{
-			if(pathEnd == fullPathInternal.begin())
-				break;
-
-			parentPath = parentPath.parent_path();
-			pathEnd--;
-		}
-
-		for(; pathEnd != fullPathInternal.end(); ++pathEnd)
-		{
-			create_directory(parentPath);
-
-			parentPath /= *pathEnd;
-		}
-
-		create_directory(parentPath);
-	}
-
-	void FileSystem::getChildren(const Path& dirPath, Vector<Path>::type& files, Vector<Path>::type& directories)
-	{
-		directory_iterator dirIter(dirPath.toWString().c_str());
-
-		while(dirIter != directory_iterator())
-		{
-			boost::filesystem3::path curPath = dirIter->path();
-
-			if(is_regular_file(curPath))
-				files.push_back(Path(curPath.c_str()));
-			else if(is_directory(curPath))
-				directories.push_back(Path(curPath.c_str()));
-
-			dirIter++;
-		}
-	}
-	std::time_t FileSystem::getLastModifiedTime(const Path& fullPath)
-	{
-		return last_write_time(fullPath.toWString().c_str());
-	}
-
-	Path FileSystem::getWorkingDirectoryPath()
-	{
-		return current_path().wstring().c_str();
-	}
-}

+ 413 - 0
CamelotUtility/Source/Win32/CmFileSystem.cpp

@@ -0,0 +1,413 @@
+#include "CmFileSystem.h"
+#include "CmException.h"
+#include "CmDataStream.h"
+#include "CmPath.h"
+#include <windows.h>
+
+namespace BansheeEngine
+{
+	void win32_handleError(DWORD error, const WString& path)
+	{
+		switch (error)
+		{
+		case ERROR_FILE_NOT_FOUND:
+			CM_EXCEPT(FileNotFoundException, "File at path: \"" + toString(path) + "\" not found.");
+		case ERROR_PATH_NOT_FOUND:
+		case ERROR_BAD_NETPATH:
+		case ERROR_CANT_RESOLVE_FILENAME:
+		case ERROR_INVALID_DRIVE:
+			CM_EXCEPT(FileNotFoundException, "Path \"" + toString(path) + "\" not found.");
+		case ERROR_ACCESS_DENIED:
+			CM_EXCEPT(IOException, "Access to path \"" + toString(path) + "\" denied.");
+		case ERROR_ALREADY_EXISTS:
+		case ERROR_FILE_EXISTS:
+			CM_EXCEPT(IOException, "File/folder at path \"" + toString(path) + "\" already exists.");
+		case ERROR_INVALID_NAME:
+		case ERROR_DIRECTORY:
+		case ERROR_FILENAME_EXCED_RANGE:
+		case ERROR_BAD_PATHNAME:
+			CM_EXCEPT(IOException, "Invalid path string: \"" + toString(path) + "\".");
+		case ERROR_FILE_READ_ONLY:
+			CM_EXCEPT(IOException, "File at path \"" + toString(path) + "\" is read only.");
+		case ERROR_CANNOT_MAKE:
+			CM_EXCEPT(IOException, "Cannot create file/folder at path: \"" + toString(path) + "\".");
+		case ERROR_DIR_NOT_EMPTY:
+			CM_EXCEPT(IOException, "Directory at path \"" + toString(path) + "\" not empty.");
+		case ERROR_WRITE_FAULT:
+			CM_EXCEPT(IOException, "Error while writing a file at path \"" + toString(path) + "\".");
+		case ERROR_READ_FAULT:
+			CM_EXCEPT(IOException, "Error while reading a file at path \"" + toString(path) + "\".");
+		case ERROR_SHARING_VIOLATION:
+			CM_EXCEPT(IOException, "Sharing violation at path \"" + toString(path) + "\".");
+		case ERROR_LOCK_VIOLATION:
+			CM_EXCEPT(IOException, "Lock violation at path \"" + toString(path) + "\".");
+		case ERROR_HANDLE_EOF:
+			CM_EXCEPT(IOException, "End of file reached for file at path \"" + toString(path) + "\".");
+		case ERROR_HANDLE_DISK_FULL:
+		case ERROR_DISK_FULL:
+			CM_EXCEPT(IOException, "Disk full.");
+		case ERROR_NEGATIVE_SEEK:
+			CM_EXCEPT(IOException, "Negative seek.");
+		default:
+			CM_EXCEPT(IOException, "Undefined file system exception.");
+		}
+	}
+
+	WString win32_getCurrentDirectory()
+	{
+		DWORD len = GetCurrentDirectoryW(0, NULL);
+		if (len > 0)
+		{
+			wchar_t* buffer = (wchar_t*)cm_alloc(len * sizeof(wchar_t));
+
+			DWORD n = GetCurrentDirectoryW(len, buffer);
+			if (n > 0 && n <= len)
+			{
+				WString result(buffer);
+				if (result[result.size() - 1] != '\\')
+					result.append(L"\\");
+
+				cm_free(buffer);
+				return result;
+			}
+
+			cm_free(buffer);
+		}
+
+		return StringUtil::WBLANK;
+	}
+
+	bool win32_pathExists(const WString& path)
+	{
+		DWORD attr = GetFileAttributesW(path.c_str());
+		if (attr == 0xFFFFFFFF)
+		{
+			switch (GetLastError())
+			{
+			case ERROR_FILE_NOT_FOUND:
+			case ERROR_PATH_NOT_FOUND:
+			case ERROR_NOT_READY:
+			case ERROR_INVALID_DRIVE:
+				return false;
+			default:
+				win32_handleError(GetLastError(), path);
+			}
+		}
+		return true;
+	}
+
+	bool win32_isDirectory(const WString& path)
+	{
+		DWORD attr = GetFileAttributesW(path.c_str());
+		if (attr == 0xFFFFFFFF)
+			win32_handleError(GetLastError(), path);
+
+		return (attr & FILE_ATTRIBUTE_DIRECTORY) != FALSE;
+	}
+
+	bool win32_isDevice(const WString& path)
+	{
+		WString ucPath = path;
+		StringUtil::toUpperCase(ucPath);
+
+		return
+			ucPath.compare(0, 4, L"\\\\.\\") == 0 ||
+			ucPath.compare(L"CON") == 0 ||
+			ucPath.compare(L"PRN") == 0 ||
+			ucPath.compare(L"AUX") == 0 ||
+			ucPath.compare(L"NUL") == 0 ||
+			ucPath.compare(L"LPT1") == 0 ||
+			ucPath.compare(L"LPT2") == 0 ||
+			ucPath.compare(L"LPT3") == 0 ||
+			ucPath.compare(L"LPT4") == 0 ||
+			ucPath.compare(L"LPT5") == 0 ||
+			ucPath.compare(L"LPT6") == 0 ||
+			ucPath.compare(L"LPT7") == 0 ||
+			ucPath.compare(L"LPT8") == 0 ||
+			ucPath.compare(L"LPT9") == 0 ||
+			ucPath.compare(L"COM1") == 0 ||
+			ucPath.compare(L"COM2") == 0 ||
+			ucPath.compare(L"COM3") == 0 ||
+			ucPath.compare(L"COM4") == 0 ||
+			ucPath.compare(L"COM5") == 0 ||
+			ucPath.compare(L"COM6") == 0 ||
+			ucPath.compare(L"COM7") == 0 ||
+			ucPath.compare(L"COM8") == 0 ||
+			ucPath.compare(L"COM9") == 0;
+	}
+
+	bool win32_isFile(const WString& path)
+	{
+		return !win32_isDirectory(path) && !win32_isDevice(path);
+	}
+
+	bool win32_createFile(const WString& path)
+	{
+		HANDLE hFile = CreateFileW(path.c_str(), GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0);
+
+		if (hFile != INVALID_HANDLE_VALUE)
+		{
+			CloseHandle(hFile);
+			return true;
+		}
+		else if (GetLastError() == ERROR_FILE_EXISTS)
+			return false;
+		else
+			win32_handleError(GetLastError(), path);
+
+		return false;
+	}
+
+
+	bool win32_createDirectory(const WString& path)
+	{
+		if (win32_pathExists(path) && win32_isDirectory(path))
+			return false;
+
+		if (CreateDirectoryW(path.c_str(), 0) == FALSE)
+			win32_handleError(GetLastError(), path);
+
+		return true;
+	}
+
+	void win32_remove(const WString& path)
+	{
+		if (win32_isDirectory(path))
+		{
+			if (RemoveDirectoryW(path.c_str()) == 0)
+				win32_handleError(GetLastError(), path);
+		}
+		else
+		{
+			if (DeleteFileW(path.c_str()) == 0)
+				win32_handleError(GetLastError(), path);
+		}
+	}
+
+	void win32_copy(const WString& from, const WString& to)
+	{
+		if (CopyFileW(from.c_str(), to.c_str(), FALSE) == FALSE)
+			win32_handleError(GetLastError(), from);
+	}
+
+
+	void win32_rename(const WString& oldPath, const WString& newPath)
+	{
+		if (MoveFileW(oldPath.c_str(), newPath.c_str()) == 0)
+			win32_handleError(GetLastError(), oldPath);
+	}
+
+	UINT64 win32_getFileSize(const WString& path)
+	{
+		WIN32_FILE_ATTRIBUTE_DATA attrData;
+		if (GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &attrData) == FALSE)
+			win32_handleError(GetLastError(), path);
+
+		LARGE_INTEGER li;
+		li.LowPart = attrData.nFileSizeLow;
+		li.HighPart = attrData.nFileSizeHigh;
+		return (UINT64)li.QuadPart;
+	}
+
+	std::time_t win32_getLastModifiedTime(const WString& path)
+	{
+		WIN32_FILE_ATTRIBUTE_DATA fad;
+		if (GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &fad) == 0)
+			win32_handleError(GetLastError(), path);
+
+		ULARGE_INTEGER ull;
+		ull.LowPart = fad.ftLastWriteTime.dwLowDateTime;
+		ull.HighPart = fad.ftLastWriteTime.dwHighDateTime;
+
+		return (std::time_t) ((ull.QuadPart / 10000000ULL) - 11644473600ULL);
+	}
+
+	DataStreamPtr FileSystem::openFile(const Path& fullPath, bool readOnly)
+	{
+		UINT64 fileSize = getFileSize(fullPath);
+
+		// Always open in binary mode
+		// Also, always include reading
+		std::ios::openmode mode = std::ios::in | std::ios::binary;
+		std::shared_ptr<std::istream> baseStream = 0;
+		std::shared_ptr<std::ifstream> roStream = 0;
+		std::shared_ptr<std::fstream> rwStream = 0;
+
+		if (!readOnly)
+		{
+			mode |= std::ios::out;
+			rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
+			rwStream->open(fullPath.toWString().c_str(), mode);
+			baseStream = rwStream;
+		}
+		else
+		{
+			roStream = cm_shared_ptr<std::ifstream, ScratchAlloc>();
+			roStream->open(fullPath.toWString().c_str(), mode);
+			baseStream = roStream;
+		}
+
+		// Should check ensure open succeeded, in case fail for some reason.
+		if (baseStream->fail())
+			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + fullPath.toString());
+
+		/// Construct return stream, tell it to delete on destroy
+		FileDataStream* stream = 0;
+		if (rwStream)
+		{
+			// use the writeable stream 
+			stream = cm_new<FileDataStream, ScratchAlloc>(rwStream, (size_t)fileSize, true);
+		}
+		else
+		{
+			// read-only stream
+			stream = cm_new<FileDataStream, ScratchAlloc>(roStream, (size_t)fileSize, true);
+		}
+
+		return cm_shared_ptr<FileDataStream, ScratchAlloc>(stream);
+	}
+
+	DataStreamPtr FileSystem::createAndOpenFile(const Path& fullPath)
+	{
+		// Always open in binary mode
+		// Also, always include reading
+		std::ios::openmode mode = std::ios::out | std::ios::binary;
+		std::shared_ptr<std::fstream> rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
+		rwStream->open(fullPath.toWString().c_str(), mode);
+
+		// Should check ensure open succeeded, in case fail for some reason.
+		if (rwStream->fail())
+			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + fullPath.toString());
+
+		/// Construct return stream, tell it to delete on destroy
+		return cm_shared_ptr<FileDataStream, ScratchAlloc>(rwStream, 0, true);
+	}
+
+	UINT64 FileSystem::getFileSize(const Path& fullPath)
+	{
+		return win32_getFileSize(fullPath.toWString());
+	}
+
+	void FileSystem::remove(const Path& fullPath, bool recursively)
+	{
+		WString fullPathStr = fullPath.toWString();
+
+		if (recursively)
+		{
+			Vector<Path>::type files;
+			Vector<Path>::type directories;
+
+			getChildren(fullPath, files, directories);
+
+			for (auto& file : files)
+				remove(file, false);
+
+			for (auto& dir : directories)
+				remove(dir, true);
+		}
+
+		win32_remove(fullPathStr);
+	}
+
+	void FileSystem::move(const Path& oldPath, const Path& newPath, bool overwriteExisting)
+	{
+		WString oldPathStr = oldPath.toWString();
+		WString newPathStr = newPath.toWString();
+
+		if (win32_pathExists(newPathStr))
+		{
+			if (overwriteExisting)
+				win32_remove(newPathStr);
+			else
+			{
+				CM_EXCEPT(InvalidStateException, "Move operation failed because another file already exists at the new path: \"" + toString(newPathStr) + "\"");
+			}
+		}
+
+		win32_rename(oldPathStr, newPathStr);
+	}
+
+	bool FileSystem::exists(const Path& fullPath)
+	{
+		return win32_pathExists(fullPath.toWString());
+	}
+
+	bool FileSystem::isFile(const Path& fullPath)
+	{
+		WString pathStr = fullPath.toWString();
+
+		return win32_pathExists(pathStr) && win32_isFile(pathStr);
+	}
+
+	bool FileSystem::isDirectory(const Path& fullPath)
+	{
+		WString pathStr = fullPath.toWString();
+
+		return win32_pathExists(pathStr) && win32_isDirectory(pathStr);
+	}
+
+	void FileSystem::createDir(const Path& fullPath)
+	{
+		Path parentPath = fullPath;
+		while (!exists(parentPath))
+		{
+			parentPath = parentPath.getParent();
+		}
+
+		for (UINT32 i = parentPath.getNumDirectories(); i < fullPath.getNumDirectories(); i++)
+		{
+			win32_createDirectory(parentPath.toWString());
+			parentPath.append(fullPath[i]);
+		}
+	}
+
+	void FileSystem::getChildren(const Path& dirPath, Vector<Path>::type& files, Vector<Path>::type& directories)
+	{
+		if (dirPath.isFile())
+			return;
+
+		WString findPath = dirPath.toWString();
+		findPath.append(L"*");
+
+		WIN32_FIND_DATAW findData;
+		HANDLE fileHandle = FindFirstFileW(findPath.c_str(), &findData);
+
+		bool lastFailed = false;
+		WString tempName;
+		do
+		{
+			if (lastFailed || fileHandle == INVALID_HANDLE_VALUE)
+			{
+				if (GetLastError() == ERROR_NO_MORE_FILES)
+					break;
+				else
+					win32_handleError(GetLastError(), findPath);
+			}
+			else
+			{
+				tempName = findData.cFileName;
+
+				if (tempName != L"." && tempName != L"..")
+				{
+					Path fullPath = dirPath;
+					if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+						directories.push_back(fullPath.append(tempName));
+					else
+						files.push_back(fullPath.append(tempName));
+				}
+			}
+
+			lastFailed = FindNextFileW(fileHandle, &findData) == FALSE;
+		} while (true);
+	}
+
+	std::time_t FileSystem::getLastModifiedTime(const Path& fullPath)
+	{
+		return win32_getLastModifiedTime(fullPath.toWString().c_str());
+	}
+
+	Path FileSystem::getWorkingDirectoryPath()
+	{
+		return Path(win32_getCurrentDirectory());
+	}
+}