Kaynağa Gözat

New Path class

Marko Pintera 11 yıl önce
ebeveyn
işleme
f9d0a66b4b

+ 2 - 2
BansheeEditor/Source/BsEditorApplication.cpp

@@ -436,7 +436,7 @@ namespace BansheeEngine
 
 	EditorWidgetLayoutPtr EditorApplication::loadWidgetLayout()
 	{
-		WString layoutPath = Path::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
+		WString layoutPath = OldPath::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
 
 		if(FileSystem::exists(layoutPath))
 		{
@@ -449,7 +449,7 @@ namespace BansheeEngine
 
 	void EditorApplication::saveWidgetLayout(const EditorWidgetLayoutPtr& layout)
 	{
-		WString layoutPath = Path::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
+		WString layoutPath = OldPath::combine(getActiveProjectPath(), WIDGET_LAYOUT_PATH);
 
 		FileSerializer fs;
 		fs.encode(layout.get(), layoutPath);

+ 17 - 17
BansheeEditor/Source/BsGUIResourceTreeView.cpp

@@ -40,7 +40,7 @@ namespace BansheeEngine
 		const ProjectLibrary::LibraryEntry* rootEntry = ProjectLibrary::instance().getRootEntry();
 
 		mRootElement.mFullPath = rootEntry->path;
-		mRootElement.mElementName = Path::getFilename(mRootElement.mFullPath);
+		mRootElement.mElementName = OldPath::getFilename(mRootElement.mFullPath);
 		expandElement(&mRootElement);
 
 		updateFromProjectLibraryEntry(&mRootElement, rootEntry);
@@ -87,7 +87,7 @@ namespace BansheeEngine
 		ResourceTreeElement* resourceTreeElement = static_cast<ResourceTreeElement*>(element);
 		
 		WString oldPath = resourceTreeElement->mFullPath;
-		WString newPath = Path::combine(Path::parentPath(oldPath), name);
+		WString newPath = OldPath::combine(OldPath::parentPath(oldPath), name);
 
 		ProjectLibrary::instance().moveEntry(oldPath, findUniquePath(newPath));
 	}
@@ -140,11 +140,11 @@ namespace BansheeEngine
 	{
 		ResourceTreeElement* newChild = cm_new<ResourceTreeElement>();
 		newChild->mParent = parent;
-		newChild->mName = toString(Path::getFilename(fullPath));
+		newChild->mName = toString(OldPath::getFilename(fullPath));
 		newChild->mFullPath = fullPath;
 		newChild->mSortedIdx = (UINT32)parent->mChildren.size();
 		newChild->mIsVisible = parent->mIsVisible && parent->mIsExpanded;
-		newChild->mElementName = Path::getFilename(fullPath);
+		newChild->mElementName = OldPath::getFilename(fullPath);
 
 		parent->mChildren.push_back(newChild);
 
@@ -194,13 +194,13 @@ namespace BansheeEngine
 
 	GUIResourceTreeView::ResourceTreeElement* GUIResourceTreeView::findTreeElement(const WString& fullPath)
 	{
-		Vector<WString>::type pathElems = Path::split(fullPath);
-		Vector<WString>::type rootElems = Path::split(mRootElement.mFullPath);
+		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() && Path::comparePathElements(*pathIter, *rootIter))
+		while(pathIter != pathElems.end() && rootIter != rootElems.end() && OldPath::comparePathElements(*pathIter, *rootIter))
 		{
 			++pathIter;
 			++rootIter;
@@ -219,7 +219,7 @@ namespace BansheeEngine
 			ResourceTreeElement* current = todo.top();
 			todo.pop();
 
-			if(Path::comparePathElements(*pathIter, current->mElementName))
+			if(OldPath::comparePathElements(*pathIter, current->mElementName))
 			{
 				++pathIter;
 
@@ -239,7 +239,7 @@ namespace BansheeEngine
 
 	void GUIResourceTreeView::entryAdded(const WString& path)
 	{
-		WString parentPath = Path::parentPath(path);
+		WString parentPath = OldPath::parentPath(path);
 
 		ResourceTreeElement* parentElement = findTreeElement(parentPath);
 		assert(parentElement != nullptr);
@@ -361,14 +361,14 @@ namespace BansheeEngine
 		if(FileSystem::exists(path))
 		{
 			WString noExtensionPath = path;
-			WString extension = Path::getExtension(path);
-			Path::replaceExtension(noExtensionPath, L"");
+			WString extension = OldPath::getExtension(path);
+			OldPath::replaceExtension(noExtensionPath, L"");
 
 			WString newPath;
 			UINT32 cnt = 1;
 			do 
 			{
-				newPath = Path::combine(Path::combine(noExtensionPath, L" " + toWString(cnt)), extension);
+				newPath = OldPath::combine(OldPath::combine(noExtensionPath, L" " + toWString(cnt)), extension);
 				cnt++;
 			} while (FileSystem::exists(newPath));
 
@@ -417,16 +417,16 @@ namespace BansheeEngine
 
 			WString destDir = resourceTreeElement->mFullPath;
 			if(FileSystem::isFile(destDir))
-				destDir = Path::parentPath(destDir);
+				destDir = OldPath::parentPath(destDir);
 
 			for(UINT32 i = 0; i < mDraggedResources->numObjects; i++)
 			{
-				WString filename = Path::getFilename(mDraggedResources->resourcePaths[i]);
-				WString currentParent = Path::parentPath(mDraggedResources->resourcePaths[i]);
+				WString filename = OldPath::getFilename(mDraggedResources->resourcePaths[i]);
+				WString currentParent = OldPath::parentPath(mDraggedResources->resourcePaths[i]);
 
-				if(!Path::equals(currentParent, destDir))
+				if(!OldPath::equals(currentParent, destDir))
 				{
-					WString newPath = Path::combine(destDir, filename);
+					WString newPath = OldPath::combine(destDir, filename);
 					ProjectLibrary::instance().moveEntry(mDraggedResources->resourcePaths[i], findUniquePath(newPath));
 				}
 			}

+ 32 - 32
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -49,7 +49,7 @@ namespace BansheeEngine
 	ProjectLibrary::ProjectLibrary(const WString& projectFolder)
 		:mRootEntry(nullptr), mProjectFolder(projectFolder)
 	{
-		mResourcesFolder = Path::combine(mProjectFolder, RESOURCES_DIR);
+		mResourcesFolder = OldPath::combine(mProjectFolder, RESOURCES_DIR);
 		mMonitor = cm_new<FolderMonitor>();
 
 		FolderChange folderChanges = (FolderChange)((UINT32)FolderChange::FileName | (UINT32)FolderChange::DirName | 
@@ -88,20 +88,20 @@ namespace BansheeEngine
 
 	void ProjectLibrary::checkForModifications(const WString& fullPath)
 	{
-		if(!Path::includes(fullPath, mResourcesFolder))
+		if(!OldPath::includes(fullPath, mResourcesFolder))
 			return; // Folder not part of our resources path, so no modifications
 
 		if(mRootEntry == nullptr)
 		{
 			WString resPath = mResourcesFolder;
-			mRootEntry = cm_new<DirectoryEntry>(resPath, Path::getFilename(resPath), nullptr);
+			mRootEntry = cm_new<DirectoryEntry>(resPath, OldPath::getFilename(resPath), nullptr);
 		}
 
 		WString pathToSearch = fullPath;
 		LibraryEntry* entry = findEntry(pathToSearch);
 		if(entry == nullptr) // File could be new, try to find parent directory entry
 		{
-			WString parentDirPath = Path::parentPath(pathToSearch);
+			WString parentDirPath = OldPath::parentPath(pathToSearch);
 			entry = findEntry(parentDirPath);
 
 			// Cannot find parent directory. Create the needed hierarchy.
@@ -174,7 +174,7 @@ namespace BansheeEngine
 						if(isMeta(filePath))
 						{
 							WString sourceFilePath = filePath;
-							Path::replaceExtension(sourceFilePath, L"");
+							OldPath::replaceExtension(sourceFilePath, L"");
 
 							if(!FileSystem::isFile(sourceFilePath))
 							{
@@ -189,7 +189,7 @@ namespace BansheeEngine
 							UINT32 idx = 0;
 							for(auto& child : currentDir->mChildren)
 							{
-								if(child->type == LibraryEntryType::File && Path::equals(child->path, filePath))
+								if(child->type == LibraryEntryType::File && OldPath::equals(child->path, filePath))
 								{
 									existingEntries[idx] = true;
 									existingEntry = static_cast<ResourceEntry*>(child);
@@ -216,7 +216,7 @@ namespace BansheeEngine
 						UINT32 idx = 0;
 						for(auto& child : currentDir->mChildren)
 						{
-							if(child->type == LibraryEntryType::Directory && Path::equals(child->path, dirPath))
+							if(child->type == LibraryEntryType::Directory && OldPath::equals(child->path, dirPath))
 							{
 								existingEntries[idx] = true;
 								existingEntry = static_cast<DirectoryEntry*>(child);
@@ -260,7 +260,7 @@ namespace BansheeEngine
 
 	ProjectLibrary::ResourceEntry* ProjectLibrary::addResourceInternal(DirectoryEntry* parent, const WString& filePath)
 	{
-		ResourceEntry* newResource = cm_new<ResourceEntry>(filePath, Path::getFilename(filePath), parent);
+		ResourceEntry* newResource = cm_new<ResourceEntry>(filePath, OldPath::getFilename(filePath), parent);
 		parent->mChildren.push_back(newResource);
 
 		reimportResourceInternal(newResource);
@@ -273,7 +273,7 @@ namespace BansheeEngine
 
 	ProjectLibrary::DirectoryEntry* ProjectLibrary::addDirectoryInternal(DirectoryEntry* parent, const WString& dirPath)
 	{
-		DirectoryEntry* newEntry = cm_new<DirectoryEntry>(dirPath, Path::getFilename(dirPath), parent);
+		DirectoryEntry* newEntry = cm_new<DirectoryEntry>(dirPath, OldPath::getFilename(dirPath), parent);
 		parent->mChildren.push_back(newEntry);
 
 		if(!onEntryAdded.empty())
@@ -339,7 +339,7 @@ namespace BansheeEngine
 
 	void ProjectLibrary::reimportResourceInternal(ResourceEntry* resource)
 	{
-		WString ext = Path::getExtension(resource->path);
+		WString ext = OldPath::getExtension(resource->path);
 		WString metaPath = resource->path + L".meta";
 
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
@@ -386,11 +386,11 @@ namespace BansheeEngine
 				Importer::instance().reimport(importedResource, resource->path, importOptions);
 			}
 
-			WString internalResourcesPath = Path::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
+			WString internalResourcesPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
 			if(!FileSystem::isDirectory(internalResourcesPath))
 				FileSystem::createDir(internalResourcesPath);
 
-			internalResourcesPath = Path::combine(internalResourcesPath, toWString(importedResource.getUUID()) + L".asset");
+			internalResourcesPath = OldPath::combine(internalResourcesPath, toWString(importedResource.getUUID()) + L".asset");
 
 			gResources().save(importedResource, internalResourcesPath, true);
 			gResources().unload(importedResource);
@@ -419,13 +419,13 @@ namespace BansheeEngine
 
 	ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const WString& fullPath) const
 	{
-		Vector<WString>::type pathElems = Path::split(fullPath);
-		Vector<WString>::type rootElems = Path::split(mRootEntry->path);
+		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() && Path::comparePathElements(*pathIter, *rootIter))
+		while(pathIter != pathElems.end() && rootIter != rootElems.end() && OldPath::comparePathElements(*pathIter, *rootIter))
 		{
 			++pathIter;
 			++rootIter;
@@ -443,7 +443,7 @@ namespace BansheeEngine
 			LibraryEntry* current = todo.top();
 			todo.pop();
 
-			if(Path::comparePathElements(*pathIter, current->elementName))
+			if(OldPath::comparePathElements(*pathIter, current->elementName))
 			{
 				++pathIter;
 
@@ -477,7 +477,7 @@ namespace BansheeEngine
 		if(oldEntry != nullptr) // Moving from the Resources folder
 		{
 			// Moved outside of Resources, delete entry & meta file
-			if(!Path::includes(newPath, mResourcesFolder))
+			if(!OldPath::includes(newPath, mResourcesFolder))
 			{
 				if(oldEntry->type == LibraryEntryType::File)
 				{
@@ -499,7 +499,7 @@ namespace BansheeEngine
 				if(findIter != parent->mChildren.end())
 					parent->mChildren.erase(findIter);
 
-				WString parentPath = Path::parentPath(newPath);
+				WString parentPath = OldPath::parentPath(newPath);
 
 				DirectoryEntry* newEntryParent = nullptr;
 				LibraryEntry* newEntryParentLib = findEntry(parentPath);
@@ -516,7 +516,7 @@ namespace BansheeEngine
 				newEntryParent->mChildren.push_back(oldEntry);
 				oldEntry->parent = newEntryParent;
 				oldEntry->path = newPath;
-				oldEntry->elementName = Path::getFilename(newPath);
+				oldEntry->elementName = OldPath::getFilename(newPath);
 
 				if(oldEntry->type == LibraryEntryType::Directory) // Update child paths
 				{
@@ -531,7 +531,7 @@ namespace BansheeEngine
 						DirectoryEntry* curDirEntry = static_cast<DirectoryEntry*>(curEntry);
 						for(auto& child : curDirEntry->mChildren)
 						{
-							child->path = Path::combine(child->parent->path, child->elementName);
+							child->path = OldPath::combine(child->parent->path, child->elementName);
 
 							if(child->type == LibraryEntryType::Directory)
 								todo.push(child);
@@ -584,7 +584,7 @@ namespace BansheeEngine
 		Stack<WString>::type parentPaths;
 		do 
 		{
-			WString newParentPath = Path::parentPath(parentPath);
+			WString newParentPath = OldPath::parentPath(parentPath);
 
 			if(newParentPath == parentPath)
 				break;
@@ -629,7 +629,7 @@ namespace BansheeEngine
 
 	bool ProjectLibrary::isMeta(const WString& fullPath) const
 	{
-		return Path::getExtension(fullPath) == L".meta";
+		return OldPath::getExtension(fullPath) == L".meta";
 	}
 
 	void ProjectLibrary::onMonitorFileModified(const WString& path)
@@ -639,7 +639,7 @@ namespace BansheeEngine
 		else
 		{
 			WString resourcePath = path;
-			Path::replaceExtension(resourcePath, L"");
+			OldPath::replaceExtension(resourcePath, L"");
 
 			checkForModifications(resourcePath);
 		}
@@ -649,14 +649,14 @@ namespace BansheeEngine
 	{
 		std::shared_ptr<ProjectLibraryEntries> libEntries = ProjectLibraryEntries::create(*mRootEntry);
 
-		WString libraryEntriesPath = Path::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		libraryEntriesPath = Path::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
+		WString libraryEntriesPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
+		libraryEntriesPath = OldPath::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
 
 		FileSerializer fs;
 		fs.encode(libEntries.get(), libraryEntriesPath);
 
-		WString resourceManifestPath = Path::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		resourceManifestPath = Path::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
+		WString resourceManifestPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
+		resourceManifestPath = OldPath::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
 
 		ResourceManifest::save(mResourceManifest, resourceManifestPath, mProjectFolder);
 	}
@@ -670,10 +670,10 @@ namespace BansheeEngine
 		}
 
 		WString resPath = mResourcesFolder;
-		mRootEntry = cm_new<DirectoryEntry>(resPath, Path::getFilename(resPath), nullptr);
+		mRootEntry = cm_new<DirectoryEntry>(resPath, OldPath::getFilename(resPath), nullptr);
 
-		WString libraryEntriesPath = Path::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		libraryEntriesPath = Path::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
+		WString libraryEntriesPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
+		libraryEntriesPath = OldPath::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
 
 		if(FileSystem::exists(libraryEntriesPath))
 		{
@@ -727,8 +727,8 @@ namespace BansheeEngine
 		}
 
 		// Load resource manifest
-		WString resourceManifestPath = Path::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
-		resourceManifestPath = Path::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
+		WString resourceManifestPath = OldPath::combine(mProjectFolder, INTERNAL_RESOURCES_DIR);
+		resourceManifestPath = OldPath::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
 
 		if(FileSystem::exists(resourceManifestPath))
 		{

+ 1 - 1
CamelotCore/Source/CmGpuProgIncludeImporter.cpp

@@ -37,7 +37,7 @@ namespace BansheeEngine
 
 		GpuProgIncludePtr gpuInclude = GpuProgInclude::_createPtr(includeString);
 
-		WString fileName = Path::getFilename(filePath, false);
+		WString fileName = OldPath::getFilename(filePath, false);
 		gpuInclude->setName(toString(fileName));
 
 		return gpuInclude;

+ 2 - 2
CamelotCore/Source/CmGpuProgramImporter.cpp

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

+ 1 - 1
CamelotCore/Source/CmImporter.cpp

@@ -137,7 +137,7 @@ namespace BansheeEngine
 
 	SpecificImporter* Importer::getImporterForFile(const WString& inputFilePath) const
 	{
-		WString ext = Path::getExtension(inputFilePath);
+		WString ext = OldPath::getExtension(inputFilePath);
 		ext = ext.substr(1, ext.size() - 1); // Remove the .
 		if(!supportsFileType(ext))
 		{

+ 11 - 11
CamelotCore/Source/CmResourceManifest.cpp

@@ -31,7 +31,7 @@ namespace BansheeEngine
 	{
 		auto iterFind = mUUIDToFilePath.find(uuid);
 
-		WString standardizedFilePath = Path::standardizePath(filePath);
+		WString standardizedFilePath = OldPath::standardizePath(filePath);
 		StringUtil::toLowerCase(standardizedFilePath);
 
 		if(iterFind != mUUIDToFilePath.end())
@@ -80,7 +80,7 @@ namespace BansheeEngine
 
 	bool ResourceManifest::filePathToUUID(const WString& filePath, String& outUUID) const
 	{
-		WString standardizedFilePath = Path::standardizePath(filePath);
+		WString standardizedFilePath = OldPath::standardizePath(filePath);
 		StringUtil::toLowerCase(standardizedFilePath);
 
 		auto iterFind = mFilePathToUUID.find(standardizedFilePath);
@@ -106,7 +106,7 @@ namespace BansheeEngine
 
 	bool ResourceManifest::filePathExists(const WString& filePath) const
 	{
-		WString standardizedFilePath = Path::standardizePath(filePath);
+		WString standardizedFilePath = OldPath::standardizePath(filePath);
 		StringUtil::toLowerCase(standardizedFilePath);
 
 		auto iterFind = mFilePathToUUID.find(standardizedFilePath);
@@ -116,33 +116,33 @@ namespace BansheeEngine
 
 	void ResourceManifest::save(const ResourceManifestPtr& manifest, const WString& path, const WString& relativePath)
 	{
-		WString standRelativePath = Path::standardizePath(relativePath);
+		WString standRelativePath = OldPath::standardizePath(relativePath);
 		StringUtil::toLowerCase(standRelativePath);
 
 		ResourceManifestPtr copy = create(manifest->mName);
 
 		for(auto& elem : manifest->mFilePathToUUID)
 		{
-			if(!Path::includes(elem.first, standRelativePath))
+			if(!OldPath::includes(elem.first, standRelativePath))
 			{
 				CM_EXCEPT(InvalidStateException, "Path in resource manifest cannot be made relative to: \"" + 
 					toString(relativePath) + "\". Path: \"" + toString(elem.first) + "\"");
 			}
 
-			WString relativePath = Path::relative(standRelativePath, elem.first);
+			WString relativePath = OldPath::relative(standRelativePath, elem.first);
 
 			copy->mFilePathToUUID[relativePath] = elem.second;
 		}
 
 		for(auto& elem : manifest->mUUIDToFilePath)
 		{
-			if(!Path::includes(elem.second, standRelativePath))
+			if(!OldPath::includes(elem.second, standRelativePath))
 			{
 				CM_EXCEPT(InvalidStateException, "Path in resource manifest cannot be made relative to: \"" + 
 					toString(relativePath) + "\". Path: \"" + toString(elem.second) + "\"");
 			}
 
-			WString relativePath = Path::relative(standRelativePath, elem.second);
+			WString relativePath = OldPath::relative(standRelativePath, elem.second);
 
 			copy->mUUIDToFilePath[elem.first] = relativePath;
 		}
@@ -153,7 +153,7 @@ namespace BansheeEngine
 
 	ResourceManifestPtr ResourceManifest::load(const WString& path, const WString& relativePath)
 	{
-		WString standRelativePath = Path::standardizePath(relativePath);
+		WString standRelativePath = OldPath::standardizePath(relativePath);
 		StringUtil::toLowerCase(standRelativePath);
 
 		FileSerializer fs;
@@ -163,13 +163,13 @@ namespace BansheeEngine
 
 		for(auto& elem : manifest->mFilePathToUUID)
 		{
-			WString absPath = Path::combine(standRelativePath, elem.first);
+			WString absPath = OldPath::combine(standRelativePath, elem.first);
 			copy->mFilePathToUUID[absPath] = elem.second;
 		}
 
 		for(auto& elem : manifest->mUUIDToFilePath)
 		{
-			WString absPath = Path::combine(standRelativePath, elem.second);
+			WString absPath = OldPath::combine(standRelativePath, elem.second);
 			copy->mUUIDToFilePath[elem.first] = absPath;
 		}
 

+ 1 - 1
CamelotCore/Source/CmResources.cpp

@@ -150,7 +150,7 @@ namespace BansheeEngine
 		}
 		else
 		{
-			String fileName = toString(Path::getFilename(filePath));
+			String fileName = toString(OldPath::getFilename(filePath));
 			String taskName = "Resource load: " + fileName;
 
 			TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, newResource));

+ 1 - 1
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -53,7 +53,7 @@ namespace BansheeEngine
 		MeshPtr mesh = Mesh::_createPtr(meshData);
 		mesh->setSubMeshes(subMeshes);
 
-		WString fileName = Path::getFilename(filePath, false);
+		WString fileName = OldPath::getFilename(filePath, false);
 		mesh->setName(toString(fileName));
 
 		return mesh;

+ 1 - 1
CamelotFontImporter/Source/CmFontImporter.cpp

@@ -319,7 +319,7 @@ namespace BansheeEngine
 
 		FT_Done_FreeType(library);
 
-		WString fileName = Path::getFilename(filePath, false);
+		WString fileName = OldPath::getFilename(filePath, false);
 		newFont->setName(toString(fileName));
 
 		return newFont;

+ 1 - 1
CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp

@@ -146,7 +146,7 @@ namespace BansheeEngine
 
 		fileData->close();
 
-		WString fileName = Path::getFilename(filePath, false);
+		WString fileName = OldPath::getFilename(filePath, false);
 		newTexture->setName(toString(fileName));
 
 		return newTexture;

+ 20 - 0
CamelotUtility/Include/BsSpinLock.h

@@ -4,6 +4,13 @@
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	Synchronization primitive with low overhead.
+	 *
+	 * @note	However it will actively block the thread waiting for the lock,
+	 *			not allowing any other work to be done, so it is best used for short
+	 *			locks.
+	 */
 	class SpinLock
 	{
 	public:
@@ -12,12 +19,19 @@ namespace BansheeEngine
 			mLock.clear(std::memory_order_relaxed);
 		}
 
+		/**
+		 * @brief	Lock any following operations with the spin lock, not allowing
+		 *			any other thread to access them.
+		 */
 		void lock()
 		{
 			while(mLock.test_and_set(std::memory_order_acquire))
 			{ }
 		}
 
+		/**
+		 * @brief	Release the lock and allow other threads to acquire the lock.
+		 */
 		void unlock()
 		{
 			mLock.clear(std::memory_order_release);
@@ -27,6 +41,12 @@ namespace BansheeEngine
 		std::atomic_flag mLock;
 	};
 
+	/**
+	 * @brief	Spin lock that is automatically locked upon creation and
+	 *			unlocked upon destruction.
+	 *
+	 * @see		SpinLock
+	 */
 	class ScopedSpinLock
 	{
 	public:

+ 582 - 2
CamelotUtility/Include/CmPath.h

@@ -6,10 +6,590 @@
 namespace BansheeEngine
 {
 	/**
-	 * @brief	Various string manipulations of file paths.
+	 * @brief	Class for storing and manipulating file paths. Paths may be parsed
+	 *			from and to raw strings according to various platform specific path
+	 *			types.
 	 */
 	class CM_UTILITY_EXPORT Path
 	{
+	public:
+		enum class PathType
+		{
+			Windows,
+			Unix,
+			Default
+		};
+
+	public:
+		/**
+		 * @brief	Constructs a path by parsing the provided path string. 
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		Path(const WString& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		Path(const String& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path null terminated string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		Path(wchar_t* pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path null terminated string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		Path(const char* pathStr, PathType type = PathType::Default);
+		Path(const Path& other);
+
+		/**
+		 * @brief	Assigns a path by parsing the provided path string. Path will be 
+		 *			parsed according to the rules of the platform the application is 
+		 *			being compiled to.
+		 */
+		Path& operator= (const WString& pathStr);
+
+		/**
+		 * @brief	Assigns a path by parsing the provided path string. Path will be
+		 *			parsed according to the rules of the platform the application is
+		 *			being compiled to.
+		 */
+		Path& operator= (const String& pathStr);
+
+		/**
+		 * @brief	Assigns a path by parsing the provided path null terminated string. 
+		 *			Path will be parsed according to the rules of the platform the 
+		 *			application is being compiled to.
+		 */
+		Path& operator= (const wchar_t* pathStr);
+
+		/**
+		 * @brief	Assigns a path by parsing the provided path null terminated string.
+		 *			Path will be parsed according to the rules of the platform the
+		 *			application is being compiled to.
+		 */
+		Path& operator= (const char* pathStr);
+
+		Path& operator= (const Path& path);
+
+		/**
+		 * @brief	Compares two paths and returns true if they match. Comparison is
+		 *			case insensitive and paths will be compared as-is, without canonization.
+		 */
+		bool operator== (const Path& path) const { return equals(path); }
+
+		/**
+		 * @brief	Compares two paths and returns true if they don't match. Comparison is
+		 *			case insensitive and paths will be compared as-is, without canonization.
+		 */
+		bool operator!= (const Path& path) const { return !equals(path); }
+
+		/**
+		* @brief	Gets a directory name with the specified index from the path.
+		*/
+		const WString& operator[] (UINT32 idx) const { return getWDirectory(idx); }
+
+		/**
+		 * @brief	Swap internal data with another Path object.
+		 */
+		void swap(Path& path);
+
+		/**
+		 * @brief	Create a path from another Path object.
+		 */
+		void assign(const Path& path);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const WString& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const String& pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path null terminated string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const wchar_t* pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Constructs a path by parsing the provided path null terminated string.
+		 *			Throws exception if provided path is not valid.
+		 *
+		 * @param	type	If set to default path will be parsed according to the
+		 *					rules of the platform the application is being compiled to.
+		 *					Otherwise it will be parsed according to provided type.
+		 */
+		void assign(const char* pathStr, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Converts the path in a string according to platform path rules.
+		 *
+		 * @type	If set to default path will be parsed according to the
+		 *			rules of the platform the application is being compiled to.
+		 *			Otherwise it will be parsed according to provided type.
+		 */
+		WString toWString(PathType type = PathType::Default) const;
+
+		/**
+		 * @brief	Converts the path in a string according to platform path rules.
+		 *
+		 * @type	If set to default path will be parsed according to the
+		 *			rules of the platform the application is being compiled to.
+		 *			Otherwise it will be parsed according to provided type.
+		 */
+		String toString(PathType type = PathType::Default) const;
+
+		/**
+		 * @brief	Checks is the path a directory (contains no file-name).
+		 */
+		bool isDirectory() const { return mFilename.empty(); }
+
+		/**
+		 * @brief	Checks does the path point to a file.
+		 */
+		bool isFile() const { return !mFilename.empty(); }
+
+		/**
+		 * @brief	Checks is the contained path absolute.
+		 */
+		bool isAbsolute() const { return mIsAbsolute; }
+
+		/**
+		 * @brief	Returns parent path. If current path points to a file
+		 *			the parent path will be the folder where the file is located.
+		 *			Or if it contains a directory the parent will be the parent directory.
+		 *			If no parent exists, same path will be returned.
+		 */
+		Path getParent() const;
+
+		/**
+		 * @brief	Returns an absolute path by appending the current path to the provided base.
+		 *			If path was already absolute no changes are made and copy of current path
+		 *			is returned.
+		 *			If base is not absolute, then the returned path will be made relative to base,
+		 *			but will not be absolute.
+		 */
+		Path getAbsolute(const Path& base) const;
+
+		/**
+		 * @brief	Returns a relative path by making the current path relative to the provided base.
+		 *			Base must be a part of the current path. If base is not a part
+		 *			of the path no changes are made and a copy of the current path
+		 *			is returned.
+		 */
+		Path getRelative(const Path& base) const;
+
+		/**
+		 * @brief	Returns the path as a path to directory. If path was pointing
+		 *			to a file, the filename is removed, otherwise no changes are made
+		 *			and exact copy is returned.
+		 */
+		Path getDirectory() const;
+
+		/**
+		 * @brief	Makes the path the parent of the current path. If current path points to a file
+		 *			the parent path will be the folder where the file is located.
+		 *			Or if it contains a directory the parent will be the parent directory.
+		 *			If no parent exists, same path will be returned.
+		 */
+		void makeParent();
+
+		/**
+		 * @brief	Makes the current path absolute by appending it to base.
+		 *			If path was already absolute no changes are made and copy of current path
+		 *			is returned.
+		 *			If base is not absolute, then the returned path will be made relative to base,
+		 *			but will not be absolute.
+		 */
+		void makeAbsolute(const Path& base);
+
+		/**
+		 * @brief	Makes the current path relative to the provided base.
+		 *			Base must be a part of the current path. If base is not a part
+		 *			of the path no changes are made and a copy of the current path
+		 *			is returned.
+		 */
+		void makeRelative(const Path& base);
+
+		/**
+		 * @brief	Appends another path to the end of this path.
+		 *			If this path contains a filename, it is removed.
+		 */
+		void append(const Path& path);
+
+		/**
+		 * @brief	Checks if the current path contains the provided path.
+		 *			Comparison is case insensitive and paths will be compared 
+		 *			as-is, without canonization.
+		 */
+		bool includes(const Path& child) const;
+
+		/**
+		 * @brief	Compares two paths and returns true if they match. Comparison is
+		 *			case insensitive and paths will be compared as-is, without canonization.
+		 */
+		bool equals(const Path& other) const;
+
+		/**
+		 * @brief	Change or set the filename in the path.
+		 */
+		void setFilename(const WString& filename) { mFilename = filename; }
+
+		/**
+		 * @brief	Change or set the filename in the path.
+		 */
+		void setFilename(const String& filename) { mFilename = BansheeEngine::toWString(filename); }
+
+		/**
+		 * @brief	Change or set the base name in the path. Base name changes the
+		 *			filename by changing its base to the provided value but keeping extension intact.
+		 */
+		void setBasename(const WString& basename);
+
+		/**
+		 * @brief	Change or set the base name in the path. Base name changes the
+		 *			filename by changing its base to the provided value but keeping extension intact.
+		 */
+		void setBasename(const String& basename);
+
+		/**
+		 * @brief	Change or set the extension of the filename in the path.
+		 */
+		void setExtension(const WString& extension);
+
+		/**
+		 * @brief	Change or set the extension of the filename in the path.
+		 */
+		void setExtension(const String& extension);
+
+		/**
+		 * @brief	Returns a filename in the path.
+		 *
+		 * @param	extension	If true, returned filename will contain an extension.
+		 */
+		WString getWFilename(bool extension = true) const;
+
+		/**
+		 * @brief	Returns a filename in the path.
+		 *
+		 * @param	extension	If true, returned filename will contain an extension.
+		 */
+		String getFilename(bool extension = true) const;
+
+		/**
+		 * @brief	Returns file extension with the leading ".".
+		 */
+		WString getWExtension() const;
+
+		/**
+		 * @brief	Returns file extension with the leading ".".
+		 */
+		String getExtension() const;
+
+		/**
+		 * @brief	Gets the number of directories in the path.
+		 */
+		UINT32 getNumDirectories() const { return (UINT32)mDirectories.size(); }
+
+		/**
+		 * @brief	Gets a directory name with the specified index from the path.
+		 */
+		const WString& getWDirectory(UINT32 idx) const;
+
+		/**
+		* @brief	Gets a directory name with the specified index from the path.
+		*/
+		String getDirectory(UINT32 idx) const;
+
+		/**
+		 * @brief	Returns path device (e.g. drive, volume, etc.) if one exists in the path.
+		 */
+		const WString& getWDevice() const { return mDevice; }
+
+		/**
+		* @brief	Returns path device (e.g. drive, volume, etc.) if one exists in the path.
+		*/
+		String getDevice() const { return BansheeEngine::toString(mDevice); }
+
+		/**
+		* @brief	Returns path node (e.g. network name) if one exists in the path.
+		*/
+		const WString& getWNode() const { return mNode; }
+
+		/**
+		* @brief	Returns path node (e.g. network name) if one exists in the path.
+		*/
+		String getNode() const { return BansheeEngine::toString(mNode); }
+
+		/**
+		 * @brief	Clears the path to nothing.
+		 */
+		void clear();
+
+	private:
+		Path();
+
+		/**
+		* @brief	Constructs a path by parsing the provided raw string data.
+		*			Throws exception if provided path is not valid.
+		*
+		* @param	type	If set to default path will be parsed according to the
+		*					rules of the platform the application is being compiled to.
+		*					Otherwise it will be parsed according to provided type.
+		*/
+		void assign(const wchar_t* pathStr, UINT32 numChars, PathType type = PathType::Default);
+
+		/**
+		* @brief	Constructs a path by parsing the provided raw string data.
+		*			Throws exception if provided path is not valid.
+		*
+		* @param	type	If set to default path will be parsed according to the
+		*					rules of the platform the application is being compiled to.
+		*					Otherwise it will be parsed according to provided type.
+		*/
+		void assign(const char* pathStr, UINT32 numChars, PathType type = PathType::Default);
+
+		/**
+		 * @brief	Parses a Windows path and stores the parsed data internally.
+		 *			Throws an exception if parsing fails.
+		 */
+		template<class T>
+		void parseWindows(const T* pathStr, UINT32 numChars)
+		{
+			clear();
+
+			UINT32 idx = 0;
+			BasicStringStream<T>::type tempStream;
+
+			if (idx < numChars)
+			{
+				if (pathStr[idx] == '\\' || pathStr[idx] == '/')
+				{
+					mIsAbsolute = true;
+					idx++;
+				}
+			}
+
+			if (idx < numChars)
+			{
+				// Path starts with a node, a drive letter or is relative
+				if (mIsAbsolute && pathStr[idx] == '\\' || pathStr[idx] == '/') // Node
+				{
+					idx++;
+
+					tempStream.clear();
+					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
+						tempStream << pathStr[idx++];
+
+					setNode(tempStream.str());
+
+					if (idx < numChars)
+						idx++;
+				}
+				else // A drive letter or not absolute
+				{
+					T drive = pathStr[idx];
+					idx++;
+
+					if (idx < numChars && pathStr[idx] == ':')
+					{
+						if (mIsAbsolute || !((drive >= 'a' && drive <= 'z') || (drive >= 'A' && drive <= 'Z')))
+							throwInvalidPathException(BasicString<T>::type(pathStr, numChars));
+
+						mIsAbsolute = true;
+						setDevice(BansheeEngine::toWString(drive));
+
+						idx++;
+
+						if (idx < numChars || (pathStr[idx] != '\\' && pathStr[idx] != '/'))
+							throwInvalidPathException(BasicString<T>::type(pathStr, numChars));
+
+						idx++;
+					}
+					else
+						idx--;
+				}
+
+				while (idx < numChars)
+				{
+					tempStream.clear();
+					while (idx < numChars && pathStr[idx] != '\\' && pathStr[idx] != '/')
+					{
+						tempStream << pathStr[idx];
+						idx++;
+					}
+
+					if (idx < numChars)
+						pushDirectory(tempStream.str());
+					else
+						setFilename(tempStream.str());
+
+					idx++;
+				}
+			}
+		}
+
+		/**
+		* @brief	Parses a Unix path and stores the parsed data internally.
+		*			Throws an exception if parsing fails.
+		*/
+		template<class T>
+		void parseUnix(const T* pathStr, UINT32 numChars)
+		{
+			clear();
+
+			UINT32 idx = 0;
+			BasicStringStream<T>::type tempStream;
+
+			if (idx < numChars)
+			{
+				if (pathStr[idx] == '/')
+				{
+					mIsAbsolute = true;
+					idx++;
+				}
+				else if (pathStr[idx] == '~')
+				{
+					idx++;
+					if (idx >= numChars || pathStr[idx] == '/')
+					{
+						pushDirectory(BansheeEngine::toWString('~'));
+						mIsAbsolute = true;
+					}
+					else
+						idx--;
+				}
+
+				while (idx < numChars)
+				{
+					tempStream.clear();
+					while (idx < numChars && pathStr[idx] != '/')
+					{
+						tempStream << pathStr[idx];
+						idx++;
+					}
+
+					if (idx < numChars)
+					{
+						if (mDirectories.empty())
+						{
+							BasicString<T>::type deviceStr = tempStream.str();
+							if (!deviceStr.empty() && *(deviceStr.rbegin()) == ':')
+							{
+								setDevice(deviceStr.substr(0, deviceStr.length() - 1));
+								mIsAbsolute = true;
+							}
+							else
+							{
+								pushDirectory(deviceStr);
+							}
+						}
+						else
+						{
+							pushDirectory(tempStream.str());
+						}
+					}
+					else
+					{
+						setFilename(tempStream.str());
+					}
+
+					idx++;
+				}
+			}
+		}
+
+		void setNode(const WString& node) { mNode = node; }
+		void setNode(const String& node) { mNode = BansheeEngine::toWString(node); }
+
+		void setDevice(const WString& device) { mDevice = device; }
+		void setDevice(const String& device) { mDevice = BansheeEngine::toWString(device); }
+
+		/**
+		 * @brief	Build a Windows path string from internal path data.
+		 */
+		WString buildWindows() const;
+
+		/**
+		* @brief	Build a Unix path string from internal path data.
+		*/
+		WString buildUnix() const;
+
+		/**
+		 * @brief	Add new directory to the end of the path. 
+		 */
+		void pushDirectory(const WString& dir);
+
+		/**
+		* @brief	Add new directory to the end of the path.
+		*/
+		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. 
+		 */
+		void throwInvalidPathException(const WString& path) const;
+
+		/**
+		* @brief	Helper method that throws invalid path exception.
+		*/
+		void throwInvalidPathException(const String& path) const;
+	private:
+		Vector<WString>::type mDirectories;
+		WString mDevice;
+		WString mFilename;
+		WString mNode;
+		bool mIsAbsolute;
+	};
+
+	/**
+	 * @brief	Various string manipulations of file paths.
+	 */
+	class CM_UTILITY_EXPORT OldPath
+	{
 	public:
 		/**
 		 * @brief	Returns file extension extracted from the provided
@@ -96,7 +676,7 @@ namespace BansheeEngine
 			WString relativePath;
 			for(; iterPath != pathElems.end(); ++iterPath)
 			{
-				relativePath = Path::combine(relativePath, *iterPath);
+				relativePath = OldPath::combine(relativePath, *iterPath);
 			}
 
 			return relativePath;

+ 502 - 0
CamelotUtility/Source/CmPath.cpp

@@ -1,6 +1,508 @@
 #include "CmPath.h"
+#include "CmException.h"
 
 namespace BansheeEngine
 {
+	Path::Path()
+		:mIsAbsolute(false)
+	{ }
 
+	Path::Path(const WString& pathStr, PathType type)
+	{
+		assign(pathStr, type);
+	}
+
+	Path::Path(const String& pathStr, PathType type)
+	{
+		assign(pathStr, type);
+	}
+
+	Path::Path(wchar_t* pathStr, PathType type)
+	{
+		assign(pathStr);
+	}
+
+	Path::Path(const char* pathStr, PathType type)
+	{
+		assign(pathStr);
+	}
+
+	Path::Path(const Path& other)
+	{
+		assign(other);
+	}
+
+	Path& Path::operator= (const Path& path)
+	{
+		assign(path);
+		return *this;
+	}
+
+	Path& Path::operator= (const WString& pathStr)
+	{
+		assign(pathStr);
+		return *this;
+	}
+
+	Path& Path::operator= (const String& pathStr)
+	{
+		assign(pathStr);
+		return *this;
+	}
+
+	Path& Path::operator= (const wchar_t* pathStr)
+	{
+		assign(pathStr);
+		return *this;
+	}
+
+	Path& Path::operator= (const char* pathStr)
+	{
+		assign(pathStr);
+		return *this;
+	}
+
+	void Path::swap(Path& path)
+	{
+		std::swap(mDirectories, path.mDirectories);
+		std::swap(mFilename, path.mFilename);
+		std::swap(mDevice, path.mDevice);
+		std::swap(mNode, path.mNode);
+		std::swap(mIsAbsolute, path.mIsAbsolute);
+	}
+
+	void Path::assign(const Path& path)
+	{
+		mDirectories = path.mDirectories;
+		mFilename = path.mFilename;
+		mDevice = path.mDevice;
+		mNode = path.mNode;
+		mIsAbsolute = path.mIsAbsolute;
+	}
+
+	void Path::assign(const WString& pathStr, PathType type)
+	{
+		assign(pathStr.data(), (UINT32)pathStr.length(), type);
+	}
+
+	void Path::assign(const String& pathStr, PathType type)
+	{
+		assign(pathStr.data(), (UINT32)pathStr.length(), type);
+	}
+
+	void Path::assign(const wchar_t* pathStr, PathType type)
+	{
+		assign(pathStr, (UINT32)wcslen(pathStr), type);
+	}
+
+	void Path::assign(const char* pathStr, PathType type)
+	{
+		assign(pathStr, (UINT32)strlen(pathStr), type);
+	}
+
+	void Path::assign(const wchar_t* pathStr, UINT32 numChars, PathType type)
+	{
+		switch (type)
+		{
+		case PathType::Windows:
+			parseWindows(pathStr, numChars);
+			break;
+		case PathType::Unix:
+			parseUnix(pathStr, numChars);
+			break;
+		default:
+#if CM_PLATFORM == CM_PLATFORM_WIN32
+			parseWindows(pathStr, numChars);
+#elif CM_PLATFORM == CM_PLATFORM_APPLE || CM_PLATFORM == CM_PLATFORM_LINUX
+			parseUnix(pathStr, numChars);
+#else
+			static_assert(false, "Unsupported platform for path.");
+#endif
+			break;
+		}
+	}
+
+	void Path::assign(const char* pathStr, UINT32 numChars, PathType type)
+	{
+		switch (type)
+		{
+		case PathType::Windows:
+			parseWindows(pathStr, numChars);
+			break;
+		case PathType::Unix:
+			parseUnix(pathStr, numChars);
+			break;
+		default:
+#if CM_PLATFORM == CM_PLATFORM_WIN32
+			parseWindows(pathStr, numChars);
+#elif CM_PLATFORM == CM_PLATFORM_APPLE || CM_PLATFORM == CM_PLATFORM_LINUX
+			parseUnix(pathStr, numChars);
+#else
+			static_assert(false, "Unsupported platform for path.");
+#endif
+			break;
+		}
+	}
+
+	WString Path::toWString(PathType type) const
+	{
+		switch (type)
+		{
+		case PathType::Windows:
+			return buildWindows();
+		case PathType::Unix:
+			return buildUnix();
+		default:
+#if CM_PLATFORM == CM_PLATFORM_WIN32
+			return buildWindows();
+#elif CM_PLATFORM == CM_PLATFORM_APPLE || CM_PLATFORM == CM_PLATFORM_LINUX
+			return buildUnix();
+#else
+			static_assert(false, "Unsupported platform for path.");
+#endif
+			break;
+		}
+	}
+
+	String Path::toString(PathType type) const
+	{
+		switch (type)
+		{
+		case PathType::Windows:
+			return BansheeEngine::toString(buildWindows());
+		case PathType::Unix:
+			return BansheeEngine::toString(buildUnix());
+		default:
+#if CM_PLATFORM == CM_PLATFORM_WIN32
+			return BansheeEngine::toString(buildWindows());
+#elif CM_PLATFORM == CM_PLATFORM_APPLE || CM_PLATFORM == CM_PLATFORM_LINUX
+			return BansheeEngine::toString(buildUnix());
+#else
+			static_assert(false, "Unsupported platform for path.");
+#endif
+			break;
+		}
+	}
+
+	Path Path::getParent() const
+	{
+		Path copy = *this;
+		copy.makeParent();
+
+		return copy;
+	}
+
+	Path Path::getAbsolute(const Path& base) const
+	{
+		Path copy = *this;
+		copy.makeAbsolute(base);
+
+		return copy;
+	}
+
+	Path Path::getRelative(const Path& base) const
+	{
+		Path copy = *this;
+		copy.makeRelative(base);
+
+		return copy;
+	}
+
+	Path Path::getDirectory() const
+	{
+		Path copy = *this;
+		copy.mFilename.clear();
+
+		return copy;
+	}
+
+	void Path::makeParent()
+	{
+		if (mFilename.empty())
+		{
+			if (mDirectories.empty())
+			{
+				if (!mIsAbsolute)
+					mDirectories.push_back(L"..");
+			}
+			else
+			{
+				if (mDirectories.back() == L"..")
+					mDirectories.push_back(L"..");
+				else
+					mDirectories.pop_back();
+			}
+		}
+		else
+		{
+			mFilename.clear();
+		}
+	}
+
+	void Path::makeAbsolute(const Path& base)
+	{
+		if (mIsAbsolute)
+			return;
+
+		Path absDir = base.getDirectory();
+		for (auto& dir : mDirectories)
+			absDir.pushDirectory(dir);
+
+		*this = absDir;
+	}
+
+	void Path::makeRelative(const Path& base)
+	{
+		if (!base.includes(*this))
+			return;
+
+		mDirectories.erase(mDirectories.begin(), mDirectories.begin() + base.mDirectories.size());
+		mIsAbsolute = false;
+	}
+
+	bool Path::includes(const Path& child) const
+	{
+		auto iterParent = mDirectories.begin();
+		auto iterChild = child.mDirectories.begin();
+
+		for (; iterParent != mDirectories.end(); ++iterChild, ++iterParent)
+		{
+			if (iterChild == child.mDirectories.end())
+				return false;
+
+			if (!comparePathElem(*iterChild, *iterParent))
+				return false;
+		}
+
+		return true;
+	}
+
+	bool Path::equals(const Path& other) const
+	{
+		if (mIsAbsolute != other.mIsAbsolute)
+			return false;
+
+		if (mIsAbsolute)
+		{
+			if (!comparePathElem(mDevice, other.mDevice))
+				return false;
+		}
+
+		if (mDirectories.size() != other.mDirectories.size())
+			return false;
+
+		if (!comparePathElem(mFilename, other.mFilename))
+			return false;
+
+		if (!comparePathElem(mNode, other.mNode))
+			return false;
+
+		auto iterMe = mDirectories.begin();
+		auto iterOther = other.mDirectories.begin();
+
+		for (; iterMe != mDirectories.end(); ++iterMe, ++iterOther)
+		{
+			if (!comparePathElem(*iterMe, *iterOther))
+				return false;
+		}
+
+		return true;
+	}
+
+	void Path::append(const Path& path)
+	{
+		for (auto& dir : path.mDirectories)
+			pushDirectory(dir);
+
+		mFilename = path.mFilename;
+	}
+
+	void Path::setBasename(const WString& basename)
+	{
+		mFilename = basename + getWExtension();
+	}
+
+	void Path::setBasename(const String& basename)
+	{
+		mFilename = BansheeEngine::toWString(basename) + getWExtension();
+	}
+
+	void Path::setExtension(const WString& extension)
+	{
+		WStringStream stream;
+		stream << getWFilename(false);
+		stream << extension;
+
+		mFilename = stream.str();
+	}
+
+	void Path::setExtension(const String& extension)
+	{
+		setExtension(BansheeEngine::toWString(extension));
+	}
+
+	WString Path::getWFilename(bool extension) const
+	{
+		if (extension)
+			return mFilename;
+		else
+		{
+			WString::size_type pos = mFilename.rfind(L'.');
+			if (pos != WString::npos)
+				return mFilename.substr(0, pos);
+			else
+				return mFilename;
+		}
+	}
+
+	String Path::getFilename(bool extension) const
+	{
+		return BansheeEngine::toString(getWFilename(extension));
+	}
+
+	WString Path::getWExtension() const
+	{
+		WString::size_type pos = mFilename.rfind(L'.');
+		if (pos != WString::npos)
+			return mFilename.substr(pos);
+		else
+			return WString();
+	}
+
+	String Path::getExtension() const
+	{
+		return BansheeEngine::toString(getWExtension());
+	}
+
+	const WString& Path::getWDirectory(UINT32 idx) const
+	{
+		if (idx >= (UINT32)mDirectories.size())
+		{
+			CM_EXCEPT(InvalidParametersException, "Index out of range: " + BansheeEngine::toString(idx) + 
+				". Valid range: [0, " + BansheeEngine::toString((UINT32)mDirectories.size() - 1) + "]");
+		}
+
+		return mDirectories[idx];
+	}
+
+	String Path::getDirectory(UINT32 idx) const
+	{
+		return BansheeEngine::toString(getWDirectory(idx));
+	}
+
+	void Path::clear()
+	{
+		mDirectories.clear();
+		mDevice.clear();
+		mFilename.clear();
+		mNode.clear();
+		mIsAbsolute = true;
+	}
+
+	void Path::throwInvalidPathException(const WString& path) const
+	{
+		CM_EXCEPT(InvalidParametersException, "Incorrectly formatted path provided: " + BansheeEngine::toString(path));
+	}
+
+	void Path::throwInvalidPathException(const String& path) const
+	{
+		CM_EXCEPT(InvalidParametersException, "Incorrectly formatted path provided: " + path);
+	}
+
+	WString Path::buildWindows() const
+	{
+		WStringStream result;
+		if (!mNode.empty())
+		{
+			result << L"\\\\";
+			result << mNode;
+			result << L"\\";
+		}
+		else if (!mDevice.empty())
+		{
+			result << mDevice;
+			result << L":\\";
+		}
+		else if (mIsAbsolute)
+		{
+			result << L"\\";
+		}
+
+		for (auto& dir : mDirectories)
+		{
+			result << dir;
+			result << L"\\";
+		}
+
+		result << mFilename;
+		return result.str();
+	}
+
+	WString Path::buildUnix() const
+	{
+		WStringStream result;
+		auto dirIter = mDirectories.begin();
+
+		if (!mDevice.empty())
+		{
+			result << L"/";
+			result << mDevice;
+			result << L":/";
+		}
+		else if (mIsAbsolute)
+		{
+			if (dirIter != mDirectories.end() && *dirIter == L"~")
+			{
+				result << L"~";
+				dirIter++;
+			}
+
+			result << L"/";
+		}
+
+		for (; dirIter != mDirectories.end(); ++dirIter)
+		{
+			result << *dirIter;
+			result << L"/";
+		}
+
+		result << mFilename;
+		return result.str();
+	}
+
+	bool Path::comparePathElem(const WString& left, const WString& right) const
+	{
+		if (left.size() != right.size())
+			return false;
+
+		// TODO: Case sensitive/insensitive file path actually depends on used file-system but I'm not gonna check that
+		for (UINT32 i = 0; i < (UINT32)left.size(); i++)
+		{
+			if (tolower(left[i]) != tolower(right[i]))
+				return false;
+		}
+
+		return true;
+	}
+
+	void Path::pushDirectory(const WString& dir)
+	{
+		if (!dir.empty() && dir != L".")
+		{
+			if (dir == L"..")
+			{
+				if (!mDirectories.empty() && mDirectories.back() != L"..")
+					mDirectories.pop_back();
+				else
+					mDirectories.push_back(dir);
+			}
+			else
+				mDirectories.push_back(dir);
+		}
+	}
+
+	void Path::pushDirectory(const String& dir)
+	{
+		pushDirectory(BansheeEngine::toWString(dir));
+	}
 }