فهرست منبع

Moved everything to new Path system

Marko Pintera 11 سال پیش
والد
کامیت
e73983da31
43فایلهای تغییر یافته به همراه666 افزوده شده و 630 حذف شده
  1. 3 2
      BansheeEditor/Include/BsEditorApplication.h
  2. 2 1
      BansheeEditor/Include/BsEditorGUI.h
  3. 7 7
      BansheeEditor/Include/BsGUIResourceTreeView.h
  4. 22 21
      BansheeEditor/Include/BsProjectLibrary.h
  5. 7 5
      BansheeEditor/Source/BsEditorApplication.cpp
  6. 5 3
      BansheeEditor/Source/BsEditorGUI.cpp
  7. 48 55
      BansheeEditor/Source/BsGUIResourceTreeView.cpp
  8. 95 94
      BansheeEditor/Source/BsProjectLibrary.cpp
  9. 3 2
      BansheeEngine/Include/BsBuiltinResources.h
  10. 15 5
      BansheeEngine/Source/BsBuiltinResources.cpp
  11. 1 1
      CamelotCore/Include/CmGpuProgIncludeImporter.h
  12. 1 1
      CamelotCore/Include/CmGpuProgramImporter.h
  13. 4 4
      CamelotCore/Include/CmImporter.h
  14. 1 4
      CamelotCore/Include/CmPrerequisites.h
  15. 9 8
      CamelotCore/Include/CmResourceManifest.h
  16. 3 2
      CamelotCore/Include/CmResourceManifestRTTI.h
  17. 8 8
      CamelotCore/Include/CmResources.h
  18. 1 1
      CamelotCore/Include/CmSpecificImporter.h
  19. 6 6
      CamelotCore/Include/CmWin32FolderMonitor.h
  20. 2 2
      CamelotCore/Source/CmGpuProgIncludeImporter.cpp
  21. 3 3
      CamelotCore/Source/CmGpuProgramImporter.cpp
  22. 9 9
      CamelotCore/Source/CmImporter.cpp
  23. 24 39
      CamelotCore/Source/CmResourceManifest.cpp
  24. 12 12
      CamelotCore/Source/CmResources.cpp
  25. 20 30
      CamelotCore/Source/CmWin32FolderMonitor.cpp
  26. 2 2
      CamelotFBXImporter/Include/CmFBXImporter.h
  27. 4 4
      CamelotFBXImporter/Source/CmFBXImporter.cpp
  28. 1 1
      CamelotFontImporter/Include/CmFontImporter.h
  29. 5 5
      CamelotFontImporter/Source/CmFontImporter.cpp
  30. 1 1
      CamelotFreeImgImporter/Include/CmFreeImgImporter.h
  31. 2 2
      CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp
  32. 1 1
      CamelotUtility/Include/CmDebug.h
  33. 2 2
      CamelotUtility/Include/CmFileSerializer.h
  34. 12 20
      CamelotUtility/Include/CmFileSystem.h
  35. 6 1
      CamelotUtility/Include/CmFwdDeclUtil.h
  36. 102 205
      CamelotUtility/Include/CmPath.h
  37. 95 3
      CamelotUtility/Include/CmRTTIPrerequisites.h
  38. 14 0
      CamelotUtility/Include/CmString.h
  39. 3 2
      CamelotUtility/Source/CmDebug.cpp
  40. 5 4
      CamelotUtility/Source/CmFileSerializer.cpp
  41. 30 44
      CamelotUtility/Source/CmFileSystem.cpp
  42. 48 8
      CamelotUtility/Source/CmPath.cpp
  43. 22 0
      CamelotUtility/Source/CmString.cpp

+ 3 - 2
BansheeEditor/Include/BsEditorApplication.h

@@ -2,6 +2,7 @@
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
 #include "CmModule.h"
 #include "CmModule.h"
+#include "CmPath.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -21,9 +22,9 @@ namespace BansheeEngine
 		void runMainLoop();
 		void runMainLoop();
 
 
 		bool isProjectLoaded() const;
 		bool isProjectLoaded() const;
-		const WString& getActiveProjectPath() const;
+		const Path& getActiveProjectPath() const;
 	private:
 	private:
-		static const WString WIDGET_LAYOUT_PATH;
+		static const Path WIDGET_LAYOUT_PATH;
 		RenderSystemPlugin mActiveRSPlugin;
 		RenderSystemPlugin mActiveRSPlugin;
 
 
 		static const String& getLibraryNameForRenderSystem(RenderSystemPlugin plugin);
 		static const String& getLibraryNameForRenderSystem(RenderSystemPlugin plugin);

+ 2 - 1
BansheeEditor/Include/BsEditorGUI.h

@@ -3,6 +3,7 @@
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 #include "CmModule.h"
 #include "CmModule.h"
+#include "CmPath.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -16,7 +17,7 @@ namespace BansheeEngine
 	private:
 	private:
 		GUISkin mSkin;
 		GUISkin mSkin;
 
 
-		static const WString DefaultFolder;
+		static const Path DefaultFolder;
 
 
 		static const WString DefaultFontPath;
 		static const WString DefaultFontPath;
 		static const UINT32 DefaultFontSize;
 		static const UINT32 DefaultFontSize;

+ 7 - 7
BansheeEditor/Include/BsGUIResourceTreeView.h

@@ -11,7 +11,7 @@ namespace BansheeEngine
 	{
 	{
 		struct ResourceTreeElement : public GUITreeView::TreeElement
 		struct ResourceTreeElement : public GUITreeView::TreeElement
 		{
 		{
-			WString mFullPath;
+			Path mFullPath;
 			WString mElementName;
 			WString mElementName;
 		};
 		};
 
 
@@ -26,7 +26,7 @@ namespace BansheeEngine
 			~InternalDraggedResources();
 			~InternalDraggedResources();
 
 
 			UINT32 numObjects;
 			UINT32 numObjects;
-			WString* resourcePaths;
+			Path* resourcePaths;
 		};
 		};
 
 
 	public:
 	public:
@@ -79,14 +79,14 @@ namespace BansheeEngine
 		virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const;
 		virtual bool _acceptDragAndDrop(const Vector2I position, UINT32 typeId) const;
 
 
 		void updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry);
 		void updateFromProjectLibraryEntry(ResourceTreeElement* treeElement, const ProjectLibrary::LibraryEntry* libraryEntry);
-		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const WString& fullPath);
+		ResourceTreeElement* addTreeElement(ResourceTreeElement* parent, const Path& fullPath);
 		void deleteTreeElement(ResourceTreeElement* element);
 		void deleteTreeElement(ResourceTreeElement* element);
 		void sortTreeElement(ResourceTreeElement* element);
 		void sortTreeElement(ResourceTreeElement* element);
 
 
-		ResourceTreeElement* findTreeElement(const WString& fullPath);
+		ResourceTreeElement* findTreeElement(const Path& fullPath);
 
 
-		void entryAdded(const WString& path);
-		void entryRemoved(const WString& path);
+		void entryAdded(const Path& path);
+		void entryRemoved(const Path& path);
 
 
 		void setDropTarget(RenderWindow* parentWindow, INT32 x, INT32 y, UINT32 width, UINT32 height);
 		void setDropTarget(RenderWindow* parentWindow, INT32 x, INT32 y, UINT32 width, UINT32 height);
 		void clearDropTarget();
 		void clearDropTarget();
@@ -95,7 +95,7 @@ namespace BansheeEngine
 		void dropTargetDragLeave();
 		void dropTargetDragLeave();
 		void dropTargetDragDropped(INT32 x, INT32 y);
 		void dropTargetDragDropped(INT32 x, INT32 y);
 
 
-		WString findUniquePath(const WString& path);
+		Path findUniquePath(const Path& path);
 
 
 		void _changeParentWidget(GUIWidget* widget);
 		void _changeParentWidget(GUIWidget* widget);
 	};
 	};

+ 22 - 21
BansheeEditor/Include/BsProjectLibrary.h

@@ -2,6 +2,7 @@
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
 #include "CmModule.h"
 #include "CmModule.h"
+#include "CmPath.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -21,10 +22,10 @@ namespace BansheeEngine
 		struct LibraryEntry
 		struct LibraryEntry
 		{
 		{
 			LibraryEntry();
 			LibraryEntry();
-			LibraryEntry(const WString& path, const WString& name, DirectoryEntry* parent, LibraryEntryType type);
+			LibraryEntry(const Path& path, const WString& name, DirectoryEntry* parent, LibraryEntryType type);
 
 
 			LibraryEntryType type;
 			LibraryEntryType type;
-			WString path;
+			Path path;
 			WString elementName;
 			WString elementName;
 
 
 			DirectoryEntry* parent;
 			DirectoryEntry* parent;
@@ -33,7 +34,7 @@ namespace BansheeEngine
 		struct ResourceEntry : public LibraryEntry
 		struct ResourceEntry : public LibraryEntry
 		{
 		{
 			ResourceEntry();
 			ResourceEntry();
-			ResourceEntry(const WString& path, const WString& name, DirectoryEntry* parent);
+			ResourceEntry(const Path& path, const WString& name, DirectoryEntry* parent);
 
 
 			ResourceMetaPtr meta;
 			ResourceMetaPtr meta;
 			std::time_t lastUpdateTime;
 			std::time_t lastUpdateTime;
@@ -42,55 +43,55 @@ namespace BansheeEngine
 		struct DirectoryEntry : public LibraryEntry
 		struct DirectoryEntry : public LibraryEntry
 		{
 		{
 			DirectoryEntry();
 			DirectoryEntry();
-			DirectoryEntry(const WString& path, const WString& name, DirectoryEntry* parent);
+			DirectoryEntry(const Path& path, const WString& name, DirectoryEntry* parent);
 
 
 			Vector<LibraryEntry*>::type mChildren;
 			Vector<LibraryEntry*>::type mChildren;
 		};
 		};
 
 
 	public:
 	public:
-		ProjectLibrary(const WString& projectFolder);
+		ProjectLibrary(const Path& projectFolder);
 		~ProjectLibrary();
 		~ProjectLibrary();
 
 
 		void update();
 		void update();
-		void checkForModifications(const WString& fullPath);
+		void checkForModifications(const Path& fullPath);
 
 
 		const LibraryEntry* getRootEntry() const { return mRootEntry; }
 		const LibraryEntry* getRootEntry() const { return mRootEntry; }
-		LibraryEntry* findEntry(const WString& fullPath) const;
+		LibraryEntry* findEntry(const Path& fullPath) const;
 
 
-		void moveEntry(const WString& oldPath, const WString& newPath);
-		void deleteEntry(const WString& path);
+		void moveEntry(const Path& oldPath, const Path& newPath);
+		void deleteEntry(const Path& path);
 
 
-		boost::signal<void(const WString&)> onEntryRemoved;
-		boost::signal<void(const WString&)> onEntryAdded;
+		boost::signal<void(const Path&)> onEntryRemoved;
+		boost::signal<void(const Path&)> onEntryAdded;
 	private:
 	private:
-		static const WString RESOURCES_DIR;
-		static const WString INTERNAL_RESOURCES_DIR;
+		static const Path RESOURCES_DIR;
+		static const Path INTERNAL_RESOURCES_DIR;
 		static const WString LIBRARY_ENTRIES_FILENAME;
 		static const WString LIBRARY_ENTRIES_FILENAME;
 		static const WString RESOURCE_MANIFEST_FILENAME;
 		static const WString RESOURCE_MANIFEST_FILENAME;
 
 
 		ResourceManifestPtr mResourceManifest;
 		ResourceManifestPtr mResourceManifest;
 		DirectoryEntry* mRootEntry;
 		DirectoryEntry* mRootEntry;
 		FolderMonitor* mMonitor;
 		FolderMonitor* mMonitor;
-		WString mProjectFolder;
-		WString mResourcesFolder;
+		Path mProjectFolder;
+		Path mResourcesFolder;
 
 
 		void save();
 		void save();
 		void load();
 		void load();
 
 
-		ResourceEntry* addResourceInternal(DirectoryEntry* parent, const WString& filePath);
-		DirectoryEntry* addDirectoryInternal(DirectoryEntry* parent, const WString& dirPath);
+		ResourceEntry* addResourceInternal(DirectoryEntry* parent, const Path& filePath);
+		DirectoryEntry* addDirectoryInternal(DirectoryEntry* parent, const Path& dirPath);
 
 
 		void deleteResourceInternal(ResourceEntry* resource);
 		void deleteResourceInternal(ResourceEntry* resource);
 		void deleteDirectoryInternal(DirectoryEntry* directory);
 		void deleteDirectoryInternal(DirectoryEntry* directory);
 
 
 		void reimportResourceInternal(ResourceEntry* resource);
 		void reimportResourceInternal(ResourceEntry* resource);
 
 
-		void createInternalParentHierarchy(const WString& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf);
+		void createInternalParentHierarchy(const Path& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf);
 
 
 		bool isUpToDate(ResourceEntry* resource) const;
 		bool isUpToDate(ResourceEntry* resource) const;
-		WString getMetaPath(const WString& path) const;
-		bool isMeta(const WString& fullPath) const;
+		Path getMetaPath(const Path& path) const;
+		bool isMeta(const Path& fullPath) const;
 
 
-		void onMonitorFileModified(const WString& path);
+		void onMonitorFileModified(const Path& path);
 	};
 	};
 }
 }

+ 7 - 5
BansheeEditor/Source/BsEditorApplication.cpp

@@ -39,7 +39,7 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	const WString EditorApplication::WIDGET_LAYOUT_PATH = L"Internal\\Layout.asset";
+	const Path EditorApplication::WIDGET_LAYOUT_PATH = L"Internal\\Layout.asset";
 
 
 	EditorApplication::EditorApplication(RenderSystemPlugin renderSystemPlugin)
 	EditorApplication::EditorApplication(RenderSystemPlugin renderSystemPlugin)
 		:mActiveRSPlugin(renderSystemPlugin)
 		:mActiveRSPlugin(renderSystemPlugin)
@@ -408,9 +408,9 @@ namespace BansheeEngine
 		return true; // TODO - DEBUG ONLY
 		return true; // TODO - DEBUG ONLY
 	}
 	}
 
 
-	const WString& EditorApplication::getActiveProjectPath() const
+	const Path& EditorApplication::getActiveProjectPath() const
 	{
 	{
-		static WString dummyProjectPath = L"D:\\DummyBansheeProject";
+		static Path dummyProjectPath = L"D:\\DummyBansheeProject\\";
 
 
 		return dummyProjectPath;
 		return dummyProjectPath;
 	}
 	}
@@ -436,7 +436,8 @@ namespace BansheeEngine
 
 
 	EditorWidgetLayoutPtr EditorApplication::loadWidgetLayout()
 	EditorWidgetLayoutPtr EditorApplication::loadWidgetLayout()
 	{
 	{
-		WString layoutPath = OldPath::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
+		Path layoutPath = getActiveProjectPath();
+		layoutPath.append(WIDGET_LAYOUT_PATH);
 
 
 		if(FileSystem::exists(layoutPath))
 		if(FileSystem::exists(layoutPath))
 		{
 		{
@@ -449,7 +450,8 @@ namespace BansheeEngine
 
 
 	void EditorApplication::saveWidgetLayout(const EditorWidgetLayoutPtr& layout)
 	void EditorApplication::saveWidgetLayout(const EditorWidgetLayoutPtr& layout)
 	{
 	{
-		WString layoutPath = OldPath::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
+		Path layoutPath = getActiveProjectPath();
+		layoutPath.append(WIDGET_LAYOUT_PATH);
 
 
 		FileSerializer fs;
 		FileSerializer fs;
 		fs.encode(layout.get(), layoutPath);
 		fs.encode(layout.get(), layoutPath);

+ 5 - 3
BansheeEditor/Source/BsEditorGUI.cpp

@@ -21,7 +21,7 @@ namespace BansheeEngine
 	const WString EditorGUI::DefaultFontPath = L"arial.ttf";
 	const WString EditorGUI::DefaultFontPath = L"arial.ttf";
 	const UINT32 EditorGUI::DefaultFontSize = 10;
 	const UINT32 EditorGUI::DefaultFontSize = 10;
 
 
-	const WString EditorGUI::DefaultFolder = L"..\\..\\..\\..\\Data\\Editor\\Skin\\";
+	const Path EditorGUI::DefaultFolder = L"..\\..\\..\\..\\Data\\Editor\\Skin\\";
 
 
 	const WString EditorGUI::WindowBackgroundTexture = L"WindowBgTile.psd";
 	const WString EditorGUI::WindowBackgroundTexture = L"WindowBgTile.psd";
 
 
@@ -144,7 +144,9 @@ namespace BansheeEngine
 		HFont font;
 		HFont font;
 
 
 		{
 		{
-			WString fontPath = DefaultFolder + DefaultFontPath;
+			Path fontPath = DefaultFolder;
+			fontPath.append(DefaultFontPath);
+
 			ImportOptionsPtr fontImportOptions = Importer::instance().createImportOptions(fontPath);
 			ImportOptionsPtr fontImportOptions = Importer::instance().createImportOptions(fontPath);
 			if(rtti_is_of_type<FontImportOptions>(fontImportOptions))
 			if(rtti_is_of_type<FontImportOptions>(fontImportOptions))
 			{
 			{
@@ -816,6 +818,6 @@ namespace BansheeEngine
 
 
 	HSpriteTexture EditorGUI::getTexture(const WString& name)
 	HSpriteTexture EditorGUI::getTexture(const WString& name)
 	{
 	{
-		return SpriteTexture::create(static_resource_cast<Texture>(Importer::instance().import(FileSystem::getWorkingDirectoryPath() + L"\\" + DefaultFolder + name)));
+		return SpriteTexture::create(static_resource_cast<Texture>(Importer::instance().import(FileSystem::getWorkingDirectoryPath().append(DefaultFolder).append(name))));
 	}
 	}
 }
 }

+ 48 - 55
BansheeEditor/Source/BsGUIResourceTreeView.cpp

@@ -19,7 +19,7 @@ namespace BansheeEngine
 	GUIResourceTreeView::InternalDraggedResources::InternalDraggedResources(UINT32 numObjects)
 	GUIResourceTreeView::InternalDraggedResources::InternalDraggedResources(UINT32 numObjects)
 		:numObjects(numObjects)
 		:numObjects(numObjects)
 	{
 	{
-		resourcePaths = cm_newN<WString>(numObjects);
+		resourcePaths = cm_newN<Path>(numObjects);
 	}
 	}
 
 
 	GUIResourceTreeView::InternalDraggedResources::~InternalDraggedResources()
 	GUIResourceTreeView::InternalDraggedResources::~InternalDraggedResources()
@@ -40,7 +40,8 @@ namespace BansheeEngine
 		const ProjectLibrary::LibraryEntry* rootEntry = ProjectLibrary::instance().getRootEntry();
 		const ProjectLibrary::LibraryEntry* rootEntry = ProjectLibrary::instance().getRootEntry();
 
 
 		mRootElement.mFullPath = rootEntry->path;
 		mRootElement.mFullPath = rootEntry->path;
-		mRootElement.mElementName = OldPath::getFilename(mRootElement.mFullPath);
+		mRootElement.mElementName = mRootElement.mFullPath.getWTail();
+
 		expandElement(&mRootElement);
 		expandElement(&mRootElement);
 
 
 		updateFromProjectLibraryEntry(&mRootElement, rootEntry);
 		updateFromProjectLibraryEntry(&mRootElement, rootEntry);
@@ -86,8 +87,9 @@ namespace BansheeEngine
 	{
 	{
 		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
 		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
 		
 		
-		WString oldPath = resourceTreeElement->mFullPath;
-		WString newPath = OldPath::combine(OldPath::parentPath(oldPath), name);
+		Path oldPath = resourceTreeElement->mFullPath;
+		Path newPath = oldPath.getParent();
+		newPath.append(name);
 
 
 		ProjectLibrary::instance().moveEntry(oldPath, findUniquePath(newPath));
 		ProjectLibrary::instance().moveEntry(oldPath, findUniquePath(newPath));
 	}
 	}
@@ -136,15 +138,15 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const WString& fullPath)
+	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::addTreeElement(ResourceTreeElement* parent, const Path& fullPath)
 	{
 	{
 		ResourceTreeElement* newChild = cm_new<ResourceTreeElement>();
 		ResourceTreeElement* newChild = cm_new<ResourceTreeElement>();
 		newChild->mParent = parent;
 		newChild->mParent = parent;
-		newChild->mName = toString(OldPath::getFilename(fullPath));
+		newChild->mName = fullPath.getFilename();
 		newChild->mFullPath = fullPath;
 		newChild->mFullPath = fullPath;
 		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
 		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
 		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
 		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
-		newChild->mElementName = OldPath::getFilename(fullPath);
+		newChild->mElementName = fullPath.getWTail();
 
 
 		parent->mChildren.push_back(newChild);
 		parent->mChildren.push_back(newChild);
 
 
@@ -192,54 +194,46 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const WString& fullPath)
+	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const Path& fullPath)
 	{
 	{
-		Vector<WString>::type pathElems = OldPath::split(fullPath);
-		Vector<WString>::type rootElems = OldPath::split(mRootElement.mFullPath);
-
-		auto pathIter = pathElems.begin();
-		auto rootIter = rootElems.begin();
-
-		while(pathIter != pathElems.end() && rootIter != rootElems.end() && OldPath::comparePathElements(*pathIter, *rootIter))
-		{
-			++pathIter;
-			++rootIter;
-		}
-
-		if(pathIter == pathElems.begin()) // Supplied path not part of the root path
+		if (!mRootElement.mFullPath.includes(fullPath))
 			return nullptr;
 			return nullptr;
 
 
-		--pathIter;
-
-		Stack<ResourceTreeElement*>::type todo;
-		todo.push(&mRootElement);
+		Path relPath = fullPath.getRelative(mRootElement.mFullPath);
+		UINT32 numElems = relPath.getNumDirectories() + (relPath.isFile() ? 1 : 0);
+		UINT32 idx = 0;
 
 
-		while(!todo.empty())
+		ResourceTreeElement* current = &mRootElement;
+		while (current != nullptr)
 		{
 		{
-			ResourceTreeElement* current = todo.top();
-			todo.pop();
+			if (idx == numElems)
+				return current;
 
 
-			if(OldPath::comparePathElements(*pathIter, current->mElementName))
-			{
-				++pathIter;
-
-				if(pathIter == pathElems.end())
-					return current;
-
-				while(!todo.empty())
-					todo.pop();
+			WString curElem;
+			if (relPath.isFile() && idx == (numElems - 1))
+				curElem = relPath.getWFilename();
+			else
+				curElem = relPath[idx];
 
 
-				for(auto& child : current->mChildren)
-					todo.push(static_cast<ResourceTreeElement*>(child));
+			current = nullptr;
+			for (auto& child : current->mChildren)
+			{
+				ResourceTreeElement* resourceChild = static_cast<ResourceTreeElement*>(child);
+				if (Path::comparePathElem(curElem, resourceChild->mElementName))
+				{
+					idx++;
+					current = resourceChild;
+					break;
+				}
 			}
 			}
 		}
 		}
 
 
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
-	void GUIResourceTreeView::entryAdded(const WString& path)
+	void GUIResourceTreeView::entryAdded(const Path& path)
 	{
 	{
-		WString parentPath = OldPath::parentPath(path);
+		Path parentPath = path.getParent();
 
 
 		ResourceTreeElement* parentElement = findTreeElement(parentPath);
 		ResourceTreeElement* parentElement = findTreeElement(parentPath);
 		assert(parentElement != nullptr);
 		assert(parentElement != nullptr);
@@ -255,7 +249,7 @@ namespace BansheeEngine
 		markContentAsDirty();
 		markContentAsDirty();
 	}
 	}
 
 
-	void GUIResourceTreeView::entryRemoved(const WString& path)
+	void GUIResourceTreeView::entryRemoved(const Path& path)
 	{
 	{
 		ResourceTreeElement* treeElement = findTreeElement(path);
 		ResourceTreeElement* treeElement = findTreeElement(path);
 		
 		
@@ -356,19 +350,16 @@ namespace BansheeEngine
 		markContentAsDirty();
 		markContentAsDirty();
 	}
 	}
 
 
-	WString GUIResourceTreeView::findUniquePath(const WString& path)
+	Path GUIResourceTreeView::findUniquePath(const Path& path)
 	{
 	{
 		if(FileSystem::exists(path))
 		if(FileSystem::exists(path))
 		{
 		{
-			WString noExtensionPath = path;
-			WString extension = OldPath::getExtension(path);
-			OldPath::replaceExtension(noExtensionPath, L"");
-
-			WString newPath;
+			Path newPath = path;
+			WString filename = path.getWFilename(false);
 			UINT32 cnt = 1;
 			UINT32 cnt = 1;
 			do 
 			do 
 			{
 			{
-				newPath = OldPath::combine(OldPath::combine(noExtensionPath, L" " + toWString(cnt)), extension);
+				newPath.setBasename(filename + toWString(cnt));
 				cnt++;
 				cnt++;
 			} while (FileSystem::exists(newPath));
 			} while (FileSystem::exists(newPath));
 
 
@@ -415,18 +406,20 @@ namespace BansheeEngine
 		{
 		{
 			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(overTreeElement);
 			ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(overTreeElement);
 
 
-			WString destDir = resourceTreeElement->mFullPath;
+			Path destDir = resourceTreeElement->mFullPath;
 			if(FileSystem::isFile(destDir))
 			if(FileSystem::isFile(destDir))
-				destDir = OldPath::parentPath(destDir);
+				destDir = destDir.getParent();
 
 
 			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
 			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
 			{
 			{
-				WString filename = OldPath::getFilename(mDraggedResources->resourcePaths[i]);
-				WString currentParent = OldPath::parentPath(mDraggedResources->resourcePaths[i]);
+				WString filename = mDraggedResources->resourcePaths[i].getWFilename();
+				Path currentParent = mDraggedResources->resourcePaths[i].getParent();
 
 
-				if(!OldPath::equals(currentParent, destDir))
+				if(currentParent != destDir)
 				{
 				{
-					WString newPath = OldPath::combine(destDir, filename);
+					Path newPath = destDir;
+					newPath.append(filename);
+
 					ProjectLibrary::instance().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
 					ProjectLibrary::instance().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
 				}
 				}
 			}
 			}

+ 95 - 94
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -18,8 +18,8 @@ using namespace std::placeholders;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	const WString ProjectLibrary::RESOURCES_DIR = L"Resources";
-	const WString ProjectLibrary::INTERNAL_RESOURCES_DIR = L"Internal\\Resources";
+	const Path ProjectLibrary::RESOURCES_DIR = L"Resources\\";
+	const Path ProjectLibrary::INTERNAL_RESOURCES_DIR = L"Internal\\Resources\\";
 	const WString ProjectLibrary::LIBRARY_ENTRIES_FILENAME = L"ProjectLibrary.asset";
 	const WString ProjectLibrary::LIBRARY_ENTRIES_FILENAME = L"ProjectLibrary.asset";
 	const WString ProjectLibrary::RESOURCE_MANIFEST_FILENAME = L"ResourceManifest.asset";
 	const WString ProjectLibrary::RESOURCE_MANIFEST_FILENAME = L"ResourceManifest.asset";
 
 
@@ -27,7 +27,7 @@ namespace BansheeEngine
 		:parent(nullptr), type(LibraryEntryType::Directory)
 		:parent(nullptr), type(LibraryEntryType::Directory)
 	{ }
 	{ }
 
 
-	ProjectLibrary::LibraryEntry::LibraryEntry(const WString& path, const WString& name, DirectoryEntry* parent, LibraryEntryType type)
+	ProjectLibrary::LibraryEntry::LibraryEntry(const Path& path, const WString& name, DirectoryEntry* parent, LibraryEntryType type)
 		:path(path), parent(parent), type(type), elementName(name)
 		:path(path), parent(parent), type(type), elementName(name)
 	{ }
 	{ }
 
 
@@ -35,21 +35,22 @@ namespace BansheeEngine
 		:lastUpdateTime(0)
 		:lastUpdateTime(0)
 	{ }
 	{ }
 
 
-	ProjectLibrary::ResourceEntry::ResourceEntry(const WString& path, const WString& name, DirectoryEntry* parent)
+	ProjectLibrary::ResourceEntry::ResourceEntry(const Path& path, const WString& name, DirectoryEntry* parent)
 		:LibraryEntry(path, name, parent, LibraryEntryType::File), lastUpdateTime(0)
 		:LibraryEntry(path, name, parent, LibraryEntryType::File), lastUpdateTime(0)
 	{ }
 	{ }
 
 
 	ProjectLibrary::DirectoryEntry::DirectoryEntry()
 	ProjectLibrary::DirectoryEntry::DirectoryEntry()
 	{ }
 	{ }
 
 
-	ProjectLibrary::DirectoryEntry::DirectoryEntry(const WString& path, const WString& name, DirectoryEntry* parent)
+	ProjectLibrary::DirectoryEntry::DirectoryEntry(const Path& path, const WString& name, DirectoryEntry* parent)
 		:LibraryEntry(path, name, parent, LibraryEntryType::Directory)
 		:LibraryEntry(path, name, parent, LibraryEntryType::Directory)
 	{ }
 	{ }
 
 
-	ProjectLibrary::ProjectLibrary(const WString& projectFolder)
+	ProjectLibrary::ProjectLibrary(const Path& projectFolder)
 		:mRootEntry(nullptr), mProjectFolder(projectFolder)
 		:mRootEntry(nullptr), mProjectFolder(projectFolder)
 	{
 	{
-		mResourcesFolder = OldPath::combine(mProjectFolder, RESOURCES_DIR);
+		mResourcesFolder = mProjectFolder;
+		mResourcesFolder.append(RESOURCES_DIR);
 		mMonitor = cm_new<FolderMonitor>();
 		mMonitor = cm_new<FolderMonitor>();
 
 
 		FolderChange folderChanges = (FolderChange)((UINT32)FolderChange::FileName | (UINT32)FolderChange::DirName | 
 		FolderChange folderChanges = (FolderChange)((UINT32)FolderChange::FileName | (UINT32)FolderChange::DirName | 
@@ -86,22 +87,21 @@ namespace BansheeEngine
 		mMonitor->_update();
 		mMonitor->_update();
 	}
 	}
 
 
-	void ProjectLibrary::checkForModifications(const WString& fullPath)
+	void ProjectLibrary::checkForModifications(const Path& fullPath)
 	{
 	{
-		if(!OldPath::includes(fullPath, mResourcesFolder))
+		if (!mResourcesFolder.includes(fullPath))
 			return; // Folder not part of our resources path, so no modifications
 			return; // Folder not part of our resources path, so no modifications
 
 
 		if(mRootEntry == nullptr)
 		if(mRootEntry == nullptr)
 		{
 		{
-			WString resPath = mResourcesFolder;
-			mRootEntry = cm_new<DirectoryEntry>(resPath, OldPath::getFilename(resPath), nullptr);
+			mRootEntry = cm_new<DirectoryEntry>(mResourcesFolder, mResourcesFolder.getWTail(), nullptr);
 		}
 		}
 
 
-		WString pathToSearch = fullPath;
+		Path pathToSearch = fullPath;
 		LibraryEntry* entry = findEntry(pathToSearch);
 		LibraryEntry* entry = findEntry(pathToSearch);
 		if(entry == nullptr) // File could be new, try to find parent directory entry
 		if(entry == nullptr) // File could be new, try to find parent directory entry
 		{
 		{
-			WString parentDirPath = OldPath::parentPath(pathToSearch);
+			Path parentDirPath = pathToSearch.getParent();
 			entry = findEntry(parentDirPath);
 			entry = findEntry(parentDirPath);
 
 
 			// Cannot find parent directory. Create the needed hierarchy.
 			// Cannot find parent directory. Create the needed hierarchy.
@@ -149,8 +149,8 @@ namespace BansheeEngine
 				Stack<DirectoryEntry*>::type todo;
 				Stack<DirectoryEntry*>::type todo;
 				todo.push(static_cast<DirectoryEntry*>(entry));
 				todo.push(static_cast<DirectoryEntry*>(entry));
 
 
-				Vector<WString>::type childFiles;
-				Vector<WString>::type childDirectories;
+				Vector<Path>::type childFiles;
+				Vector<Path>::type childDirectories;
 				Vector<bool>::type existingEntries;
 				Vector<bool>::type existingEntries;
 				Vector<LibraryEntry*>::type toDelete;
 				Vector<LibraryEntry*>::type toDelete;
 
 
@@ -173,8 +173,8 @@ namespace BansheeEngine
 					{
 					{
 						if(isMeta(filePath))
 						if(isMeta(filePath))
 						{
 						{
-							WString sourceFilePath = filePath;
-							OldPath::replaceExtension(sourceFilePath, L"");
+							Path sourceFilePath = filePath;
+							sourceFilePath.setExtension(L"");
 
 
 							if(!FileSystem::isFile(sourceFilePath))
 							if(!FileSystem::isFile(sourceFilePath))
 							{
 							{
@@ -189,7 +189,7 @@ namespace BansheeEngine
 							UINT32 idx = 0;
 							UINT32 idx = 0;
 							for(auto& child : currentDir->mChildren)
 							for(auto& child : currentDir->mChildren)
 							{
 							{
-								if(child->type == LibraryEntryType::File && OldPath::equals(child->path, filePath))
+								if(child->type == LibraryEntryType::File && child->path == filePath)
 								{
 								{
 									existingEntries[idx] = true;
 									existingEntries[idx] = true;
 									existingEntry = static_cast<ResourceEntry*>(child);
 									existingEntry = static_cast<ResourceEntry*>(child);
@@ -216,7 +216,7 @@ namespace BansheeEngine
 						UINT32 idx = 0;
 						UINT32 idx = 0;
 						for(auto& child : currentDir->mChildren)
 						for(auto& child : currentDir->mChildren)
 						{
 						{
-							if(child->type == LibraryEntryType::Directory && OldPath::equals(child->path, dirPath))
+							if(child->type == LibraryEntryType::Directory && child->path == dirPath)
 							{
 							{
 								existingEntries[idx] = true;
 								existingEntries[idx] = true;
 								existingEntry = static_cast<DirectoryEntry*>(child);
 								existingEntry = static_cast<DirectoryEntry*>(child);
@@ -258,9 +258,9 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	ProjectLibrary::ResourceEntry* ProjectLibrary::addResourceInternal(DirectoryEntry* parent, const WString& filePath)
+	ProjectLibrary::ResourceEntry* ProjectLibrary::addResourceInternal(DirectoryEntry* parent, const Path& filePath)
 	{
 	{
-		ResourceEntry* newResource = cm_new<ResourceEntry>(filePath, OldPath::getFilename(filePath), parent);
+		ResourceEntry* newResource = cm_new<ResourceEntry>(filePath, filePath.getWTail(), parent);
 		parent->mChildren.push_back(newResource);
 		parent->mChildren.push_back(newResource);
 
 
 		reimportResourceInternal(newResource);
 		reimportResourceInternal(newResource);
@@ -271,9 +271,9 @@ namespace BansheeEngine
 		return newResource;
 		return newResource;
 	}
 	}
 
 
-	ProjectLibrary::DirectoryEntry* ProjectLibrary::addDirectoryInternal(DirectoryEntry* parent, const WString& dirPath)
+	ProjectLibrary::DirectoryEntry* ProjectLibrary::addDirectoryInternal(DirectoryEntry* parent, const Path& dirPath)
 	{
 	{
-		DirectoryEntry* newEntry = cm_new<DirectoryEntry>(dirPath, OldPath::getFilename(dirPath), parent);
+		DirectoryEntry* newEntry = cm_new<DirectoryEntry>(dirPath, dirPath.getWTail(), parent);
 		parent->mChildren.push_back(newEntry);
 		parent->mChildren.push_back(newEntry);
 
 
 		if(!onEntryAdded.empty())
 		if(!onEntryAdded.empty())
@@ -286,7 +286,7 @@ namespace BansheeEngine
 	{
 	{
 		if(resource->meta != nullptr)
 		if(resource->meta != nullptr)
 		{
 		{
-			WString path;
+			Path path;
 			if(mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
 			if(mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
 			{
 			{
 				if(FileSystem::isFile(path))
 				if(FileSystem::isFile(path))
@@ -339,8 +339,9 @@ namespace BansheeEngine
 
 
 	void ProjectLibrary::reimportResourceInternal(ResourceEntry* resource)
 	void ProjectLibrary::reimportResourceInternal(ResourceEntry* resource)
 	{
 	{
-		WString ext = OldPath::getExtension(resource->path);
-		WString metaPath = resource->path + L".meta";
+		WString ext = resource->path.getWExtension();
+		Path metaPath = resource->path;
+		metaPath.setFilename(metaPath.getWFilename() + L".meta");
 
 
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		if(!Importer::instance().supportsFileType(ext))
 		if(!Importer::instance().supportsFileType(ext))
@@ -386,11 +387,13 @@ namespace BansheeEngine
 				Importer::instance().reimport(importedResource, resource->path, importOptions);
 				Importer::instance().reimport(importedResource, resource->path, importOptions);
 			}
 			}
 
 
-			WString internalResourcesPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
+			Path internalResourcesPath = mProjectFolder;
+			internalResourcesPath.append(INTERNAL_RESOURCES_DIR);
+
 			if(!FileSystem::isDirectory(internalResourcesPath))
 			if(!FileSystem::isDirectory(internalResourcesPath))
 				FileSystem::createDir(internalResourcesPath);
 				FileSystem::createDir(internalResourcesPath);
 
 
-			internalResourcesPath = OldPath::combine(internalResourcesPath, toWString(importedResource.getUUID()) + L".asset");
+			internalResourcesPath.setFilename(toWString(importedResource.getUUID()) + L".asset");
 
 
 			gResources().save(importedResource, internalResourcesPath, true);
 			gResources().save(importedResource, internalResourcesPath, true);
 			gResources().unload(importedResource);
 			gResources().unload(importedResource);
@@ -406,7 +409,7 @@ namespace BansheeEngine
 		if(resource->meta == nullptr)
 		if(resource->meta == nullptr)
 			return false;
 			return false;
 
 
-		WString path;
+		Path path;
 		if(!mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
 		if(!mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
 			return false;
 			return false;
 
 
@@ -417,47 +420,39 @@ namespace BansheeEngine
 		return lastModifiedTime <= resource->lastUpdateTime;
 		return lastModifiedTime <= resource->lastUpdateTime;
 	}
 	}
 
 
-	ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const WString& fullPath) const
+	ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const Path& fullPath) const
 	{
 	{
-		Vector<WString>::type pathElems = OldPath::split(fullPath);
-		Vector<WString>::type rootElems = OldPath::split(mRootEntry->path);
-
-		auto pathIter = pathElems.begin();
-		auto rootIter = rootElems.begin();
-
-		while(pathIter != pathElems.end() && rootIter != rootElems.end() && OldPath::comparePathElements(*pathIter, *rootIter))
-		{
-			++pathIter;
-			++rootIter;
-		}
-
-		if(pathIter == pathElems.begin()) // Not a single entry matches Resources path
+		if (!mRootEntry->path.includes(fullPath))
 			return nullptr;
 			return nullptr;
 
 
-		--pathIter;
-		Stack<LibraryEntry*>::type todo;
-		todo.push(mRootEntry);
+		Path relPath = fullPath.getRelative(mRootEntry->path);
+		UINT32 numElems = relPath.getNumDirectories() + (relPath.isFile() ? 1 : 0);
+		UINT32 idx = 0;
 
 
-		while(!todo.empty())
+		LibraryEntry* current = mRootEntry;
+		while (current != nullptr)
 		{
 		{
-			LibraryEntry* current = todo.top();
-			todo.pop();
+			if (idx == numElems)
+				return current;
 
 
-			if(OldPath::comparePathElements(*pathIter, current->elementName))
-			{
-				++pathIter;
-
-				if(pathIter == pathElems.end())
-					return current;
-
-				while(!todo.empty())
-					todo.pop();
+			WString curElem;
+			if (relPath.isFile() && idx == (numElems - 1))
+				curElem = relPath.getWFilename();
+			else
+				curElem = relPath[idx];
 
 
-				if(current->type == LibraryEntryType::Directory)
+			current = nullptr;
+			if (current->type == LibraryEntryType::Directory)
+			{
+				DirectoryEntry* dirEntry = static_cast<DirectoryEntry*>(current);
+				for (auto& child : dirEntry->mChildren)
 				{
 				{
-					DirectoryEntry* dirEntry = static_cast<DirectoryEntry*>(current);
-					for(auto& child : dirEntry->mChildren)
-						todo.push(child);
+					if (Path::comparePathElem(curElem, child->elementName))
+					{
+						idx++;
+						current = child;
+						break;
+					}
 				}
 				}
 			}
 			}
 		}
 		}
@@ -465,19 +460,19 @@ namespace BansheeEngine
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
-	void ProjectLibrary::moveEntry(const WString& oldPath, const WString& newPath)
+	void ProjectLibrary::moveEntry(const Path& oldPath, const Path& newPath)
 	{
 	{
 		if(FileSystem::isFile(oldPath) || FileSystem::isDirectory(oldPath))
 		if(FileSystem::isFile(oldPath) || FileSystem::isDirectory(oldPath))
 			FileSystem::move(oldPath, newPath);
 			FileSystem::move(oldPath, newPath);
 
 
-		WString oldMetaPath = getMetaPath(oldPath);
-		WString newMetaPath = getMetaPath(newPath);
+		Path oldMetaPath = getMetaPath(oldPath);
+		Path newMetaPath = getMetaPath(newPath);
 
 
 		LibraryEntry* oldEntry = findEntry(oldPath);
 		LibraryEntry* oldEntry = findEntry(oldPath);
 		if(oldEntry != nullptr) // Moving from the Resources folder
 		if(oldEntry != nullptr) // Moving from the Resources folder
 		{
 		{
 			// Moved outside of Resources, delete entry & meta file
 			// Moved outside of Resources, delete entry & meta file
-			if(!OldPath::includes(newPath, mResourcesFolder))
+			if (!mResourcesFolder.includes(newPath))
 			{
 			{
 				if(oldEntry->type == LibraryEntryType::File)
 				if(oldEntry->type == LibraryEntryType::File)
 				{
 				{
@@ -499,7 +494,7 @@ namespace BansheeEngine
 				if(findIter != parent->mChildren.end())
 				if(findIter != parent->mChildren.end())
 					parent->mChildren.erase(findIter);
 					parent->mChildren.erase(findIter);
 
 
-				WString parentPath = OldPath::parentPath(newPath);
+				Path parentPath = newPath.getParent();
 
 
 				DirectoryEntry* newEntryParent = nullptr;
 				DirectoryEntry* newEntryParent = nullptr;
 				LibraryEntry* newEntryParentLib = findEntry(parentPath);
 				LibraryEntry* newEntryParentLib = findEntry(parentPath);
@@ -516,7 +511,7 @@ namespace BansheeEngine
 				newEntryParent->mChildren.push_back(oldEntry);
 				newEntryParent->mChildren.push_back(oldEntry);
 				oldEntry->parent = newEntryParent;
 				oldEntry->parent = newEntryParent;
 				oldEntry->path = newPath;
 				oldEntry->path = newPath;
-				oldEntry->elementName = OldPath::getFilename(newPath);
+				oldEntry->elementName = newPath.getWTail();
 
 
 				if(oldEntry->type == LibraryEntryType::Directory) // Update child paths
 				if(oldEntry->type == LibraryEntryType::Directory) // Update child paths
 				{
 				{
@@ -531,7 +526,8 @@ namespace BansheeEngine
 						DirectoryEntry* curDirEntry = static_cast<DirectoryEntry*>(curEntry);
 						DirectoryEntry* curDirEntry = static_cast<DirectoryEntry*>(curEntry);
 						for(auto& child : curDirEntry->mChildren)
 						for(auto& child : curDirEntry->mChildren)
 						{
 						{
-							child->path = OldPath::combine(child->parent->path, child->elementName);
+							child->path = child->parent->path;
+							child->path.append(child->elementName);
 
 
 							if(child->type == LibraryEntryType::Directory)
 							if(child->type == LibraryEntryType::Directory)
 								todo.push(child);
 								todo.push(child);
@@ -555,7 +551,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void ProjectLibrary::deleteEntry(const WString& path)
+	void ProjectLibrary::deleteEntry(const Path& path)
 	{
 	{
 		if(FileSystem::exists(path))
 		if(FileSystem::exists(path))
 			FileSystem::remove(path);
 			FileSystem::remove(path);
@@ -567,7 +563,7 @@ namespace BansheeEngine
 			{
 			{
 				deleteResourceInternal(static_cast<ResourceEntry*>(entry));
 				deleteResourceInternal(static_cast<ResourceEntry*>(entry));
 
 
-				WString metaPath = getMetaPath(path);
+				Path metaPath = getMetaPath(path);
 				if(FileSystem::isFile(metaPath))
 				if(FileSystem::isFile(metaPath))
 					FileSystem::remove(metaPath);
 					FileSystem::remove(metaPath);
 			}
 			}
@@ -576,15 +572,15 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void ProjectLibrary::createInternalParentHierarchy(const WString& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf)
+	void ProjectLibrary::createInternalParentHierarchy(const Path& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf)
 	{
 	{
-		WString parentPath = fullPath;
+		Path parentPath = fullPath;
 
 
 		DirectoryEntry* newEntryParent = nullptr;
 		DirectoryEntry* newEntryParent = nullptr;
-		Stack<WString>::type parentPaths;
+		Stack<Path>::type parentPaths;
 		do 
 		do 
 		{
 		{
-			WString newParentPath = OldPath::parentPath(parentPath);
+			Path newParentPath = parentPath.getParent();
 
 
 			if(newParentPath == parentPath)
 			if(newParentPath == parentPath)
 				break;
 				break;
@@ -610,7 +606,7 @@ namespace BansheeEngine
 
 
 		while(!parentPaths.empty())
 		while(!parentPaths.empty())
 		{
 		{
-			WString curPath = parentPaths.top();
+			Path curPath = parentPaths.top();
 			parentPaths.pop();
 			parentPaths.pop();
 
 
 			newEntryParent = addDirectoryInternal(newEntryParent, curPath);
 			newEntryParent = addDirectoryInternal(newEntryParent, curPath);
@@ -620,26 +616,27 @@ namespace BansheeEngine
 			*newHierarchyLeaf = newEntryParent;
 			*newHierarchyLeaf = newEntryParent;
 	}
 	}
 
 
-	WString ProjectLibrary::getMetaPath(const WString& path) const
+	Path ProjectLibrary::getMetaPath(const Path& path) const
 	{
 	{
-		WString metaPath = path + L".meta";
+		Path metaPath = path;
+		metaPath.setFilename(metaPath.getWFilename() + L".meta");
 
 
 		return metaPath;
 		return metaPath;
 	}
 	}
 
 
-	bool ProjectLibrary::isMeta(const WString& fullPath) const
+	bool ProjectLibrary::isMeta(const Path& fullPath) const
 	{
 	{
-		return OldPath::getExtension(fullPath) == L".meta";
+		return fullPath.getWExtension() == L".meta";
 	}
 	}
 
 
-	void ProjectLibrary::onMonitorFileModified(const WString& path)
+	void ProjectLibrary::onMonitorFileModified(const Path& path)
 	{
 	{
 		if(!isMeta(path))
 		if(!isMeta(path))
 			checkForModifications(path);
 			checkForModifications(path);
 		else
 		else
 		{
 		{
-			WString resourcePath = path;
-			OldPath::replaceExtension(resourcePath, L"");
+			Path resourcePath = path;
+			resourcePath.setExtension(L"");
 
 
 			checkForModifications(resourcePath);
 			checkForModifications(resourcePath);
 		}
 		}
@@ -649,14 +646,16 @@ namespace BansheeEngine
 	{
 	{
 		std::shared_ptr<ProjectLibraryEntries> libEntries = ProjectLibraryEntries::create(*mRootEntry);
 		std::shared_ptr<ProjectLibraryEntries> libEntries = ProjectLibraryEntries::create(*mRootEntry);
 
 
-		WString libraryEntriesPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		libraryEntriesPath = OldPath::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
+		Path libraryEntriesPath = mProjectFolder;
+		libraryEntriesPath.append(INTERNAL_RESOURCES_DIR);
+		libraryEntriesPath.append(LIBRARY_ENTRIES_FILENAME);
 
 
 		FileSerializer fs;
 		FileSerializer fs;
 		fs.encode(libEntries.get(), libraryEntriesPath);
 		fs.encode(libEntries.get(), libraryEntriesPath);
 
 
-		WString resourceManifestPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		resourceManifestPath = OldPath::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
+		Path resourceManifestPath = mProjectFolder;
+		resourceManifestPath.append(INTERNAL_RESOURCES_DIR);
+		resourceManifestPath.append(RESOURCE_MANIFEST_FILENAME);
 
 
 		ResourceManifest::save(mResourceManifest, resourceManifestPath, mProjectFolder);
 		ResourceManifest::save(mResourceManifest, resourceManifestPath, mProjectFolder);
 	}
 	}
@@ -669,11 +668,11 @@ namespace BansheeEngine
 			mRootEntry = nullptr;
 			mRootEntry = nullptr;
 		}
 		}
 
 
-		WString resPath = mResourcesFolder;
-		mRootEntry = cm_new<DirectoryEntry>(resPath, OldPath::getFilename(resPath), nullptr);
+		mRootEntry = cm_new<DirectoryEntry>(mResourcesFolder, mResourcesFolder.getWTail(), nullptr);
 
 
-		WString libraryEntriesPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		libraryEntriesPath = OldPath::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
+		Path libraryEntriesPath = mProjectFolder;
+		libraryEntriesPath.append(INTERNAL_RESOURCES_DIR);
+		libraryEntriesPath.append(LIBRARY_ENTRIES_FILENAME);
 
 
 		if(FileSystem::exists(libraryEntriesPath))
 		if(FileSystem::exists(libraryEntriesPath))
 		{
 		{
@@ -704,7 +703,8 @@ namespace BansheeEngine
 
 
 					if(resEntry->meta == nullptr)
 					if(resEntry->meta == nullptr)
 					{
 					{
-						WString metaPath = resEntry->path + L".meta";
+						Path metaPath = resEntry->path;
+						metaPath.setFilename(metaPath.getWFilename() + L".meta");
 
 
 						FileSerializer fs;
 						FileSerializer fs;
 						if(FileSystem::isFile(metaPath))
 						if(FileSystem::isFile(metaPath))
@@ -727,8 +727,9 @@ namespace BansheeEngine
 		}
 		}
 
 
 		// Load resource manifest
 		// Load resource manifest
-		WString resourceManifestPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		resourceManifestPath = OldPath::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
+		Path resourceManifestPath = mProjectFolder;
+		resourceManifestPath.append(INTERNAL_RESOURCES_DIR);
+		resourceManifestPath.append(RESOURCE_MANIFEST_FILENAME);
 
 
 		if(FileSystem::exists(resourceManifestPath))
 		if(FileSystem::exists(resourceManifestPath))
 		{
 		{

+ 3 - 2
BansheeEngine/Include/BsBuiltinResources.h

@@ -3,6 +3,7 @@
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 #include "CmModule.h"
 #include "CmModule.h"
+#include "CmPath.h"
 #include "CmVector2I.h"
 #include "CmVector2I.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -45,8 +46,8 @@ namespace BansheeEngine
 
 
 		HSpriteTexture mWhiteSpriteTexture;
 		HSpriteTexture mWhiteSpriteTexture;
 
 
-		static const WString DefaultSkinFolder;
-		static const WString DefaultCursorFolder;
+		static const Path DefaultSkinFolder;
+		static const Path DefaultCursorFolder;
 
 
 		static const WString DefaultFontPath;
 		static const WString DefaultFontPath;
 		static const UINT32 DefaultFontSize;
 		static const UINT32 DefaultFontSize;

+ 15 - 5
BansheeEngine/Source/BsBuiltinResources.cpp

@@ -21,8 +21,8 @@ namespace BansheeEngine
 	const WString BuiltinResources::DefaultFontPath = L"arial.ttf";
 	const WString BuiltinResources::DefaultFontPath = L"arial.ttf";
 	const UINT32 BuiltinResources::DefaultFontSize = 10;
 	const UINT32 BuiltinResources::DefaultFontSize = 10;
 
 
-	const WString BuiltinResources::DefaultSkinFolder = L"..\\..\\..\\..\\Data\\Engine\\Skin\\";
-	const WString BuiltinResources::DefaultCursorFolder = L"..\\..\\..\\..\\Data\\Engine\\Cursors\\";
+	const Path BuiltinResources::DefaultSkinFolder = L"..\\..\\..\\..\\Data\\Engine\\Skin\\";
+	const Path BuiltinResources::DefaultCursorFolder = L"..\\..\\..\\..\\Data\\Engine\\Cursors\\";
 
 
 	const WString BuiltinResources::WhiteTex = L"White.psd";
 	const WString BuiltinResources::WhiteTex = L"White.psd";
 
 
@@ -168,7 +168,9 @@ namespace BansheeEngine
 		HFont font;
 		HFont font;
 
 
 		{
 		{
-			WString fontPath = DefaultSkinFolder + DefaultFontPath;
+			Path fontPath = DefaultSkinFolder;
+			fontPath.append(DefaultFontPath);
+
 			ImportOptionsPtr fontImportOptions = Importer::instance().createImportOptions(fontPath);
 			ImportOptionsPtr fontImportOptions = Importer::instance().createImportOptions(fontPath);
 			if(rtti_is_of_type<FontImportOptions>(fontImportOptions))
 			if(rtti_is_of_type<FontImportOptions>(fontImportOptions))
 			{
 			{
@@ -541,12 +543,20 @@ namespace BansheeEngine
 
 
 	HSpriteTexture BuiltinResources::getSkinTexture(const WString& name)
 	HSpriteTexture BuiltinResources::getSkinTexture(const WString& name)
 	{
 	{
-		return SpriteTexture::create(static_resource_cast<Texture>(Importer::instance().import(FileSystem::getWorkingDirectoryPath() + L"\\" + DefaultSkinFolder + name)));
+		Path texturePath = FileSystem::getWorkingDirectoryPath();
+		texturePath.append(DefaultSkinFolder);
+		texturePath.append(name);
+
+		return SpriteTexture::create(static_resource_cast<Texture>(Importer::instance().import(texturePath)));
 	}
 	}
 
 
 	HTexture BuiltinResources::getCursorTexture(const WString& name)
 	HTexture BuiltinResources::getCursorTexture(const WString& name)
 	{
 	{
-		return static_resource_cast<Texture>(Importer::instance().import(FileSystem::getWorkingDirectoryPath() + L"\\" + DefaultCursorFolder + name));
+		Path cursorPath = FileSystem::getWorkingDirectoryPath();
+		cursorPath.append(DefaultCursorFolder);
+		cursorPath.append(name);
+
+		return static_resource_cast<Texture>(Importer::instance().import(cursorPath));
 	}
 	}
 
 
 	const PixelData& BuiltinResources::getCursorArrow(Vector2I& hotSpot)
 	const PixelData& BuiltinResources::getCursorArrow(Vector2I& hotSpot)

+ 1 - 1
CamelotCore/Include/CmGpuProgIncludeImporter.h

@@ -22,7 +22,7 @@ namespace BansheeEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 
 		/** @copydoc SpecificImporter::import */
 		/** @copydoc SpecificImporter::import */
-		virtual ResourcePtr import(const WString& filePath, ConstImportOptionsPtr importOptions);
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
 	private:
 	private:
 	};
 	};
 }
 }

+ 1 - 1
CamelotCore/Include/CmGpuProgramImporter.h

@@ -19,7 +19,7 @@ namespace BansheeEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 
 		/** @copydoc SpecificImporter::import */
 		/** @copydoc SpecificImporter::import */
-		virtual ResourcePtr import(const WString& filePath, ConstImportOptionsPtr importOptions);
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
 
 
 		/** @copydoc SpecificImporter::createImportOptions */
 		/** @copydoc SpecificImporter::createImportOptions */
 		virtual ImportOptionsPtr createImportOptions() const;
 		virtual ImportOptionsPtr createImportOptions() const;

+ 4 - 4
CamelotCore/Include/CmImporter.h

@@ -25,7 +25,7 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @see		createImportOptions
 		 * @see		createImportOptions
 		 */
 		 */
-		HResource import(const WString& inputFilePath, ConstImportOptionsPtr importOptions = nullptr);
+		HResource import(const Path& inputFilePath, ConstImportOptionsPtr importOptions = nullptr);
 
 
 		/**
 		/**
 		 * @brief	Imports a resource and replaces the contents of the provided existing resource with new imported data.
 		 * @brief	Imports a resource and replaces the contents of the provided existing resource with new imported data.
@@ -37,7 +37,7 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @see		createImportOptions
 		 * @see		createImportOptions
 		 */
 		 */
-		void reimport(HResource& existingResource, const WString& inputFilePath, ConstImportOptionsPtr importOptions = nullptr);
+		void reimport(HResource& existingResource, const Path& inputFilePath, ConstImportOptionsPtr importOptions = nullptr);
 
 
 		/**
 		/**
 		 * @brief	Automatically detects the importer needed for the provided file and returns valid type of
 		 * @brief	Automatically detects the importer needed for the provided file and returns valid type of
@@ -54,7 +54,7 @@ namespace BansheeEngine
 		 *			nullptr is returned if the file path is not valid, or if a valid importer cannot be found for
 		 *			nullptr is returned if the file path is not valid, or if a valid importer cannot be found for
 		 *			the specified file.
 		 *			the specified file.
 		 */
 		 */
-		ImportOptionsPtr createImportOptions(const WString& inputFilePath);
+		ImportOptionsPtr createImportOptions(const Path& inputFilePath);
 
 
 		/**
 		/**
 		 * @brief	Checks if we can import a file with the specified extension.
 		 * @brief	Checks if we can import a file with the specified extension.
@@ -84,6 +84,6 @@ namespace BansheeEngine
 	private:
 	private:
 		Vector<SpecificImporter*>::type mAssetImporters;
 		Vector<SpecificImporter*>::type mAssetImporters;
 
 
-		SpecificImporter* getImporterForFile(const WString& inputFilePath) const;
+		SpecificImporter* getImporterForFile(const Path& inputFilePath) const;
 	};
 	};
 }
 }

+ 1 - 4
CamelotCore/Include/CmPrerequisites.h

@@ -271,8 +271,6 @@ namespace BansheeEngine
 		TID_Font = 1051,
 		TID_Font = 1051,
 		TID_FONT_DESC = 1052,
 		TID_FONT_DESC = 1052,
 		TID_CHAR_DESC = 1053,
 		TID_CHAR_DESC = 1053,
-		TID_STDVECTOR = 1054,
-		TID_STDMAP = 1055,
 		TID_FontImportOptions = 1056,
 		TID_FontImportOptions = 1056,
 		TID_FontData = 1057,
 		TID_FontData = 1057,
 		TID_SceneObject = 1059,
 		TID_SceneObject = 1059,
@@ -284,8 +282,7 @@ namespace BansheeEngine
 		TID_MeshBase = 1065,
 		TID_MeshBase = 1065,
 		TID_GameObjectHandleBase = 1066,
 		TID_GameObjectHandleBase = 1066,
 		TID_ResourceManifest = 1067,
 		TID_ResourceManifest = 1067,
-		TID_ResourceManifestEntry = 1068,
-		TID_STDPAIR = 1069
+		TID_ResourceManifestEntry = 1068
 	};
 	};
 }
 }
 
 

+ 9 - 8
CamelotCore/Include/CmResourceManifest.h

@@ -2,6 +2,7 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmIReflectable.h"
 #include "CmIReflectable.h"
+#include "CmPath.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -22,14 +23,14 @@ namespace BansheeEngine
 
 
 		const String& getName() const { return mName; }
 		const String& getName() const { return mName; }
 
 
-		void registerResource(const String& uuid, const WString& filePath);
+		void registerResource(const String& uuid, const Path& filePath);
 		void unregisterResource(const String& uuid);
 		void unregisterResource(const String& uuid);
 
 
-		bool uuidToFilePath(const String& uuid, WString& filePath) const;
-		bool filePathToUUID(const WString& filePath, String& outUUID) const;
+		bool uuidToFilePath(const String& uuid, Path& filePath) const;
+		bool filePathToUUID(const Path& filePath, String& outUUID) const;
 
 
 		bool uuidExists(const String& uuid) const;
 		bool uuidExists(const String& uuid) const;
-		bool filePathExists(const WString& filePath) const;
+		bool filePathExists(const Path& filePath) const;
 
 
 		/**
 		/**
 		 * @brief	Saves the resource manifest to the specified location.
 		 * @brief	Saves the resource manifest to the specified location.
@@ -39,7 +40,7 @@ namespace BansheeEngine
 		 * @param	relativePath	If not empty, all pathnames in the manifest will be stored
 		 * @param	relativePath	If not empty, all pathnames in the manifest will be stored
 		 * 							as if relative to this path.
 		 * 							as if relative to this path.
 		 */
 		 */
-		static void save(const ResourceManifestPtr& manifest, const WString& path, const WString& relativePath);
+		static void save(const ResourceManifestPtr& manifest, const Path& path, const Path& relativePath);
 
 
 		/**
 		/**
 		 * @brief	Loads the resource manifest from the specified location.
 		 * @brief	Loads the resource manifest from the specified location.
@@ -48,14 +49,14 @@ namespace BansheeEngine
 		 * @param	relativePath	If not empty, all loaded pathnames will have this
 		 * @param	relativePath	If not empty, all loaded pathnames will have this
 		 * 							path prepended.
 		 * 							path prepended.
 		 */
 		 */
-		static ResourceManifestPtr load(const WString& path, const WString& relativePath);
+		static ResourceManifestPtr load(const Path& path, const Path& relativePath);
 
 
 		static ResourceManifestPtr create(const String& name);
 		static ResourceManifestPtr create(const String& name);
 
 
 	private:
 	private:
 		String mName;
 		String mName;
-		Map<String, WString>::type mUUIDToFilePath;
-		Map<WString, String>::type mFilePathToUUID;
+		UnorderedMap<String, Path>::type mUUIDToFilePath;
+		UnorderedMap<Path, String>::type mFilePathToUUID;
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/

+ 3 - 2
CamelotCore/Include/CmResourceManifestRTTI.h

@@ -3,6 +3,7 @@
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmRTTIType.h"
 #include "CmRTTIType.h"
 #include "CmResourceManifest.h"
 #include "CmResourceManifest.h"
+#include "CmPath.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -19,12 +20,12 @@ namespace BansheeEngine
 			obj->mName = val;
 			obj->mName = val;
 		}
 		}
 
 
-		Map<String, WString>::type& getUUIDMap(ResourceManifest* obj) 
+		UnorderedMap<String, Path>::type& getUUIDMap(ResourceManifest* obj)
 		{ 
 		{ 
 			return obj->mUUIDToFilePath;
 			return obj->mUUIDToFilePath;
 		}
 		}
 
 
-		void setUUIDMap(ResourceManifest* obj, Map<String, WString>::type& val) 
+		void setUUIDMap(ResourceManifest* obj, UnorderedMap<String, Path>::type& val)
 		{ 
 		{ 
 			obj->mUUIDToFilePath = val; 
 			obj->mUUIDToFilePath = val; 
 
 

+ 8 - 8
CamelotCore/Include/CmResources.h

@@ -29,7 +29,7 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @return	Loaded resource, or null if it cannot be found.
 		 * @return	Loaded resource, or null if it cannot be found.
 		 */
 		 */
-		HResource load(const WString& filePath);
+		HResource load(const Path& filePath);
 
 
 		/**
 		/**
 		 * @brief	Loads the resource asynchronously. Initially returned resource should not be used
 		 * @brief	Loads the resource asynchronously. Initially returned resource should not be used
@@ -39,7 +39,7 @@ namespace BansheeEngine
 		 * 						
 		 * 						
 		 * @return	Resource where the data will eventually be loaded, or null if the file cannot be found.
 		 * @return	Resource where the data will eventually be loaded, or null if the file cannot be found.
 		 */
 		 */
-		HResource loadAsync(const WString& filePath);
+		HResource loadAsync(const Path& filePath);
 
 
 		/**
 		/**
 		 * @brief	Loads the resource with the given uuid.
 		 * @brief	Loads the resource with the given uuid.
@@ -87,7 +87,7 @@ namespace BansheeEngine
 		 * 			sure all those commands are submitted before you call this method. Otherwise an obsolete
 		 * 			sure all those commands are submitted before you call this method. Otherwise an obsolete
 		 * 			version of the resource might get saved.
 		 * 			version of the resource might get saved.
 		 */
 		 */
-		void save(HResource resource, const WString& filePath, bool overwrite);
+		void save(HResource resource, const Path& filePath, bool overwrite);
 
 
 		/**
 		/**
 		 * @brief	Creates a new resource handle from a resource pointer. 
 		 * @brief	Creates a new resource handle from a resource pointer. 
@@ -118,8 +118,8 @@ namespace BansheeEngine
 		 */
 		 */
 		ResourceManifestPtr getResourceManifest(const String& name) const;
 		ResourceManifestPtr getResourceManifest(const String& name) const;
 
 
-		bool getFilePathFromUUID(const String& uuid, WString& filePath) const;
-		bool getUUIDFromFilePath(const WString& path, String& uuid) const;
+		bool getFilePathFromUUID(const String& uuid, Path& filePath) const;
+		bool getUUIDFromFilePath(const Path& path, String& uuid) const;
 
 
 	private:
 	private:
 		Vector<ResourceManifestPtr>::type mResourceManifests;
 		Vector<ResourceManifestPtr>::type mResourceManifests;
@@ -131,10 +131,10 @@ namespace BansheeEngine
 		UnorderedMap<String, HResource>::type mLoadedResources; 
 		UnorderedMap<String, HResource>::type mLoadedResources; 
 		UnorderedMap<String, HResource>::type mInProgressResources; // Resources that are being asynchronously loaded
 		UnorderedMap<String, HResource>::type mInProgressResources; // Resources that are being asynchronously loaded
 
 
-		HResource loadInternal(const WString& filePath, bool synchronous); 
-		ResourcePtr loadFromDiskAndDeserialize(const WString& filePath);
+		HResource loadInternal(const Path& filePath, bool synchronous);
+		ResourcePtr loadFromDiskAndDeserialize(const Path& filePath);
 
 
-		void loadCallback(const WString& filePath, HResource& resource);
+		void loadCallback(const Path& filePath, HResource& resource);
 	};
 	};
 
 
 	CM_EXPORT Resources& gResources();
 	CM_EXPORT Resources& gResources();

+ 1 - 1
CamelotCore/Include/CmSpecificImporter.h

@@ -37,7 +37,7 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @return	null if it fails, otherwise the loaded object.
 		 * @return	null if it fails, otherwise the loaded object.
 		 */
 		 */
-		virtual ResourcePtr import(const WString& filePath, ConstImportOptionsPtr importOptions) = 0;
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions) = 0;
 
 
 		/**
 		/**
 		 * @brief	Creates import options specific for this importer. Import
 		 * @brief	Creates import options specific for this importer. Import

+ 6 - 6
CamelotCore/Include/CmWin32FolderMonitor.h

@@ -42,12 +42,12 @@ namespace BansheeEngine
 		 * @param	changeFilter	A set of flags you may OR together. Different notification events will
 		 * @param	changeFilter	A set of flags you may OR together. Different notification events will
 		 *							trigger depending on which flags you set.
 		 *							trigger depending on which flags you set.
 		 */
 		 */
-		void startMonitor(const WString& folderPath, bool subdirectories, FolderChange changeFilter);
+		void startMonitor(const Path& folderPath, bool subdirectories, FolderChange changeFilter);
 
 
 		/**
 		/**
 		 * @brief	Stops monitoring the folder at the specified path.
 		 * @brief	Stops monitoring the folder at the specified path.
 		 */
 		 */
-		void stopMonitor(const WString& folderPath);
+		void stopMonitor(const Path& folderPath);
 
 
 		/**
 		/**
 		 * @brief	Stops monitoring all folders that are currently being monitored.
 		 * @brief	Stops monitoring all folders that are currently being monitored.
@@ -65,25 +65,25 @@ namespace BansheeEngine
 		 * @brief	Triggers when a file is modified. Provides
 		 * @brief	Triggers when a file is modified. Provides
 		 *			full path to the file.
 		 *			full path to the file.
 		 */
 		 */
-		boost::signal<void(const WString&)> onModified;
+		boost::signal<void(const Path&)> onModified;
 
 
 		/**
 		/**
 		 * @brief	Triggers when a file/folder is adeed. Provides
 		 * @brief	Triggers when a file/folder is adeed. Provides
 		 *			full path to the file/folder.
 		 *			full path to the file/folder.
 		 */
 		 */
-		boost::signal<void(const WString&)> onAdded;
+		boost::signal<void(const Path&)> onAdded;
 
 
 		/**
 		/**
 		 * @brief	Triggers when a file/folder is removed. Provides
 		 * @brief	Triggers when a file/folder is removed. Provides
 		 *			full path to the file/folder.
 		 *			full path to the file/folder.
 		 */
 		 */
-		boost::signal<void(const WString&)> onRemoved;
+		boost::signal<void(const Path&)> onRemoved;
 
 
 		/**
 		/**
 		 * @brief	Triggers when a file/folder is renamed. Provides
 		 * @brief	Triggers when a file/folder is renamed. Provides
 		 *			full path to the old and new name.
 		 *			full path to the old and new name.
 		 */
 		 */
-		boost::signal<void(const WString&, const WString&)> onRenamed;
+		boost::signal<void(const Path&, const Path&)> onRenamed;
 
 
 	private:
 	private:
 		Pimpl* mPimpl;
 		Pimpl* mPimpl;

+ 2 - 2
CamelotCore/Source/CmGpuProgIncludeImporter.cpp

@@ -30,14 +30,14 @@ namespace BansheeEngine
 		return true; // Plain-text so I don't even check for magic number
 		return true; // Plain-text so I don't even check for magic number
 	}
 	}
 
 
-	ResourcePtr GpuProgIncludeImporter::import(const WString& filePath, ConstImportOptionsPtr importOptions)
+	ResourcePtr GpuProgIncludeImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
 	{
 	{
 		DataStreamPtr stream = FileSystem::openFile(filePath);
 		DataStreamPtr stream = FileSystem::openFile(filePath);
 		String includeString = stream->getAsString();
 		String includeString = stream->getAsString();
 
 
 		GpuProgIncludePtr gpuInclude = GpuProgInclude::_createPtr(includeString);
 		GpuProgIncludePtr gpuInclude = GpuProgInclude::_createPtr(includeString);
 
 
-		WString fileName = OldPath::getFilename(filePath, false);
+		WString fileName = filePath.getWFilename(false);
 		gpuInclude->setName(toString(fileName));
 		gpuInclude->setName(toString(fileName));
 
 
 		return gpuInclude;
 		return gpuInclude;

+ 3 - 3
CamelotCore/Source/CmGpuProgramImporter.cpp

@@ -21,9 +21,9 @@ namespace BansheeEngine
 		return true;
 		return true;
 	}
 	}
 
 
-	ResourcePtr GpuProgramImporter::import(const WString& filePath, ConstImportOptionsPtr importOptions)
+	ResourcePtr GpuProgramImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
 	{
 	{
-		WString ext = OldPath::getExtension(filePath);
+		WString ext = filePath.getWExtension();
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 
 
 		DataStreamPtr stream = FileSystem::openFile(filePath);
 		DataStreamPtr stream = FileSystem::openFile(filePath);
@@ -40,7 +40,7 @@ namespace BansheeEngine
 		HighLevelGpuProgramPtr gpuProgram = HighLevelGpuProgram::_createPtr(shaderSource, entryPoint, language, gptype, profile, &includes);
 		HighLevelGpuProgramPtr gpuProgram = HighLevelGpuProgram::_createPtr(shaderSource, entryPoint, language, gptype, profile, &includes);
 		gpuProgram->synchronize();
 		gpuProgram->synchronize();
 
 
-		WString fileName = OldPath::getFilename(filePath, false);
+		WString fileName = filePath.getWFilename(false);
 		gpuProgram->setName(toString(fileName));
 		gpuProgram->setName(toString(fileName));
 
 
 		return gpuProgram;
 		return gpuProgram;

+ 9 - 9
CamelotCore/Source/CmImporter.cpp

@@ -53,11 +53,11 @@ namespace BansheeEngine
 		return false;
 		return false;
 	}
 	}
 
 
-	HResource Importer::import(const WString& inputFilePath, ConstImportOptionsPtr importOptions)
+	HResource Importer::import(const Path& inputFilePath, ConstImportOptionsPtr importOptions)
 	{
 	{
 		if(!FileSystem::isFile(inputFilePath))
 		if(!FileSystem::isFile(inputFilePath))
 		{
 		{
-			LOGWRN("Trying to import asset that doesn't exists. Asset path: " + toString(inputFilePath));
+			LOGWRN("Trying to import asset that doesn't exists. Asset path: " + inputFilePath.toString());
 			return HResource();
 			return HResource();
 		}
 		}
 
 
@@ -81,11 +81,11 @@ namespace BansheeEngine
 		return gResources().createResourceHandle(importedResource);
 		return gResources().createResourceHandle(importedResource);
 	}
 	}
 
 
-	void Importer::reimport(HResource& existingResource, const WString& inputFilePath, ConstImportOptionsPtr importOptions)
+	void Importer::reimport(HResource& existingResource, const Path& inputFilePath, ConstImportOptionsPtr importOptions)
 	{
 	{
 		if(!FileSystem::isFile(inputFilePath))
 		if(!FileSystem::isFile(inputFilePath))
 		{
 		{
-			LOGWRN("Trying to import asset that doesn't exists. Asset path: " + toString(inputFilePath));
+			LOGWRN("Trying to import asset that doesn't exists. Asset path: " + inputFilePath.toString());
 			return;
 			return;
 		}
 		}
 
 
@@ -109,11 +109,11 @@ namespace BansheeEngine
 		existingResource._setHandleData(importedResource, existingResource.getUUID());
 		existingResource._setHandleData(importedResource, existingResource.getUUID());
 	}
 	}
 
 
-	ImportOptionsPtr Importer::createImportOptions(const WString& inputFilePath)
+	ImportOptionsPtr Importer::createImportOptions(const Path& inputFilePath)
 	{
 	{
 		if(!FileSystem::isFile(inputFilePath))
 		if(!FileSystem::isFile(inputFilePath))
 		{
 		{
-			LOGWRN("Trying to import asset that doesn't exists. Asset path: " + toString(inputFilePath));
+			LOGWRN("Trying to import asset that doesn't exists. Asset path: " + inputFilePath.toString());
 			return nullptr;
 			return nullptr;
 		}
 		}
 
 
@@ -135,13 +135,13 @@ namespace BansheeEngine
 		mAssetImporters.push_back(importer);
 		mAssetImporters.push_back(importer);
 	}
 	}
 
 
-	SpecificImporter* Importer::getImporterForFile(const WString& inputFilePath) const
+	SpecificImporter* Importer::getImporterForFile(const Path& inputFilePath) const
 	{
 	{
-		WString ext = OldPath::getExtension(inputFilePath);
+		WString ext = inputFilePath.getWExtension();
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		if(!supportsFileType(ext))
 		if(!supportsFileType(ext))
 		{
 		{
-			LOGWRN("There is no importer for the provided file type. (" + toString(inputFilePath) + ")");
+			LOGWRN("There is no importer for the provided file type. (" + inputFilePath.toString() + ")");
 			return nullptr;
 			return nullptr;
 		}
 		}
 
 

+ 24 - 39
CamelotCore/Source/CmResourceManifest.cpp

@@ -27,27 +27,24 @@ namespace BansheeEngine
 		return cm_shared_ptr<ResourceManifest>(ConstructPrivately());
 		return cm_shared_ptr<ResourceManifest>(ConstructPrivately());
 	}
 	}
 
 
-	void ResourceManifest::registerResource(const String& uuid, const WString& filePath)
+	void ResourceManifest::registerResource(const String& uuid, const Path& filePath)
 	{
 	{
 		auto iterFind = mUUIDToFilePath.find(uuid);
 		auto iterFind = mUUIDToFilePath.find(uuid);
 
 
-		WString standardizedFilePath = OldPath::standardizePath(filePath);
-		StringUtil::toLowerCase(standardizedFilePath);
-
 		if(iterFind != mUUIDToFilePath.end())
 		if(iterFind != mUUIDToFilePath.end())
 		{
 		{
-			if(iterFind->second != standardizedFilePath)
+			if (iterFind->second != filePath)
 			{
 			{
 				mFilePathToUUID.erase(iterFind->second);
 				mFilePathToUUID.erase(iterFind->second);
 
 
-				mUUIDToFilePath[uuid] = standardizedFilePath;
-				mFilePathToUUID[standardizedFilePath] = uuid;
+				mUUIDToFilePath[uuid] = filePath;
+				mFilePathToUUID[filePath] = uuid;
 			}
 			}
 		}
 		}
 		else
 		else
 		{
 		{
-			mUUIDToFilePath[uuid] = standardizedFilePath;
-			mFilePathToUUID[standardizedFilePath] = uuid;
+			mUUIDToFilePath[uuid] = filePath;
+			mFilePathToUUID[filePath] = uuid;
 		}
 		}
 	}
 	}
 
 
@@ -62,7 +59,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	bool ResourceManifest::uuidToFilePath(const String& uuid, WString& filePath) const
+	bool ResourceManifest::uuidToFilePath(const String& uuid, Path& filePath) const
 	{
 	{
 		auto iterFind = mUUIDToFilePath.find(uuid);
 		auto iterFind = mUUIDToFilePath.find(uuid);
 
 
@@ -73,17 +70,14 @@ namespace BansheeEngine
 		}
 		}
 		else
 		else
 		{
 		{
-			filePath = StringUtil::WBLANK;
+			filePath = Path::BLANK;
 			return false;
 			return false;
 		}
 		}
 	}
 	}
 
 
-	bool ResourceManifest::filePathToUUID(const WString& filePath, String& outUUID) const
+	bool ResourceManifest::filePathToUUID(const Path& filePath, String& outUUID) const
 	{
 	{
-		WString standardizedFilePath = OldPath::standardizePath(filePath);
-		StringUtil::toLowerCase(standardizedFilePath);
-
-		auto iterFind = mFilePathToUUID.find(standardizedFilePath);
+		auto iterFind = mFilePathToUUID.find(filePath);
 
 
 		if(iterFind != mFilePathToUUID.end())
 		if(iterFind != mFilePathToUUID.end())
 		{
 		{
@@ -104,58 +98,49 @@ namespace BansheeEngine
 		return iterFind != mUUIDToFilePath.end();
 		return iterFind != mUUIDToFilePath.end();
 	}
 	}
 
 
-	bool ResourceManifest::filePathExists(const WString& filePath) const
+	bool ResourceManifest::filePathExists(const Path& filePath) const
 	{
 	{
-		WString standardizedFilePath = OldPath::standardizePath(filePath);
-		StringUtil::toLowerCase(standardizedFilePath);
-
-		auto iterFind = mFilePathToUUID.find(standardizedFilePath);
+		auto iterFind = mFilePathToUUID.find(filePath);
 
 
 		return iterFind != mFilePathToUUID.end();
 		return iterFind != mFilePathToUUID.end();
 	}
 	}
 
 
-	void ResourceManifest::save(const ResourceManifestPtr& manifest, const WString& path, const WString& relativePath)
+	void ResourceManifest::save(const ResourceManifestPtr& manifest, const Path& path, const Path& relativePath)
 	{
 	{
-		WString standRelativePath = OldPath::standardizePath(relativePath);
-		StringUtil::toLowerCase(standRelativePath);
-
 		ResourceManifestPtr copy = create(manifest->mName);
 		ResourceManifestPtr copy = create(manifest->mName);
 
 
 		for(auto& elem : manifest->mFilePathToUUID)
 		for(auto& elem : manifest->mFilePathToUUID)
 		{
 		{
-			if(!OldPath::includes(elem.first, standRelativePath))
+			if (!relativePath.includes(elem.first))
 			{
 			{
 				CM_EXCEPT(InvalidStateException, "Path in resource manifest cannot be made relative to: \"" + 
 				CM_EXCEPT(InvalidStateException, "Path in resource manifest cannot be made relative to: \"" + 
-					toString(relativePath) + "\". Path: \"" + toString(elem.first) + "\"");
+					relativePath.toString() + "\". Path: \"" + elem.first.toString() + "\"");
 			}
 			}
 
 
-			WString relativePath = OldPath::relative(standRelativePath, elem.first);
+			Path elementRelativePath = elem.first.getRelative(relativePath);
 
 
-			copy->mFilePathToUUID[relativePath] = elem.second;
+			copy->mFilePathToUUID[elementRelativePath] = elem.second;
 		}
 		}
 
 
 		for(auto& elem : manifest->mUUIDToFilePath)
 		for(auto& elem : manifest->mUUIDToFilePath)
 		{
 		{
-			if(!OldPath::includes(elem.second, standRelativePath))
+			if(!relativePath.includes(elem.second))
 			{
 			{
 				CM_EXCEPT(InvalidStateException, "Path in resource manifest cannot be made relative to: \"" + 
 				CM_EXCEPT(InvalidStateException, "Path in resource manifest cannot be made relative to: \"" + 
-					toString(relativePath) + "\". Path: \"" + toString(elem.second) + "\"");
+					relativePath.toString() + "\". Path: \"" + elem.second.toString() + "\"");
 			}
 			}
 
 
-			WString relativePath = OldPath::relative(standRelativePath, elem.second);
+			Path elementRelativePath = elem.second.getRelative(relativePath);
 
 
-			copy->mUUIDToFilePath[elem.first] = relativePath;
+			copy->mUUIDToFilePath[elem.first] = elementRelativePath;
 		}
 		}
 
 
 		FileSerializer fs;
 		FileSerializer fs;
 		fs.encode(copy.get(), path);
 		fs.encode(copy.get(), path);
 	}
 	}
 
 
-	ResourceManifestPtr ResourceManifest::load(const WString& path, const WString& relativePath)
+	ResourceManifestPtr ResourceManifest::load(const Path& path, const Path& relativePath)
 	{
 	{
-		WString standRelativePath = OldPath::standardizePath(relativePath);
-		StringUtil::toLowerCase(standRelativePath);
-
 		FileSerializer fs;
 		FileSerializer fs;
 		ResourceManifestPtr manifest = std::static_pointer_cast<ResourceManifest>(fs.decode(path));
 		ResourceManifestPtr manifest = std::static_pointer_cast<ResourceManifest>(fs.decode(path));
 
 
@@ -163,13 +148,13 @@ namespace BansheeEngine
 
 
 		for(auto& elem : manifest->mFilePathToUUID)
 		for(auto& elem : manifest->mFilePathToUUID)
 		{
 		{
-			WString absPath = OldPath::combine(standRelativePath, elem.first);
+			Path absPath = elem.first.getAbsolute(relativePath);
 			copy->mFilePathToUUID[absPath] = elem.second;
 			copy->mFilePathToUUID[absPath] = elem.second;
 		}
 		}
 
 
 		for(auto& elem : manifest->mUUIDToFilePath)
 		for(auto& elem : manifest->mUUIDToFilePath)
 		{
 		{
-			WString absPath = OldPath::combine(standRelativePath, elem.second);
+			Path absPath = elem.second.getAbsolute(relativePath);
 			copy->mUUIDToFilePath[elem.first] = absPath;
 			copy->mUUIDToFilePath[elem.first] = absPath;
 		}
 		}
 
 

+ 12 - 12
CamelotCore/Source/CmResources.cpp

@@ -22,19 +22,19 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
-	HResource Resources::load(const WString& filePath)
+	HResource Resources::load(const Path& filePath)
 	{
 	{
 		return loadInternal(filePath, true);
 		return loadInternal(filePath, true);
 	}
 	}
 
 
-	HResource Resources::loadAsync(const WString& filePath)
+	HResource Resources::loadAsync(const Path& filePath)
 	{
 	{
 		return loadInternal(filePath, false);
 		return loadInternal(filePath, false);
 	}
 	}
 
 
 	HResource Resources::loadFromUUID(const String& uuid)
 	HResource Resources::loadFromUUID(const String& uuid)
 	{
 	{
-		WString filePath;
+		Path filePath;
 		bool foundPath = false;
 		bool foundPath = false;
 
 
 		// Default manifest is at 0th index but all other take priority since Default manifest could
 		// Default manifest is at 0th index but all other take priority since Default manifest could
@@ -59,7 +59,7 @@ namespace BansheeEngine
 
 
 	HResource Resources::loadFromUUIDAsync(const String& uuid)
 	HResource Resources::loadFromUUIDAsync(const String& uuid)
 	{
 	{
-		WString filePath;
+		Path filePath;
 		bool foundPath = false;
 		bool foundPath = false;
 
 
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
@@ -80,7 +80,7 @@ namespace BansheeEngine
 		return loadAsync(filePath);
 		return loadAsync(filePath);
 	}
 	}
 
 
-	HResource Resources::loadInternal(const WString& filePath, bool synchronous)
+	HResource Resources::loadInternal(const Path& filePath, bool synchronous)
 	{
 	{
 		String uuid;
 		String uuid;
 		bool foundUUID = false;
 		bool foundUUID = false;
@@ -133,7 +133,7 @@ namespace BansheeEngine
 
 
 		if(!FileSystem::isFile(filePath))
 		if(!FileSystem::isFile(filePath))
 		{
 		{
-			gDebug().logWarning("Specified file: " + toString(filePath) + " doesn't exist.");
+			gDebug().logWarning("Specified file: " + filePath.toString() + " doesn't exist.");
 			return HResource();
 			return HResource();
 		}
 		}
 
 
@@ -150,7 +150,7 @@ namespace BansheeEngine
 		}
 		}
 		else
 		else
 		{
 		{
-			String fileName = toString(OldPath::getFilename(filePath));
+			String fileName = filePath.getFilename();
 			String taskName = "Resource load: " + fileName;
 			String taskName = "Resource load: " + fileName;
 
 
 			TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, newResource));
 			TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, newResource));
@@ -160,7 +160,7 @@ namespace BansheeEngine
 		return newResource;
 		return newResource;
 	}
 	}
 
 
-	ResourcePtr Resources::loadFromDiskAndDeserialize(const WString& filePath)
+	ResourcePtr Resources::loadFromDiskAndDeserialize(const Path& filePath)
 	{
 	{
 		FileSerializer fs;
 		FileSerializer fs;
 		std::shared_ptr<IReflectable> loadedData = fs.decode(filePath);
 		std::shared_ptr<IReflectable> loadedData = fs.decode(filePath);
@@ -207,7 +207,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void Resources::save(HResource resource, const WString& filePath, bool overwrite)
+	void Resources::save(HResource resource, const Path& filePath, bool overwrite)
 	{
 	{
 		if(!resource.isLoaded())
 		if(!resource.isLoaded())
 			resource.synchronize();
 			resource.synchronize();
@@ -264,7 +264,7 @@ namespace BansheeEngine
 		return newHandle;
 		return newHandle;
 	}
 	}
 
 
-	bool Resources::getFilePathFromUUID(const String& uuid, WString& filePath) const
+	bool Resources::getFilePathFromUUID(const String& uuid, Path& filePath) const
 	{
 	{
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
 		{
 		{
@@ -275,7 +275,7 @@ namespace BansheeEngine
 		return false;
 		return false;
 	}
 	}
 
 
-	bool Resources::getUUIDFromFilePath(const WString& path, String& uuid) const
+	bool Resources::getUUIDFromFilePath(const Path& path, String& uuid) const
 	{
 	{
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
 		{
 		{
@@ -286,7 +286,7 @@ namespace BansheeEngine
 		return false;
 		return false;
 	}
 	}
 
 
-	void Resources::loadCallback(const WString& filePath, HResource& resource)
+	void Resources::loadCallback(const Path& filePath, HResource& resource)
 	{
 	{
 		ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
 		ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
 
 

+ 20 - 30
CamelotCore/Source/CmWin32FolderMonitor.cpp

@@ -1,6 +1,7 @@
 #include "CmWin32FolderMonitor.h"
 #include "CmWin32FolderMonitor.h"
 #include "CmFileSystem.h"
 #include "CmFileSystem.h"
 #include "CmException.h"
 #include "CmException.h"
+#include "CmPath.h"
 
 
 #include "CmDebug.h"
 #include "CmDebug.h"
 
 
@@ -30,7 +31,7 @@ namespace BansheeEngine
 
 
 	struct FolderMonitor::FolderWatchInfo
 	struct FolderMonitor::FolderWatchInfo
 	{
 	{
-		FolderWatchInfo(const WString& folderToMonitor, HANDLE dirHandle, bool monitorSubdirectories, DWORD monitorFlags);
+		FolderWatchInfo(const Path& folderToMonitor, HANDLE dirHandle, bool monitorSubdirectories, DWORD monitorFlags);
 		~FolderWatchInfo();
 		~FolderWatchInfo();
 
 
 		void startMonitor(HANDLE compPortHandle);
 		void startMonitor(HANDLE compPortHandle);
@@ -38,7 +39,7 @@ namespace BansheeEngine
 
 
 		static const UINT32 READ_BUFFER_SIZE = 65536;
 		static const UINT32 READ_BUFFER_SIZE = 65536;
 
 
-		WString mFolderToMonitor;
+		Path mFolderToMonitor;
 		HANDLE mDirHandle;
 		HANDLE mDirHandle;
 		OVERLAPPED mOverlapped;
 		OVERLAPPED mOverlapped;
 		MonitorState mState;
 		MonitorState mState;
@@ -54,13 +55,10 @@ namespace BansheeEngine
 		CM_THREAD_SYNCHRONISER(mStartStopEvent)
 		CM_THREAD_SYNCHRONISER(mStartStopEvent)
 	};
 	};
 
 
-	FolderMonitor::FolderWatchInfo::FolderWatchInfo(const WString& folderToMonitor, HANDLE dirHandle, bool monitorSubdirectories, DWORD monitorFlags)
+	FolderMonitor::FolderWatchInfo::FolderWatchInfo(const Path& folderToMonitor, HANDLE dirHandle, bool monitorSubdirectories, DWORD monitorFlags)
 		:mFolderToMonitor(folderToMonitor), mDirHandle(dirHandle), mState(MonitorState::Inactive), mBufferSize(0),
 		:mFolderToMonitor(folderToMonitor), mDirHandle(dirHandle), mState(MonitorState::Inactive), mBufferSize(0),
 		mMonitorSubdirectories(monitorSubdirectories), mMonitorFlags(monitorFlags), mReadError(0)
 		mMonitorSubdirectories(monitorSubdirectories), mMonitorFlags(monitorFlags), mReadError(0)
 	{
 	{
-		StringUtil::trim(mFolderToMonitor, L"\\", false, true);
-		StringUtil::toLowerCase(mFolderToMonitor);
-
 		memset(&mOverlapped, 0, sizeof(mOverlapped));
 		memset(&mOverlapped, 0, sizeof(mOverlapped));
 	}
 	}
 
 
@@ -94,7 +92,7 @@ namespace BansheeEngine
 			}
 			}
 
 
 			CM_EXCEPT(InternalErrorException, "Failed to start folder monitor on folder \"" + 
 			CM_EXCEPT(InternalErrorException, "Failed to start folder monitor on folder \"" + 
-				toString(mFolderToMonitor) + "\" because ReadDirectoryChangesW failed.");
+				mFolderToMonitor.toString() + "\" because ReadDirectoryChangesW failed.");
 		}
 		}
 	}
 	}
 
 
@@ -131,7 +129,7 @@ namespace BansheeEngine
 	
 	
 		DWORD	getAction() const;
 		DWORD	getAction() const;
 		WString getFileName() const;
 		WString getFileName() const;
-		WString getFileNameWithPath(const WString& rootPath) const;
+		WString getFileNameWithPath(const Path& rootPath) const;
 
 
 	
 	
 	protected:
 	protected:
@@ -186,14 +184,10 @@ namespace BansheeEngine
 		return WString();
 		return WString();
 	}		
 	}		
 
 
-	WString FolderMonitor::FileNotifyInfo::getFileNameWithPath(const WString& rootPath) const
+	WString FolderMonitor::FileNotifyInfo::getFileNameWithPath(const Path& rootPath) const
 	{
 	{
-		WStringStream wss;
-		wss<<rootPath;
-		wss<<L"\\";
-		wss<<getFileName();
-
-		return wss.str();
+		Path fullPath = rootPath;
+		return fullPath.append(getFileName()).toWString();
 	}
 	}
 
 
 	enum class FileActionType
 	enum class FileActionType
@@ -325,21 +319,21 @@ namespace BansheeEngine
 		cm_delete(mPimpl);
 		cm_delete(mPimpl);
 	}
 	}
 
 
-	void FolderMonitor::startMonitor(const WString& folderPath, bool subdirectories, FolderChange changeFilter)
+	void FolderMonitor::startMonitor(const Path& folderPath, bool subdirectories, FolderChange changeFilter)
 	{
 	{
 		if(!FileSystem::isDirectory(folderPath))
 		if(!FileSystem::isDirectory(folderPath))
 		{
 		{
-			CM_EXCEPT(InvalidParametersException, "Provided path \"" + toString(folderPath) + "\" is not a directory");
+			CM_EXCEPT(InvalidParametersException, "Provided path \"" + folderPath.toString() + "\" is not a directory");
 		}
 		}
 
 
-		WString extendedFolderPath = L"\\\\?\\" + folderPath;
-		HANDLE dirHandle = CreateFileW(folderPath.c_str(), FILE_LIST_DIRECTORY, 
+		WString extendedFolderPath = L"\\\\?\\" + folderPath.toWString(Path::PathType::Windows);
+		HANDLE dirHandle = CreateFileW(extendedFolderPath.c_str(), FILE_LIST_DIRECTORY,
 			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING,
 			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING,
 			FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
 			FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
 
 
 		if(dirHandle == INVALID_HANDLE_VALUE)
 		if(dirHandle == INVALID_HANDLE_VALUE)
 		{
 		{
-			CM_EXCEPT(InternalErrorException, "Failed to open folder \"" + toString(folderPath) + "\" for monitoring. Error code: " + toString((UINT64)GetLastError()));
+			CM_EXCEPT(InternalErrorException, "Failed to open folder \"" + folderPath.toString() + "\" for monitoring. Error code: " + toString((UINT64)GetLastError()));
 		}
 		}
 
 
 		DWORD filterFlags = 0;
 		DWORD filterFlags = 0;
@@ -414,14 +408,10 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void FolderMonitor::stopMonitor(const WString& folderPath)
+	void FolderMonitor::stopMonitor(const Path& folderPath)
 	{
 	{
-		WString folderPathForComparison = folderPath;
-		StringUtil::trim(folderPathForComparison, L"\\", false, true);
-		StringUtil::toLowerCase(folderPathForComparison);
-
 		auto findIter = std::find_if(mPimpl->mFoldersToWatch.begin(), mPimpl->mFoldersToWatch.end(), 
 		auto findIter = std::find_if(mPimpl->mFoldersToWatch.begin(), mPimpl->mFoldersToWatch.end(), 
-			[&] (const FolderWatchInfo* x) { return x->mFolderToMonitor == folderPathForComparison; });
+			[&](const FolderWatchInfo* x) { return x->mFolderToMonitor == folderPath; });
 
 
 		if(findIter != mPimpl->mFoldersToWatch.end())
 		if(findIter != mPimpl->mFoldersToWatch.end())
 		{
 		{
@@ -654,19 +644,19 @@ namespace BansheeEngine
 			{
 			{
 			case FileActionType::Added:
 			case FileActionType::Added:
 				if(!onAdded.empty())
 				if(!onAdded.empty())
-					onAdded(WString(action->newName));
+					onAdded(Path(action->newName));
 				break;
 				break;
 			case FileActionType::Removed:
 			case FileActionType::Removed:
 				if(!onRemoved.empty())
 				if(!onRemoved.empty())
-					onRemoved(WString(action->newName));
+					onRemoved(Path(action->newName));
 				break;
 				break;
 			case FileActionType::Modified:
 			case FileActionType::Modified:
 				if(!onModified.empty())
 				if(!onModified.empty())
-					onModified(WString(action->newName));
+					onModified(Path(action->newName));
 				break;
 				break;
 			case FileActionType::Renamed:
 			case FileActionType::Renamed:
 				if(!onRenamed.empty())
 				if(!onRenamed.empty())
-					onRenamed(WString(action->oldName), WString(action->newName));
+					onRenamed(Path(action->oldName), Path(action->newName));
 				break;
 				break;
 			}
 			}
 
 

+ 2 - 2
CamelotFBXImporter/Include/CmFBXImporter.h

@@ -36,14 +36,14 @@ namespace BansheeEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 
 		/** Inherited from SpecificImporter */
 		/** Inherited from SpecificImporter */
-		virtual ResourcePtr import(const WString& filePath, ConstImportOptionsPtr importOptions);
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
 	private:
 	private:
 		Vector<WString>::type mExtensions;
 		Vector<WString>::type mExtensions;
 
 
 		void startUpSdk(FbxManager*& manager, FbxScene*& scene);
 		void startUpSdk(FbxManager*& manager, FbxScene*& scene);
 		void shutDownSdk(FbxManager* manager);
 		void shutDownSdk(FbxManager* manager);
 
 
-		void loadScene(FbxManager* manager, FbxScene* scene, const WString& filePath);
+		void loadScene(FbxManager* manager, FbxScene* scene, const Path& filePath);
 		MeshDataPtr parseScene(FbxManager* manager, FbxScene* scene, Vector<SubMesh>::type& subMeshes);
 		MeshDataPtr parseScene(FbxManager* manager, FbxScene* scene, Vector<SubMesh>::type& subMeshes);
 
 
 		MeshDataPtr parseMesh(FbxMesh* mesh, Vector<SubMesh>::type& subMeshes, bool createTangentsIfMissing = true);
 		MeshDataPtr parseMesh(FbxMesh* mesh, Vector<SubMesh>::type& subMeshes, bool createTangentsIfMissing = true);

+ 4 - 4
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -37,7 +37,7 @@ namespace BansheeEngine
 		return true; // FBX files can be plain-text so I don't even check for magic number
 		return true; // FBX files can be plain-text so I don't even check for magic number
 	}
 	}
 
 
-	ResourcePtr FBXImporter::import(const WString& filePath, ConstImportOptionsPtr importOptions)
+	ResourcePtr FBXImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
 	{
 	{
 		FbxManager* fbxManager = nullptr;
 		FbxManager* fbxManager = nullptr;
 		FbxScene* fbxScene = nullptr;
 		FbxScene* fbxScene = nullptr;
@@ -53,7 +53,7 @@ namespace BansheeEngine
 		MeshPtr mesh = Mesh::_createPtr(meshData);
 		MeshPtr mesh = Mesh::_createPtr(meshData);
 		mesh->setSubMeshes(subMeshes);
 		mesh->setSubMeshes(subMeshes);
 
 
-		WString fileName = OldPath::getFilename(filePath, false);
+		WString fileName = filePath.getWFilename(false);
 		mesh->setName(toString(fileName));
 		mesh->setName(toString(fileName));
 
 
 		return mesh;
 		return mesh;
@@ -81,14 +81,14 @@ namespace BansheeEngine
 		manager->Destroy();
 		manager->Destroy();
 	}
 	}
 
 
-	void FBXImporter::loadScene(FbxManager* manager, FbxScene* scene, const WString& filePath)
+	void FBXImporter::loadScene(FbxManager* manager, FbxScene* scene, const Path& filePath)
 	{
 	{
 		int lFileMajor, lFileMinor, lFileRevision;
 		int lFileMajor, lFileMinor, lFileRevision;
 		int lSDKMajor,  lSDKMinor,  lSDKRevision;
 		int lSDKMajor,  lSDKMinor,  lSDKRevision;
 		FbxManager::GetFileFormatVersion(lSDKMajor, lSDKMinor, lSDKRevision);
 		FbxManager::GetFileFormatVersion(lSDKMajor, lSDKMinor, lSDKRevision);
 
 
 		FbxImporter* importer = FbxImporter::Create(manager, "");
 		FbxImporter* importer = FbxImporter::Create(manager, "");
-		bool importStatus = importer->Initialize(toString(filePath).c_str(), -1, manager->GetIOSettings());
+		bool importStatus = importer->Initialize(filePath.toString().c_str(), -1, manager->GetIOSettings());
 		
 		
 		importer->GetFileVersion(lFileMajor, lFileMinor, lFileRevision);
 		importer->GetFileVersion(lFileMajor, lFileMinor, lFileRevision);
 
 

+ 1 - 1
CamelotFontImporter/Include/CmFontImporter.h

@@ -32,7 +32,7 @@ namespace BansheeEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 
 		/** Inherited from SpecificImporter */
 		/** Inherited from SpecificImporter */
-		virtual ResourcePtr import(const WString& filePath, ConstImportOptionsPtr importOptions);
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
 
 
 		/**
 		/**
 		 * @copydoc SpecificImporter::createImportOptions().
 		 * @copydoc SpecificImporter::createImportOptions().

+ 5 - 5
CamelotFontImporter/Source/CmFontImporter.cpp

@@ -49,7 +49,7 @@ namespace BansheeEngine
 		return cm_shared_ptr<FontImportOptions, ScratchAlloc>();
 		return cm_shared_ptr<FontImportOptions, ScratchAlloc>();
 	}
 	}
 
 
-	ResourcePtr FontImporter::import(const WString& filePath, ConstImportOptionsPtr importOptions)
+	ResourcePtr FontImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
 	{
 	{
 		const FontImportOptions* fontImportOptions = static_cast<const FontImportOptions*>(importOptions.get());
 		const FontImportOptions* fontImportOptions = static_cast<const FontImportOptions*>(importOptions.get());
 
 
@@ -60,15 +60,15 @@ namespace BansheeEngine
 			CM_EXCEPT(InternalErrorException, "Error occurred during FreeType library initialization.");
 			CM_EXCEPT(InternalErrorException, "Error occurred during FreeType library initialization.");
 
 
 		FT_Face face;
 		FT_Face face;
-		error = FT_New_Face(library, toString(filePath).c_str(), 0, &face);
+		error = FT_New_Face(library, filePath.toString().c_str(), 0, &face);
 
 
 		if (error == FT_Err_Unknown_File_Format)
 		if (error == FT_Err_Unknown_File_Format)
 		{
 		{
-			CM_EXCEPT(InternalErrorException, "Failed to load font file: " + toString(filePath) + ". Unsupported file format.");
+			CM_EXCEPT(InternalErrorException, "Failed to load font file: " + filePath.toString() + ". Unsupported file format.");
 		}
 		}
 		else if (error)
 		else if (error)
 		{
 		{
-			CM_EXCEPT(InternalErrorException, "Failed to load font file: " + toString(filePath) + ". Unknown error.");
+			CM_EXCEPT(InternalErrorException, "Failed to load font file: " + filePath.toString() + ". Unknown error.");
 		}
 		}
 
 
 		Vector<std::pair<UINT32, UINT32>>::type charIndexRanges = fontImportOptions->getCharIndexRanges();
 		Vector<std::pair<UINT32, UINT32>>::type charIndexRanges = fontImportOptions->getCharIndexRanges();
@@ -319,7 +319,7 @@ namespace BansheeEngine
 
 
 		FT_Done_FreeType(library);
 		FT_Done_FreeType(library);
 
 
-		WString fileName = OldPath::getFilename(filePath, false);
+		WString fileName = filePath.getWFilename(false);
 		newFont->setName(toString(fileName));
 		newFont->setName(toString(fileName));
 
 
 		return newFont;
 		return newFont;

+ 1 - 1
CamelotFreeImgImporter/Include/CmFreeImgImporter.h

@@ -34,7 +34,7 @@ namespace BansheeEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 
 		/** Inherited from SpecificImporter */
 		/** Inherited from SpecificImporter */
-		virtual ResourcePtr import(const WString& filePath, ConstImportOptionsPtr importOptions);
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
 	private:
 	private:
 		Vector<WString>::type mExtensions;
 		Vector<WString>::type mExtensions;
 		UnorderedMap<WString, int>::type mExtensionToFID;
 		UnorderedMap<WString, int>::type mExtensionToFID;

+ 2 - 2
CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp

@@ -120,7 +120,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	ResourcePtr FreeImgImporter::import(const WString& filePath, ConstImportOptionsPtr importOptions)
+	ResourcePtr FreeImgImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
 	{
 	{
 		DataStreamPtr fileData = FileSystem::openFile(filePath, true);
 		DataStreamPtr fileData = FileSystem::openFile(filePath, true);
 
 
@@ -146,7 +146,7 @@ namespace BansheeEngine
 
 
 		fileData->close();
 		fileData->close();
 
 
-		WString fileName = OldPath::getFilename(filePath, false);
+		WString fileName = filePath.getWFilename(false);
 		newTexture->setName(toString(fileName));
 		newTexture->setName(toString(fileName));
 
 
 		return newTexture;
 		return newTexture;

+ 1 - 1
CamelotUtility/Include/CmDebug.h

@@ -46,7 +46,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Converts raw pixels into a BMP image. See "BitmapWriter" for more information.
 		 * @brief	Converts raw pixels into a BMP image. See "BitmapWriter" for more information.
 		 */
 		 */
-		void writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const WString& filePath, bool overwrite = true) const;
+		void writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const Path& filePath, bool overwrite = true) const;
 
 
 	private:
 	private:
 		Log mLog;
 		Log mLog;

+ 2 - 2
CamelotUtility/Include/CmFileSerializer.h

@@ -20,13 +20,13 @@ namespace BansheeEngine
 		 * @brief	Parses the provided object, serializes all of its data as specified by its
 		 * @brief	Parses the provided object, serializes all of its data as specified by its
 		 *			RTTIType and saves the serialized data to the provided file location.
 		 *			RTTIType and saves the serialized data to the provided file location.
 		 */
 		 */
-		void encode(IReflectable* object, WString fileLocation);
+		void encode(IReflectable* object, const Path& fileLocation);
 
 
 		/**
 		/**
 		 * @brief	Deserializes an IReflectable object by reading the binary data at
 		 * @brief	Deserializes an IReflectable object by reading the binary data at
 		 *			the provided file location.
 		 *			the provided file location.
 		 */
 		 */
-		std::shared_ptr<IReflectable> decode(WString fileLocation);
+		std::shared_ptr<IReflectable> decode(const Path& fileLocation);
 
 
 	private:
 	private:
 		std::ofstream mOutputStream;
 		std::ofstream mOutputStream;

+ 12 - 20
CamelotUtility/Include/CmFileSystem.h

@@ -16,7 +16,7 @@ namespace BansheeEngine
 		 * @param	fullPath	Full path to a file.
 		 * @param	fullPath	Full path to a file.
 		 * @param	readOnly	(optional) If true, returned stream will only be readable.
 		 * @param	readOnly	(optional) If true, returned stream will only be readable.
 		 */
 		 */
-		static DataStreamPtr openFile(const WString& fullPath, bool readOnly = true);
+		static DataStreamPtr openFile(const Path& fullPath, bool readOnly = true);
 
 
 		/**
 		/**
 		 * @brief	Opens a file and returns a data stream capable of reading and writing to that file.
 		 * @brief	Opens a file and returns a data stream capable of reading and writing to that file.
@@ -24,14 +24,14 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @param	fullPath	Full path to a file.
 		 * @param	fullPath	Full path to a file.
 		 */
 		 */
-		static DataStreamPtr createAndOpenFile(const WString& fullPath);
+		static DataStreamPtr createAndOpenFile(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Returns the size of a file in bytes.
 		 * @brief	Returns the size of a file in bytes.
 		 *
 		 *
 		 * @param	fullPath	Full path to a file.
 		 * @param	fullPath	Full path to a file.
 		 */
 		 */
-		static UINT64 getFileSize(const WString& fullPath);
+		static UINT64 getFileSize(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Deletes a file or a folder at the specified path.
 		 * @brief	Deletes a file or a folder at the specified path.
@@ -41,7 +41,7 @@ namespace BansheeEngine
 		 * 						deleted as well. Otherwise an exception will be
 		 * 						deleted as well. Otherwise an exception will be
 		 * 						thrown for non-empty folders.
 		 * 						thrown for non-empty folders.
 		 */
 		 */
-		static void remove(const WString& fullPath, bool recursively = true);
+		static void remove(const Path& fullPath, bool recursively = true);
 
 
 		/**
 		/**
 		 * @brief	Moves a file or a folder from one to another path. This
 		 * @brief	Moves a file or a folder from one to another path. This
@@ -52,35 +52,35 @@ namespace BansheeEngine
 		 * @param	overwriteExisting	(optional) If true, any existing file/folder at the new location will be overwritten,
 		 * @param	overwriteExisting	(optional) If true, any existing file/folder at the new location will be overwritten,
 		 * 								otherwise an exception will be thrown if a file/folder already exists.
 		 * 								otherwise an exception will be thrown if a file/folder already exists.
 		 */
 		 */
-		static void move(const WString& oldPath, const WString& newPath, bool overwriteExisting = true);
+		static void move(const Path& oldPath, const Path& newPath, bool overwriteExisting = true);
 
 
 		/**
 		/**
 		 * @brief	Creates a folder at the specified path.
 		 * @brief	Creates a folder at the specified path.
 		 *
 		 *
 		 * @param	fullPath	Full path to a full folder to create.
 		 * @param	fullPath	Full path to a full folder to create.
 		 */
 		 */
-		static void createDir(const WString& fullPath);
+		static void createDir(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Returns true if a file or a folder exists at the specified path.
 		 * @brief	Returns true if a file or a folder exists at the specified path.
 		 *
 		 *
 		 * @param	fullPath	Full path to a file or folder.
 		 * @param	fullPath	Full path to a file or folder.
 		 */
 		 */
-		static bool exists(const WString& fullPath);
+		static bool exists(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Returns true if a file exists at the specified path.
 		 * @brief	Returns true if a file exists at the specified path.
 		 *
 		 *
 		 * @param	fullPath	Full path to a file or folder.
 		 * @param	fullPath	Full path to a file or folder.
 		 */
 		 */
-		static bool isFile(const WString& fullPath);
+		static bool isFile(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Returns true if a folder exists at the specified path.
 		 * @brief	Returns true if a folder exists at the specified path.
 		 *
 		 *
 		 * @param	fullPath	Full path to a file or folder.
 		 * @param	fullPath	Full path to a file or folder.
 		 */
 		 */
-		static bool isDirectory(const WString& fullPath);
+		static bool isDirectory(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Returns all files or folders located in the specified folder.
 		 * @brief	Returns all files or folders located in the specified folder.
@@ -89,26 +89,18 @@ namespace BansheeEngine
 		 * @param [out]	files	   		Full paths to all files located directly in specified folder.
 		 * @param [out]	files	   		Full paths to all files located directly in specified folder.
 		 * @param [out]	directories		Full paths to all folders located directly in specified folder.
 		 * @param [out]	directories		Full paths to all folders located directly in specified folder.
 		 */
 		 */
-		static void getChildren(const WString& dirPath, Vector<WString>::type& files, Vector<WString>::type& directories);
+		static void getChildren(const Path& dirPath, Vector<Path>::type& files, Vector<Path>::type& directories);
 
 
 		/**
 		/**
 		 * @brief	Returns the last modified time of a file or a folder at the specified path.
 		 * @brief	Returns the last modified time of a file or a folder at the specified path.
 		 *
 		 *
 		 * @param	fullPath	Full path to a file or a folder.
 		 * @param	fullPath	Full path to a file or a folder.
 		 */
 		 */
-		static std::time_t getLastModifiedTime(const WString& fullPath);
+		static std::time_t getLastModifiedTime(const Path& fullPath);
 
 
 		/**
 		/**
 		 * @brief	Returns the path to the currently working directory.
 		 * @brief	Returns the path to the currently working directory.
 		 */
 		 */
-		static WString getWorkingDirectoryPath();
-
-		/**
-		 * @brief	Returns a parent path of the provided file path.
-		 * 			If path represents a directory, then that directory path is returned.
-		 * 			
-		 * @param	fullPath	Full path to a file.
-		 */
-		static WString getParentDirectory(const WString& fullPath);
+		static Path getWorkingDirectoryPath();
 	};
 	};
 }
 }

+ 6 - 1
CamelotUtility/Include/CmFwdDeclUtil.h

@@ -50,6 +50,7 @@ namespace BansheeEngine
 	class HString;
 	class HString;
 	class StringTable;
 	class StringTable;
 	struct LocalizedStringData;
 	struct LocalizedStringData;
+	class Path;
 	// Reflection
 	// Reflection
 	class IReflectable;
 	class IReflectable;
 	class RTTITypeBase;
 	class RTTITypeBase;
@@ -74,6 +75,10 @@ namespace BansheeEngine
 	{
 	{
 		TID_Abstract = 50, // Special type ID used for Abstract classes. Only type ID that may be used by more than one class.
 		TID_Abstract = 50, // Special type ID used for Abstract classes. Only type ID that may be used by more than one class.
 		TID_WString = 51,
 		TID_WString = 51,
-		TID_WPath = 52
+		TID_Path = 52,
+		TID_Vector = 53,
+		TID_Map = 54,
+		TID_UnorderedMap = 55,
+		TID_Pair = 56
 	};
 	};
 }
 }

+ 102 - 205
CamelotUtility/Include/CmPath.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "CmPrerequisitesUtil.h"
 #include "CmPrerequisitesUtil.h"
+#include "CmUtil.h"
 #include <boost/filesystem.hpp>
 #include <boost/filesystem.hpp>
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -9,6 +10,10 @@ namespace BansheeEngine
 	 * @brief	Class for storing and manipulating file paths. Paths may be parsed
 	 * @brief	Class for storing and manipulating file paths. Paths may be parsed
 	 *			from and to raw strings according to various platform specific path
 	 *			from and to raw strings according to various platform specific path
 	 *			types.
 	 *			types.
+	 *
+	 * @note	In order to allow the system to easily distinguish between file and directory
+	 *			paths, try to ensure that all directory paths end with a separator (\ or / depending
+	 *			on platform). System won't fail if you don't but it will be easier to misuse.
 	 */
 	 */
 	class CM_UTILITY_EXPORT Path
 	class CM_UTILITY_EXPORT Path
 	{
 	{
@@ -21,6 +26,8 @@ namespace BansheeEngine
 		};
 		};
 
 
 	public:
 	public:
+		Path();
+
 		/**
 		/**
 		 * @brief	Constructs a path by parsing the provided path string. 
 		 * @brief	Constructs a path by parsing the provided path string. 
 		 *			Throws exception if provided path is not valid.
 		 *			Throws exception if provided path is not valid.
@@ -230,7 +237,7 @@ namespace BansheeEngine
 		 *			Or if it contains a directory the parent will be the parent directory.
 		 *			Or if it contains a directory the parent will be the parent directory.
 		 *			If no parent exists, same path will be returned.
 		 *			If no parent exists, same path will be returned.
 		 */
 		 */
-		void makeParent();
+		Path& makeParent();
 
 
 		/**
 		/**
 		 * @brief	Makes the current path absolute by appending it to base.
 		 * @brief	Makes the current path absolute by appending it to base.
@@ -239,7 +246,7 @@ namespace BansheeEngine
 		 *			If base is not absolute, then the returned path will be made relative to base,
 		 *			If base is not absolute, then the returned path will be made relative to base,
 		 *			but will not be absolute.
 		 *			but will not be absolute.
 		 */
 		 */
-		void makeAbsolute(const Path& base);
+		Path& makeAbsolute(const Path& base);
 
 
 		/**
 		/**
 		 * @brief	Makes the current path relative to the provided base.
 		 * @brief	Makes the current path relative to the provided base.
@@ -247,13 +254,12 @@ namespace BansheeEngine
 		 *			of the path no changes are made and a copy of the current path
 		 *			of the path no changes are made and a copy of the current path
 		 *			is returned.
 		 *			is returned.
 		 */
 		 */
-		void makeRelative(const Path& base);
+		Path& makeRelative(const Path& base);
 
 
 		/**
 		/**
 		 * @brief	Appends another path to the end of this path.
 		 * @brief	Appends another path to the end of this path.
-		 *			If this path contains a filename, it is removed.
 		 */
 		 */
-		void append(const Path& path);
+		Path& append(const Path& path);
 
 
 		/**
 		/**
 		 * @brief	Checks if the current path contains the provided path.
 		 * @brief	Checks if the current path contains the provided path.
@@ -359,14 +365,43 @@ namespace BansheeEngine
 		*/
 		*/
 		String getNode() const { return BansheeEngine::toString(mNode); }
 		String getNode() const { return BansheeEngine::toString(mNode); }
 
 
+		/**
+		* @brief	Gets last element in the path, filename if it exists, otherwise the last directory.
+		*			If no directories exist returns device or node.
+		*
+		* @param	type	Determines format of node or device, in case they are returned. When default,
+		*					format for the active platform will be used, otherwise the format defined
+		*					by the parameter will be used.
+		*/
+		WString getWTail(PathType type = PathType::Default) const;
+
+		/**
+		 * @brief	Gets last element in the path, filename if it exists, otherwise the last directory.
+		 *			If no directories exist returns device or node.
+		 *
+		 * @param	type	Determines format of node or device, in case they are returned. When default,
+		 *					format for the active platform will be used, otherwise the format defined
+		 *					by the parameter will be used.
+		 */
+		String getTail(PathType type = PathType::Default) const;
+
 		/**
 		/**
 		 * @brief	Clears the path to nothing.
 		 * @brief	Clears the path to nothing.
 		 */
 		 */
 		void clear();
 		void clear();
 
 
-	private:
-		Path();
+		/**
+		 * @brief	Returns true if no path has been set.
+		 */
+		bool isEmpty() const { return mDirectories.empty() && mFilename.empty() && mDevice.empty() && mNode.empty(); }
 
 
+		/**
+		* @brief	Compares two path elements (i.e. filenames, directory names, etc.)
+		*/
+		static bool comparePathElem(const WString& left, const WString& right);
+
+		static const Path BLANK;
+	private:
 		/**
 		/**
 		* @brief	Constructs a path by parsing the provided raw string data.
 		* @brief	Constructs a path by parsing the provided raw string data.
 		*			Throws exception if provided path is not valid.
 		*			Throws exception if provided path is not valid.
@@ -415,6 +450,7 @@ namespace BansheeEngine
 				{
 				{
 					idx++;
 					idx++;
 
 
+					tempStream.str(BasicString<T>::type());
 					tempStream.clear();
 					tempStream.clear();
 					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
 					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
 						tempStream << pathStr[idx++];
 						tempStream << pathStr[idx++];
@@ -439,7 +475,7 @@ namespace BansheeEngine
 
 
 						idx++;
 						idx++;
 
 
-						if (idx < numChars || (pathStr[idx] != '\\' && pathStr[idx] != '/'))
+						if (idx >= numChars || (pathStr[idx] != '\\' && pathStr[idx] != '/'))
 							throwInvalidPathException(BasicString<T>::type(pathStr, numChars));
 							throwInvalidPathException(BasicString<T>::type(pathStr, numChars));
 
 
 						idx++;
 						idx++;
@@ -450,6 +486,7 @@ namespace BansheeEngine
 
 
 				while (idx < numChars)
 				while (idx < numChars)
 				{
 				{
+					tempStream.str(BasicString<T>::type());
 					tempStream.clear();
 					tempStream.clear();
 					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
 					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
 					{
 					{
@@ -500,6 +537,7 @@ namespace BansheeEngine
 
 
 				while (idx < numChars)
 				while (idx < numChars)
 				{
 				{
+					tempStream.str(BasicString<T>::type());
 					tempStream.clear();
 					tempStream.clear();
 					while (idx < numChars && pathStr[idx] != '/')
 					while (idx < numChars && pathStr[idx] != '/')
 					{
 					{
@@ -563,11 +601,6 @@ namespace BansheeEngine
 		*/
 		*/
 		void pushDirectory(const String& dir);
 		void pushDirectory(const String& dir);
 
 
-		/**
-		 * @brief	Compares two path elements (i.e. filenames, directory names, etc.)
-		 */
-		bool comparePathElem(const WString& left, const WString& right) const;
-
 		/**
 		/**
 		 * @brief	Helper method that throws invalid path exception. 
 		 * @brief	Helper method that throws invalid path exception. 
 		 */
 		 */
@@ -578,6 +611,9 @@ namespace BansheeEngine
 		*/
 		*/
 		void throwInvalidPathException(const String& path) const;
 		void throwInvalidPathException(const String& path) const;
 	private:
 	private:
+		friend struct RTTIPlainType<Path>; // For serialization
+		friend struct ::std::hash<BansheeEngine::Path>;
+
 		Vector<WString>::type mDirectories;
 		Vector<WString>::type mDirectories;
 		WString mDevice;
 		WString mDevice;
 		WString mFilename;
 		WString mFilename;
@@ -586,215 +622,76 @@ namespace BansheeEngine
 	};
 	};
 
 
 	/**
 	/**
-	 * @brief	Various string manipulations of file paths.
-	 */
-	class CM_UTILITY_EXPORT OldPath
+	* @brief	RTTIPlainType specialization for Path that allows paths be serialized as
+	* 			value types.
+	*
+	* @see		RTTIPlainType
+	*/
+	template<> struct RTTIPlainType<Path>
 	{
 	{
-	public:
-		/**
-		 * @brief	Returns file extension extracted from the provided
-		 * 			path, with a leading ".".
-		 */
-		static WString getExtension(const WString& path)
-		{
-			boost::filesystem3::wpath ext = boost::filesystem3::extension(boost::filesystem3::wpath(path.c_str()));
-			return ext.wstring().c_str();
-		}
+		enum { id = TID_Path }; enum { hasDynamicSize = 1 };
 
 
-		/**
-		 * @brief	Query if a path has the specified extension. Provided
-		 * 			extension must contain the leading ".".
-		 */
-		static bool hasExtension(const WString& path, const WString& extension)
-		{
-			return getExtension(path) == extension;
-		}
-
-		/**
-		 * @brief	Replaces or adds an extension on a file path. Provided
-		 * 			extension must contain the leading ".".
-		 */
-		static void replaceExtension(WString& path, const WString& newExtension)
-		{
-			boost::filesystem3::path internalPath = path.c_str();
-
-			path = internalPath.replace_extension(newExtension.c_str()).c_str();
-		}
-
-		/**
-		 * @brief	Returns a path that is one level higher than the provided path, unless the path
-		 * 			is already at the root. Otherwise returns the initial path.
-		 */
-		static WString parentPath(const WString& path)
+		static void toMemory(const Path& data, char* memory)
 		{
 		{
-			boost::filesystem3::path internalPath = path.c_str();
-
-			return internalPath.parent_path().c_str();
+			UINT32 size = getDynamicSize(data);
+			memcpy(memory, &size, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			memory = rttiWriteElem(data.mDevice, memory);
+			memory = rttiWriteElem(data.mNode, memory);
+			memory = rttiWriteElem(data.mFilename, memory);
+			memory = rttiWriteElem(data.mIsAbsolute, memory);
+			memory = rttiWriteElem(data.mDirectories, memory);
 		}
 		}
 
 
-		/**
-		 * @brief	Returns true if path child is included in path parent.
-		 * 			Both paths must be canonical.
-		 */
-		static bool includes(const WString& child, const WString& parent)
+		static UINT32 fromMemory(Path& data, char* memory)
 		{
 		{
-			Vector<WString>::type childPathElems = split(child);
-			Vector<WString>::type parentPathElems = split(parent);
+			UINT32 size;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
 
 
-			auto iterChild = childPathElems.begin();
-			auto iterParent = parentPathElems.begin();
+			memory = rttiReadElem(data.mDevice, memory);
+			memory = rttiReadElem(data.mNode, memory);
+			memory = rttiReadElem(data.mFilename, memory);
+			memory = rttiReadElem(data.mIsAbsolute, memory);
+			memory = rttiReadElem(data.mDirectories, memory);
 
 
-			for(; iterParent != parentPathElems.end(); ++iterChild, ++iterParent)
-			{
-				if(iterChild == childPathElems.end())
-					return false;
-
-				if(!comparePathElements(*iterChild, *iterParent))
-					return false;
-			}
-
-			return true;
+			return size;
 		}
 		}
 
 
-		/**
-		 * @brief	Returns path relative to base.
-		 */
-		static WString relative(const WString& base, const WString& path)
+		static UINT32 getDynamicSize(const Path& data)
 		{
 		{
-			Vector<WString>::type basePathElems = split(base);
-			Vector<WString>::type pathElems = split(path);
+			UINT64 dataSize = rttiGetElemSize(data.mDevice) + rttiGetElemSize(data.mNode) + rttiGetElemSize(data.mFilename) +
+				rttiGetElemSize(data.mIsAbsolute) + rttiGetElemSize(data.mDirectories) + sizeof(UINT32);
 
 
-			auto iterBase = basePathElems.begin();
-			auto iterPath = pathElems.begin();
-
-			for(; iterBase != basePathElems.end(); ++iterBase, ++iterPath)
+#if CM_DEBUG_MODE
+			if (dataSize > std::numeric_limits<UINT32>::max())
 			{
 			{
-				if(!comparePathElements(*iterBase, *iterPath))
-					return L"";
+				__string_throwDataOverflowException();
 			}
 			}
-
-			WString relativePath;
-			for(; iterPath != pathElems.end(); ++iterPath)
-			{
-				relativePath = OldPath::combine(relativePath, *iterPath);
-			}
-
-			return relativePath;
-		}
-
-		/**
-		 * @brief	Splits a path into string entries. Path separator
-		 * 			may be "\" or "/". Path separator will not be included
-		 * 			in the returned strings.
-		 */
-		static Vector<WString>::type split(const WString& path)
-		{
-			Vector<WString>::type splitPath;
-
-			WString standardizedPath = standardizePath(path);
-			return StringUtil::split(standardizedPath, L"/");
-		}
-
-		/**
-		 * @brief	Combines two paths using the "/" path separator.
-		 */
-		static WString combine(const WString& base, const WString& name)
-		{
-			if (base.empty())
-				return name;
-			else
-				return base + L'/' + name;
-		}
-
-		/**
-		 * @brief	Compares two canonical paths and returns true if they are equal.
-		 */
-		static bool equals(const WString& left, const WString& right)
-		{
-			Vector<WString>::type leftElements = split(left);
-			Vector<WString>::type rightElements = split(right);
-
-			UINT32 idx = 0;
-			for(auto& leftElem : leftElements)
-			{
-				if(leftElem.empty())
-					continue;
-				
-				while(idx < (UINT32)rightElements.size() && rightElements[idx].empty())
-					idx++;
-
-				if(idx >= (UINT32)rightElements.size())
-					return false; // Right path is deeper than left path
-
-				if(!comparePathElements(leftElem, rightElements[idx]))
-					return false;
-
-				idx++;
-			}
-
-			while(idx < (UINT32)rightElements.size() && rightElements[idx].empty())
-				idx++;
-
-			if(idx < (UINT32)rightElements.size())
-				return false; // Left path is deeper than right path
-
-			return true;
-		}
-
-		/**
-		 * @brief	Compares two path elements for equality. 
-		 * 			
-		 * @note	Should not be used for comparing entire paths. First you need to split your
-		 * 			path into sub-elements using some other method and then send those sub-elements to
-		 * 			this method. 
-		 */
-		static bool comparePathElements(const WString& left, const WString& right)
-		{
-			if(left.size() != right.size())
-				return false;
-
-			for(UINT32 i = 0; i < (UINT32)left.size(); i++)
-			{
-#if CM_PLATFORM == CM_PLATFORM_WIN32 // Compare case insensitive
-				if(tolower(left[i]) != tolower(right[i]))
-					return false;
-#else
-				assert(false); // Implement case sensitive or insensitive comparison, depending on platform
 #endif
 #endif
-			}
-
-			return true;
-		}
 
 
-		/**
-		 * @brief	Extracts filename from the provided path.
-		 *
-		 * @param	path				Path to the file.
-		 * @param	includeExtension	(optional) If true, filename extension will be included in the returned string.
-		 */
-		static WString getFilename(const WString& path, bool includeExtension = true)
-		{
-			boost::filesystem3::path internalPath = path.c_str();
-			
-			if(includeExtension)
-				return internalPath.filename().c_str();
-			else
-				return internalPath.stem().c_str();
+			return (UINT32)dataSize;
 		}
 		}
+	};
+}
 
 
-		/**
-		 * @brief	Method for standardizing paths - use forward slashes only, end without a slash.
-		 */
-		static WString standardizePath(const WString& inPath)
-		{
-			WString path = inPath;
-
-			std::replace(path.begin(), path.end(), L'\\', L'/');
+/**
+* @brief	Hash value generator for Path.
+*/
+template<>
+struct std::hash<BansheeEngine::Path>
+{
+	size_t operator()(const BansheeEngine::Path& path) const
+	{
+		size_t hash = 0;
+		BansheeEngine::hash_combine(hash, path.mFilename);
+		BansheeEngine::hash_combine(hash, path.mDevice);
+		BansheeEngine::hash_combine(hash, path.mNode);
 
 
-			while(path.length() > 0 && path.back() == L'/')
-				path.pop_back();
+		for (auto& dir : path.mDirectories)
+			BansheeEngine::hash_combine(hash, dir);
 
 
-			return path;
-		}
-	};
-}
+		return hash;
+	}
+};

+ 95 - 3
CamelotUtility/Include/CmRTTIPrerequisites.h

@@ -169,7 +169,7 @@ namespace BansheeEngine
 	 */
 	 */
 	template<class T> struct RTTIPlainType<std::vector<T, StdAlloc<T>>>
 	template<class T> struct RTTIPlainType<std::vector<T, StdAlloc<T>>>
 	{	
 	{	
-		enum { id = TID_STDVECTOR }; enum { hasDynamicSize = 1 };
+		enum { id = TID_Vector }; enum { hasDynamicSize = 1 };
 
 
 		/**
 		/**
 		 * @copydoc		RTTIPlainType::toMemory
 		 * @copydoc		RTTIPlainType::toMemory
@@ -245,7 +245,7 @@ namespace BansheeEngine
 	 */
 	 */
 	template<class Key, class Value> struct RTTIPlainType<std::map<Key, Value, std::less<Key>, StdAlloc<std::pair<const Key, Value>>>>
 	template<class Key, class Value> struct RTTIPlainType<std::map<Key, Value, std::less<Key>, StdAlloc<std::pair<const Key, Value>>>>
 	{	
 	{	
-		enum { id = TID_STDMAP }; enum { hasDynamicSize = 1 };
+		enum { id = TID_Map }; enum { hasDynamicSize = 1 };
 
 
 		/**
 		/**
 		 * @copydoc		RTTIPlainType::toMemory
 		 * @copydoc		RTTIPlainType::toMemory
@@ -327,6 +327,98 @@ namespace BansheeEngine
 		}	
 		}	
 	}; 
 	}; 
 
 
+	/**
+	* @brief	RTTIPlainType for std::unordered_map.
+	*
+	* @see		RTTIPlainType
+	*/
+	template<class Key, class Value> 
+	struct RTTIPlainType<std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, StdAlloc<std::pair<const Key, Value>>>>
+	{
+		enum { id = TID_UnorderedMap }; enum { hasDynamicSize = 1 };
+
+		typedef std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, StdAlloc<std::pair<const Key, Value>>> MapType;
+
+		/**
+		* @copydoc		RTTIPlainType::toMemory
+		*/
+		static void toMemory(MapType& data, char* memory)
+		{
+			UINT32 size = sizeof(UINT32);
+			char* memoryStart = memory;
+			memory += sizeof(UINT32);
+
+			UINT32 numElements = (UINT32)data.size();
+			memcpy(memory, &numElements, sizeof(UINT32));
+			memory += sizeof(UINT32);
+			size += sizeof(UINT32);
+
+			for (auto iter = data.begin(); iter != data.end(); ++iter)
+			{
+				UINT32 keySize = RTTIPlainType<Key>::getDynamicSize(iter->first);
+				RTTIPlainType<Key>::toMemory(iter->first, memory);
+
+				memory += keySize;
+				size += keySize;
+
+				UINT32 valueSize = RTTIPlainType<Value>::getDynamicSize(iter->second);
+				RTTIPlainType<Value>::toMemory(iter->second, memory);
+
+				memory += valueSize;
+				size += valueSize;
+			}
+
+			memcpy(memoryStart, &size, sizeof(UINT32));
+		}
+
+		/**
+		* @copydoc		RTTIPlainType::fromMemory
+		*/
+		static UINT32 fromMemory(MapType& data, char* memory)
+		{
+			UINT32 size = 0;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			UINT32 numElements;
+			memcpy(&numElements, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			for (UINT32 i = 0; i < numElements; i++)
+			{
+				Key key;
+				UINT32 keySize = RTTIPlainType<Key>::fromMemory(key, memory);
+				memory += keySize;
+
+				Value value;
+				UINT32 valueSize = RTTIPlainType<Value>::fromMemory(value, memory);
+				memory += valueSize;
+
+				data[key] = value;
+			}
+
+			return size;
+		}
+
+		/**
+		* @copydoc		RTTIPlainType::getDynamicSize
+		*/
+		static UINT32 getDynamicSize(const MapType& data)
+		{
+			UINT64 dataSize = sizeof(UINT32)* 2;
+
+			for (auto iter = data.begin(); iter != data.end(); ++iter)
+			{
+				dataSize += RTTIPlainType<Key>::getDynamicSize(iter->first);
+				dataSize += RTTIPlainType<Value>::getDynamicSize(iter->second);
+			}
+
+			assert(dataSize <= std::numeric_limits<UINT32>::max());
+
+			return (UINT32)dataSize;
+		}
+	};
+
 	/**
 	/**
 	 * @brief	RTTIPlainType for std::pair.
 	 * @brief	RTTIPlainType for std::pair.
 	 * 			
 	 * 			
@@ -334,7 +426,7 @@ namespace BansheeEngine
 	 */
 	 */
 	template<class A, class B> struct RTTIPlainType<std::pair<A, B>>
 	template<class A, class B> struct RTTIPlainType<std::pair<A, B>>
 	{	
 	{	
-		enum { id = TID_STDPAIR }; enum { hasDynamicSize = 1 };
+		enum { id = TID_Pair }; enum { hasDynamicSize = 1 };
 
 
 		/**
 		/**
 		 * @copydoc		RTTIPlainType::toMemory
 		 * @copydoc		RTTIPlainType::toMemory

+ 14 - 0
CamelotUtility/Include/CmString.h

@@ -484,6 +484,20 @@ namespace BansheeEngine
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
+	/**
+	* @brief	Converts an narrow char unsigned to a string.
+	*/
+	CM_UTILITY_EXPORT WString toWString(char val,
+		unsigned short width = 0, char fill = ' ',
+		std::ios::fmtflags flags = std::ios::fmtflags(0));
+
+	/**
+	* @brief	Converts an wide bit char unsigned to a string.
+	*/
+	CM_UTILITY_EXPORT WString toWString(wchar_t val,
+		unsigned short width = 0, char fill = ' ',
+		std::ios::fmtflags flags = std::ios::fmtflags(0));
+
     /**
     /**
      * @brief	Converts a boolean to a string.
      * @brief	Converts a boolean to a string.
      *
      *

+ 3 - 2
CamelotUtility/Source/CmDebug.cpp

@@ -4,6 +4,7 @@
 #include "CmBitmapWriter.h"
 #include "CmBitmapWriter.h"
 #include "CmFileSystem.h"
 #include "CmFileSystem.h"
 #include "CmDataStream.h"
 #include "CmDataStream.h"
+#include "CmPath.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -32,14 +33,14 @@ namespace BansheeEngine
 		mLog.logMsg(msg, channel);
 		mLog.logMsg(msg, channel);
 	}
 	}
 
 
-	void Debug::writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const WString& filePath, bool overwrite) const
+	void Debug::writeAsBMP(UINT8* rawPixels, UINT32 bytesPerPixel, UINT32 width, UINT32 height, const Path& filePath, bool overwrite) const
 	{
 	{
 		if(FileSystem::isFile(filePath))
 		if(FileSystem::isFile(filePath))
 		{
 		{
 			if(overwrite)
 			if(overwrite)
 				FileSystem::remove(filePath);
 				FileSystem::remove(filePath);
 			else
 			else
-				CM_EXCEPT(FileNotFoundException, "File already exists at specified location: " + toString(filePath));
+				CM_EXCEPT(FileNotFoundException, "File already exists at specified location: " + filePath.toString());
 		}
 		}
 
 
 		DataStreamPtr ds = FileSystem::createAndOpenFile(filePath);
 		DataStreamPtr ds = FileSystem::createAndOpenFile(filePath);

+ 5 - 4
CamelotUtility/Source/CmFileSerializer.cpp

@@ -3,6 +3,7 @@
 #include "CmException.h"
 #include "CmException.h"
 #include "CmIReflectable.h"
 #include "CmIReflectable.h"
 #include "CmBinarySerializer.h"
 #include "CmBinarySerializer.h"
+#include "CmPath.h"
 
 
 #include <numeric>
 #include <numeric>
 
 
@@ -20,9 +21,9 @@ namespace BansheeEngine
 		cm_free<ScratchAlloc>(mWriteBuffer);
 		cm_free<ScratchAlloc>(mWriteBuffer);
 	}
 	}
 
 
-	void FileSerializer::encode(IReflectable* object, WString fileLocation)
+	void FileSerializer::encode(IReflectable* object, const Path& fileLocation)
 	{
 	{
-		mOutputStream.open(fileLocation.c_str(), std::ios::out | std::ios::binary);
+		mOutputStream.open(fileLocation.toString().c_str(), std::ios::out | std::ios::binary);
 
 
 		BinarySerializer bs;
 		BinarySerializer bs;
 		int totalBytesWritten = 0;
 		int totalBytesWritten = 0;
@@ -32,9 +33,9 @@ namespace BansheeEngine
 		mOutputStream.clear();
 		mOutputStream.clear();
 	}
 	}
 
 
-	std::shared_ptr<IReflectable> FileSerializer::decode(WString fileLocation)
+	std::shared_ptr<IReflectable> FileSerializer::decode(const Path& fileLocation)
 	{
 	{
-		mInputStream.open(fileLocation.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
+		mInputStream.open(fileLocation.toString().c_str(), std::ios::in | std::ios::ate | std::ios::binary);
 		
 		
 		std::streamoff fileSize = mInputStream.tellg();
 		std::streamoff fileSize = mInputStream.tellg();
 		if(fileSize > std::numeric_limits<UINT32>::max())
 		if(fileSize > std::numeric_limits<UINT32>::max())

+ 30 - 44
CamelotUtility/Source/CmFileSystem.cpp

@@ -10,7 +10,7 @@ using namespace boost::filesystem3;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	DataStreamPtr FileSystem::openFile(const WString& fullPath, bool readOnly)
+	DataStreamPtr FileSystem::openFile(const Path& fullPath, bool readOnly)
 	{
 	{
 		UINT64 fileSize = getFileSize(fullPath);
 		UINT64 fileSize = getFileSize(fullPath);
 
 
@@ -25,19 +25,19 @@ namespace BansheeEngine
 		{
 		{
 			mode |= std::ios::out;
 			mode |= std::ios::out;
 			rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
 			rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
-			rwStream->open(fullPath.c_str(), mode);
+			rwStream->open(fullPath.toWString().c_str(), mode);
 			baseStream = rwStream;
 			baseStream = rwStream;
 		}
 		}
 		else
 		else
 		{
 		{
 			roStream = cm_shared_ptr<std::ifstream, ScratchAlloc>();
 			roStream = cm_shared_ptr<std::ifstream, ScratchAlloc>();
-			roStream->open(fullPath.c_str(), mode);
+			roStream->open(fullPath.toWString().c_str(), mode);
 			baseStream = roStream;
 			baseStream = roStream;
 		}
 		}
 
 
 		// Should check ensure open succeeded, in case fail for some reason.
 		// Should check ensure open succeeded, in case fail for some reason.
 		if (baseStream->fail())
 		if (baseStream->fail())
-			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + toString(fullPath));
+			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + fullPath.toString());
 
 
 		/// Construct return stream, tell it to delete on destroy
 		/// Construct return stream, tell it to delete on destroy
 		FileDataStream* stream = 0;
 		FileDataStream* stream = 0;
@@ -54,39 +54,39 @@ namespace BansheeEngine
 		return cm_shared_ptr<FileDataStream, ScratchAlloc>(stream);
 		return cm_shared_ptr<FileDataStream, ScratchAlloc>(stream);
 	}
 	}
 
 
-	DataStreamPtr FileSystem::createAndOpenFile(const WString& fullPath)
+	DataStreamPtr FileSystem::createAndOpenFile(const Path& fullPath)
 	{
 	{
 		// Always open in binary mode
 		// Always open in binary mode
 		// Also, always include reading
 		// Also, always include reading
 		std::ios::openmode mode = std::ios::out | std::ios::binary;
 		std::ios::openmode mode = std::ios::out | std::ios::binary;
 		std::shared_ptr<std::fstream> rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
 		std::shared_ptr<std::fstream> rwStream = cm_shared_ptr<std::fstream, ScratchAlloc>();
-		rwStream->open(fullPath.c_str(), mode);
+		rwStream->open(fullPath.toWString().c_str(), mode);
 
 
 		// Should check ensure open succeeded, in case fail for some reason.
 		// Should check ensure open succeeded, in case fail for some reason.
 		if (rwStream->fail())
 		if (rwStream->fail())
-			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + toString(fullPath));
+			CM_EXCEPT(FileNotFoundException, "Cannot open file: " + fullPath.toString());
 
 
 		/// Construct return stream, tell it to delete on destroy
 		/// Construct return stream, tell it to delete on destroy
 		return cm_shared_ptr<FileDataStream, ScratchAlloc>(rwStream, 0, true);
 		return cm_shared_ptr<FileDataStream, ScratchAlloc>(rwStream, 0, true);
 	}
 	}
 
 
-	UINT64 FileSystem::getFileSize(const WString& fullPath)
+	UINT64 FileSystem::getFileSize(const Path& fullPath)
 	{
 	{
-		return file_size(fullPath.c_str());
+		return file_size(fullPath.toWString().c_str());
 	}
 	}
 
 
-	void FileSystem::remove(const WString& fullPath, bool recursively)
+	void FileSystem::remove(const Path& fullPath, bool recursively)
 	{
 	{
 		if(recursively)
 		if(recursively)
-			boost::filesystem3::remove_all(fullPath.c_str());
+			boost::filesystem3::remove_all(fullPath.toWString().c_str());
 		else
 		else
-			boost::filesystem3::remove(fullPath.c_str());
+			boost::filesystem3::remove(fullPath.toWString().c_str());
 	}
 	}
 
 
-	void FileSystem::move(const WString& oldPath, const WString& newPath, bool overwriteExisting)
+	void FileSystem::move(const Path& oldPath, const Path& newPath, bool overwriteExisting)
 	{
 	{
-		boost::filesystem3::path oldPathInternal = oldPath.c_str();
-		boost::filesystem3::path newPathInternal = newPath.c_str();
+		boost::filesystem3::path oldPathInternal = oldPath.toWString().c_str();
+		boost::filesystem3::path newPathInternal = newPath.toWString().c_str();
 
 
 		if(boost::filesystem3::exists(newPathInternal))
 		if(boost::filesystem3::exists(newPathInternal))
 		{
 		{
@@ -101,30 +101,30 @@ namespace BansheeEngine
 		boost::filesystem3::rename(oldPathInternal, newPathInternal);
 		boost::filesystem3::rename(oldPathInternal, newPathInternal);
 	}
 	}
 
 
-	bool FileSystem::exists(const WString& fullPath)
+	bool FileSystem::exists(const Path& fullPath)
 	{
 	{
-		return boost::filesystem3::exists(fullPath.c_str());
+		return boost::filesystem3::exists(fullPath.toWString().c_str());
 	}
 	}
 
 
-	bool FileSystem::isFile(const WString& fullPath)
+	bool FileSystem::isFile(const Path& fullPath)
 	{
 	{
-		if(boost::filesystem3::exists(fullPath.c_str()) && !is_directory(fullPath.c_str()))
+		if (boost::filesystem3::exists(fullPath.toWString().c_str()) && !is_directory(fullPath.toWString().c_str()))
 			return true;
 			return true;
 
 
 		return false;
 		return false;
 	}
 	}
 
 
-	bool FileSystem::isDirectory(const WString& fullPath)
+	bool FileSystem::isDirectory(const Path& fullPath)
 	{
 	{
-		if(boost::filesystem3::exists(fullPath.c_str()) && is_directory(fullPath.c_str()))
+		if (boost::filesystem3::exists(fullPath.toWString().c_str()) && is_directory(fullPath.toWString().c_str()))
 			return true;
 			return true;
 
 
 		return false;
 		return false;
 	}
 	}
 
 
-	void FileSystem::createDir(const WString& fullPath)
+	void FileSystem::createDir(const Path& fullPath)
 	{
 	{
-		boost::filesystem3::path fullPathInternal = fullPath.c_str();
+		boost::filesystem3::path fullPathInternal = fullPath.toWString().c_str();
 		if(fullPathInternal.empty())
 		if(fullPathInternal.empty())
 			return;
 			return;
 
 
@@ -150,43 +150,29 @@ namespace BansheeEngine
 		create_directory(parentPath);
 		create_directory(parentPath);
 	}
 	}
 
 
-	void FileSystem::getChildren(const WString& dirPath, Vector<WString>::type& files, Vector<WString>::type& directories)
+	void FileSystem::getChildren(const Path& dirPath, Vector<Path>::type& files, Vector<Path>::type& directories)
 	{
 	{
-		directory_iterator dirIter(dirPath.c_str());
+		directory_iterator dirIter(dirPath.toWString().c_str());
 
 
-		Vector<WString>::type foundFiles;
 		while(dirIter != directory_iterator())
 		while(dirIter != directory_iterator())
 		{
 		{
 			boost::filesystem3::path curPath = dirIter->path();
 			boost::filesystem3::path curPath = dirIter->path();
 
 
 			if(is_regular_file(curPath))
 			if(is_regular_file(curPath))
-				files.push_back(curPath.c_str());
+				files.push_back(Path(curPath.c_str()));
 			else if(is_directory(curPath))
 			else if(is_directory(curPath))
-				directories.push_back(curPath.c_str());
+				directories.push_back(Path(curPath.c_str()));
 
 
 			dirIter++;
 			dirIter++;
 		}
 		}
 	}
 	}
-	std::time_t FileSystem::getLastModifiedTime(const WString& fullPath)
+	std::time_t FileSystem::getLastModifiedTime(const Path& fullPath)
 	{
 	{
-		return last_write_time(fullPath.c_str());
+		return last_write_time(fullPath.toWString().c_str());
 	}
 	}
 
 
-	WString FileSystem::getWorkingDirectoryPath()
+	Path FileSystem::getWorkingDirectoryPath()
 	{
 	{
 		return current_path().wstring().c_str();
 		return current_path().wstring().c_str();
 	}
 	}
-
-	WString FileSystem::getParentDirectory(const WString& fullPath)
-	{
-		boost::filesystem3::path p(fullPath.c_str());
-		
-		if(!is_directory(p))
-		{
-			boost::filesystem3::path dir = p.parent_path();
-			return dir.wstring().c_str();
-		}
-
-		return fullPath;
-	}
 }
 }

+ 48 - 8
CamelotUtility/Source/CmPath.cpp

@@ -3,6 +3,8 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	const Path Path::BLANK = Path();
+
 	Path::Path()
 	Path::Path()
 		:mIsAbsolute(false)
 		:mIsAbsolute(false)
 	{ }
 	{ }
@@ -216,7 +218,7 @@ namespace BansheeEngine
 		return copy;
 		return copy;
 	}
 	}
 
 
-	void Path::makeParent()
+	Path& Path::makeParent()
 	{
 	{
 		if (mFilename.empty())
 		if (mFilename.empty())
 		{
 		{
@@ -237,31 +239,46 @@ namespace BansheeEngine
 		{
 		{
 			mFilename.clear();
 			mFilename.clear();
 		}
 		}
+
+		return *this;
 	}
 	}
 
 
-	void Path::makeAbsolute(const Path& base)
+	Path& Path::makeAbsolute(const Path& base)
 	{
 	{
 		if (mIsAbsolute)
 		if (mIsAbsolute)
-			return;
+			return *this;
 
 
 		Path absDir = base.getDirectory();
 		Path absDir = base.getDirectory();
+		if (base.isFile())
+			absDir.pushDirectory(base.mFilename);
+
 		for (auto& dir : mDirectories)
 		for (auto& dir : mDirectories)
 			absDir.pushDirectory(dir);
 			absDir.pushDirectory(dir);
 
 
 		*this = absDir;
 		*this = absDir;
+
+		return *this;
 	}
 	}
 
 
-	void Path::makeRelative(const Path& base)
+	Path& Path::makeRelative(const Path& base)
 	{
 	{
 		if (!base.includes(*this))
 		if (!base.includes(*this))
-			return;
+			return *this;
 
 
 		mDirectories.erase(mDirectories.begin(), mDirectories.begin() + base.mDirectories.size());
 		mDirectories.erase(mDirectories.begin(), mDirectories.begin() + base.mDirectories.size());
 		mIsAbsolute = false;
 		mIsAbsolute = false;
+
+		return *this;
 	}
 	}
 
 
 	bool Path::includes(const Path& child) const
 	bool Path::includes(const Path& child) const
 	{
 	{
+		if (mDevice != child.mDevice)
+			return false;
+
+		if (mNode != child.mNode)
+			return false;
+
 		auto iterParent = mDirectories.begin();
 		auto iterParent = mDirectories.begin();
 		auto iterChild = child.mDirectories.begin();
 		auto iterChild = child.mDirectories.begin();
 
 
@@ -274,6 +291,9 @@ namespace BansheeEngine
 				return false;
 				return false;
 		}
 		}
 
 
+		if (mFilename != child.mFilename)
+			return false;
+
 		return true;
 		return true;
 	}
 	}
 
 
@@ -309,12 +329,17 @@ namespace BansheeEngine
 		return true;
 		return true;
 	}
 	}
 
 
-	void Path::append(const Path& path)
+	Path& Path::append(const Path& path)
 	{
 	{
+		if (!mFilename.empty())
+			pushDirectory(mFilename);
+
 		for (auto& dir : path.mDirectories)
 		for (auto& dir : path.mDirectories)
 			pushDirectory(dir);
 			pushDirectory(dir);
 
 
 		mFilename = path.mFilename;
 		mFilename = path.mFilename;
+
+		return *this;
 	}
 	}
 
 
 	void Path::setBasename(const WString& basename)
 	void Path::setBasename(const WString& basename)
@@ -390,13 +415,28 @@ namespace BansheeEngine
 		return BansheeEngine::toString(getWDirectory(idx));
 		return BansheeEngine::toString(getWDirectory(idx));
 	}
 	}
 
 
+	WString Path::getWTail(PathType type) const
+	{
+		if (isFile())
+			return mFilename;
+		else if (mDirectories.size() > 0)
+			return mDirectories.back();
+		else
+			return toWString(type);
+	}
+
+	String Path::getTail(PathType type) const
+	{
+		return BansheeEngine::toString(getWTail(type));
+	}
+
 	void Path::clear()
 	void Path::clear()
 	{
 	{
 		mDirectories.clear();
 		mDirectories.clear();
 		mDevice.clear();
 		mDevice.clear();
 		mFilename.clear();
 		mFilename.clear();
 		mNode.clear();
 		mNode.clear();
-		mIsAbsolute = true;
+		mIsAbsolute = false;
 	}
 	}
 
 
 	void Path::throwInvalidPathException(const WString& path) const
 	void Path::throwInvalidPathException(const WString& path) const
@@ -470,7 +510,7 @@ namespace BansheeEngine
 		return result.str();
 		return result.str();
 	}
 	}
 
 
-	bool Path::comparePathElem(const WString& left, const WString& right) const
+	bool Path::comparePathElem(const WString& left, const WString& right)
 	{
 	{
 		if (left.size() != right.size())
 		if (left.size() != right.size())
 			return false;
 			return false;

+ 22 - 0
CamelotUtility/Source/CmString.cpp

@@ -237,6 +237,28 @@ namespace BansheeEngine
 		return stream.str();
 		return stream.str();
 	}
 	}
 
 
+	WString toWString(char val, unsigned short width, char fill, std::ios::fmtflags flags)
+	{
+		WStringStream stream;
+		stream.width(width);
+		stream.fill(fill);
+		if (flags)
+			stream.setf(flags);
+		stream << val;
+		return stream.str();
+	}
+
+	WString toWString(wchar_t val, unsigned short width, char fill, std::ios::fmtflags flags)
+	{
+		WStringStream stream;
+		stream.width(width);
+		stream.fill(fill);
+		if (flags)
+			stream.setf(flags);
+		stream << val;
+		return stream.str();
+	}
+
 	WString toWString(const Vector2& val)
 	WString toWString(const Vector2& val)
 	{
 	{
 		WStringStream stream;
 		WStringStream stream;