diff --git a/source/graphics/ColladaManager.cpp b/source/graphics/ColladaManager.cpp index d17613c554..8c792423d0 100644 --- a/source/graphics/ColladaManager.cpp +++ b/source/graphics/ColladaManager.cpp @@ -203,11 +203,11 @@ VfsPath CColladaManager::GetLoadableFilename(const VfsPath& pathnameNoExtension, // (TODO: the comments and variable names say "pmd" but actually they can // be "psa" too.) - VfsPath dae(Path::ChangeExtension(pathnameNoExtension, L".dae")); + VfsPath dae(pathnameNoExtension.ChangeExtension(L".dae")); if (! VfsFileExists(dae)) { // No .dae - got to use the .pmd, assuming there is one - return Path::ChangeExtension(pathnameNoExtension, extn); + return pathnameNoExtension.ChangeExtension(extn); } // There is a .dae - see if there's an up-to-date cached copy @@ -216,7 +216,7 @@ VfsPath CColladaManager::GetLoadableFilename(const VfsPath& pathnameNoExtension, if (g_VFS->GetFileInfo(dae, &fileInfo) < 0) { // This shouldn't occur for any sensible reasons - LOGERROR(L"Failed to stat DAE file '%ls'", dae.c_str()); + LOGERROR(L"Failed to stat DAE file '%ls'", dae.string().c_str()); return VfsPath(); } @@ -240,16 +240,16 @@ VfsPath CColladaManager::GetLoadableFilename(const VfsPath& pathnameNoExtension, extension += extn; // realDaePath_ is "[..]/mods/whatever/art/meshes/whatever.dae" - std::wstring realDaePath_; + OsPath realDaePath_; LibError ret = g_VFS->GetRealPath(dae, realDaePath_); debug_assert(ret == INFO::OK); wchar_t realDaeBuf[PATH_MAX]; - wcscpy_s(realDaeBuf, ARRAY_SIZE(realDaeBuf), realDaePath_.c_str()); + wcscpy_s(realDaeBuf, ARRAY_SIZE(realDaeBuf), realDaePath_.string().c_str()); const wchar_t* realDaePath = wcsstr(realDaeBuf, L"mods/"); // cachedPmdVfsPath is "cache/mods/whatever/art/meshes/whatever_{hash}.pmd" - VfsPath cachedPmdVfsPath = Path::Join("cache", VfsPath(realDaePath)); - cachedPmdVfsPath = Path::ChangeExtension(cachedPmdVfsPath, extension); + VfsPath cachedPmdVfsPath = VfsPath("cache") / realDaePath; + cachedPmdVfsPath = cachedPmdVfsPath.ChangeExtension(extension); // If it's not in the cache, we'll have to create it first if (! VfsFileExists(cachedPmdVfsPath)) diff --git a/source/graphics/MapGenerator.cpp b/source/graphics/MapGenerator.cpp index eab1315fc7..69290316f2 100644 --- a/source/graphics/MapGenerator.cpp +++ b/source/graphics/MapGenerator.cpp @@ -58,10 +58,10 @@ bool CMapGenerator::GenerateMap(const VfsPath& scriptFile, const CScriptValRoote return false; // Load RMS - LOGMESSAGE(L"Loading RMS '%ls'", scriptFile.c_str()); + LOGMESSAGE(L"Loading RMS '%ls'", scriptFile.string().c_str()); if (!m_ScriptInterface.LoadGlobalScriptFile(scriptFile)) { - LOGERROR(L"Failed to load RMS '%ls'", scriptFile.c_str()); + LOGERROR(L"Failed to load RMS '%ls'", scriptFile.string().c_str()); return false; } @@ -108,17 +108,17 @@ bool CMapGenerator::LoadScripts(const std::wstring& libraryName) // Load all scripts in mapgen directory if (fs_util::GetPathnames(g_VFS, path, L"*.js", pathnames) < 0) { - LOGERROR(L"Error reading scripts in directory '%ls'", path.c_str()); + LOGERROR(L"Error reading scripts in directory '%ls'", path.string().c_str()); return false; } for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it) { - LOGMESSAGE(L"Loading map generator script '%ls'", it->c_str()); + LOGMESSAGE(L"Loading map generator script '%ls'", it->string().c_str()); if (!m_ScriptInterface.LoadGlobalScriptFile(*it)) { - LOGERROR(L"Failed to load script '%ls'", it->c_str()); + LOGERROR(L"Failed to load script '%ls'", it->string().c_str()); return false; } } diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index aea1eea116..40119fe39c 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -72,7 +72,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_, m_CameraStartupTarget = INVALID_ENTITY; - filename_xml = Path::ChangeExtension(pathname, L".xml"); + filename_xml = pathname.ChangeExtension(L".xml"); // In some cases (particularly tests) we don't want to bother storing a large // mostly-empty .pmp file, so we let the XML file specify basic terrain instead. @@ -310,7 +310,7 @@ int CMapReader::ApplyData() PSRETURN CMapSummaryReader::LoadMap(const VfsPath& pathname) { - VfsPath filename_xml = Path::ChangeExtension(pathname, L".xml"); + VfsPath filename_xml = pathname.ChangeExtension(L".xml"); CXeromyces xmb_file; if (xmb_file.Load(g_VFS, filename_xml) != PSRETURN_OK) diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp index eef87c1d2e..8f70ed69d1 100644 --- a/source/graphics/MapWriter.cpp +++ b/source/graphics/MapWriter.cpp @@ -62,7 +62,7 @@ void CMapWriter::SaveMap(const VfsPath& pathname, CTerrain* pTerrain, // write it out packer.Write(pathname); - VfsPath pathnameXML = Path::ChangeExtension(pathname, L".xml"); + VfsPath pathnameXML = pathname.ChangeExtension(L".xml"); WriteXML(pathnameXML, pWaterMan, pSkyMan, pLightEnv, pCamera, pCinema, pSimulation2); } diff --git a/source/graphics/MeshManager.cpp b/source/graphics/MeshManager.cpp index e5fd0516b4..733114259a 100644 --- a/source/graphics/MeshManager.cpp +++ b/source/graphics/MeshManager.cpp @@ -40,7 +40,7 @@ CMeshManager::~CMeshManager() CModelDefPtr CMeshManager::GetMesh(const VfsPath& pathname) { - const VfsPath name = Path::ChangeExtension(pathname, L""); + const VfsPath name = pathname.ChangeExtension(L""); // Find the mesh if it's already been loaded and cached mesh_map::iterator iter = m_MeshMap.find(name); @@ -53,7 +53,7 @@ CModelDefPtr CMeshManager::GetMesh(const VfsPath& pathname) if (pmdFilename.empty()) { - LOGERROR(L"Could not load mesh '%ls'", pathname.c_str()); + LOGERROR(L"Could not load mesh '%ls'", pathname.string().c_str()); return CModelDefPtr(); } @@ -65,7 +65,7 @@ CModelDefPtr CMeshManager::GetMesh(const VfsPath& pathname) } catch (PSERROR_File&) { - LOGERROR(L"Could not load mesh '%ls'", pathname.c_str()); + LOGERROR(L"Could not load mesh '%ls'", pathname.string().c_str()); return CModelDefPtr(); } } diff --git a/source/graphics/MeshManager.h b/source/graphics/MeshManager.h index 32e5a8caa9..36643fdc18 100644 --- a/source/graphics/MeshManager.h +++ b/source/graphics/MeshManager.h @@ -18,11 +18,10 @@ #ifndef INCLUDED_MESHMANAGER #define INCLUDED_MESHMANAGER -#include "ps/CStr.h" #include "lib/file/vfs/vfs_path.h" -#include "lib/sysdep/stl.h" #include +#include #include class CModelDef; @@ -40,7 +39,7 @@ public: CModelDefPtr GetMesh(const VfsPath& pathname); private: - typedef STL_HASH_MAP, CStrW_hash_compare> mesh_map; + typedef boost::unordered_map > mesh_map; mesh_map m_MeshMap; CColladaManager& m_ColladaManager; }; diff --git a/source/graphics/ObjectBase.cpp b/source/graphics/ObjectBase.cpp index 35a5e9d4a9..09477fa221 100644 --- a/source/graphics/ObjectBase.cpp +++ b/source/graphics/ObjectBase.cpp @@ -90,7 +90,7 @@ bool CObjectBase::Load(const VfsPath& pathname) m_VariantGroups.clear(); m_Pathname = pathname; - m_ShortName = Path::Basename(pathname); + m_ShortName = pathname.Basename().string(); // Set up the vector> m_Variants to contain the right number @@ -142,11 +142,11 @@ bool CObjectBase::Load(const VfsPath& pathname) if (option_name == el_mesh) { - currentVariant->m_ModelFilename = Path::Join("art/meshes", option.GetText().FromUTF8()); + currentVariant->m_ModelFilename = VfsPath("art/meshes") / option.GetText().FromUTF8(); } else if (option_name == el_texture) { - currentVariant->m_TextureFilename = Path::Join("art/textures/skins", option.GetText().FromUTF8()); + currentVariant->m_TextureFilename = VfsPath("art/textures/skins") / option.GetText().FromUTF8(); } else if (option_name == el_decal) { @@ -178,7 +178,7 @@ bool CObjectBase::Load(const VfsPath& pathname) } else if (ae.Name == at_file) { - anim.m_FileName = Path::Join("art/animation", ae.Value.FromUTF8()); + anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8(); } else if (ae.Name == at_speed) { @@ -224,7 +224,7 @@ bool CObjectBase::Load(const VfsPath& pathname) if (currentGroup->size() == 0) { - LOGERROR(L"Actor group has zero variants ('%ls')", pathname.c_str()); + LOGERROR(L"Actor group has zero variants ('%ls')", pathname.string().c_str()); } ++currentGroup; @@ -239,7 +239,7 @@ bool CObjectBase::Load(const VfsPath& pathname) } else if (child_name == el_material) { - m_Material = Path::Join("art/materials", child.GetText().FromUTF8()); + m_Material = VfsPath("art/materials") / child.GetText().FromUTF8(); } } diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h index 143ed5f9c1..956b872462 100644 --- a/source/graphics/ObjectBase.h +++ b/source/graphics/ObjectBase.h @@ -55,7 +55,7 @@ public: // name of the prop point to attach to - "Prop01", "Prop02", "Head", "LeftHand", etc .. CStr m_PropPointName; // name of the model file - art/actors/props/sword.xml or whatever - VfsPath m_ModelName; + CStrW m_ModelName; }; struct Decal diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index 804c7413e7..36fcc59e38 100644 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -103,7 +103,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections CModelDefPtr modeldef (objectManager.GetMeshManager().GetMesh(m_ModelName)); if (!modeldef) { - LOGERROR(L"CObjectEntry::BuildVariation(): Model %ls failed to load", m_ModelName.c_str()); + LOGERROR(L"CObjectEntry::BuildVariation(): Model %ls failed to load", m_ModelName.string().c_str()); return false; } @@ -161,7 +161,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections { // start up idling if (!model->SetAnimation(GetRandomAnimation("idle"))) - LOGERROR(L"Failed to set idle animation in model \"%ls\"", m_ModelName.c_str()); + LOGERROR(L"Failed to set idle animation in model \"%ls\"", m_ModelName.string().c_str()); } // build props - TODO, RC - need to fix up bounds here @@ -211,7 +211,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections propmodel->ToCModel()->SetAnimation(oe->GetRandomAnimation("idle")); } else - LOGERROR(L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.c_str(), m_Base->m_ShortName.c_str()); + LOGERROR(L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.string().c_str(), m_Base->m_ShortName.c_str()); } // setup flags diff --git a/source/graphics/ObjectEntry.h b/source/graphics/ObjectEntry.h index ca31abde78..1e0a4f990b 100644 --- a/source/graphics/ObjectEntry.h +++ b/source/graphics/ObjectEntry.h @@ -55,7 +55,7 @@ public: // so we can have lots of colour variations without wasting memory on // lots of objectEntries) - CStrW m_ProjectileModelName; + std::wstring m_ProjectileModelName; // Returns a randomly-chosen animation matching the given name. // If none is found, returns NULL. diff --git a/source/graphics/ObjectManager.cpp b/source/graphics/ObjectManager.cpp index 16c45719db..c77b428e00 100644 --- a/source/graphics/ObjectManager.cpp +++ b/source/graphics/ObjectManager.cpp @@ -85,7 +85,7 @@ CObjectBase* CObjectManager::FindObjectBase(const CStrW& objectname) CObjectBase* obj = new CObjectBase(*this); - VfsPath pathname = Path::Join("art/actors/", objectname); + VfsPath pathname = VfsPath("art/actors/") / objectname; if (obj->Load(pathname)) { @@ -123,7 +123,7 @@ CObjectEntry* CObjectManager::FindObjectVariation(CObjectBase* base, const std:: // Look to see whether this particular variation has already been loaded std::vector choices = base->CalculateVariationKey(selections); - ObjectKey key (base->m_Pathname, choices); + ObjectKey key (base->m_Pathname.string(), choices); std::map::iterator it = m_Objects.find(key); if (it != m_Objects.end()) diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp index cce7d31edb..b86c3f859c 100644 --- a/source/graphics/ParticleEmitter.cpp +++ b/source/graphics/ParticleEmitter.cpp @@ -108,11 +108,11 @@ bool CEmitter::LoadXml(const VfsPath& pathname) if( root.GetNodeName() != el_Emitter ) { - LOGERROR(L"CEmitter::LoadXml: XML root was not \"Emitter\" in file %ls. Load failed.", pathname.c_str() ); + LOGERROR(L"CEmitter::LoadXml: XML root was not \"Emitter\" in file %ls. Load failed.", pathname.string().c_str() ); return( false ); } - m_tag = Path::Basename(pathname); + m_tag = pathname.Basename().string(); //TODO figure out if we need to use Type attribute to construct different emitter types, // probably have to move some of this code into a static factory method or out into ParticleEngine class diff --git a/source/graphics/SkeletonAnimManager.cpp b/source/graphics/SkeletonAnimManager.cpp index 75d6f00436..d4f52d9d61 100644 --- a/source/graphics/SkeletonAnimManager.cpp +++ b/source/graphics/SkeletonAnimManager.cpp @@ -51,7 +51,7 @@ CSkeletonAnimManager::~CSkeletonAnimManager() // doesn't refer to valid animation file CSkeletonAnimDef* CSkeletonAnimManager::GetAnimation(const VfsPath& pathname) { - VfsPath name = Path::ChangeExtension(pathname, L""); + VfsPath name = pathname.ChangeExtension(L""); // Find if it's already been loaded boost::unordered_map::iterator iter = m_Animations.find(name); @@ -65,7 +65,7 @@ CSkeletonAnimDef* CSkeletonAnimManager::GetAnimation(const VfsPath& pathname) if (psaFilename.empty()) { - LOGERROR(L"Could not load animation '%ls'", pathname.c_str()); + LOGERROR(L"Could not load animation '%ls'", pathname.string().c_str()); def = NULL; } else @@ -81,9 +81,9 @@ CSkeletonAnimDef* CSkeletonAnimManager::GetAnimation(const VfsPath& pathname) } if (def) - LOGMESSAGE(L"CSkeletonAnimManager::GetAnimation(%ls): Loaded successfully", pathname.c_str()); + LOGMESSAGE(L"CSkeletonAnimManager::GetAnimation(%ls): Loaded successfully", pathname.string().c_str()); else - LOGERROR(L"CSkeletonAnimManager::GetAnimation(%ls): Failed loading, marked file as bad", pathname.c_str()); + LOGERROR(L"CSkeletonAnimManager::GetAnimation(%ls): Failed loading, marked file as bad", pathname.string().c_str()); // Add to map m_Animations[name] = def; // NULL if failed to load - we won't try loading it again diff --git a/source/graphics/TerrainProperties.cpp b/source/graphics/TerrainProperties.cpp index 9ba04766fe..d79caebfd5 100644 --- a/source/graphics/TerrainProperties.cpp +++ b/source/graphics/TerrainProperties.cpp @@ -56,7 +56,7 @@ CTerrainPropertiesPtr CTerrainProperties::FromXML(const CTerrainPropertiesPtr& p { LOGERROR( L"TerrainProperties: Loading %ls: Root node is not terrains (found \"%hs\")", - pathname.c_str(), + pathname.string().c_str(), rootName.c_str()); return CTerrainPropertiesPtr(); } @@ -81,7 +81,7 @@ CTerrainPropertiesPtr CTerrainProperties::FromXML(const CTerrainPropertiesPtr& p { LOGWARNING( L"TerrainProperties: Loading %ls: Unexpected node %hs\n", - pathname.c_str(), + pathname.string().c_str(), XeroFile.GetElementString(child.GetNodeName()).c_str()); // Keep reading - typos shouldn't be showstoppers } diff --git a/source/graphics/TerrainTextureEntry.cpp b/source/graphics/TerrainTextureEntry.cpp index 9e1f8cdcde..ace12b8b37 100644 --- a/source/graphics/TerrainTextureEntry.cpp +++ b/source/graphics/TerrainTextureEntry.cpp @@ -19,6 +19,7 @@ #include +#include "lib/utf8.h" #include "lib/ogl.h" #include "lib/path_util.h" #include "lib/res/graphics/ogl_tex.h" @@ -54,7 +55,7 @@ CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr props, const Vf for (;it!=m_Groups.end();++it) (*it)->AddTerrain(this); - m_Tag = CStrW(Path::Basename(path)).ToUTF8(); + m_Tag = utf8_from_wstring(path.Basename().string()); } CTerrainTextureEntry::~CTerrainTextureEntry() diff --git a/source/graphics/TerrainTextureManager.cpp b/source/graphics/TerrainTextureManager.cpp index 8bca56603a..7539266bf7 100644 --- a/source/graphics/TerrainTextureManager.cpp +++ b/source/graphics/TerrainTextureManager.cpp @@ -124,8 +124,9 @@ void CTerrainTextureManager::LoadTextures(const CTerrainPropertiesPtr& props, co // 'real' texture name for(size_t i = 0; i < pathnames.size(); i++) { - if(boost::algorithm::ends_with(Path::Filename(pathnames[i]), L".cached.dds")) - pathnames[i] = Path::Join(Path::Path(pathnames[i]), boost::algorithm::erase_last_copy(Path::Filename(pathnames[i]), L".cached.dds")); + const std::wstring filename = pathnames[i].Filename().string(); + if(boost::algorithm::ends_with(filename, L".cached.dds")) + pathnames[i] = pathnames[i].Parent() / boost::algorithm::erase_last_copy(filename, L".cached.dds"); } // Remove any duplicates created by the stripping @@ -143,14 +144,14 @@ void CTerrainTextureManager::LoadTextures(const CTerrainPropertiesPtr& props, co if(!tex_is_known_extension(pathnames[i])) continue; - VfsPath pathnameXML = Path::ChangeExtension(pathnames[i], L".xml"); + VfsPath pathnameXML = pathnames[i].ChangeExtension(L".xml"); CTerrainPropertiesPtr myprops; // Has XML file -> attempt to load properties if (VfsFileExists(pathnameXML)) { myprops = GetPropertiesFromFile(props, pathnameXML); if (myprops) - LOGMESSAGE(L"CTerrainTextureManager: Successfully loaded override xml %ls for texture %ls", pathnameXML.c_str(), pathnames[i].c_str()); + LOGMESSAGE(L"CTerrainTextureManager: Successfully loaded override xml %ls for texture %ls", pathnameXML.string().c_str(), pathnames[i].string().c_str()); } // Error or non-existant xml file -> use parent props @@ -163,19 +164,19 @@ void CTerrainTextureManager::LoadTextures(const CTerrainPropertiesPtr& props, co void CTerrainTextureManager::RecurseDirectory(const CTerrainPropertiesPtr& parentProps, const VfsPath& path) { - //LOGMESSAGE(L"CTextureManager::RecurseDirectory(%ls)", path.c_str()); + //LOGMESSAGE(L"CTextureManager::RecurseDirectory(%ls)", path.string().c_str()); CTerrainPropertiesPtr props; // Load terrains.xml first, if it exists - VfsPath pathname = Path::Join(path, "terrains.xml"); + VfsPath pathname = path / "terrains.xml"; if (VfsFileExists(pathname)) props = GetPropertiesFromFile(parentProps, pathname); // No terrains.xml, or read failures -> use parent props (i.e. if (!props) { - LOGMESSAGE(L"CTerrainTextureManager::RecurseDirectory(%ls): no terrains.xml (or errors while loading) - using parent properties", path.c_str()); + LOGMESSAGE(L"CTerrainTextureManager::RecurseDirectory(%ls): no terrains.xml (or errors while loading) - using parent properties", path.string().c_str()); props = parentProps; } @@ -184,7 +185,7 @@ void CTerrainTextureManager::RecurseDirectory(const CTerrainPropertiesPtr& paren (void)g_VFS->GetDirectoryEntries(path, 0, &subdirectoryNames); for (size_t i=0;iLoadFile(src, file, fileSize) < 0) { - LOGERROR(L"Failed to load texture \"%ls\"", src.c_str()); + LOGERROR(L"Failed to load texture \"%ls\"", src.string().c_str()); return false; } Tex tex; if (tex_decode(file, fileSize, &tex) < 0) { - LOGERROR(L"Failed to decode texture \"%ls\"", src.c_str()); + LOGERROR(L"Failed to decode texture \"%ls\"", src.string().c_str()); return false; } @@ -334,7 +334,7 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath // Convert to uncompressed BGRA with no mipmaps if (tex_transform_to(&tex, (tex.flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) < 0) { - LOGERROR(L"Failed to transform texture \"%ls\"", src.c_str()); + LOGERROR(L"Failed to transform texture \"%ls\"", src.string().c_str()); tex_free(&tex); return false; } diff --git a/source/graphics/TextureManager.cpp b/source/graphics/TextureManager.cpp index 7cda3dc17c..b03e65cd1c 100644 --- a/source/graphics/TextureManager.cpp +++ b/source/graphics/TextureManager.cpp @@ -171,7 +171,7 @@ public: Handle h = ogl_tex_load(m_VFS, path, RES_UNIQUE); if (h <= 0) { - LOGERROR(L"Texture failed to load; \"%ls\"", texture->m_Properties.m_Path.c_str()); + LOGERROR(L"Texture failed to load; \"%ls\"", texture->m_Properties.m_Path.string().c_str()); // Replace with error texture to make it obvious texture->SetHandle(m_ErrorHandle); @@ -211,7 +211,7 @@ public: // Upload to GL if (!m_DisableGL && ogl_tex_upload(h) < 0) { - LOGERROR(L"Texture failed to upload: \"%ls\"", texture->m_Properties.m_Path.c_str()); + LOGERROR(L"Texture failed to upload: \"%ls\"", texture->m_Properties.m_Path.string().c_str()); ogl_tex_free(h); @@ -303,7 +303,7 @@ public: CTexturePtr texture = CreateTexture(textureProps); CTextureConverter::Settings settings = GetConverterSettings(texture); - if (!m_TextureConverter.ConvertTexture(texture, sourcePath, Path::Join("cache", archiveCachePath), settings)) + if (!m_TextureConverter.ConvertTexture(texture, sourcePath, VfsPath("cache") / archiveCachePath, settings)) return false; while (true) @@ -334,7 +334,7 @@ public: } else { - LOGERROR(L"Texture failed to convert: \"%ls\"", texture->m_Properties.m_Path.c_str()); + LOGERROR(L"Texture failed to convert: \"%ls\"", texture->m_Properties.m_Path.string().c_str()); texture->SetHandle(m_ErrorHandle); } texture->m_State = CTexture::LOADED; @@ -404,18 +404,18 @@ public: */ CTextureConverter::Settings GetConverterSettings(const CTexturePtr& texture) { - fs::wpath srcPath = texture->m_Properties.m_Path; + fs::wpath srcPath = texture->m_Properties.m_Path.string(); std::vector files; VfsPath p; for (fs::wpath::iterator it = srcPath.begin(); it != srcPath.end(); ++it) { - VfsPath settingsPath = Path::Join(p, "textures.xml"); + VfsPath settingsPath = p / "textures.xml"; m_HotloadFiles[settingsPath].insert(texture); CTextureConverter::SettingsFile* f = GetSettingsFile(settingsPath); if (f) files.push_back(f); - p = Path::Join(p, *it); + p = p / *it; } return m_TextureConverter.ComputeSettings(srcPath.leaf(), files); } diff --git a/source/graphics/tests/test_MeshManager.h b/source/graphics/tests/test_MeshManager.h index 044526607d..5f56d0e937 100644 --- a/source/graphics/tests/test_MeshManager.h +++ b/source/graphics/tests/test_MeshManager.h @@ -17,6 +17,7 @@ #include "lib/self_test.h" +#include "lib/file/file_system_util.h" #include "lib/file/vfs/vfs.h" #include "lib/file/io/io.h" @@ -27,17 +28,17 @@ #include "ps/CLogger.h" #include "ps/XML/RelaxNG.h" -static NativePath MOD_PATH(Path::Join(DataDir(), "mods/_test.mesh")); -static NativePath CACHE_PATH(Path::Join(DataDir(), "_testcache")); +static OsPath MOD_PATH(DataDir()/"mods/_test.mesh"); +static OsPath CACHE_PATH(DataDir()/"_testcache"); -const wchar_t* srcDAE = L"collada/sphere.dae"; -const wchar_t* srcPMD = L"collada/sphere.pmd"; -const wchar_t* testDAE = L"art/skeletons/test.dae"; -const wchar_t* testPMD = L"art/skeletons/test.pmd"; -const wchar_t* testBase = L"art/skeletons/test"; +const OsPath srcDAE(L"collada/sphere.dae"); +const OsPath srcPMD(L"collada/sphere.pmd"); +const OsPath testDAE(L"art/skeletons/test.dae"); +const OsPath testPMD(L"art/skeletons/test.pmd"); +const OsPath testBase(L"art/skeletons/test"); -const wchar_t* srcSkeletonDefs = L"collada/skeletons.xml"; -const wchar_t* testSkeletonDefs = L"art/skeletons/skeletons.xml"; +const OsPath srcSkeletonDefs(L"collada/skeletons.xml"); +const OsPath testSkeletonDefs(L"art/skeletons/skeletons.xml"); extern PIVFS g_VFS; @@ -51,15 +52,15 @@ class TestMeshManager : public CxxTest::TestSuite // Make sure the required directories doesn't exist when we start, // in case the previous test aborted and left them full of junk - if(DirectoryExists(MOD_PATH)) + if(fs_util::DirectoryExists(MOD_PATH)) DeleteDirectory(MOD_PATH); - if(DirectoryExists(CACHE_PATH)) + if(fs_util::DirectoryExists(CACHE_PATH)) DeleteDirectory(CACHE_PATH); g_VFS = CreateVfs(20*MiB); TS_ASSERT_OK(g_VFS->Mount(L"", MOD_PATH)); - TS_ASSERT_OK(g_VFS->Mount(L"collada/", Path::Join(DataDir(), "tests/collada"), VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"collada/", DataDir()/"tests/collada", VFS_MOUNT_MUST_EXIST)); // Mount _testcache onto virtual /cache - don't use the normal cache // directory because that's full of loads of cached files from the @@ -126,7 +127,7 @@ public: CModelDefPtr modeldef = meshManager->GetMesh(testPMD); TS_ASSERT(modeldef); - if (modeldef) TS_ASSERT_WSTR_EQUALS(modeldef->GetName(), testBase); + if (modeldef) TS_ASSERT_PATH_EQUALS(modeldef->GetName(), testBase); } void test_load_pmd_without_extension() @@ -135,7 +136,7 @@ public: CModelDefPtr modeldef = meshManager->GetMesh(testBase); TS_ASSERT(modeldef); - if (modeldef) TS_ASSERT_WSTR_EQUALS(modeldef->GetName(), testBase); + if (modeldef) TS_ASSERT_PATH_EQUALS(modeldef->GetName(), testBase); } void test_caching() @@ -155,7 +156,7 @@ public: CModelDefPtr modeldef = meshManager->GetMesh(testDAE); TS_ASSERT(modeldef); - if (modeldef) TS_ASSERT_WSTR_EQUALS(modeldef->GetName(), testBase); + if (modeldef) TS_ASSERT_PATH_EQUALS(modeldef->GetName(), testBase); } void test_load_dae_caching() @@ -166,7 +167,7 @@ public: VfsPath daeName1 = colladaManager->GetLoadableFilename(testBase, CColladaManager::PMD); VfsPath daeName2 = colladaManager->GetLoadableFilename(testBase, CColladaManager::PMD); TS_ASSERT(!daeName1.empty()); - TS_ASSERT_WSTR_EQUALS(daeName1, daeName2); + TS_ASSERT_PATH_EQUALS(daeName1, daeName2); // TODO: it'd be nice to test that it really isn't doing the DAE->PMD // conversion a second time, but there doesn't seem to be an easy way // to check that @@ -229,7 +230,7 @@ public: copyFile(srcSkeletonDefs, testSkeletonDefs); CModelDefPtr modeldef = meshManager->GetMesh(testDAE); TS_ASSERT(modeldef); - if (modeldef) TS_ASSERT_WSTR_EQUALS(modeldef->GetName(), testBase); + if (modeldef) TS_ASSERT_PATH_EQUALS(modeldef->GetName(), testBase); TS_ASSERT(v.Validate(L"doc", L"2.0")); } diff --git a/source/graphics/tests/test_TextureConverter.h b/source/graphics/tests/test_TextureConverter.h index 326a1f35f5..b3500d1d7c 100644 --- a/source/graphics/tests/test_TextureConverter.h +++ b/source/graphics/tests/test_TextureConverter.h @@ -32,11 +32,11 @@ public: void setUp() { - DeleteDirectory(Path::Join(DataDir(), "_testcache")); // clean up in case the last test run failed + DeleteDirectory(DataDir()/"_testcache"); // clean up in case the last test run failed m_VFS = CreateVfs(20*MiB); - TS_ASSERT_OK(m_VFS->Mount(L"", Path::Join(DataDir(), "mods/_test.tex"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(m_VFS->Mount(L"cache/", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(m_VFS->Mount(L"", DataDir()/"mods/_test.tex", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir()/"_testcache")); tex_codec_register_all(); } @@ -46,7 +46,7 @@ public: tex_codec_unregister_all(); m_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } void test_convert_quality() diff --git a/source/graphics/tests/test_TextureManager.h b/source/graphics/tests/test_TextureManager.h index f23f80231c..ff2a6844fb 100644 --- a/source/graphics/tests/test_TextureManager.h +++ b/source/graphics/tests/test_TextureManager.h @@ -34,11 +34,11 @@ public: void setUp() { - DeleteDirectory(Path::Join(DataDir(), "_testcache")); // clean up in case the last test run failed + DeleteDirectory(DataDir()/"_testcache"); // clean up in case the last test run failed m_VFS = CreateVfs(20*MiB); - TS_ASSERT_OK(m_VFS->Mount(L"", Path::Join(DataDir(), "mods/_test.tex"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(m_VFS->Mount(L"cache/", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(m_VFS->Mount(L"", DataDir()/"mods/_test.tex", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir()/"_testcache")); h_mgr_init(); tex_codec_register_all(); @@ -54,7 +54,7 @@ public: h_mgr_shutdown(); m_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } void test_load_basic() diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index c7751acbd4..dbcab55da4 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -1083,7 +1083,7 @@ void CGUI::LoadXmlFile(const VfsPath& Filename, boost::unordered_set& P } catch (PSERROR_GUI& e) { - LOGERROR(L"Errors loading GUI file %ls (%d)", Filename.c_str(), e.getCode()); + LOGERROR(L"Errors loading GUI file %ls (%d)", Filename.string().c_str(), e.getCode()); return; } } @@ -1578,7 +1578,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite if (attr_name == "texture") { - image.m_TextureName = Path::Join("art/textures/ui", attr_value); + image.m_TextureName = VfsPath("art/textures/ui") / attr_value; } else if (attr_name == "size") diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index dc495e751f..de5d05614e 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -115,7 +115,7 @@ void CGUIManager::LoadPage(SGUIPage& page) page.gui.reset(new CGUI()); page.gui->Initialize(); - VfsPath path = Path::Join("gui", VfsPath(page.name.c_str())); + VfsPath path = VfsPath("gui") / page.name; page.inputs.insert(path); CXeromyces xero; @@ -144,7 +144,7 @@ void CGUIManager::LoadPage(SGUIPage& page) CStrW name (node.GetText().FromUTF8()); TIMER(name.c_str()); - VfsPath path = Path::Join("gui", VfsPath(name.c_str())); + VfsPath path = VfsPath("gui") / name; page.gui->LoadXmlFile(path, page.inputs); } @@ -169,7 +169,7 @@ LibError CGUIManager::ReloadChangedFiles(const VfsPath& path) { if (it->inputs.count(path)) { - LOGMESSAGE(L"GUI file '%ls' changed - reloading page '%ls'", path.c_str(), it->name.c_str()); + LOGMESSAGE(L"GUI file '%ls' changed - reloading page '%ls'", path.string().c_str(), it->name.c_str()); LoadPage(*it); // TODO: this can crash if LoadPage runs an init script which modifies the page stack and breaks our iterators } diff --git a/source/gui/GUIRenderer.cpp b/source/gui/GUIRenderer.cpp index d959736777..ecbc93af28 100644 --- a/source/gui/GUIRenderer.cpp +++ b/source/gui/GUIRenderer.cpp @@ -384,7 +384,7 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, // TODO: Should check (nicely) that this is a valid file? SGUIImage Image; - Image.m_TextureName = Path::Join("art/textures/ui", wstring_from_utf8(SpriteName.substr(10))); + Image.m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(10)); CClientArea ca(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100)); Image.m_Size = ca; diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 4712659f41..24384f4eb2 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -312,7 +312,7 @@ CScriptVal LoadMapSettings(void* cbdata, VfsPath pathname) CMapSummaryReader reader; - if (reader.LoadMap(VfsPath(pathname + L".xml")) != PSRETURN_OK) + if (reader.LoadMap(pathname.ChangeExtension(L".xml")) != PSRETURN_OK) return CScriptVal(); return reader.GetMapSettings(guiManager->GetScriptInterface()).get(); @@ -433,8 +433,8 @@ void ForceGC(void* cbdata) void DumpSimState(void* UNUSED(cbdata)) { - NativePath path = Path::Join(psLogDir(), "sim_dump.txt"); - std::ofstream file (StringFromNativePath(path).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath path = psLogDir()/"sim_dump.txt"; + std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); g_Game->GetSimulation2()->DumpDebugState(file); } diff --git a/source/lib/app_hooks.cpp b/source/lib/app_hooks.cpp index 791395a42b..eb1f29fd54 100644 --- a/source/lib/app_hooks.cpp +++ b/source/lib/app_hooks.cpp @@ -41,14 +41,14 @@ static void def_override_gl_upload_caps() } -static const NativePath& def_get_log_dir() +static const OsPath& def_get_log_dir() { - static NativePath logDir; + static OsPath logDir; if(logDir.empty()) { - NativePath exePathname; + OsPath exePathname; (void)sys_get_executable_name(exePathname); - logDir = Path::Path(exePathname); + logDir = exePathname.Parent(); } return logDir; } @@ -153,7 +153,7 @@ void ah_override_gl_upload_caps() ah.override_gl_upload_caps(); } -const NativePath& ah_get_log_dir() +const OsPath& ah_get_log_dir() { return ah.get_log_dir(); } diff --git a/source/lib/app_hooks.h b/source/lib/app_hooks.h index d7ebad492d..568e2bfb7b 100644 --- a/source/lib/app_hooks.h +++ b/source/lib/app_hooks.h @@ -117,7 +117,7 @@ extern void ah_override_gl_upload_caps(); * * @return path ending with directory separator (e.g. '/'). **/ -extern const NativePath& ah_get_log_dir(); +extern const OsPath& ah_get_log_dir(); /** * gather all app-related logs/information and write it to file. @@ -179,7 +179,7 @@ extern ErrorReactionInternal ah_display_error(const wchar_t* text, size_t flags) struct AppHooks { void (*override_gl_upload_caps)(); - const NativePath& (*get_log_dir)(); + const OsPath& (*get_log_dir)(); void (*bundle_logs)(FILE* f); const wchar_t* (*translate)(const wchar_t* text); void (*translate_free)(const wchar_t* text); diff --git a/source/lib/debug.cpp b/source/lib/debug.cpp index 59dfe95a65..538c5c6988 100644 --- a/source/lib/debug.cpp +++ b/source/lib/debug.cpp @@ -173,10 +173,9 @@ LibError debug_WriteCrashlog(const wchar_t* text) if(!cpu_CAS(&state, IDLE, BUSY)) return ERR::REENTERED; // NOWARN - FILE* f; - NativePath pathname = Path::Join(ah_get_log_dir(), "crashlog.txt"); - errno_t err = _wfopen_s(&f, pathname.c_str(), L"w"); - if(err != 0) + OsPath pathname = ah_get_log_dir()/"crashlog.txt"; + FILE* f = sys_OpenFile(pathname, "w"); + if(!f) { state = FAILED; // must come before DEBUG_DISPLAY_ERROR DEBUG_DISPLAY_ERROR(L"Unable to open crashlog.txt for writing (please ensure the log directory is writable)"); diff --git a/source/lib/external_libraries/dbghelp.cpp b/source/lib/external_libraries/dbghelp.cpp index 832dee07d7..10e3ca9416 100644 --- a/source/lib/external_libraries/dbghelp.cpp +++ b/source/lib/external_libraries/dbghelp.cpp @@ -43,8 +43,8 @@ void dbghelp_ImportFunctions() // application loaded.") and then the system directory, whose // dbghelp.dll is too old. we therefore specify the full path // to our executable directory, which contains a newer dbghelp.dll. - const NativePath pathname = Path::Join(wutil_DetectExecutablePath(), "dbghelp.dll"); - HMODULE hDbghelp = LoadLibraryW(pathname.c_str()); + const OsPath pathname = wutil_DetectExecutablePath()/"dbghelp.dll"; + HMODULE hDbghelp = LoadLibraryW(OsString(pathname).c_str()); debug_assert(hDbghelp); #define FUNC(ret, name, params) p##name = (ret (__stdcall*) params)GetProcAddress(hDbghelp, #name); #include "lib/external_libraries/dbghelp_funcs.h" diff --git a/source/lib/file/archive/archive.h b/source/lib/file/archive/archive.h index e5cb7dae50..2d29fa9087 100644 --- a/source/lib/file/archive/archive.h +++ b/source/lib/file/archive/archive.h @@ -91,7 +91,7 @@ struct IArchiveWriter * @param pathname the actual file to add * @param pathnameInArchive the name to store in the archive **/ - virtual LibError AddFile(const NativePath& pathname, const NativePath& pathameInArchive) = 0; + virtual LibError AddFile(const OsPath& pathname, const Path& pathameInArchive) = 0; }; typedef shared_ptr PIArchiveWriter; diff --git a/source/lib/file/archive/archive_zip.cpp b/source/lib/file/archive/archive_zip.cpp index 1cfc066053..a16b6d042a 100644 --- a/source/lib/file/archive/archive_zip.cpp +++ b/source/lib/file/archive/archive_zip.cpp @@ -34,8 +34,8 @@ #include "lib/bits.h" #include "lib/byte_order.h" #include "lib/fat_time.h" -#include "lib/path_util.h" #include "lib/allocators/pool.h" +#include "lib/sysdep/filesystem.h" #include "lib/file/archive/archive.h" #include "lib/file/archive/codec_zlib.h" #include "lib/file/archive/stream.h" @@ -64,9 +64,9 @@ enum ZipMethod class LFH { public: - void Init(const FileInfo& fileInfo, off_t csize, ZipMethod method, u32 checksum, const NativePath& pathname) + void Init(const FileInfo& fileInfo, off_t csize, ZipMethod method, u32 checksum, const Path& pathname) { - const std::string pathnameUTF8 = utf8_from_wstring(pathname); + const std::string pathnameUTF8 = utf8_from_wstring(pathname.string()); const size_t pathnameSize = pathnameUTF8.length(); m_magic = lfh_magic; @@ -112,9 +112,9 @@ cassert(sizeof(LFH) == 30); class CDFH { public: - void Init(const FileInfo& fileInfo, off_t ofs, off_t csize, ZipMethod method, u32 checksum, const NativePath& pathname, size_t slack) + void Init(const FileInfo& fileInfo, off_t ofs, off_t csize, ZipMethod method, u32 checksum, const Path& pathname, size_t slack) { - const std::string pathnameUTF8 = utf8_from_wstring(pathname); + const std::string pathnameUTF8 = utf8_from_wstring(pathname.string()); const size_t pathnameLength = pathnameUTF8.length(); m_magic = cdfh_magic; @@ -135,11 +135,11 @@ public: memcpy((char*)this + sizeof(CDFH), pathnameUTF8.c_str(), pathnameLength); } - NativePath Pathname() const + Path Pathname() const { const size_t length = (size_t)read_le16(&m_fn_len); const char* pathname = (const char*)this + sizeof(CDFH); // not 0-terminated! - return NativePathFromString(std::string(pathname, length)); + return Path(std::string(pathname, length)); } off_t HeaderOffset() const @@ -264,12 +264,12 @@ public: return 'A'; } - virtual NativePath Path() const + virtual OsPath Path() const { return m_file->Pathname(); } - virtual LibError Load(const NativePath& UNUSED(name), const shared_ptr& buf, size_t size) const + virtual LibError Load(const OsPath& UNUSED(name), const shared_ptr& buf, size_t size) const { AdjustOffset(); @@ -381,7 +381,7 @@ private: class ArchiveReader_Zip : public IArchiveReader { public: - ArchiveReader_Zip(const NativePath& pathname) + ArchiveReader_Zip(const OsPath& pathname) : m_file(new File(pathname, 'r')) { FileInfo fileInfo; @@ -411,10 +411,10 @@ public: if(!cdfh) WARN_RETURN(ERR::CORRUPTED); - const VfsPath relativePathname(cdfh->Pathname()); - if(!Path::IsDirectory(relativePathname)) + const Path relativePathname(cdfh->Pathname()); + if(!relativePathname.IsDirectory()) { - const NativePath name = Path::Filename(relativePathname); + const OsPath name = relativePathname.Filename(); FileInfo fileInfo(name, cdfh->USize(), cdfh->MTime()); shared_ptr archiveFile(new ArchiveFile_Zip(m_file, cdfh->HeaderOffset(), cdfh->CSize(), cdfh->Checksum(), cdfh->Method())); cb(relativePathname, fileInfo, archiveFile, cbData); @@ -514,7 +514,7 @@ private: off_t m_fileSize; }; -PIArchiveReader CreateArchiveReader_Zip(const NativePath& archivePathname) +PIArchiveReader CreateArchiveReader_Zip(const OsPath& archivePathname) { return PIArchiveReader(new ArchiveReader_Zip(archivePathname)); } @@ -527,7 +527,7 @@ PIArchiveReader CreateArchiveReader_Zip(const NativePath& archivePathname) class ArchiveWriter_Zip : public IArchiveWriter { public: - ArchiveWriter_Zip(const NativePath& archivePathname, bool noDeflate) + ArchiveWriter_Zip(const OsPath& archivePathname, bool noDeflate) : m_file(new File(archivePathname, 'w')), m_fileSize(0) , m_unalignedWriter(new UnalignedWriter(m_file, 0)) , m_numEntries(0), m_noDeflate(noDeflate) @@ -552,16 +552,16 @@ public: (void)pool_destroy(&m_cdfhPool); - const NativePath pathname = m_file->Pathname(); // (must be retrieved before resetting m_file) + const OsPath pathname = m_file->Pathname(); // (must be retrieved before resetting m_file) m_file.reset(); m_fileSize += off_t(cd_size+sizeof(ECDR)); // remove padding added by UnalignedWriter - wtruncate(pathname.c_str(), m_fileSize); + wtruncate(pathname, m_fileSize); } - LibError AddFile(const NativePath& pathname, const NativePath& pathnameInArchive) + LibError AddFile(const OsPath& pathname, const OsPath& pathnameInArchive) { FileInfo fileInfo; RETURN_ERR(GetFileInfo(pathname, &fileInfo)); @@ -580,7 +580,7 @@ public: PFile file(new File); RETURN_ERR(file->Open(pathname, 'r')); - const size_t pathnameLength = pathnameInArchive.length(); + const size_t pathnameLength = pathnameInArchive.string().length(); // choose method and the corresponding codec ZipMethod method; @@ -638,9 +638,9 @@ public: } private: - static bool IsFileTypeIncompressible(const NativePath& pathname) + static bool IsFileTypeIncompressible(const OsPath& pathname) { - const NativePath extension = Path::Extension(pathname); + const OsPath extension = pathname.Extension(); // file extensions that we don't want to compress static const wchar_t* incompressibleExtensions[] = @@ -652,7 +652,7 @@ private: for(size_t i = 0; i < ARRAY_SIZE(incompressibleExtensions); i++) { - if(!wcscasecmp(extension.c_str(), incompressibleExtensions[i])) + if(extension == incompressibleExtensions[i]) return true; } @@ -669,7 +669,7 @@ private: bool m_noDeflate; }; -PIArchiveWriter CreateArchiveWriter_Zip(const NativePath& archivePathname, bool noDeflate) +PIArchiveWriter CreateArchiveWriter_Zip(const OsPath& archivePathname, bool noDeflate) { return PIArchiveWriter(new ArchiveWriter_Zip(archivePathname, noDeflate)); } diff --git a/source/lib/file/archive/archive_zip.h b/source/lib/file/archive/archive_zip.h index dd3fb33caa..7780a5273f 100644 --- a/source/lib/file/archive/archive_zip.h +++ b/source/lib/file/archive/archive_zip.h @@ -29,7 +29,7 @@ #include "lib/file/archive/archive.h" -LIB_API PIArchiveReader CreateArchiveReader_Zip(const NativePath& archivePathname); -LIB_API PIArchiveWriter CreateArchiveWriter_Zip(const NativePath& archivePathname, bool noDeflate); +LIB_API PIArchiveReader CreateArchiveReader_Zip(const OsPath& archivePathname); +LIB_API PIArchiveWriter CreateArchiveWriter_Zip(const OsPath& archivePathname, bool noDeflate); #endif // #ifndef INCLUDED_ARCHIVE_ZIP diff --git a/source/lib/file/common/file_loader.h b/source/lib/file/common/file_loader.h index 060bc69d7e..1137e74972 100644 --- a/source/lib/file/common/file_loader.h +++ b/source/lib/file/common/file_loader.h @@ -31,9 +31,9 @@ struct IFileLoader virtual size_t Precedence() const = 0; virtual wchar_t LocationCode() const = 0; - virtual NativePath Path() const = 0; + virtual OsPath Path() const = 0; - virtual LibError Load(const NativePath& name, const shared_ptr& buf, size_t size) const = 0; + virtual LibError Load(const OsPath& name, const shared_ptr& buf, size_t size) const = 0; }; typedef shared_ptr PIFileLoader; diff --git a/source/lib/file/common/real_directory.cpp b/source/lib/file/common/real_directory.cpp index 7aadf465df..6faad12e46 100644 --- a/source/lib/file/common/real_directory.cpp +++ b/source/lib/file/common/real_directory.cpp @@ -23,12 +23,12 @@ #include "precompiled.h" #include "lib/file/common/real_directory.h" -#include "lib/path_util.h" +#include "lib/sysdep/filesystem.h" #include "lib/file/file.h" #include "lib/file/io/io.h" -RealDirectory::RealDirectory(const NativePath& path, size_t priority, size_t flags) +RealDirectory::RealDirectory(const OsPath& path, size_t priority, size_t flags) : m_path(path), m_priority(priority), m_flags(flags) { } @@ -46,9 +46,9 @@ RealDirectory::RealDirectory(const NativePath& path, size_t priority, size_t fla } -/*virtual*/ LibError RealDirectory::Load(const NativePath& name, const shared_ptr& buf, size_t size) const +/*virtual*/ LibError RealDirectory::Load(const OsPath& name, const shared_ptr& buf, size_t size) const { - const NativePath pathname = Path::Join(m_path, name); + const OsPath pathname = m_path / name; PFile file(new File); RETURN_ERR(file->Open(pathname, 'r')); @@ -58,9 +58,9 @@ RealDirectory::RealDirectory(const NativePath& path, size_t priority, size_t fla } -LibError RealDirectory::Store(const NativePath& name, const shared_ptr& fileContents, size_t size) +LibError RealDirectory::Store(const OsPath& name, const shared_ptr& fileContents, size_t size) { - const NativePath pathname = Path::Join(m_path, name); + const OsPath pathname = m_path / name; { PFile file(new File); @@ -72,7 +72,7 @@ LibError RealDirectory::Store(const NativePath& name, const shared_ptr& file // length. ftruncate can't be used because Windows' FILE_FLAG_NO_BUFFERING // only allows resizing to sector boundaries, so the file must first // be closed. - wtruncate(pathname.c_str(), size); + wtruncate(pathname, size); return INFO::OK; } @@ -85,8 +85,8 @@ void RealDirectory::Watch() } -PRealDirectory CreateRealSubdirectory(const PRealDirectory& realDirectory, const NativePath& subdirectoryName) +PRealDirectory CreateRealSubdirectory(const PRealDirectory& realDirectory, const OsPath& subdirectoryName) { - const NativePath path = Path::AddSlash(Path::Join(realDirectory->Path(), subdirectoryName)); + const OsPath path = realDirectory->Path() / subdirectoryName/""; return PRealDirectory(new RealDirectory(path, realDirectory->Priority(), realDirectory->Flags())); } diff --git a/source/lib/file/common/real_directory.h b/source/lib/file/common/real_directory.h index d5551f028c..e1b4af9cc5 100644 --- a/source/lib/file/common/real_directory.h +++ b/source/lib/file/common/real_directory.h @@ -30,7 +30,7 @@ class RealDirectory : public IFileLoader { NONCOPYABLE(RealDirectory); public: - RealDirectory(const NativePath& path, size_t priority, size_t flags); + RealDirectory(const OsPath& path, size_t priority, size_t flags); size_t Priority() const { @@ -45,13 +45,13 @@ public: // IFileLoader virtual size_t Precedence() const; virtual wchar_t LocationCode() const; - virtual NativePath Path() const + virtual OsPath Path() const { return m_path; } - virtual LibError Load(const NativePath& name, const shared_ptr& buf, size_t size) const; + virtual LibError Load(const OsPath& name, const shared_ptr& buf, size_t size) const; - LibError Store(const NativePath& name, const shared_ptr& fileContents, size_t size); + LibError Store(const OsPath& name, const shared_ptr& fileContents, size_t size); void Watch(); @@ -59,7 +59,7 @@ private: // note: paths are relative to the root directory, so storing the // entire path instead of just the portion relative to the mount point // is not all too wasteful. - const NativePath m_path; + const OsPath m_path; const size_t m_priority; @@ -72,6 +72,6 @@ private: typedef shared_ptr PRealDirectory; -extern PRealDirectory CreateRealSubdirectory(const PRealDirectory& realDirectory, const NativePath& subdirectoryName); +extern PRealDirectory CreateRealSubdirectory(const PRealDirectory& realDirectory, const OsPath& subdirectoryName); #endif // #ifndef INCLUDED_REAL_DIRECTORY diff --git a/source/lib/file/common/tests/test_trace.h b/source/lib/file/common/tests/test_trace.h index 0a2878eaef..360ed25c30 100644 --- a/source/lib/file/common/tests/test_trace.h +++ b/source/lib/file/common/tests/test_trace.h @@ -34,7 +34,7 @@ public: TraceEntry t1(TraceEntry::Load, L"example.txt", 1234); TS_ASSERT_EQUALS(t1.Action(), TraceEntry::Load); - TS_ASSERT_WSTR_EQUALS(t1.Pathname(), L"example.txt"); + TS_ASSERT_PATH_EQUALS(t1.Pathname(), OsPath(L"example.txt")); TS_ASSERT_EQUALS(t1.Size(), (size_t)1234); buf1 = t1.EncodeAsText(); @@ -44,7 +44,7 @@ public: TraceEntry t2(TraceEntry::Store, L"example two.txt", 16777216); TS_ASSERT_EQUALS(t2.Action(), TraceEntry::Store); - TS_ASSERT_WSTR_EQUALS(t2.Pathname(), L"example two.txt"); + TS_ASSERT_PATH_EQUALS(t2.Pathname(), OsPath(L"example two.txt")); TS_ASSERT_EQUALS(t2.Size(), (size_t)16777216); buf2 = t2.EncodeAsText(); @@ -52,20 +52,20 @@ public: TraceEntry t3(buf1); TS_ASSERT_EQUALS(t3.Action(), TraceEntry::Load); - TS_ASSERT_WSTR_EQUALS(t3.Pathname(), L"example.txt"); + TS_ASSERT_PATH_EQUALS(t3.Pathname(), OsPath(L"example.txt")); TS_ASSERT_EQUALS(t3.Size(), (size_t)1234); TraceEntry t4(buf2); TS_ASSERT_EQUALS(t4.Action(), TraceEntry::Store); - TS_ASSERT_WSTR_EQUALS(t4.Pathname(), L"example two.txt"); + TS_ASSERT_PATH_EQUALS(t4.Pathname(), OsPath(L"example two.txt")); TS_ASSERT_EQUALS(t4.Size(), (size_t)16777216); } void test_maxpath() { - NativePath path1(PATH_MAX, L'x'); - std::wstring buf1 = L"0: L \"" + path1 + L"\" 0\n"; + OsPath path1(std::wstring(PATH_MAX, L'x')); + std::wstring buf1 = L"0: L \"" + path1.string() + L"\" 0\n"; TraceEntry t1(buf1); - TS_ASSERT_WSTR_EQUALS(t1.Pathname(), path1); + TS_ASSERT_PATH_EQUALS(t1.Pathname(), path1); } }; diff --git a/source/lib/file/common/trace.cpp b/source/lib/file/common/trace.cpp index 1816b265d1..6900d565f0 100644 --- a/source/lib/file/common/trace.cpp +++ b/source/lib/file/common/trace.cpp @@ -33,7 +33,7 @@ #include "lib/allocators/pool.h" #include "lib/bits.h" // round_up #include "lib/timer.h" // timer_Time -#include "lib/path_util.h" +#include "lib/sysdep/sysdep.h" // sys_OpenFile /*virtual*/ ITrace::~ITrace() @@ -44,7 +44,7 @@ //----------------------------------------------------------------------------- -TraceEntry::TraceEntry(EAction action, const NativePath& pathname, size_t size) +TraceEntry::TraceEntry(EAction action, const Path& pathname, size_t size) : m_timestamp((float)timer_Time()) , m_action(action) , m_pathname(pathname) @@ -74,9 +74,9 @@ TraceEntry::TraceEntry(const std::wstring& text) stream >> dummy; debug_assert(dummy == '"'); - NativePath pathname; + Path::String pathname; std::getline(stream, pathname, L'"'); - m_pathname = pathname; + m_pathname = Path(pathname); stream >> m_size; @@ -90,7 +90,7 @@ std::wstring TraceEntry::EncodeAsText() const { const wchar_t action = (wchar_t)m_action; wchar_t buf[1000]; - swprintf_s(buf, ARRAY_SIZE(buf), L"%#010f: %c \"%ls\" %lu\n", m_timestamp, action, m_pathname.c_str(), (unsigned long)m_size); + swprintf_s(buf, ARRAY_SIZE(buf), L"%#010f: %c \"%ls\" %lu\n", m_timestamp, action, m_pathname.string().c_str(), (unsigned long)m_size); return buf; } @@ -105,20 +105,20 @@ public: } - virtual void NotifyLoad(const NativePath& UNUSED(pathname), size_t UNUSED(size)) + virtual void NotifyLoad(const Path& UNUSED(pathname), size_t UNUSED(size)) { } - virtual void NotifyStore(const NativePath& UNUSED(pathname), size_t UNUSED(size)) + virtual void NotifyStore(const Path& UNUSED(pathname), size_t UNUSED(size)) { } - virtual LibError Load(const NativePath& UNUSED(pathname)) + virtual LibError Load(const OsPath& UNUSED(pathname)) { return INFO::OK; } - virtual LibError Store(const NativePath& UNUSED(pathname)) const + virtual LibError Store(const OsPath& UNUSED(pathname)) const { return INFO::OK; } @@ -156,24 +156,23 @@ public: (void)pool_destroy(&m_pool); } - virtual void NotifyLoad(const NativePath& pathname, size_t size) + virtual void NotifyLoad(const Path& pathname, size_t size) { new(Allocate()) TraceEntry(TraceEntry::Load, pathname, size); } - virtual void NotifyStore(const NativePath& pathname, size_t size) + virtual void NotifyStore(const Path& pathname, size_t size) { new(Allocate()) TraceEntry(TraceEntry::Store, pathname, size); } - virtual LibError Load(const NativePath& pathname) + virtual LibError Load(const OsPath& pathname) { pool_free_all(&m_pool); errno = 0; - FILE* file; - errno_t err = _wfopen_s(&file, pathname.c_str(), L"rt"); - if(err != 0) + FILE* file = sys_OpenFile(pathname, "rt"); + if(!file) return LibError_from_errno(); for(;;) @@ -188,12 +187,11 @@ public: return INFO::OK; } - virtual LibError Store(const NativePath& pathname) const + virtual LibError Store(const OsPath& pathname) const { errno = 0; - FILE* file; - errno_t err = _wfopen_s(&file, pathname.c_str(), L"at"); - if(err != 0) + FILE* file = sys_OpenFile(pathname, "at"); + if(!file) return LibError_from_errno(); for(size_t i = 0; i < NumEntries(); i++) { diff --git a/source/lib/file/common/trace.h b/source/lib/file/common/trace.h index f06717795a..02b1ca4298 100644 --- a/source/lib/file/common/trace.h +++ b/source/lib/file/common/trace.h @@ -47,7 +47,7 @@ public: Store = 'S' }; - TraceEntry(EAction action, const NativePath& pathname, size_t size); + TraceEntry(EAction action, const Path& pathname, size_t size); TraceEntry(const std::wstring& text); EAction Action() const @@ -55,7 +55,7 @@ public: return m_action; } - const NativePath& Pathname() const + const Path& Pathname() const { return m_pathname; } @@ -78,7 +78,7 @@ private: EAction m_action; - NativePath m_pathname; + Path m_pathname; // size of file. // rationale: other applications using this trace format might not @@ -93,8 +93,8 @@ struct ITrace { virtual ~ITrace(); - virtual void NotifyLoad(const NativePath& pathname, size_t size) = 0; - virtual void NotifyStore(const NativePath& pathname, size_t size) = 0; + virtual void NotifyLoad(const Path& pathname, size_t size) = 0; + virtual void NotifyStore(const Path& pathname, size_t size) = 0; /** * store all entries into a file. @@ -105,7 +105,7 @@ struct ITrace * because storing filename strings in a binary format would be a * bit awkward. **/ - virtual LibError Store(const NativePath& pathname) const = 0; + virtual LibError Store(const OsPath& pathname) const = 0; /** * load entries from file. @@ -114,7 +114,7 @@ struct ITrace * * replaces any existing entries. **/ - virtual LibError Load(const NativePath& osPathname) = 0; + virtual LibError Load(const OsPath& pathname) = 0; virtual const TraceEntry* Entries() const = 0; virtual size_t NumEntries() const = 0; diff --git a/source/lib/file/file.cpp b/source/lib/file/file.cpp index 8a0ba736f8..5738846a75 100644 --- a/source/lib/file/file.cpp +++ b/source/lib/file/file.cpp @@ -38,7 +38,7 @@ ERROR_ASSOCIATE(ERR::IO, L"Error during IO", EIO); namespace FileImpl { -LibError Open(const NativePath& pathname, wchar_t accessType, int& fd) +LibError Open(const OsPath& pathname, wchar_t accessType, int& fd) { int oflag = 0; switch(accessType) @@ -61,7 +61,7 @@ LibError Open(const NativePath& pathname, wchar_t accessType, int& fd) // prevent exploits by disallowing writes to our files by other users. // note that the system-wide installed cache is read-only. const mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; // 0644 - fd = wopen(pathname.c_str(), oflag, mode); + fd = wopen(pathname, oflag, mode); if(fd < 0) return LibError_from_errno(false); diff --git a/source/lib/file/file.h b/source/lib/file/file.h index 1b2faf987d..910932c576 100644 --- a/source/lib/file/file.h +++ b/source/lib/file/file.h @@ -39,7 +39,7 @@ namespace ERR namespace FileImpl { - LIB_API LibError Open(const NativePath& pathname, wchar_t mode, int& fd); + LIB_API LibError Open(const OsPath& pathname, wchar_t mode, int& fd); LIB_API void Close(int& fd); LIB_API LibError IO(int fd, wchar_t mode, off_t ofs, u8* buf, size_t size); LIB_API LibError Issue(aiocb& req, int fd, wchar_t mode, off_t alignedOfs, u8* alignedBuf, size_t alignedSize); @@ -55,7 +55,7 @@ public: { } - LibError Open(const NativePath& pathname, wchar_t mode) + LibError Open(const OsPath& pathname, wchar_t mode) { RETURN_ERR(FileImpl::Open(pathname, mode, m_fd)); m_pathname = pathname; @@ -68,7 +68,7 @@ public: FileImpl::Close(m_fd); } - File(const NativePath& pathname, wchar_t mode) + File(const OsPath& pathname, wchar_t mode) { (void)Open(pathname, mode); } @@ -78,7 +78,7 @@ public: Close(); } - const NativePath& Pathname() const + const OsPath& Pathname() const { return m_pathname; } @@ -104,7 +104,7 @@ public: } private: - NativePath m_pathname; + OsPath m_pathname; int m_fd; wchar_t m_mode; }; diff --git a/source/lib/file/file_system.cpp b/source/lib/file/file_system.cpp index 79cceb750c..e2df0d4048 100644 --- a/source/lib/file/file_system.cpp +++ b/source/lib/file/file_system.cpp @@ -40,19 +40,11 @@ struct DirDeleter } }; -// is name "." or ".."? -static bool IsDummyDirectory(const NativePath& name) -{ - if(name[0] != '.') - return false; - return (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); -} - -LibError GetDirectoryEntries(const NativePath& path, FileInfos* files, DirectoryNames* subdirectoryNames) +LibError GetDirectoryEntries(const OsPath& path, FileInfos* files, DirectoryNames* subdirectoryNames) { // open directory errno = 0; - WDIR* pDir = wopendir(path.c_str()); + WDIR* pDir = wopendir(path); if(!pDir) return LibError_from_errno(false); shared_ptr osDir(pDir, DirDeleter()); @@ -69,8 +61,8 @@ LibError GetDirectoryEntries(const NativePath& path, FileInfos* files, Directory return LibError_from_errno(); } - const NativePath name(osEnt->d_name); - RETURN_ERR(path_component_validate(name.c_str())); + const OsPath name(osEnt->d_name); + RETURN_ERR(name.Validate()); // get file information (mode, size, mtime) struct stat s; @@ -80,39 +72,39 @@ LibError GetDirectoryEntries(const NativePath& path, FileInfos* files, Directory #else // .. call regular stat(). errno = 0; - const NativePath pathname = Path::Join(path, name); - if(wstat(pathname.c_str(), &s) != 0) + const OsPath pathname = path / name; + if(wstat(pathname, &s) != 0) return LibError_from_errno(); #endif if(files && S_ISREG(s.st_mode)) files->push_back(FileInfo(name, s.st_size, s.st_mtime)); - else if(subdirectoryNames && S_ISDIR(s.st_mode) && !IsDummyDirectory(name)) + else if(subdirectoryNames && S_ISDIR(s.st_mode) && name != L"." && name != L"..") subdirectoryNames->push_back(name); } } -LibError GetFileInfo(const NativePath& pathname, FileInfo* pfileInfo) +LibError GetFileInfo(const OsPath& pathname, FileInfo* pfileInfo) { errno = 0; struct stat s; memset(&s, 0, sizeof(s)); - if(wstat(pathname.c_str(), &s) != 0) + if(wstat(pathname, &s) != 0) return LibError_from_errno(); - *pfileInfo = FileInfo(Path::Filename(pathname), s.st_size, s.st_mtime); + *pfileInfo = FileInfo(pathname.Filename(), s.st_size, s.st_mtime); return INFO::OK; } -LibError CreateDirectories(const NativePath& path, mode_t mode) +LibError CreateDirectories(const OsPath& path, mode_t mode) { if(path.empty()) return INFO::OK; struct stat s; - if(wstat(path.c_str(), &s) == 0) + if(wstat(path, &s) == 0) { if(!S_ISDIR(s.st_mode)) // encountered a file WARN_RETURN(ERR::FAIL); @@ -120,21 +112,21 @@ LibError CreateDirectories(const NativePath& path, mode_t mode) } // If we were passed a path ending with '/', strip the '/' now so that - // we can consistently use Path to find parent directory names - if(Path::IsDirectory(path)) - return CreateDirectories(Path::Path(path), mode); + // we can consistently use Parent to find parent directory names + if(path.IsDirectory()) + return CreateDirectories(path.Parent(), mode); - RETURN_ERR(CreateDirectories(Path::Path(path), mode)); + RETURN_ERR(CreateDirectories(path.Parent(), mode)); errno = 0; - if(wmkdir(path.c_str(), mode) != 0) + if(wmkdir(path, mode) != 0) return LibError_from_errno(); return INFO::OK; } -LibError DeleteDirectory(const NativePath& path) +LibError DeleteDirectory(const OsPath& path) { // note: we have to recursively empty the directory before it can // be deleted (required by Windows and POSIX rmdir()). @@ -145,18 +137,18 @@ LibError DeleteDirectory(const NativePath& path) // delete files for(size_t i = 0; i < files.size(); i++) { - const NativePath pathname = Path::Join(path, files[i].Name()); + const OsPath pathname = path / files[i].Name(); errno = 0; - if(wunlink(pathname.c_str()) != 0) + if(wunlink(pathname) != 0) return LibError_from_errno(); } // recurse over subdirectoryNames for(size_t i = 0; i < subdirectoryNames.size(); i++) - RETURN_ERR(DeleteDirectory(Path::Join(path, subdirectoryNames[i]))); + RETURN_ERR(DeleteDirectory(path / subdirectoryNames[i])); errno = 0; - if(wrmdir(path.c_str()) != 0) + if(wrmdir(path) != 0) return LibError_from_errno(); return INFO::OK; diff --git a/source/lib/file/file_system.h b/source/lib/file/file_system.h index 33874ecb16..91acd9062c 100644 --- a/source/lib/file/file_system.h +++ b/source/lib/file/file_system.h @@ -34,12 +34,12 @@ public: { } - FileInfo(const NativePath& name, off_t size, time_t mtime) + FileInfo(const OsPath& name, off_t size, time_t mtime) : name(name), size(size), mtime(mtime) { } - const NativePath& Name() const + const OsPath& Name() const { return name; } @@ -55,22 +55,22 @@ public: } private: - NativePath name; + OsPath name; off_t size; time_t mtime; }; -extern LibError GetFileInfo(const NativePath& pathname, FileInfo* fileInfo); +extern LibError GetFileInfo(const OsPath& pathname, FileInfo* fileInfo); typedef std::vector FileInfos; -typedef std::vector DirectoryNames; +typedef std::vector DirectoryNames; -extern LibError GetDirectoryEntries(const NativePath& path, FileInfos* files, DirectoryNames* subdirectoryNames); +extern LibError GetDirectoryEntries(const OsPath& path, FileInfos* files, DirectoryNames* subdirectoryNames); // same as boost::filesystem::create_directories, except that mkdir is invoked with // instead of 0755. -extern LibError CreateDirectories(const NativePath& path, mode_t mode); +extern LibError CreateDirectories(const OsPath& path, mode_t mode); -extern LibError DeleteDirectory(const NativePath& dirPath); +extern LibError DeleteDirectory(const OsPath& dirPath); #endif // #ifndef INCLUDED_FILE_SYSTEM diff --git a/source/lib/file/file_system_util.cpp b/source/lib/file/file_system_util.cpp index 8189348263..9850ed8cf2 100644 --- a/source/lib/file/file_system_util.cpp +++ b/source/lib/file/file_system_util.cpp @@ -31,12 +31,40 @@ #include #include -#include "lib/path_util.h" +#include "lib/sysdep/filesystem.h" #include "lib/regex.h" namespace fs_util { +bool DirectoryExists(const OsPath& path) +{ + WDIR* dir = wopendir(path); + if(dir) + { + wclosedir(dir); + return true; + } + return false; +} + + +bool FileExists(const OsPath& pathname) +{ + struct stat s; + const bool exists = wstat(pathname, &s) == 0; + return exists; +} + + +u64 FileSize(const OsPath& pathname) +{ + struct stat s; + debug_assert(wstat(pathname, &s) == 0); + return s.st_size; +} + + LibError GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames) { std::vector files; @@ -47,42 +75,14 @@ LibError GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filte for(size_t i = 0; i < files.size(); i++) { - if(match_wildcard(files[i].Name().c_str(), filter)) - pathnames.push_back(Path::Join(path, files[i].Name())); + if(match_wildcard(files[i].Name().string().c_str(), filter)) + pathnames.push_back(path / files[i].Name()); } return INFO::OK; } -struct FileInfoNameLess : public std::binary_function -{ - bool operator()(const FileInfo& fileInfo1, const FileInfo& fileInfo2) const - { - return wcscasecmp(fileInfo1.Name().c_str(), fileInfo2.Name().c_str()) < 0; - } -}; - -void SortFiles(FileInfos& files) -{ - std::sort(files.begin(), files.end(), FileInfoNameLess()); -} - - -struct NameLess : public std::binary_function -{ - bool operator()(const NativePath& name1, const NativePath& name2) const - { - return wcscasecmp(name1.c_str(), name2.c_str()) < 0; - } -}; - -void SortDirectories(DirectoryNames& directories) -{ - std::sort(directories.begin(), directories.end(), NameLess()); -} - - LibError ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags) { // (declare here to avoid reallocations) @@ -91,7 +91,7 @@ LibError ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, // (a FIFO queue is more efficient than recursion because it uses less // stack space and avoids seeks due to breadth-first traversal.) std::queue pendingDirectories; - pendingDirectories.push(Path::AddSlash(startPath)); + pendingDirectories.push(startPath/""); while(!pendingDirectories.empty()) { const VfsPath& path = pendingDirectories.front(); @@ -101,10 +101,10 @@ LibError ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, for(size_t i = 0; i < files.size(); i++) { const FileInfo fileInfo = files[i]; - if(!match_wildcard(fileInfo.Name().c_str(), pattern)) + if(!match_wildcard(fileInfo.Name().string().c_str(), pattern)) continue; - const VfsPath pathname(Path::Join(path, fileInfo.Name())); // (FileInfo only stores the name) + const VfsPath pathname(path / fileInfo.Name()); // (FileInfo only stores the name) cb(pathname, fileInfo, cbData); } @@ -112,15 +112,7 @@ LibError ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, break; for(size_t i = 0; i < subdirectoryNames.size(); i++) - { - VfsPath pathname; - if(path == L"/") // special case for startPath == L"" - pathname = Path::AddSlash(VfsPath(subdirectoryNames[i])); - else - pathname = Path::AddSlash(Path::Join(path, subdirectoryNames[i])); - - pendingDirectories.push(pathname); - } + pendingDirectories.push(path / subdirectoryNames[i]/""); pendingDirectories.pop(); } @@ -137,8 +129,8 @@ void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t // add 3rd -> without this measure it would get number 1, not 3. if(nextNumber == 0) { - const NativePath nameFormat = Path::Filename(pathnameFormat); - const VfsPath path = Path::AddSlash(Path::Path(pathnameFormat)); + const VfsPath nameFormat = pathnameFormat.Filename(); + const VfsPath path = pathnameFormat.Parent()/""; size_t maxNumber = 0; FileInfos files; @@ -146,7 +138,7 @@ void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t for(size_t i = 0; i < files.size(); i++) { int number; - if(swscanf_s(files[i].Name().c_str(), nameFormat.c_str(), &number) == 1) + if(swscanf_s(files[i].Name().string().c_str(), nameFormat.string().c_str(), &number) == 1) maxNumber = std::max(size_t(number), maxNumber); } @@ -161,7 +153,7 @@ void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t do { wchar_t pathnameBuf[PATH_MAX]; - swprintf_s(pathnameBuf, ARRAY_SIZE(pathnameBuf), pathnameFormat.c_str(), nextNumber++); + swprintf_s(pathnameBuf, ARRAY_SIZE(pathnameBuf), pathnameFormat.string().c_str(), nextNumber++); nextPathname = pathnameBuf; } while(fs->GetFileInfo(nextPathname, 0) == INFO::OK); diff --git a/source/lib/file/file_system_util.h b/source/lib/file/file_system_util.h index 58bc73a762..60af39ab08 100644 --- a/source/lib/file/file_system_util.h +++ b/source/lib/file/file_system_util.h @@ -27,16 +27,18 @@ #ifndef INCLUDED_FILE_SYSTEM_UTIL #define INCLUDED_FILE_SYSTEM_UTIL +#include "lib/native_path.h" #include "lib/file/vfs/vfs.h" namespace fs_util { -extern void SortFiles(FileInfos& files); -extern void SortDirectories(DirectoryNames& directories); +extern bool DirectoryExists(const OsPath& path); +extern bool FileExists(const OsPath& pathname); + +extern u64 FileSize(const OsPath& pathname); extern LibError GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames); - /** * called for files in a directory. * diff --git a/source/lib/file/io/block_cache.cpp b/source/lib/file/io/block_cache.cpp index 19f70247d5..8f320e5e9c 100644 --- a/source/lib/file/io/block_cache.cpp +++ b/source/lib/file/io/block_cache.cpp @@ -43,9 +43,10 @@ BlockId::BlockId() { } -BlockId::BlockId(const NativePath& pathname, off_t ofs) +BlockId::BlockId(const OsPath& pathname, off_t ofs) { - m_id = fnv_hash64(pathname.c_str(), pathname.length()*sizeof(pathname[0])); + const Path::String& string = pathname.string(); + m_id = fnv_hash64(string.c_str(), string.length()*sizeof(string[0])); const size_t indexBits = 16; m_id <<= indexBits; const off_t blockIndex = off_t(ofs / BLOCK_SIZE); diff --git a/source/lib/file/io/block_cache.h b/source/lib/file/io/block_cache.h index cbfd96dfb3..c28896ca74 100644 --- a/source/lib/file/io/block_cache.h +++ b/source/lib/file/io/block_cache.h @@ -36,7 +36,7 @@ class BlockId { public: BlockId(); - BlockId(const NativePath& pathname, off_t ofs); + BlockId(const OsPath& pathname, off_t ofs); bool operator==(const BlockId& rhs) const; bool operator!=(const BlockId& rhs) const; diff --git a/source/lib/file/vfs/file_cache.cpp b/source/lib/file/vfs/file_cache.cpp index a5aaff78a2..48353a9fc2 100644 --- a/source/lib/file/vfs/file_cache.cpp +++ b/source/lib/file/vfs/file_cache.cpp @@ -216,7 +216,7 @@ public: } private: - typedef Cache< VfsPath, shared_ptr > CacheType; + typedef Cache > CacheType; CacheType m_cache; PAllocator m_allocator; diff --git a/source/lib/file/vfs/vfs.cpp b/source/lib/file/vfs/vfs.cpp index d4fc51b214..711409b24d 100644 --- a/source/lib/file/vfs/vfs.cpp +++ b/source/lib/file/vfs/vfs.cpp @@ -24,7 +24,7 @@ #include "lib/file/vfs/vfs.h" #include "lib/allocators/shared_ptr.h" -#include "lib/path_util.h" +#include "lib/file/file_system_util.h" #include "lib/file/common/file_stats.h" #include "lib/file/common/trace.h" #include "lib/file/archive/archive.h" @@ -47,9 +47,9 @@ public: { } - virtual LibError Mount(const VfsPath& mountPoint, const NativePath& path, size_t flags /* = 0 */, size_t priority /* = 0 */) + virtual LibError Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags /* = 0 */, size_t priority /* = 0 */) { - if(!DirectoryExists(path)) + if(!fs_util::DirectoryExists(path)) { if(flags & VFS_MOUNT_MUST_EXIST) return ERR::VFS_DIR_NOT_FOUND; // NOWARN @@ -119,7 +119,7 @@ public: CHECK_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE)); const PRealDirectory& realDirectory = directory->AssociatedDirectory(); - const NativePath name = Path::Filename(pathname); + const OsPath name = pathname.Filename(); RETURN_ERR(realDirectory->Store(name, fileContents, size)); // wipe out any cached blocks. this is necessary to cover the (rare) case @@ -129,7 +129,7 @@ public: const VfsFile file(name, size, time(0), realDirectory->Priority(), realDirectory); directory->AddFile(file); - m_trace->NotifyStore(pathname.c_str(), size); + m_trace->NotifyStore(pathname, size); return INFO::OK; } @@ -163,7 +163,7 @@ public: stats_io_user_request(size); stats_cache(isCacheHit? CR_HIT : CR_MISS, size); - m_trace->NotifyLoad(pathname.c_str(), size); + m_trace->NotifyLoad(pathname, size); return INFO::OK; } @@ -176,20 +176,20 @@ public: return textRepresentation; } - virtual LibError GetRealPath(const VfsPath& pathname, NativePath& realPathname) + virtual LibError GetRealPath(const VfsPath& pathname, OsPath& realPathname) { VfsDirectory* directory; VfsFile* file; CHECK_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); - realPathname = Path::Join(file->Loader()->Path(), Path::Filename(pathname)); + realPathname = file->Loader()->Path() / pathname.Filename(); return INFO::OK; } - virtual LibError GetVirtualPath(const NativePath& realPathname, VfsPath& pathname) + virtual LibError GetVirtualPath(const OsPath& realPathname, VfsPath& pathname) { - const NativePath realPath = Path::AddSlash(Path::Path(realPathname)); + const OsPath realPath = realPathname.Parent()/""; VfsPath path; RETURN_ERR(FindRealPathR(realPath, m_rootDirectory, L"", path)); - pathname = Path::Join(path, Path::Filename(realPathname)); + pathname = path / realPathname.Filename(); return INFO::OK; } @@ -199,7 +199,7 @@ public: VfsDirectory* directory; RETURN_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, 0)); - const NativePath name = Path::Filename(pathname); + const OsPath name = pathname.Filename(); directory->Invalidate(name); return INFO::OK; @@ -211,7 +211,7 @@ public: } private: - LibError FindRealPathR(const NativePath& realPath, const VfsDirectory& directory, const VfsPath& curPath, VfsPath& path) + LibError FindRealPathR(const OsPath& realPath, const VfsDirectory& directory, const VfsPath& curPath, VfsPath& path) { PRealDirectory realDirectory = directory.AssociatedDirectory(); if(realDirectory && realDirectory->Path() == realPath) @@ -223,9 +223,9 @@ private: const VfsDirectory::VfsSubdirectories& subdirectories = directory.Subdirectories(); for(VfsDirectory::VfsSubdirectories::const_iterator it = subdirectories.begin(); it != subdirectories.end(); ++it) { - const NativePath& subdirectoryName = it->first; + const OsPath& subdirectoryName = it->first; const VfsDirectory& subdirectory = it->second; - LibError ret = FindRealPathR(realPath, subdirectory, Path::AddSlash(Path::Join(curPath, subdirectoryName)), path); + LibError ret = FindRealPathR(realPath, subdirectory, curPath / subdirectoryName/"", path); if(ret == INFO::OK) return INFO::OK; } diff --git a/source/lib/file/vfs/vfs.h b/source/lib/file/vfs/vfs.h index 3b583d94ae..677e70cb22 100644 --- a/source/lib/file/vfs/vfs.h +++ b/source/lib/file/vfs/vfs.h @@ -79,7 +79,7 @@ struct IVFS * if files with archive extensions are seen, their contents are added * as well. **/ - virtual LibError Mount(const VfsPath& mountPoint, const NativePath& path, size_t flags = 0, size_t priority = 0) = 0; + virtual LibError Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags = 0, size_t priority = 0) = 0; /** * Retrieve information about a file (similar to POSIX stat). @@ -151,7 +151,7 @@ struct IVFS * * this is useful for passing paths to external libraries. **/ - virtual LibError GetRealPath(const VfsPath& pathname, NativePath& realPathname) = 0; + virtual LibError GetRealPath(const VfsPath& pathname, OsPath& realPathname) = 0; /** * retrieve the VFS pathname that corresponds to a real file. @@ -162,7 +162,7 @@ struct IVFS * number of directories; this could be accelerated by only checking * directories below a mount point with a matching real path. **/ - virtual LibError GetVirtualPath(const NativePath& realPathname, VfsPath& pathname) = 0; + virtual LibError GetVirtualPath(const OsPath& realPathname, VfsPath& pathname) = 0; /** * indicate that a file has changed; remove its data from the cache and diff --git a/source/lib/file/vfs/vfs_lookup.cpp b/source/lib/file/vfs/vfs_lookup.cpp index b7168ce469..595187efce 100644 --- a/source/lib/file/vfs/vfs_lookup.cpp +++ b/source/lib/file/vfs/vfs_lookup.cpp @@ -29,7 +29,7 @@ #include "lib/external_libraries/suppress_boost_warnings.h" -#include "lib/path_util.h" // path_foreach_component +#include "lib/sysdep/filesystem.h" #include "lib/file/vfs/vfs.h" // error codes #include "lib/file/vfs/vfs_tree.h" #include "lib/file/vfs/vfs_populate.h" @@ -37,11 +37,11 @@ #include "lib/timer.h" -static LibError CreateDirectory(const NativePath& path) +static LibError CreateDirectory(const OsPath& path) { { const mode_t mode = S_IRWXU; // 0700 as prescribed by XDG basedir - const int ret = wmkdir(path.c_str(), mode); + const int ret = wmkdir(path, mode); if(ret == 0) // success return INFO::OK; } @@ -55,7 +55,7 @@ static LibError CreateDirectory(const NativePath& path) // but first ensure it's really a directory (otherwise, a // file is "in the way" and needs to be deleted) struct stat s; - const int ret = wstat(path.c_str(), &s); + const int ret = wstat(path, &s); debug_assert(ret == 0); // (wmkdir said it existed) debug_assert(S_ISDIR(s.st_mode)); return INFO::OK; @@ -96,10 +96,10 @@ LibError vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDi size_t pos = 0; // (needed outside of loop) for(;;) { - const size_t nextSlash = pathname.find_first_of('/', pos); - if(nextSlash == VfsPath::npos) + const size_t nextSlash = pathname.string().find_first_of('/', pos); + if(nextSlash == VfsPath::String::npos) break; - const NativePath subdirectoryName = pathname.substr(pos, nextSlash-pos); + const VfsPath subdirectoryName = pathname.string().substr(pos, nextSlash-pos); pos = nextSlash+1; VfsDirectory* subdirectory = directory->GetSubdirectory(subdirectoryName); @@ -113,10 +113,10 @@ LibError vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDi if(createMissingDirectories && !subdirectory->AssociatedDirectory()) { - NativePath currentPath; + OsPath currentPath; if(directory->AssociatedDirectory()) // (is NULL when mounting into root) currentPath = directory->AssociatedDirectory()->Path(); - currentPath = Path::Join(currentPath, subdirectoryName); + currentPath = currentPath / subdirectoryName; RETURN_ERR(CreateDirectory(currentPath)); @@ -132,8 +132,8 @@ LibError vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDi if(pfile) { - const NativePath& filename = pathname.substr(pos); - debug_assert(!filename.empty()); // asked for file but specified directory path + debug_assert(!pathname.IsDirectory()); + const VfsPath filename = pathname.string().substr(pos); *pfile = directory->GetFile(filename); if(!*pfile) return ERR::VFS_FILE_NOT_FOUND; // NOWARN diff --git a/source/lib/file/vfs/vfs_path.h b/source/lib/file/vfs/vfs_path.h index 7310d79828..cf392d0785 100644 --- a/source/lib/file/vfs/vfs_path.h +++ b/source/lib/file/vfs/vfs_path.h @@ -36,7 +36,8 @@ * there is no restriction on path length; when dimensioning character * arrays, prefer PATH_MAX. **/ -typedef std::wstring VfsPath; + +typedef Path VfsPath; typedef std::vector VfsPaths; diff --git a/source/lib/file/vfs/vfs_populate.cpp b/source/lib/file/vfs/vfs_populate.cpp index 3d99ddf109..1d381b0123 100644 --- a/source/lib/file/vfs/vfs_populate.cpp +++ b/source/lib/file/vfs/vfs_populate.cpp @@ -104,13 +104,12 @@ private: LibError AddFiles(const FileInfos& files) const { - const NativePath path(m_realDirectory->Path()); + const OsPath path(m_realDirectory->Path()); for(size_t i = 0; i < files.size(); i++) { - const NativePath pathname = Path::Join(path, files[i].Name()); - const NativePath extension = Path::Extension(pathname); - if(wcscasecmp(extension.c_str(), L".zip") == 0) + const OsPath pathname = path / files[i].Name(); + if(pathname.Extension() == L".zip") { PIArchiveReader archiveReader = CreateArchiveReader_Zip(pathname); RETURN_ERR(archiveReader->ReadEntries(AddArchiveFile, (uintptr_t)this)); @@ -128,7 +127,7 @@ private: { // skip version control directories - this avoids cluttering the // VFS with hundreds of irrelevant files. - if(wcscasecmp(subdirectoryNames[i].c_str(), L".svn") == 0) + if(subdirectoryNames[i] == L".svn") continue; VfsDirectory* subdirectory = m_directory->AddSubdirectory(subdirectoryNames[i]); diff --git a/source/lib/file/vfs/vfs_tree.cpp b/source/lib/file/vfs/vfs_tree.cpp index 37a33009fe..d97cf34d5c 100644 --- a/source/lib/file/vfs/vfs_tree.cpp +++ b/source/lib/file/vfs/vfs_tree.cpp @@ -35,7 +35,7 @@ //----------------------------------------------------------------------------- -VfsFile::VfsFile(const NativePath& name, size_t size, time_t mtime, size_t priority, const PIFileLoader& loader) +VfsFile::VfsFile(const VfsPath& name, size_t size, time_t mtime, size_t priority, const PIFileLoader& loader) : m_name(name), m_size(size), m_mtime(mtime), m_priority(priority), m_loader(loader) { } @@ -78,7 +78,7 @@ static bool ShouldReplaceWith(const VfsFile& previousFile, const VfsFile& newFil VfsFile* VfsDirectory::AddFile(const VfsFile& file) { - std::pair value = std::make_pair(file.Name(), file); + std::pair value = std::make_pair(file.Name(), file); std::pair ret = m_files.insert(value); if(!ret.second) // already existed { @@ -98,26 +98,26 @@ VfsFile* VfsDirectory::AddFile(const VfsFile& file) // rationale: passing in a pre-constructed VfsDirectory and copying that into // our map would be slower and less convenient for the caller. -VfsDirectory* VfsDirectory::AddSubdirectory(const NativePath& name) +VfsDirectory* VfsDirectory::AddSubdirectory(const VfsPath& name) { - std::pair value = std::make_pair(name, VfsDirectory()); + std::pair value = std::make_pair(name.string(), VfsDirectory()); std::pair ret = m_subdirectories.insert(value); return &(*ret.first).second; } -VfsFile* VfsDirectory::GetFile(const NativePath& name) +VfsFile* VfsDirectory::GetFile(const VfsPath& name) { - VfsFiles::iterator it = m_files.find(name); + VfsFiles::iterator it = m_files.find(name.string()); if(it == m_files.end()) return 0; return &it->second; } -VfsDirectory* VfsDirectory::GetSubdirectory(const NativePath& name) +VfsDirectory* VfsDirectory::GetSubdirectory(const VfsPath& name) { - VfsSubdirectories::iterator it = m_subdirectories.find(name); + VfsSubdirectories::iterator it = m_subdirectories.find(name.string()); if(it == m_subdirectories.end()) return 0; return &it->second; @@ -138,9 +138,9 @@ bool VfsDirectory::ShouldPopulate() } -void VfsDirectory::Invalidate(const NativePath& name) +void VfsDirectory::Invalidate(const VfsPath& name) { - m_files.erase(name); + m_files.erase(name.string()); m_shouldPopulate = 1; } @@ -163,7 +163,7 @@ std::wstring FileDescription(const VfsFile& file) wcsftime(timestamp, ARRAY_SIZE(timestamp), L"%a %b %d %H:%M:%S %Y", localtime(&mtime)); wchar_t buf[200]; - swprintf_s(buf, ARRAY_SIZE(buf), L"(%c; %6lu; %ls) %ls", file.Loader()->LocationCode(), (unsigned long)file.Size(), timestamp, file.Name().c_str()); + swprintf_s(buf, ARRAY_SIZE(buf), L"(%c; %6lu; %ls) %ls", file.Loader()->LocationCode(), (unsigned long)file.Size(), timestamp, file.Name().string().c_str()); return buf; } @@ -195,10 +195,10 @@ void DirectoryDescriptionR(std::wstring& descriptions, const VfsDirectory& direc const VfsDirectory::VfsSubdirectories& subdirectories = directory.Subdirectories(); for(VfsDirectory::VfsSubdirectories::const_iterator it = subdirectories.begin(); it != subdirectories.end(); ++it) { - const NativePath& name = it->first; + const VfsPath& name = it->first; const VfsDirectory& subdirectory = it->second; descriptions += indentation; - descriptions += std::wstring(L"[") + name + L"]\n"; + descriptions += std::wstring(L"[") + name.string() + L"]\n"; descriptions += FileDescriptions(subdirectory, indentLevel+1); DirectoryDescriptionR(descriptions, subdirectory, indentLevel+1); diff --git a/source/lib/file/vfs/vfs_tree.h b/source/lib/file/vfs/vfs_tree.h index f8c869a63b..421961d136 100644 --- a/source/lib/file/vfs/vfs_tree.h +++ b/source/lib/file/vfs/vfs_tree.h @@ -32,13 +32,14 @@ #include "lib/file/file_system.h" // FileInfo #include "lib/file/common/file_loader.h" // PIFileLoader #include "lib/file/common/real_directory.h" // PRealDirectory +#include "lib/file/vfs/vfs_path.h" class VfsFile { public: - VfsFile(const NativePath& name, size_t size, time_t mtime, size_t priority, const PIFileLoader& provider); + VfsFile(const VfsPath& name, size_t size, time_t mtime, size_t priority, const PIFileLoader& provider); - const NativePath& Name() const + const VfsPath& Name() const { return m_name; } @@ -64,7 +65,7 @@ public: } private: - NativePath m_name; + VfsPath m_name; size_t m_size; time_t m_mtime; @@ -77,8 +78,8 @@ private: class VfsDirectory { public: - typedef std::map VfsFiles; - typedef std::map VfsSubdirectories; + typedef std::map VfsFiles; + typedef std::map VfsSubdirectories; VfsDirectory(); @@ -90,19 +91,19 @@ public: /** * @return address of existing or newly inserted subdirectory. **/ - VfsDirectory* AddSubdirectory(const NativePath& name); + VfsDirectory* AddSubdirectory(const VfsPath& name); /** * @return file with the given name. * (note: non-const to allow changes to the file) **/ - VfsFile* GetFile(const NativePath& name); + VfsFile* GetFile(const VfsPath& name); /** * @return subdirectory with the given name. * (note: non-const to allow changes to the subdirectory) **/ - VfsDirectory* GetSubdirectory(const NativePath& name); + VfsDirectory* GetSubdirectory(const VfsPath& name); // note: exposing only iterators wouldn't enable callers to reserve space. @@ -137,7 +138,7 @@ public: * indicate that a file has changed; ensure its new version supersedes * the old by removing it and marking the directory for re-population. **/ - void Invalidate(const NativePath& name); + void Invalidate(const VfsPath& name); /** * empty file and subdirectory lists (e.g. when rebuilding VFS). diff --git a/source/lib/native_path.h b/source/lib/native_path.h index 5d8398f33b..89ad756b53 100644 --- a/source/lib/native_path.h +++ b/source/lib/native_path.h @@ -23,43 +23,34 @@ #ifndef INCLUDED_NATIVE_PATH #define INCLUDED_NATIVE_PATH -#include +#include "lib/path_util.h" // rationale: -// this is conceptually a different kind of path, not a superset of VfsPath, -// hence NativePath instead of Path (PathUtil is a bit clunky as a -// namespace anyway). -// a typedef instead of wrapper class avoids the need for accessor functions -// (e.g. boost::filesystem::string()) at the cost of somewhat diminished safety. // users are responsible for ensuring the path doesn't contain any forbidden // characters (including any code points >= 0x100 on anything but Windows) -typedef std::wstring NativePath; - -static inline NativePath NativePathFromString(const std::string& string) -{ - return NativePath(string.begin(), string.end()); -} +typedef Path OsPath; #if OS_WIN -static inline std::wstring StringFromNativePath(const NativePath& npath) +static inline const Path::String& OsString(const OsPath& path) { - return npath; + return path.string(); } #else -static inline std::string StringFromNativePath(const NativePath& npath) +static inline std::string OsString(const OsPath& path) { - std::string string(npath.length(), '\0'); - for(size_t i = 0; i < npath.length(); i++) + const Path::String& wstring = path.string(); + std::string string(wstring.length(), '\0'); + for(size_t i = 0; i < wstring.length(); i++) { - debug_assert(npath[i] <= UCHAR_MAX); - string[i] = npath[i]; + debug_assert(wstring[i] <= UCHAR_MAX); + string[i] = wstring[i]; } return string; } - #endif + #endif // #ifndef INCLUDED_NATIVE_PATH diff --git a/source/lib/path_util.cpp b/source/lib/path_util.cpp index fb2b5e7ccd..a33115d0de 100644 --- a/source/lib/path_util.cpp +++ b/source/lib/path_util.cpp @@ -77,32 +77,6 @@ bool path_is_subpath(const wchar_t* s1, const wchar_t* s2) } -// if name is invalid, return a descriptive error code, otherwise INFO::OK. -// (name is a path component, i.e. that between directory separators) -LibError path_component_validate(const wchar_t* name) -{ - // disallow empty strings - if(*name == '\0') - WARN_RETURN(ERR::PATH_EMPTY); - - for(;;) - { - const int c = *name++; - - // disallow *any* dir separators (regardless of which - // platform we're on). - if(c == '\\' || c == ':' || c == '/') - WARN_RETURN(ERR::PATH_COMPONENT_SEPARATOR); - - // end of string, no errors encountered - if(c == '\0') - break; - } - - return INFO::OK; -} - - //----------------------------------------------------------------------------- // return pointer to the name component within path (i.e. skips over all @@ -117,7 +91,5 @@ const wchar_t* path_name_only(const wchar_t* path) // return name, i.e. component after the last slash const wchar_t* name = std::max(slash1, slash2)+1; - if(name[0] != '\0') // else path_component_validate would complain - path_component_validate(name); return name; } diff --git a/source/lib/path_util.h b/source/lib/path_util.h index 3b6026fece..9af3abb357 100644 --- a/source/lib/path_util.h +++ b/source/lib/path_util.h @@ -37,8 +37,9 @@ #ifndef INCLUDED_PATH_UTIL #define INCLUDED_PATH_UTIL -#include "lib/native_path.h" -#include "lib/posix/posix_filesystem.h" +#if CONFIG_ENABLE_BOOST +# include "boost/functional/hash.hpp" +#endif namespace ERR { @@ -47,13 +48,6 @@ namespace ERR const LibError PATH_NOT_FOUND = -100302; } -/** - * check if name is valid. (see source for criteria) - * - * @return LibError (ERR::PATH_* or INFO::OK) - **/ -LIB_API LibError path_component_validate(const wchar_t* name); - /** * is s2 a subpath of s1, or vice versa? (equal counts as subpath) * @@ -63,141 +57,168 @@ LIB_API LibError path_component_validate(const wchar_t* name); LIB_API bool path_is_subpath(const wchar_t* s1, const wchar_t* s2); /** - * Get the name component of a path. + * Get the path component of a path. * Skips over all characters up to the last dir separator, if any. * * @param path Input path. - * @return pointer to name component within \. + * @return pointer to path component within \. **/ LIB_API const wchar_t* path_name_only(const wchar_t* path); -namespace Path { -template -static inline bool IsDirectory(const Path_t& pathname) +// NB: there is a need for 'generic' paths (e.g. for Trace entry / archive pathnames). +// converting via c_str would be inefficient, and the Os/VfsPath typedefs are hopefully +// sufficient to avoid errors. +class Path { - if(pathname.empty()) // (ensure length()-1 is safe) - return true; // (the VFS root directory is represented as an empty string) +public: + typedef std::wstring String; - // note: ideally, path strings would only contain '/' or even SYS_DIR_SEP. - // however, windows-specific code (e.g. the sound driver detection) - // uses these routines with '\\' strings. converting them all to - // '/' and then back before passing to OS functions would be annoying. - // also, the self-tests verify correct operation of such strings. - // it would be error-prone to only test the platform's separator - // strings there. hence, we allow all separators here. - return pathname[pathname.length()-1] == '/' || pathname[pathname.length()-1] == '\\'; -} + Path() {} + Path(const char* p) : path(p, p+strlen(p)) {} + Path(const wchar_t* p) : path(p, p+wcslen(p)) {} + Path(const std::string& s) : path(s.begin(), s.end()) {} + Path(const std::wstring& s) : path(s) {} -template -static inline Path_t Path(const Path_t& pathname) -{ - size_t n = pathname.find_last_of('/'); - if(n == Path_t::npos) + bool empty() const { - n = pathname.find_last_of('\\'); - if(n == Path_t::npos) - return L""; + return path.empty(); } - return pathname.substr(0, n); -} -template -static inline Path_t Filename(const Path_t& pathname) -{ - size_t n = pathname.find_last_of('/'); - if(n == Path_t::npos) + const String& string() const { - n = pathname.find_last_of('\\'); - if(n == Path_t::npos) - return pathname; + return path; } - return pathname.substr(n+1); -} -template -static inline Path_t Basename(const Path_t& pathname) -{ - const Path_t filename = Filename(pathname); - const size_t idxDot = filename.find_last_of('.'); - if(idxDot == Path_t::npos) - return filename; - return filename.substr(0, idxDot); -} - -template -static inline std::wstring Extension(const Path_t& pathname) -{ - const size_t idxDot = pathname.find_last_of('.'); - if(idxDot == Path_t::npos) - return Path_t(); - return pathname.substr(idxDot); -} - -static inline std::wstring JoinPathStrings(const std::wstring& path1, const std::wstring& path2) -{ - std::wstring ret = path1; - if(!IsDirectory(path1)) - ret += '/'; - ret += path2; - return ret; -} - -template -static inline Path_t Join(const Path_t& path1, const Path_t& path2) -{ - return JoinPathStrings(path1, path2); -} - -template -static inline Path_t Join(const Path_t& path1, const char* literal) -{ - return JoinPathStrings(path1, NativePathFromString(literal)); -} - -template -static inline Path_t Join(const char* literal, const Path_t& path2) -{ - return JoinPathStrings(NativePathFromString(literal), path2); -} - -template -static inline Path_t AddSlash(const Path_t& path) -{ - return IsDirectory(path)? path : path+L'/'; -} - -template -static inline Path_t ChangeExtension(const Path_t& pathname, const std::wstring& extension) -{ - return Join(Path(pathname), Basename(pathname)+extension); -} - -} // namespace Path - -static inline bool FileExists(const NativePath& pathname) -{ - struct stat s; - const bool exists = wstat(pathname.c_str(), &s) == 0; - return exists; -} - -static inline u64 FileSize(const NativePath& pathname) -{ - struct stat s; - debug_assert(wstat(pathname.c_str(), &s) == 0); - return s.st_size; -} - -static inline bool DirectoryExists(const NativePath& path) -{ - WDIR* dir = wopendir(path.c_str()); - if(dir) + bool operator<(const Path& rhs) const { - wclosedir(dir); - return true; + return wcscasecmp(path.c_str(), rhs.path.c_str()) < 0; } - return false; + + bool operator==(const Path& rhs) const + { + return wcscasecmp(path.c_str(), rhs.path.c_str()) == 0; + } + + bool operator!=(const Path& rhs) const + { + return !operator==(rhs); + } + + bool IsDirectory() const + { + if(empty()) // (ensure length()-1 is safe) + return true; // (the VFS root directory is represented as an empty string) + + // note: ideally, path strings would only contain '/' or even SYS_DIR_SEP. + // however, windows-specific code (e.g. the sound driver detection) + // uses these routines with '\\' strings. converting them all to + // '/' and then back before passing to OS functions would be annoying. + // also, the self-tests verify correct operation of such strings. + // it would be error-prone to only test the platform's separators. + // we therefore allow all separators here. + return path[path.length()-1] == '/' || path[path.length()-1] == '\\'; + } + + Path Parent() const + { + size_t idxSlash = path.find_last_of('/'); + if(idxSlash == String::npos) + { + idxSlash = path.find_last_of('\\'); + if(idxSlash == String::npos) + return L""; + } + return path.substr(0, idxSlash); + } + + Path Filename() const + { + size_t idxSlash = path.find_last_of('/'); + if(idxSlash == String::npos) + { + idxSlash = path.find_last_of('\\'); + if(idxSlash == String::npos) + return path; + } + return path.substr(idxSlash+1); + } + + Path Basename() const + { + const Path filename = Filename(); + const size_t idxDot = filename.string().find_last_of('.'); + if(idxDot == String::npos) + return filename; + return filename.string().substr(0, idxDot); + } + + // (Path return type allows callers to use our operator==) + Path Extension() const + { + const Path filename = Filename(); + const size_t idxDot = filename.string().find_last_of('.'); + if(idxDot == String::npos) + return Path(); + return filename.string().substr(idxDot); + } + + Path ChangeExtension(Path extension) const + { + return Parent() / Path(Basename().string() + extension.string()); + } + + Path operator/(Path rhs) const + { + Path ret = *this; + if(!ret.IsDirectory()) + ret.path += '/'; + ret.path += rhs.path; + return ret; + } + + LibError Validate() const + { + for(size_t i = 0; i < path.length(); i++) + { + } + + return INFO::OK; + } + +private: + String path; +}; + +static inline std::wostream& operator<<(std::wostream& s, const Path& path) +{ + s << path.string(); + return s; } +static inline std::wistream& operator>>(std::wistream& s, Path& path) +{ + Path::String string; + s >> string; + path = Path(string); + return s; +} + +#if CONFIG_ENABLE_BOOST + +namespace boost { + +template<> +struct hash : std::unary_function +{ + std::size_t operator()(const Path& path) const + { + return hash_value(path.string()); + } +}; + +} + +#endif // #if CONFIG_ENABLE_BOOST + #endif // #ifndef INCLUDED_PATH_UTIL diff --git a/source/lib/res/graphics/cursor.cpp b/source/lib/res/graphics/cursor.cpp index ede931dd40..e4dcd5141d 100644 --- a/source/lib/res/graphics/cursor.cpp +++ b/source/lib/res/graphics/cursor.cpp @@ -188,21 +188,20 @@ static void Cursor_dtor(Cursor* c) static LibError Cursor_reload(Cursor* c, const PIVFS& vfs, const VfsPath& name, Handle) { - const VfsPath path(L"art/textures/cursors"); - const VfsPath pathname(Path::Join(path, name)); + const VfsPath pathname(VfsPath(L"art/textures/cursors") / name); // read pixel offset of the cursor's hotspot [the bit of it that's // drawn at (g_mouse_x,g_mouse_y)] from file. int hotspotx = 0, hotspoty = 0; { - const VfsPath pathnameHotspot = Path::ChangeExtension(pathname, L".txt"); + const VfsPath pathnameHotspot = pathname.ChangeExtension(L".txt"); shared_ptr buf; size_t size; RETURN_ERR(vfs->LoadFile(pathnameHotspot, buf, size)); std::wstringstream s(std::wstring((const wchar_t*)buf.get(), size)); s >> hotspotx >> hotspoty; } - const VfsPath pathnameImage = Path::ChangeExtension(pathname, L".png"); + const VfsPath pathnameImage = pathname.ChangeExtension(L".png"); // try loading as system cursor (2d, hardware accelerated) if(load_sys_cursor(vfs, pathnameImage, hotspotx, hotspoty, &c->system_cursor) == INFO::OK) diff --git a/source/lib/res/graphics/ogl_shader.cpp b/source/lib/res/graphics/ogl_shader.cpp index 0b856d06f0..db4c5b54ea 100644 --- a/source/lib/res/graphics/ogl_shader.cpp +++ b/source/lib/res/graphics/ogl_shader.cpp @@ -165,7 +165,7 @@ static LibError Ogl_Shader_reload(Ogl_Shader* shdr, const PIVFS& vfs, const VfsP { char* infolog = new char[log_length]; pglGetShaderInfoLog(shdr->id, log_length, 0, infolog); - debug_printf(L"Compile log for shader %ls (type %ls):\n%hs", pathname.c_str(), type.c_str(), infolog); + debug_printf(L"Compile log for shader %ls (type %ls):\n%hs", pathname.string().c_str(), type.c_str(), infolog); delete[] infolog; } @@ -177,7 +177,7 @@ static LibError Ogl_Shader_reload(Ogl_Shader* shdr, const PIVFS& vfs, const VfsP // useful some time. ogl_WarnIfError(); - debug_printf(L"Failed to compile shader %ls (type %ls)\n", pathname.c_str(), type.c_str()); + debug_printf(L"Failed to compile shader %ls (type %ls)\n", pathname.string().c_str(), type.c_str()); err = ERR::SHDR_COMPILE; goto fail_shadercreated; @@ -284,7 +284,7 @@ static LibError do_load_shader( if (Type.empty()) { - LOGERROR(L"%ls: Missing attribute \"type\" in element \"Shader\".", pathname.c_str()); + LOGERROR(L"%ls: Missing attribute \"type\" in element \"Shader\".", pathname.string().c_str()); WARN_RETURN(ERR::CORRUPTED); } @@ -292,7 +292,7 @@ static LibError do_load_shader( if (!shadertype) { - LOGERROR(L"%ls: Unknown shader type \"%hs\" (valid are: VERTEX_SHADER, FRAGMENT_SHADER).", pathname.c_str(), Type.c_str()); + LOGERROR(L"%ls: Unknown shader type \"%hs\" (valid are: VERTEX_SHADER, FRAGMENT_SHADER).", pathname.string().c_str(), Type.c_str()); WARN_RETURN(ERR::CORRUPTED); } @@ -300,7 +300,7 @@ static LibError do_load_shader( if (pathnameShader.empty()) { - LOGERROR(L"%ls: Missing shader name.", pathname.c_str()); + LOGERROR(L"%ls: Missing shader name.", pathname.string().c_str()); WARN_RETURN(ERR::CORRUPTED); } @@ -355,7 +355,7 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const PIVFS& vfs, const VfsPa if (Root.GetNodeName() != el_program) { - LOGERROR(L"%ls: XML root was not \"Program\".", pathname.c_str()); + LOGERROR(L"%ls: XML root was not \"Program\".", pathname.string().c_str()); WARN_RETURN(ERR::CORRUPTED); } @@ -376,7 +376,7 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const PIVFS& vfs, const VfsPa if (Shader.GetNodeName() != el_shader) { - LOGERROR(L"%ls: Only \"Shader\" may be child of \"Shaders\".", pathname.c_str()); + LOGERROR(L"%ls: Only \"Shader\" may be child of \"Shaders\".", pathname.string().c_str()); WARN_RETURN(ERR::CORRUPTED); } @@ -385,7 +385,7 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const PIVFS& vfs, const VfsPa } else { - LOGWARNING(L"%ls: Unknown child of \"Program\".", pathname.c_str()); + LOGWARNING(L"%ls: Unknown child of \"Program\".", pathname.string().c_str()); } } @@ -403,13 +403,13 @@ static LibError Ogl_Program_reload(Ogl_Program* p, const PIVFS& vfs, const VfsPa { char* infolog = new char[log_length]; pglGetProgramInfoLog(p->id, log_length, 0, infolog); - debug_printf(L"Linker log for %ls:\n%hs\n", pathname.c_str(), infolog); + debug_printf(L"Linker log for %ls:\n%hs\n", pathname.string().c_str(), infolog); delete[] infolog; } if (!linked) { - debug_printf(L"Link failed for %ls\n", pathname.c_str()); + debug_printf(L"Link failed for %ls\n", pathname.string().c_str()); WARN_RETURN(ERR::SHDR_LINK); } diff --git a/source/lib/res/graphics/ogl_tex.cpp b/source/lib/res/graphics/ogl_tex.cpp index 9cdccb2678..b27b80c82c 100644 --- a/source/lib/res/graphics/ogl_tex.cpp +++ b/source/lib/res/graphics/ogl_tex.cpp @@ -517,7 +517,7 @@ Handle ogl_tex_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags) // is still in memory; otherwise, a negative error code. Handle ogl_tex_find(const VfsPath& pathname) { - const uintptr_t key = fnv_hash(pathname.c_str(), pathname.length()*sizeof(pathname[0])); + const uintptr_t key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); return h_find(H_OglTex, key); } diff --git a/source/lib/res/graphics/tests/test_tex.h b/source/lib/res/graphics/tests/test_tex.h index 1b1bf7abaa..ec8c6a1816 100644 --- a/source/lib/res/graphics/tests/test_tex.h +++ b/source/lib/res/graphics/tests/test_tex.h @@ -28,7 +28,7 @@ class TestTex : public CxxTest::TestSuite { - void generate_encode_decode_compare(size_t w, size_t h, size_t flags, size_t bpp, const NativePath& extension) + void generate_encode_decode_compare(size_t w, size_t h, size_t flags, size_t bpp, const OsPath& extension) { // generate test data const size_t size = w*h*bpp/8; diff --git a/source/lib/res/graphics/unifont.cpp b/source/lib/res/graphics/unifont.cpp index 7cf4d94f82..cf518059df 100644 --- a/source/lib/res/graphics/unifont.cpp +++ b/source/lib/res/graphics/unifont.cpp @@ -85,8 +85,8 @@ static LibError UniFont_reload(UniFont* f, const PIVFS& vfs, const VfsPath& base // Read font definition file into a stringstream shared_ptr buf; size_t size; - const VfsPath fntName(basename + L".fnt"); - RETURN_ERR(vfs->LoadFile(Path::Join(path, fntName), buf, size)); // [cumulative for 12: 36ms] + const VfsPath fntName(basename.ChangeExtension(L".fnt")); + RETURN_ERR(vfs->LoadFile(path / fntName, buf, size)); // [cumulative for 12: 36ms] std::istringstream FNTStream(std::string((const char*)buf.get(), size)); int Version; @@ -150,8 +150,8 @@ static LibError UniFont_reload(UniFont* f, const PIVFS& vfs, const VfsPath& base // Load glyph texture // [cumulative for 12: 20ms] - const VfsPath imgName(basename + L".png"); - Handle ht = ogl_tex_load(vfs, Path::Join(path, imgName)); + const VfsPath imgName(basename.ChangeExtension(L".png")); + Handle ht = ogl_tex_load(vfs, path / imgName); RETURN_ERR(ht); (void)ogl_tex_set_filter(ht, GL_NEAREST); // override is necessary because the GL format is chosen as LUMINANCE, @@ -188,7 +188,7 @@ static LibError UniFont_to_string(const UniFont* f, wchar_t* buf) if (f->ht) // not true if this is called after dtor (which it is) { const VfsPath& path = h_filename(f->ht); - swprintf_s(buf, H_STRING_LEN, L"Font %ls", path.c_str()); + swprintf_s(buf, H_STRING_LEN, L"Font %ls", path.string().c_str()); } else swprintf_s(buf, H_STRING_LEN, L"Font"); diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp index d86b3b9a0f..1e10bc25d9 100644 --- a/source/lib/res/h_mgr.cpp +++ b/source/lib/res/h_mgr.cpp @@ -572,7 +572,7 @@ Handle h_alloc(H_Type type, const PIVFS& vfs, const VfsPath& pathname, size_t fl { RETURN_ERR(type_validate(type)); - const uintptr_t key = fnv_hash(pathname.c_str(), pathname.length()*sizeof(pathname[0])); + const uintptr_t key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); // see if we can reuse an existing handle Handle h = reuse_existing_handle(key, type, flags); @@ -622,7 +622,7 @@ static LibError h_free_idx(ssize_t idx, HDATA* hd) wchar_t buf[H_STRING_LEN]; if(vtbl->to_string(hd->user, buf) < 0) wcscpy_s(buf, ARRAY_SIZE(buf), L"(error)"); - debug_printf(L"H_MGR| free %ls %ls accesses=%lu %ls\n", hd->type->name, hd->pathname.c_str(), (unsigned long)hd->num_derefs, buf); + debug_printf(L"H_MGR| free %ls %ls accesses=%lu %ls\n", hd->type->name, hd->pathname.string().c_str(), (unsigned long)hd->num_derefs, buf); } #endif @@ -690,7 +690,7 @@ VfsPath h_filename(const Handle h) if(!hd) { debug_assert(0); - return 0; + return VfsPath(); } return hd->pathname; } @@ -699,7 +699,7 @@ VfsPath h_filename(const Handle h) // TODO: what if iterating through all handles is too slow? LibError h_reload(const PIVFS& vfs, const VfsPath& pathname) { - const u32 key = fnv_hash(pathname.c_str(), pathname.length()*sizeof(pathname[0])); + const u32 key = fnv_hash(pathname.string().c_str(), pathname.string().length()*sizeof(pathname.string()[0])); // destroy (note: not free!) all handles backed by this file. // do this before reloading any of them, because we don't specify reload diff --git a/source/lib/res/sound/ogg.cpp b/source/lib/res/sound/ogg.cpp index b90282d3a4..8806ce2b27 100644 --- a/source/lib/res/sound/ogg.cpp +++ b/source/lib/res/sound/ogg.cpp @@ -5,8 +5,8 @@ #include "lib/external_libraries/vorbis.h" #include "lib/byte_order.h" -#include "lib/path_util.h" #include "lib/file/file.h" +#include "lib/file/file_system_util.h" static LibError LibErrorFromVorbis(int err) @@ -52,7 +52,7 @@ class VorbisFileAdapter public: VorbisFileAdapter(const PFile& openedFile) : file(openedFile) - , size(FileSize(openedFile->Pathname())) + , size(fs_util::FileSize(openedFile->Pathname())) , offset(0) { } @@ -258,7 +258,7 @@ private: //----------------------------------------------------------------------------- -LibError OpenOggStream(const NativePath& pathname, OggStreamPtr& stream) +LibError OpenOggStream(const OsPath& pathname, OggStreamPtr& stream) { PFile file(new File); RETURN_ERR(file->Open(pathname, L'r')); diff --git a/source/lib/res/sound/ogg.h b/source/lib/res/sound/ogg.h index a2ba7d48a1..e561bc2b93 100644 --- a/source/lib/res/sound/ogg.h +++ b/source/lib/res/sound/ogg.h @@ -19,7 +19,7 @@ public: typedef shared_ptr OggStreamPtr; -extern LibError OpenOggStream(const NativePath& pathname, OggStreamPtr& stream); +extern LibError OpenOggStream(const OsPath& pathname, OggStreamPtr& stream); /** * A non-streaming OggStream (reading the whole file in advance) diff --git a/source/lib/res/sound/snd_mgr.cpp b/source/lib/res/sound/snd_mgr.cpp index 96702d4c27..388a635ada 100644 --- a/source/lib/res/sound/snd_mgr.cpp +++ b/source/lib/res/sound/snd_mgr.cpp @@ -1296,7 +1296,7 @@ static LibError VSrc_reload(VSrc* vs, const PIVFS& vfs, const VfsPath& pathname, // pathname is a definition file containing the data file name and // its gain. - if(fs::extension(pathname) == L".txt") + if(pathname.Extension() == L".txt") { shared_ptr buf; size_t size; RETURN_ERR(vfs->LoadFile(pathname, buf, size)); diff --git a/source/lib/secure_crt.cpp b/source/lib/secure_crt.cpp index c1fb2ae1e7..f53a63cb17 100644 --- a/source/lib/secure_crt.cpp +++ b/source/lib/secure_crt.cpp @@ -257,33 +257,6 @@ int tsprintf_s(tchar* buf, size_t max_chars, const tchar* fmt, ...) return len; } - -// note: there is no portable wfopen, so we need separate implementations -// of tfopen_s. (the Unicode version just converts to UTF8) -#if defined(WSECURE_CRT) - -errno_t _wfopen_s(FILE** pfile, const wchar_t* filename, const wchar_t* mode) -{ - *pfile = NULL; - const std::string filename_c = utf8_from_wstring(filename); - const std::string mode_c = utf8_from_wstring(mode); - return fopen_s(pfile, filename_c.c_str(), mode_c.c_str()); -} - -#else - -errno_t fopen_s(FILE** pfile, const char* filename, const char* mode) -{ - *pfile = NULL; - FILE* file = fopen(filename, mode); - if(!file) - return ENOENT; - *pfile = file; - return 0; -} - -#endif - #endif // #if EMULATE_SECURE_CRT #undef tchar diff --git a/source/lib/secure_crt.h b/source/lib/secure_crt.h index 1b76ab785a..44a02b6b19 100644 --- a/source/lib/secure_crt.h +++ b/source/lib/secure_crt.h @@ -98,10 +98,6 @@ extern int vswprintf_s(wchar_t* dst, size_t max_dst_chars, const wchar_t* fmt, v extern int sprintf_s(char* buf, size_t max_chars, const char* fmt, ...) PRINTF_ARGS(3); extern int swprintf_s(wchar_t* buf, size_t max_chars, const wchar_t* fmt, ...) WPRINTF_ARGS(3); -typedef int errno_t; -extern errno_t fopen_s(FILE** pfile, const char* filename, const char* mode); -extern errno_t _wfopen_s(FILE** pfile, const wchar_t* filename, const wchar_t* mode); - // we'd like to avoid deprecation warnings caused by scanf. selective // 'undeprecation' isn't possible, replacing all stdio declarations with // our own deprecation scheme is a lot of work, suppressing all deprecation diff --git a/source/lib/self_test.h b/source/lib/self_test.h index 08fc46ce91..b6a5c8abc1 100644 --- a/source/lib/self_test.h +++ b/source/lib/self_test.h @@ -266,6 +266,8 @@ namespace CxxTest #define TSM_ASSERT_STR_EQUALS(m, str1, str2) TSM_ASSERT_EQUALS(m, std::string(str1), std::string(str2)) #define TS_ASSERT_WSTR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::wstring(str1), std::wstring(str2)) #define TSM_ASSERT_WSTR_EQUALS(m, str1, str2) TSM_ASSERT_EQUALS(m, std::wstring(str1), std::wstring(str2)) +#define TS_ASSERT_PATH_EQUALS(path1, path2) TS_ASSERT_EQUALS(path1.string(), path2.string()) +#define TSM_ASSERT_PATH_EQUALS(m, path1, path2) TSM_ASSERT_EQUALS(m, path1.string(), path2.string()) bool ts_str_contains(const std::wstring& str1, const std::wstring& str2); // defined in test_setup.cpp #define TS_ASSERT_WSTR_CONTAINS(str1, str2) TSM_ASSERT(str1, ts_str_contains(str1, str2)) @@ -285,6 +287,6 @@ void ScriptTestSetup(ScriptInterface&); // Default game data directory // (TODO: game-specific functions like this probably shouldn't be inside lib/, but it's useful // here since lots of tests use it) -NativePath DataDir(); // defined in test_setup.cpp +OsPath DataDir(); // defined in test_setup.cpp #endif // #ifndef INCLUDED_SELF_TEST diff --git a/source/lib/sysdep/dir_watch.h b/source/lib/sysdep/dir_watch.h index 8dc54b0161..7eb1846833 100644 --- a/source/lib/sysdep/dir_watch.h +++ b/source/lib/sysdep/dir_watch.h @@ -27,7 +27,7 @@ #ifndef INCLUDED_DIR_WATCH #define INCLUDED_DIR_WATCH -#include "lib/path_util.h" +#include "lib/native_path.h" struct DirWatch; typedef shared_ptr PDirWatch; @@ -49,7 +49,7 @@ typedef shared_ptr PDirWatch; * convenient to store PDirWatch there instead of creating a second * tree structure here. **/ -LIB_API LibError dir_watch_Add(const NativePath& path, PDirWatch& dirWatch); +LIB_API LibError dir_watch_Add(const OsPath& path, PDirWatch& dirWatch); class DirWatchNotification { @@ -61,12 +61,12 @@ public: Changed }; - DirWatchNotification(const NativePath& pathname, EType type) + DirWatchNotification(const OsPath& pathname, EType type) : pathname(pathname), type(type) { } - const NativePath& Pathname() const + const OsPath& Pathname() const { return pathname; } @@ -77,7 +77,7 @@ public: } private: - NativePath pathname; + OsPath pathname; EType type; }; diff --git a/source/lib/sysdep/filesystem.h b/source/lib/sysdep/filesystem.h index 639331c55f..1caea9db71 100644 --- a/source/lib/sysdep/filesystem.h +++ b/source/lib/sysdep/filesystem.h @@ -27,6 +27,9 @@ #ifndef INCLUDED_FILESYSTEM #define INCLUDED_FILESYSTEM +#include "lib/native_path.h" +#include "lib/posix/posix_filesystem.h" // mode_t + // // dirent.h @@ -42,7 +45,7 @@ struct wdirent wchar_t* d_name; }; -extern WDIR* wopendir(const wchar_t* path); +extern WDIR* wopendir(const OsPath& path); extern struct wdirent* wreaddir(WDIR*); @@ -74,8 +77,8 @@ extern int wclosedir(WDIR*); #define O_NONBLOCK 0x1000000 #endif -extern int wopen(const wchar_t* pathname, int oflag); -extern int wopen(const wchar_t* pathname, int oflag, mode_t mode); +extern int wopen(const OsPath& pathname, int oflag); +extern int wopen(const OsPath& pathname, int oflag, mode_t mode); extern int wclose(int fd); @@ -83,33 +86,33 @@ extern int wclose(int fd); // unistd.h // -LIB_API int wtruncate(const wchar_t* pathname, off_t length); +LIB_API int wtruncate(const OsPath& pathname, off_t length); -LIB_API int wunlink(const wchar_t* pathname); +LIB_API int wunlink(const OsPath& pathname); -LIB_API int wrmdir(const wchar_t* path); +LIB_API int wrmdir(const OsPath& path); // // stdio.h // -LIB_API int wrename(const wchar_t* pathnameOld, const wchar_t* pathnameNew); +LIB_API int wrename(const OsPath& pathnameOld, const OsPath& pathnameNew); // // stdlib.h // -LIB_API wchar_t* wrealpath(const wchar_t* pathname, wchar_t* resolved); +LIB_API OsPath wrealpath(const OsPath& pathname); // // sys/stat.h // -LIB_API int wstat(const wchar_t* pathname, struct stat* buf); +LIB_API int wstat(const OsPath& pathname, struct stat* buf); -LIB_API int wmkdir(const wchar_t* path, mode_t mode); +LIB_API int wmkdir(const OsPath& path, mode_t mode); #endif // #ifndef INCLUDED_FILESYSTEM diff --git a/source/lib/sysdep/os/linux/dir_watch_fam.cpp b/source/lib/sysdep/os/linux/dir_watch_fam.cpp index 37cf43e837..961565c253 100644 --- a/source/lib/sysdep/os/linux/dir_watch_fam.cpp +++ b/source/lib/sysdep/os/linux/dir_watch_fam.cpp @@ -74,7 +74,7 @@ struct DirWatch FAMCancelMonitor(&fc, &req); } - NativePath path; + OsPath path; int reqnum; }; @@ -155,7 +155,7 @@ static void* fam_event_loop(void*) } } -LibError dir_watch_Add(const NativePath& npath, PDirWatch& dirWatch) +LibError dir_watch_Add(const OsPath& path, PDirWatch& dirWatch) { // init already failed; don't try again or complain if(initialized == -1) @@ -188,16 +188,15 @@ LibError dir_watch_Add(const NativePath& npath, PDirWatch& dirWatch) // but it would only save tens of milliseconds of CPU time, so it's probably // not worthwhile - const std::string path = StringFromNativePath(npath); FAMRequest req; - if(FAMMonitorDirectory(&fc, path.c_str(), &req, tmpDirWatch.get()) < 0) + if(FAMMonitorDirectory(&fc, OsString(path).c_str(), &req, tmpDirWatch.get()) < 0) { debug_warn(L"res_watch_dir failed!"); WARN_RETURN(ERR::FAIL); // no way of getting error code? } dirWatch.swap(tmpDirWatch); - dirWatch->path = npath; + dirWatch->path = path; dirWatch->reqnum = req.reqnum; return INFO::OK; @@ -209,7 +208,7 @@ LibError dir_watch_Poll(DirWatchNotifications& notifications) { if(initialized == -1) return ERR::FAIL; // NOWARN - if(!initialized) // XXX Fix Atlas instead of supressing the warning + if(!initialized) // XXX Fix Atlas instead of suppressing the warning return ERR::FAIL; //WARN_RETURN(ERR::LOGIC); std::vector polled_notifications; @@ -236,7 +235,7 @@ LibError dir_watch_Poll(DirWatchNotifications& notifications) continue; } DirWatch* dirWatch = (DirWatch*)polled_notifications[i].userdata; - NativePath pathname = Path::Join(dirWatch->path, NativePathFromString(polled_notifications[i].filename)); + OsPath pathname = dirWatch->path / polled_notifications[i].filename; notifications.push_back(DirWatchNotification(pathname, type)); } diff --git a/source/lib/sysdep/os/linux/linux.cpp b/source/lib/sysdep/os/linux/linux.cpp index 6db31f01c0..55dba9d78c 100644 --- a/source/lib/sysdep/os/linux/linux.cpp +++ b/source/lib/sysdep/os/linux/linux.cpp @@ -30,7 +30,7 @@ #include -LibError sys_get_executable_name(NativePath& pathname) +LibError sys_get_executable_name(OsPath& pathname) { const char* path; Dl_info dl_info; @@ -52,7 +52,7 @@ LibError sys_get_executable_name(NativePath& pathname) char* resolved = realpath(path, resolvedBuf); if (!resolved) return ERR::FAIL; - pathname = NativePathFromString(resolved); + pathname = resolved; return INFO::OK; } @@ -71,7 +71,7 @@ LibError sys_get_executable_name(NativePath& pathname) char* resolved = realpath(absolute, resolvedBuf); if (!resolved) return ERR::NO_SYS; - pathname = NativePathFromString(resolved); + pathname = resolved; return INFO::OK; } diff --git a/source/lib/sysdep/os/osx/dir_watch.cpp b/source/lib/sysdep/os/osx/dir_watch.cpp index 4e487c94c7..2378db95a2 100644 --- a/source/lib/sysdep/os/osx/dir_watch.cpp +++ b/source/lib/sysdep/os/osx/dir_watch.cpp @@ -25,7 +25,7 @@ // stub implementations -LibError dir_watch_Add(const NativePath& UNUSED(path), PDirWatch& UNUSED(dirWatch)) +LibError dir_watch_Add(const OsPath& UNUSED(path), PDirWatch& UNUSED(dirWatch)) { return INFO::OK; } diff --git a/source/lib/sysdep/os/osx/osx.cpp b/source/lib/sysdep/os/osx/osx.cpp index 6723656f12..d559047454 100644 --- a/source/lib/sysdep/os/osx/osx.cpp +++ b/source/lib/sysdep/os/osx/osx.cpp @@ -78,7 +78,7 @@ LibError gfx_get_video_mode(int* xres, int* yres, int* bpp, int* freq) } -LibError sys_get_executable_name(NativePath& pathname) +LibError sys_get_executable_name(OsPath& pathname) { static char name[PATH_MAX]; static bool init = false; @@ -102,7 +102,7 @@ LibError sys_get_executable_name(NativePath& pathname) debug_printf(L"app bundle name: %hs\n", name); } - pathname = NativePathFromString(name); + pathname = name; return INFO::OK; } diff --git a/source/lib/sysdep/os/unix/ufilesystem.cpp b/source/lib/sysdep/os/unix/ufilesystem.cpp index 21351f82ab..32e6dec0fb 100644 --- a/source/lib/sysdep/os/unix/ufilesystem.cpp +++ b/source/lib/sysdep/os/unix/ufilesystem.cpp @@ -34,14 +34,13 @@ struct WDIR { DIR* d; - wchar_t name[300]; + wchar_t name[PATH_MAX]; wdirent ent; }; -WDIR* wopendir(const wchar_t* wpath) +WDIR* wopendir(const OsPath& path) { - const std::string path = StringFromNativePath(wpath); - DIR* d = opendir(path.c_str()); + DIR* d = opendir(OsString(path).c_str()); if(!d) return 0; WDIR* wd = new WDIR; @@ -56,8 +55,7 @@ struct wdirent* wreaddir(WDIR* wd) dirent* ent = readdir(wd->d); if(!ent) return 0; - NativePath name = NativePathFromString(ent->d_name); - wcscpy_s(wd->name, ARRAY_SIZE(wd->name), name.c_str()); + wcscpy_s(wd->name, ARRAY_SIZE(wd->name), ent->d_name); return &wd->ent; } @@ -69,17 +67,15 @@ int wclosedir(WDIR* wd) } -int wopen(const wchar_t* wpathname, int oflag) +int wopen(const OsPath& pathname, int oflag) { debug_assert(!(oflag & O_CREAT)); - const std::string pathname = StringFromNativePath(wpathname); - return open(pathname.c_str(), oflag); + return open(OsString(pathname).c_str(), oflag); } -int wopen(const wchar_t* wpathname, int oflag, mode_t mode) +int wopen(const OsPath& pathname, int oflag, mode_t mode) { - const std::string pathname = StringFromNativePath(wpathname); - return open(pathname.c_str(), oflag, mode); + return open(OsString(pathname).c_str(), oflag, mode); } int wclose(int fd) @@ -88,51 +84,41 @@ int wclose(int fd) } -int wtruncate(const wchar_t* wpathname, off_t length) +int wtruncate(const OsPath& pathname, off_t length) { - const std::string pathname = StringFromNativePath(wpathname); - return truncate(pathname.c_str(), length); + return truncate(OsString(pathname).c_str(), length); } -int wunlink(const wchar_t* wpathname) +int wunlink(const OsPath& pathname) { - const std::string pathname = StringFromNativePath(wpathname); - return unlink(pathname.c_str()); + return unlink(OsString(pathname).c_str()); } -int wrmdir(const wchar_t* wpath) +int wrmdir(const OsPath& path) { - const std::string path = StringFromNativePath(wpath); - return rmdir(path.c_str()); + return rmdir(OsString(path).c_str()); } -int wrename(const wchar_t* wpathnameOld, const wchar_t* wpathnameNew) +int wrename(const OsPath& pathnameOld, const OsPath& pathnameNew) { - const std::string pathnameOld = StringFromNativePath(wpathnameOld); - const std::string pathnameNew = StringFromNativePath(wpathnameNew); - return rename(pathnameOld.c_str(), pathnameNew.c_str()); + return rename(OsString(pathnameOld).c_str(), OsString(pathnameNew).c_str()); } -wchar_t* wrealpath(const wchar_t* wpathname, wchar_t* wresolved) +OsPath realpath(const OsPath& pathname) { char resolvedBuf[PATH_MAX]; - const std::string pathname = StringFromNativePath(wpathname); - const char* resolved = realpath(pathname.c_str(), resolvedBuf); + const char* resolved = realpath(OsString(pathname).c_str(), resolvedBuf); if(!resolved) - return 0; - NativePath nresolved = NativePathFromString(resolved); - wcscpy_s(wresolved, PATH_MAX, nresolved.c_str()); - return wresolved; + return OsPath(); + return resolved; } -int wstat(const wchar_t* wpathname, struct stat* buf) +int wstat(const OsPath& pathname, struct stat* buf) { - const std::string pathname = StringFromNativePath(wpathname); - return stat(pathname.c_str(), buf); + return stat(OsString(pathname).c_str(), buf); } -int wmkdir(const wchar_t* wpath, mode_t mode) +int wmkdir(const OsPath& path, mode_t mode) { - const std::string path = StringFromNativePath(wpath); - return mkdir(path.c_str(), mode); + return mkdir(OsString(path).c_str(), mode); } diff --git a/source/lib/sysdep/os/win/mahaf.cpp b/source/lib/sysdep/os/win/mahaf.cpp index fd15909d29..f441025fe3 100644 --- a/source/lib/sysdep/os/win/mahaf.cpp +++ b/source/lib/sysdep/os/win/mahaf.cpp @@ -260,7 +260,7 @@ static void UninstallDriver() } -static void StartDriver(const NativePath& driverPathname) +static void StartDriver(const OsPath& driverPathname) { const SC_HANDLE hSCM = OpenServiceControlManager(); if(!hSCM) @@ -290,7 +290,7 @@ static void StartDriver(const NativePath& driverPathname) // NB: Windows 7 seems to insist upon backslashes (i.e. external_file_string) hService = CreateServiceW(hSCM, AKEN_NAME, AKEN_NAME, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, - driverPathname.c_str(), 0, 0, 0, startName, 0); + OsString(driverPathname).c_str(), 0, 0, 0, startName, 0); debug_assert(hService != 0); } @@ -323,7 +323,7 @@ static bool Is64BitOs() #endif } -static NativePath DriverPathname() +static OsPath DriverPathname() { const char* const bits = Is64BitOs()? "64" : ""; #ifdef NDEBUG @@ -333,7 +333,7 @@ static NativePath DriverPathname() #endif char filename[PATH_MAX]; sprintf_s(filename, ARRAY_SIZE(filename), "aken%s%s.sys", bits, debug); - return Path::Join(wutil_ExecutablePath(), filename); + return wutil_ExecutablePath() / filename; } @@ -345,7 +345,7 @@ static LibError Init() return ERR::NOT_SUPPORTED; // NOWARN { - const NativePath driverPathname = DriverPathname(); + const OsPath driverPathname = DriverPathname(); StartDriver(driverPathname); } diff --git a/source/lib/sysdep/os/win/wdbg_sym.cpp b/source/lib/sysdep/os/win/wdbg_sym.cpp index 49542d9e94..46ae3e15e5 100644 --- a/source/lib/sysdep/os/win/wdbg_sym.cpp +++ b/source/lib/sysdep/os/win/wdbg_sym.cpp @@ -1871,8 +1871,8 @@ void wdbg_sym_WriteMinidump(EXCEPTION_POINTERS* exception_pointers) WinScopedLock lock(WDBG_SYM_CS); - NativePath path = Path::Join(ah_get_log_dir(), "crashlog.dmp"); - HANDLE hFile = CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0); + OsPath path = ah_get_log_dir()/"crashlog.dmp"; + HANDLE hFile = CreateFileW(OsString(path).c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0); if(hFile == INVALID_HANDLE_VALUE) { DEBUG_DISPLAY_ERROR(L"wdbg_sym_WriteMinidump: unable to create crashlog.dmp."); diff --git a/source/lib/sysdep/os/win/wdir_watch.cpp b/source/lib/sysdep/os/win/wdir_watch.cpp index 70e585619e..d53c1a8838 100644 --- a/source/lib/sysdep/os/win/wdir_watch.cpp +++ b/source/lib/sysdep/os/win/wdir_watch.cpp @@ -44,12 +44,12 @@ WINIT_REGISTER_MAIN_SHUTDOWN(wdir_watch_Shutdown); class DirHandle { public: - DirHandle(const NativePath& path) + DirHandle(const OsPath& path) { WinScopedPreserveLastError s; // CreateFile const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; const DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED; - m_hDir = CreateFileW(path.c_str(), FILE_LIST_DIRECTORY, share, 0, OPEN_EXISTING, flags, 0); + m_hDir = CreateFileW(OsString(path).c_str(), FILE_LIST_DIRECTORY, share, 0, OPEN_EXISTING, flags, 0); } ~DirHandle() @@ -81,7 +81,7 @@ class DirWatchRequest { NONCOPYABLE(DirWatchRequest); public: - DirWatchRequest(const NativePath& path) + DirWatchRequest(const OsPath& path) : m_path(path), m_dirHandle(path), m_data(new u8[dataSize]) { m_ovl = (OVERLAPPED*)calloc(1, sizeof(OVERLAPPED)); // rationale for dynamic alloc: see decl @@ -124,7 +124,7 @@ public: } } - const NativePath& Path() const + const OsPath& Path() const { return m_path; } @@ -162,12 +162,12 @@ public: const FILE_NOTIFY_INFORMATION* fni = (const FILE_NOTIFY_INFORMATION*)m_data; for(;;) { - // convert name from BSTR (non-zero-terminated) to NativePath + // convert name from BSTR (non-zero-terminated) to OsPath cassert(sizeof(wchar_t) == sizeof(WCHAR)); const size_t nameChars = fni->FileNameLength / sizeof(WCHAR); - const NativePath name(fni->FileName, nameChars); + const OsPath name(Path::String(fni->FileName, nameChars)); - const NativePath pathname = Path::Join(Path(), name); + const OsPath pathname = m_path / name; const DirWatchNotification::EType type = TypeFromAction(fni->Action); notifications.push_back(DirWatchNotification(pathname, type)); @@ -199,7 +199,7 @@ private: } } - NativePath m_path; + OsPath m_path; DirHandle m_dirHandle; // rationale: @@ -368,9 +368,9 @@ private: class DirWatchManager { public: - LibError Add(const NativePath& path, PDirWatch& dirWatch) + LibError Add(const OsPath& path, PDirWatch& dirWatch) { - debug_assert(Path::IsDirectory(path)); + debug_assert(path.IsDirectory()); // check if this is a subdirectory of a tree that's already being // watched (this is much faster than issuing a new watch; it also @@ -378,7 +378,7 @@ public: for(IntrusiveLink* link = m_sentinel.Next(); link != &m_sentinel; link = link->Next()) { DirWatch* const existingDirWatch = (DirWatch*)(uintptr_t(link) - offsetof(DirWatch, link)); - if(path_is_subpath(path.c_str(), existingDirWatch->request->Path().c_str())) + if(path_is_subpath(OsString(path).c_str(), OsString(existingDirWatch->request->Path()).c_str())) { dirWatch.reset(new DirWatch(&m_sentinel, existingDirWatch->request)); return INFO::OK; @@ -412,7 +412,7 @@ static DirWatchManager* s_dirWatchManager; //----------------------------------------------------------------------------- -LibError dir_watch_Add(const NativePath& path, PDirWatch& dirWatch) +LibError dir_watch_Add(const OsPath& path, PDirWatch& dirWatch) { WinScopedLock lock(WDIR_WATCH_CS); return s_dirWatchManager->Add(path, dirWatch); diff --git a/source/lib/sysdep/os/win/wdll_ver.cpp b/source/lib/sysdep/os/win/wdll_ver.cpp index 9644af0022..811850c6c3 100644 --- a/source/lib/sysdep/os/win/wdll_ver.cpp +++ b/source/lib/sysdep/os/win/wdll_ver.cpp @@ -43,18 +43,18 @@ //----------------------------------------------------------------------------- -static LibError ReadVersionString(const NativePath& modulePathname, wchar_t* out_ver, size_t out_ver_len) +static LibError ReadVersionString(const OsPath& modulePathname, wchar_t* out_ver, size_t out_ver_len) { WinScopedPreserveLastError s; // GetFileVersion*, Ver* // determine size of and allocate memory for version information. DWORD unused; - const DWORD ver_size = GetFileVersionInfoSizeW(modulePathname.c_str(), &unused); // [bytes] + const DWORD ver_size = GetFileVersionInfoSizeW(OsString(modulePathname).c_str(), &unused); // [bytes] if(!ver_size) { // check if the failure is due to not finding modulePathname // (necessary since GetFileVersionInfoSize doesn't SetLastError) - HMODULE hModule = LoadLibraryExW(modulePathname.c_str(), 0, LOAD_LIBRARY_AS_DATAFILE); + HMODULE hModule = LoadLibraryExW(OsString(modulePathname).c_str(), 0, LOAD_LIBRARY_AS_DATAFILE); if(!hModule) return ERR::FAIL; // NOWARN (file not found - due to FS redirection?) FreeLibrary(hModule); @@ -62,7 +62,7 @@ static LibError ReadVersionString(const NativePath& modulePathname, wchar_t* out } shared_ptr mem = Allocate(ver_size); - if(!GetFileVersionInfoW(modulePathname.c_str(), 0, ver_size, mem.get())) + if(!GetFileVersionInfoW(OsString(modulePathname).c_str(), 0, ver_size, mem.get())) WARN_RETURN(ERR::_3); u16* lang; // -> 16 bit language ID, 16 bit codepage @@ -83,7 +83,7 @@ static LibError ReadVersionString(const NativePath& modulePathname, wchar_t* out } -void wdll_ver_Append(const NativePath& pathname, VersionList& list) +void wdll_ver_Append(const OsPath& pathname, VersionList& list) { if(pathname.empty()) return; // avoid error in ReadVersionString @@ -91,10 +91,10 @@ void wdll_ver_Append(const NativePath& pathname, VersionList& list) // pathname may not have an extension (e.g. driver names from the // registry). note that always appending ".dll" would be incorrect // since some have ".sys" extension. - NativePath modulePathname(pathname); - if(Path::Extension(modulePathname).empty()) - modulePathname = Path::ChangeExtension(modulePathname, L".dll"); - const NativePath moduleName(Path::Filename(modulePathname)); + OsPath modulePathname(pathname); + if(modulePathname.Extension() == "") + modulePathname = modulePathname.ChangeExtension(L".dll"); + const OsPath moduleName(modulePathname.Filename()); // read file version. try this with and without FS redirection since // pathname might assume both. @@ -112,7 +112,7 @@ void wdll_ver_Append(const NativePath& pathname, VersionList& list) if(!list.empty()) list += L", "; - list += moduleName; + list += moduleName.Filename().string(); list += L" ("; list += versionString; list += L")"; diff --git a/source/lib/sysdep/os/win/wdll_ver.h b/source/lib/sysdep/os/win/wdll_ver.h index c3837c908b..eda02391ae 100644 --- a/source/lib/sysdep/os/win/wdll_ver.h +++ b/source/lib/sysdep/os/win/wdll_ver.h @@ -41,6 +41,6 @@ typedef std::wstring VersionList; * The text output includes the module name. * On failure, the version is given as "unknown". **/ -extern void wdll_ver_Append(const NativePath& pathname, VersionList& list); +extern void wdll_ver_Append(const OsPath& pathname, VersionList& list); #endif // #ifndef INCLUDED_WDLL_VER diff --git a/source/lib/sysdep/os/win/wposix/waio.cpp b/source/lib/sysdep/os/win/wposix/waio.cpp index 0bf4e8f198..67cbac8747 100644 --- a/source/lib/sysdep/os/win/wposix/waio.cpp +++ b/source/lib/sysdep/os/win/wposix/waio.cpp @@ -139,7 +139,7 @@ static DWORD CreationDisposition(int oflag) // (re)open file in asynchronous mode and associate handle with fd. // (this works because the files default to DENY_NONE sharing) -LibError waio_reopen(int fd, const wchar_t* pathname, int oflag, ...) +LibError waio_reopen(int fd, const OsPath& pathname, int oflag, ...) { WinScopedPreserveLastError s; // CreateFile @@ -176,7 +176,7 @@ LibError waio_reopen(int fd, const wchar_t* pathname, int oflag, ...) // open file const DWORD create = CreationDisposition(oflag); - const HANDLE hFile = CreateFileW(pathname, access, share, 0, create, FILE_ATTRIBUTE_NORMAL|flags, 0); + const HANDLE hFile = CreateFileW(OsString(pathname).c_str(), access, share, 0, create, FILE_ATTRIBUTE_NORMAL|flags, 0); if(hFile == INVALID_HANDLE_VALUE) return LibError_from_GLE(); diff --git a/source/lib/sysdep/os/win/wposix/waio.h b/source/lib/sysdep/os/win/wposix/waio.h index 13273b0d4f..79c0960c55 100644 --- a/source/lib/sysdep/os/win/wposix/waio.h +++ b/source/lib/sysdep/os/win/wposix/waio.h @@ -27,12 +27,12 @@ #ifndef INCLUDED_WAIO #define INCLUDED_WAIO +#include "lib/lib_errors.h" +#include "lib/native_path.h" #include "lib/sysdep/os/win/wposix/wposix_types.h" #include "lib/sysdep/os/win/wposix/no_crt_posix.h" -#include "lib/lib_errors.h" - // Note: transfer buffers, offsets, and lengths must be sector-aligned // (we don't bother copying to an align buffer because the file cache // already requires splitting IOs into aligned blocks) @@ -115,7 +115,7 @@ extern int lio_listio(int, struct aiocb* const[], int, struct sigevent*); // (re)open file in asynchronous mode and associate handle with fd. // (this works because the files default to DENY_NONE sharing) -extern LibError waio_reopen(int fd, const wchar_t* pathname, int oflag, ...); +extern LibError waio_reopen(int fd, const OsPath& pathname, int oflag, ...); extern LibError waio_close(int fd); #endif // #ifndef INCLUDED_WAIO diff --git a/source/lib/sysdep/os/win/wposix/wdlfcn.cpp b/source/lib/sysdep/os/win/wposix/wdlfcn.cpp index 1170b60893..d9eb5face0 100644 --- a/source/lib/sysdep/os/win/wposix/wdlfcn.cpp +++ b/source/lib/sysdep/os/win/wposix/wdlfcn.cpp @@ -57,8 +57,8 @@ void* dlopen(const char* so_name, int flags) { debug_assert(!(flags & RTLD_GLOBAL)); - NativePath pathname = Path::ChangeExtension(NativePathFromString(so_name), L".dll"); - HMODULE hModule = LoadLibraryW(pathname.c_str()); + OsPath pathname = Path(so_name).ChangeExtension(L".dll"); + HMODULE hModule = LoadLibraryW(OsString(pathname).c_str()); return void_from_HMODULE(hModule); } diff --git a/source/lib/sysdep/os/win/wposix/wfilesystem.cpp b/source/lib/sysdep/os/win/wposix/wfilesystem.cpp index 4134a931bd..11ce438773 100644 --- a/source/lib/sysdep/os/win/wposix/wfilesystem.cpp +++ b/source/lib/sysdep/os/win/wposix/wfilesystem.cpp @@ -190,9 +190,9 @@ static inline void wdir_free(WDIR* d) static const DWORD hs = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM; // make sure path exists and is a normal (according to attributes) directory. -static bool is_normal_dir(const wchar_t* path) +static bool is_normal_dir(const OsPath& path) { - const DWORD fa = GetFileAttributesW(path); + const DWORD fa = GetFileAttributesW(OsString(path).c_str()); // path not found if(fa == INVALID_FILE_ATTRIBUTES) @@ -213,7 +213,7 @@ static bool is_normal_dir(const wchar_t* path) } -WDIR* wopendir(const wchar_t* path) +WDIR* wopendir(const OsPath& path) { if(!is_normal_dir(path)) { @@ -228,16 +228,14 @@ WDIR* wopendir(const wchar_t* path) return 0; } - // build search path for FindFirstFileW. note: "path\\dir" only returns - // information about that directory; trailing slashes aren't allowed. - // for dir entries to be returned, we have to append "\\*". - wchar_t search_path[PATH_MAX]; - swprintf_s(search_path, ARRAY_SIZE(search_path), L"%ls\\*", path); + // NB: c:\path only returns information about that directory; trailing + // slashes aren't allowed. append * to retrieve directory entries. + OsPath searchPath = path/"*"; // note: we could store search_path and defer FindFirstFileW until // wreaddir. this way is a bit more complex but required for // correctness (we must return a valid DIR iff is valid). - d->hFind = FindFirstFileW(search_path, &d->fd); + d->hFind = FindFirstFileW(OsString(searchPath).c_str(), &d->fd); if(d->hFind == INVALID_HANDLE_VALUE) { // not an error - the directory is just empty. @@ -327,13 +325,13 @@ int wclosedir(WDIR* d) // fcntl.h //----------------------------------------------------------------------------- -int wopen(const wchar_t* pathname, int oflag) +int wopen(const OsPath& pathname, int oflag) { debug_assert(!(oflag & O_CREAT)); - return wopen(pathname, oflag, _S_IREAD|_S_IWRITE); + return wopen(OsString(pathname).c_str(), oflag, _S_IREAD|_S_IWRITE); } -int wopen(const wchar_t* pathname, int oflag, mode_t mode_arg) +int wopen(const OsPath& pathname, int oflag, mode_t mode_arg) { mode_t mode = _S_IREAD|_S_IWRITE; if(oflag & O_CREAT) @@ -341,7 +339,7 @@ int wopen(const wchar_t* pathname, int oflag, mode_t mode_arg) WinScopedPreserveLastError s; // _wsopen_s's CreateFileW int fd; - errno_t ret = _wsopen_s(&fd, pathname, oflag, _SH_DENYNO, mode); + errno_t ret = _wsopen_s(&fd, OsString(pathname).c_str(), oflag, _SH_DENYNO, mode); if(ret != 0) { errno = ret; @@ -376,9 +374,9 @@ int wclose(int fd) // unistd.h //----------------------------------------------------------------------------- -int wtruncate(const wchar_t* pathname, off_t length) +int wtruncate(const OsPath& pathname, off_t length) { - HANDLE hFile = CreateFileW(pathname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + HANDLE hFile = CreateFileW(OsString(pathname).c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); debug_assert(hFile != INVALID_HANDLE_VALUE); LARGE_INTEGER ofs; ofs.QuadPart = length; WARN_IF_FALSE(SetFilePointerEx(hFile, ofs, 0, FILE_BEGIN)); @@ -388,28 +386,29 @@ int wtruncate(const wchar_t* pathname, off_t length) } -int wunlink(const wchar_t* pathname) +int wunlink(const OsPath& pathname) { - return _wunlink(pathname); + return _wunlink(OsString(pathname).c_str()); } -int wrmdir(const wchar_t* path) +int wrmdir(const OsPath& path) { - return _wrmdir(path); + return _wrmdir(OsString(path).c_str()); } -int wrename(const wchar_t* pathnameOld, const wchar_t* pathnameNew) +int wrename(const OsPath& pathnameOld, const OsPath& pathnameNew) { - return _wrename(pathnameOld, pathnameNew); + return _wrename(OsString(pathnameOld).c_str(), OsString(pathnameNew).c_str()); } -wchar_t* wrealpath(const wchar_t* pathname, wchar_t* resolved) +OsPath wrealpath(const OsPath& pathname) { - if(!GetFullPathNameW(pathname, PATH_MAX, resolved, 0)) - return 0; + wchar_t resolved[PATH_MAX]; + if(!GetFullPathNameW(OsString(pathname).c_str(), PATH_MAX, resolved, 0)) + return OsPath(); return resolved; } @@ -433,9 +432,9 @@ static int ErrnoFromCreateDirectory() } } -int wmkdir(const wchar_t* path, mode_t UNUSED(mode)) +int wmkdir(const OsPath& path, mode_t UNUSED(mode)) { - if(!CreateDirectoryW(path, (LPSECURITY_ATTRIBUTES)NULL)) + if(!CreateDirectoryW(OsString(path).c_str(), (LPSECURITY_ATTRIBUTES)NULL)) { errno = ErrnoFromCreateDirectory(); return -1; @@ -445,7 +444,7 @@ int wmkdir(const wchar_t* path, mode_t UNUSED(mode)) } -int wstat(const wchar_t* pathname, struct stat* buf) +int wstat(const OsPath& pathname, struct stat* buf) { - return _wstat64(pathname, buf); + return _wstat64(OsString(pathname).c_str(), buf); } diff --git a/source/lib/sysdep/os/win/wsdl.cpp b/source/lib/sysdep/os/win/wsdl.cpp index acc01c7e3a..d6efc50a98 100644 --- a/source/lib/sysdep/os/win/wsdl.cpp +++ b/source/lib/sysdep/os/win/wsdl.cpp @@ -1478,7 +1478,7 @@ void SDL_Quit() } -static NativePath GetStdoutPathname() +static OsPath GetStdoutPathname() { // the current directory is unreliable, so use the full path to // the current executable. @@ -1489,7 +1489,7 @@ static NativePath GetStdoutPathname() // add the EXE name to the filename to allow multiple executables // with their own redirections. (we can't use wutil_ExecutablePath // because it doesn't return the basename) - NativePath pathname = Path::ChangeExtension(NativePath(pathnameEXE), L"_stdout.txt"); + OsPath pathname = OsPath(pathnameEXE).ChangeExtension(L"_stdout.txt"); return pathname; } @@ -1500,7 +1500,7 @@ static void RedirectStdout() if(wutil_IsValidHandle(GetStdHandle(STD_OUTPUT_HANDLE))) return; - const NativePath pathname = GetStdoutPathname(); + const OsPath pathname = GetStdoutPathname(); // ignore BoundsChecker warnings here. subsystem is set to "Windows" // to prevent the OS from opening a console on startup (ugly). @@ -1509,7 +1509,7 @@ static void RedirectStdout() FILE* f = 0; // (return value ignored - it indicates 'file already exists' even // if f is valid) - (void)_wfreopen_s(&f, pathname.c_str(), L"wt", stdout); + (void)_wfreopen_s(&f, OsString(pathname).c_str(), L"wt", stdout); // executable directory (probably Program Files) is read-only for // non-Administrators. we can't pick another directory because // ah_log_dir might not be valid until the app's init has run, diff --git a/source/lib/sysdep/os/win/wsnd.cpp b/source/lib/sysdep/os/win/wsnd.cpp index afb7326ae6..40f6481df3 100644 --- a/source/lib/sysdep/os/win/wsnd.cpp +++ b/source/lib/sysdep/os/win/wsnd.cpp @@ -40,27 +40,27 @@ #include "lib/sysdep/os/win/wmi.h" -static bool IsOpenAlDllName(const NativePath& name) +static bool IsOpenAlDllName(const Path::String& name) { // (matches "*oal.dll" and "*OpenAL*", as with OpenAL router's search) - return name.find(L"oal.dll") != NativePath::npos || name.find(L"OpenAL") != NativePath::npos; + return name.find(L"oal.dll") != Path::String::npos || name.find(L"OpenAL") != Path::String::npos; } // ensures each OpenAL DLL is only listed once (even if present in several // directories on our search path). -typedef std::set StringSet; +typedef std::set StringSet; // find all OpenAL DLLs in a dir. // call in library search order (exe dir, then win sys dir); otherwise, // DLLs in the executable's starting directory hide those of the // same name in the system directory. -static void add_oal_dlls_in_dir(const NativePath& path, StringSet& dlls, VersionList& versionList) +static void add_oal_dlls_in_dir(const OsPath& path, StringSet& dlls, VersionList& versionList) { FileInfos files; (void)GetDirectoryEntries(path, &files, 0); for(size_t i = 0; i < files.size(); i++) { - const NativePath name = files[i].Name(); + const Path::String name = files[i].Name().string(); if(!IsOpenAlDllName(name)) continue; @@ -69,7 +69,7 @@ static void add_oal_dlls_in_dir(const NativePath& path, StringSet& dlls, Version if(!ret.second) // insert failed - element already there continue; - wdll_ver_Append(Path::Join(path, name), versionList); + wdll_ver_Append(path / name, versionList); } } @@ -86,7 +86,7 @@ static void add_oal_dlls_in_dir(const NativePath& path, StringSet& dlls, Version // the version info for that bogus driver path, we'll skip this code there. // (delay-loading dsound.dll eliminates any overhead) -static NativePath directSoundDriverPath; +static OsPath directSoundDriverPath; // store sound card name and path to DirectSound driver. // called for each DirectSound driver, but aborts after first valid driver. @@ -99,14 +99,14 @@ static BOOL CALLBACK DirectSoundCallback(void* guid, const wchar_t* UNUSED(descr // note: $system\\drivers is not in LoadLibrary's search list, // so we have to give the full pathname. - directSoundDriverPath = Path::Join(Path::Join(wutil_SystemPath(), "drivers"), NativePath(module)); + directSoundDriverPath = wutil_SystemPath()/"drivers" / module; // we assume the first "driver name" (sound card) is the one we want; // stick with that and stop calling. return FALSE; } -static const NativePath& GetDirectSoundDriverPath() +static const OsPath& GetDirectSoundDriverPath() { #define DS_OK 0 typedef BOOL (CALLBACK* LPDSENUMCALLBACKW)(void*, const wchar_t*, const wchar_t*, void*); diff --git a/source/lib/sysdep/os/win/wsysdep.cpp b/source/lib/sysdep/os/win/wsysdep.cpp index 009ef62f37..c9baab4970 100644 --- a/source/lib/sysdep/os/win/wsysdep.cpp +++ b/source/lib/sysdep/os/win/wsysdep.cpp @@ -363,7 +363,7 @@ LibError sys_error_description_r(int user_err, wchar_t* buf, size_t max_chars) } -LibError sys_get_module_filename(void* addr, NativePath& pathname) +LibError sys_get_module_filename(void* addr, OsPath& pathname) { MEMORY_BASIC_INFORMATION mbi; const SIZE_T bytesWritten = VirtualQuery(addr, &mbi, sizeof(mbi)); @@ -382,7 +382,7 @@ LibError sys_get_module_filename(void* addr, NativePath& pathname) } -LibError sys_get_executable_name(NativePath& pathname) +LibError sys_get_executable_name(OsPath& pathname) { wchar_t pathnameBuf[MAX_PATH+1]; const DWORD charsWritten = GetModuleFileNameW(0, pathnameBuf, (DWORD)ARRAY_SIZE(pathnameBuf)); @@ -418,21 +418,19 @@ static int CALLBACK BrowseCallback(HWND hWnd, unsigned int msg, LPARAM UNUSED(lP return 0; } -LibError sys_pick_directory(NativePath& path) +LibError sys_pick_directory(OsPath& path) { // (must not use multi-threaded apartment due to BIF_NEWDIALOGSTYLE) const HRESULT hr = CoInitialize(0); debug_assert(hr == S_OK || hr == S_FALSE); // S_FALSE == already initialized - // NB: BFFM_SETSELECTIONW can't deal with '/' separators - const NativePath initialPath = path; - // note: bi.pszDisplayName isn't the full path, so it isn't of any use. BROWSEINFOW bi; memset(&bi, 0, sizeof(bi)); bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE|BIF_NONEWFOLDERBUTTON; // for setting starting directory: bi.lpfn = (BFFCALLBACK)BrowseCallback; + const Path::String initialPath = OsString(path); // NB: BFFM_SETSELECTIONW can't deal with '/' separators bi.lParam = (LPARAM)initialPath.c_str(); const LPITEMIDLIST pidl = SHBrowseForFolderW(&bi); if(!pidl) // user canceled @@ -597,3 +595,11 @@ done: } #endif + +FILE* sys_OpenFile(const OsPath& pathname, const char* mode) +{ + FILE* f = 0; + const std::wstring wmode(mode, mode+strlen(mode)); + (void)_wfopen_s(&f, OsString(pathname).c_str(), wmode.c_str()); + return f; +} diff --git a/source/lib/sysdep/os/win/wutil.cpp b/source/lib/sysdep/os/win/wutil.cpp index b718f72b6c..445ee2bbef 100644 --- a/source/lib/sysdep/os/win/wutil.cpp +++ b/source/lib/sysdep/os/win/wutil.cpp @@ -267,30 +267,30 @@ bool wutil_HasCommandLineArgument(const wchar_t* arg) //----------------------------------------------------------------------------- // directories -NativePath wutil_DetectExecutablePath() +OsPath wutil_DetectExecutablePath() { wchar_t modulePathname[MAX_PATH+1] = {0}; const DWORD len = GetModuleFileNameW(GetModuleHandle(0), modulePathname, MAX_PATH); debug_assert(len != 0); - return Path::Path(NativePath(modulePathname)); + return OsPath(modulePathname).Parent(); } // (NB: wutil_Init is called before static ctors => use placement new) -static NativePath* systemPath; -static NativePath* executablePath; -static NativePath* appdataPath; +static OsPath* systemPath; +static OsPath* executablePath; +static OsPath* appdataPath; -const NativePath& wutil_SystemPath() +const OsPath& wutil_SystemPath() { return *systemPath; } -const NativePath& wutil_ExecutablePath() +const OsPath& wutil_ExecutablePath() { return *executablePath; } -const NativePath& wutil_AppdataPath() +const OsPath& wutil_AppdataPath() { return *appdataPath; } @@ -305,11 +305,11 @@ static void GetDirectories() { const UINT charsWritten = GetSystemDirectoryW(path, MAX_PATH); debug_assert(charsWritten != 0); - systemPath = new(wutil_Allocate(sizeof(NativePath))) NativePath(path); + systemPath = new(wutil_Allocate(sizeof(OsPath))) OsPath(path); } // executable's directory - executablePath = new(wutil_Allocate(sizeof(NativePath))) NativePath(wutil_DetectExecutablePath()); + executablePath = new(wutil_Allocate(sizeof(OsPath))) OsPath(wutil_DetectExecutablePath()); // application data { @@ -317,18 +317,18 @@ static void GetDirectories() HANDLE token = 0; const HRESULT ret = SHGetFolderPathW(hwnd, CSIDL_APPDATA, token, 0, path); debug_assert(SUCCEEDED(ret)); - appdataPath = new(wutil_Allocate(sizeof(NativePath))) NativePath(path); + appdataPath = new(wutil_Allocate(sizeof(OsPath))) OsPath(path); } } static void FreeDirectories() { - systemPath->~NativePath(); + systemPath->~OsPath(); wutil_Free(systemPath); - executablePath->~NativePath(); + executablePath->~OsPath(); wutil_Free(executablePath); - appdataPath->~NativePath(); + appdataPath->~OsPath(); wutil_Free(appdataPath); } diff --git a/source/lib/sysdep/os/win/wutil.h b/source/lib/sysdep/os/win/wutil.h index 865ce59f9d..211c17d5a6 100644 --- a/source/lib/sysdep/os/win/wutil.h +++ b/source/lib/sysdep/os/win/wutil.h @@ -170,11 +170,11 @@ extern bool wutil_HasCommandLineArgument(const wchar_t* arg); // used by wutil_ExecutablePath, but provided in case other code // needs to know this before our wutil_Init runs. -extern NativePath wutil_DetectExecutablePath(); +extern OsPath wutil_DetectExecutablePath(); -extern const NativePath& wutil_SystemPath(); -extern const NativePath& wutil_ExecutablePath(); -extern const NativePath& wutil_AppdataPath(); +extern const OsPath& wutil_SystemPath(); +extern const OsPath& wutil_ExecutablePath(); +extern const OsPath& wutil_AppdataPath(); //----------------------------------------------------------------------------- diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index ad8de2c090..455f712f46 100644 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -111,7 +111,7 @@ extern LibError sys_error_description_r(int err, wchar_t* buf, size_t max_chars) * * note: this is useful for handling exceptions in other modules. **/ -LibError sys_get_module_filename(void* addr, NativePath& pathname); +LibError sys_get_module_filename(void* addr, OsPath& pathname); /** * Get path to the current executable. @@ -121,7 +121,7 @@ LibError sys_get_module_filename(void* addr, NativePath& pathname); * * this is useful for determining installation directory, e.g. for VFS. **/ -LIB_API LibError sys_get_executable_name(NativePath& pathname); +LIB_API LibError sys_get_executable_name(OsPath& pathname); /** * Get the current user's login name. @@ -137,7 +137,7 @@ extern std::wstring sys_get_user_name(); * faster browsing. if INFO::OK is returned, it receives * chosen directory path. **/ -extern LibError sys_pick_directory(NativePath& path); +extern LibError sys_pick_directory(OsPath& path); /** * Open the user's default web browser to the given URL. @@ -185,6 +185,8 @@ LIB_API LibError sys_generate_random_bytes(u8* buf, size_t count); **/ LIB_API LibError sys_get_proxy_config(const std::wstring& url, std::wstring& proxy); +LIB_API FILE* sys_OpenFile(const OsPath& pathname, const char* mode); + /** * directory separation character **/ diff --git a/source/lib/sysdep/tests/test_sysdep.h b/source/lib/sysdep/tests/test_sysdep.h index 6bb9ccdf67..2dba90b06a 100644 --- a/source/lib/sysdep/tests/test_sysdep.h +++ b/source/lib/sysdep/tests/test_sysdep.h @@ -27,6 +27,7 @@ #include "lib/secure_crt.h" #include "lib/utf8.h" #include "lib/sysdep/cpu.h" +#include "lib/sysdep/filesystem.h" #include "lib/sysdep/sysdep.h" #if OS_LINUX @@ -49,16 +50,16 @@ public: void test_sys_get_executable_name() { - NativePath path; + OsPath path; // Try it first with the real executable (i.e. the // one that's running this test code) TS_ASSERT_EQUALS(sys_get_executable_name(path), INFO::OK); // Check it's absolute - TSM_ASSERT(L"Path: "+path, path_is_absolute(path.c_str())); + TSM_ASSERT(L"Path: "+path.string(), path_is_absolute(path.string().c_str())); // Check the file exists struct stat s; - TSM_ASSERT_EQUALS(L"Path: "+path, wstat(path.c_str(), &s), 0); + TSM_ASSERT_EQUALS(L"Path: "+path.string(), wstat(path, &s), 0); // Do some platform-specific tests, based on the // implementations of sys_get_executable_name: @@ -78,7 +79,7 @@ public: TS_ASSERT(realpath(root, rootres)); std::string rootstr(rootres); - std::wstring rootstrw(wstring_from_utf8(rootstr)); + OsPath rootstrw(rootstr); const char* dirs[] = { "/example", @@ -111,12 +112,12 @@ public: { Mock_dladdr d(rootstr+"/example/executable"); TS_ASSERT_EQUALS(sys_get_executable_name(path), INFO::OK); - TS_ASSERT_WSTR_EQUALS(path, rootstrw+L"/example/executable"); + TS_ASSERT_PATH_EQUALS(path, rootstrw/L"example/executable"); } { Mock_dladdr d(rootstr+"/example/./a/b/../e/../../executable"); TS_ASSERT_EQUALS(sys_get_executable_name(path), INFO::OK); - TS_ASSERT_WSTR_EQUALS(path, rootstrw+L"/example/executable"); + TS_ASSERT_PATH_EQUALS(path, rootstrw/L"example/executable"); } // Try with relative paths @@ -124,19 +125,19 @@ public: Mock_dladdr d("./executable"); Mock_getcwd m(rootstr+"/example"); TS_ASSERT_EQUALS(sys_get_executable_name(path), INFO::OK); - TS_ASSERT_WSTR_EQUALS(path, rootstrw+L"/example/executable"); + TS_ASSERT_PATH_EQUALS(path, rootstrw/L"example/executable"); } { Mock_dladdr d("./executable"); Mock_getcwd m(rootstr+"/example/"); TS_ASSERT_EQUALS(sys_get_executable_name(path), INFO::OK); - TS_ASSERT_WSTR_EQUALS(path, rootstrw+L"/example/executable"); + TS_ASSERT_PATH_EQUALS(path, rootstrw/L"example/executable"); } { Mock_dladdr d("../d/../../f/executable"); Mock_getcwd m(rootstr+"/example/a/b/c"); TS_ASSERT_EQUALS(sys_get_executable_name(path), INFO::OK); - TS_ASSERT_WSTR_EQUALS(path, rootstrw+L"/example/a/f/executable"); + TS_ASSERT_PATH_EQUALS(path, rootstrw/L"example/a/f/executable"); } // Try with pathless names diff --git a/source/lib/tex/tex.cpp b/source/lib/tex/tex.cpp index cf62626645..c4c5a96dd2 100644 --- a/source/lib/tex/tex.cpp +++ b/source/lib/tex/tex.cpp @@ -566,7 +566,7 @@ bool tex_is_known_extension(const VfsPath& pathname) { const TexCodecVTbl* dummy; // found codec for it => known extension - const NativePath extension = Path::Extension(pathname); + const OsPath extension = pathname.Extension(); if(tex_codec_for_filename(extension, &dummy) == INFO::OK) return true; @@ -699,7 +699,7 @@ size_t tex_hdr_size(const VfsPath& filename) { const TexCodecVTbl* c; - const NativePath extension = Path::Extension(filename); + const OsPath extension = filename.Extension(); CHECK_ERR(tex_codec_for_filename(extension, &c)); return c->hdr_size(0); } @@ -751,7 +751,7 @@ LibError tex_decode(const shared_ptr& data, size_t data_size, Tex* t) } -LibError tex_encode(Tex* t, const NativePath& extension, DynArray* da) +LibError tex_encode(Tex* t, const OsPath& extension, DynArray* da) { CHECK_TEX(t); CHECK_ERR(tex_validate_plain_format(t->bpp, t->flags)); diff --git a/source/lib/tex/tex.h b/source/lib/tex/tex.h index d9f0d3a23f..702975cbad 100644 --- a/source/lib/tex/tex.h +++ b/source/lib/tex/tex.h @@ -105,6 +105,7 @@ library and IO layer. Read and write are zero-copy. #define INCLUDED_TEX #include "lib/res/handle.h" +#include "lib/native_path.h" #include "lib/file/vfs/vfs_path.h" #include "lib/allocators/dynarray.h" @@ -290,7 +291,7 @@ extern LibError tex_decode(const shared_ptr& data, size_t data_size, Tex* t) * when no longer needed. Invalid unless function succeeds. * @return LibError **/ -extern LibError tex_encode(Tex* t, const NativePath& extension, DynArray* da); +extern LibError tex_encode(Tex* t, const OsPath& extension, DynArray* da); /** * store the given image data into a Tex object; this will be as if diff --git a/source/lib/tex/tex_bmp.cpp b/source/lib/tex/tex_bmp.cpp index a99dab9873..397a258c41 100644 --- a/source/lib/tex/tex_bmp.cpp +++ b/source/lib/tex/tex_bmp.cpp @@ -74,9 +74,9 @@ static bool bmp_is_hdr(const u8* file) } -static bool bmp_is_ext(const NativePath& extension) +static bool bmp_is_ext(const OsPath& extension) { - return !wcscasecmp(extension.c_str(), L".bmp"); + return extension == L".bmp"; } diff --git a/source/lib/tex/tex_codec.cpp b/source/lib/tex/tex_codec.cpp index 40f03cb648..d89135e880 100644 --- a/source/lib/tex/tex_codec.cpp +++ b/source/lib/tex/tex_codec.cpp @@ -63,7 +63,7 @@ void tex_codec_unregister_all() // or return ERR::TEX_UNKNOWN_FORMAT if unknown. // note: does not raise a warning because it is used by // tex_is_known_extension. -LibError tex_codec_for_filename(const NativePath& extension, const TexCodecVTbl** c) +LibError tex_codec_for_filename(const OsPath& extension, const TexCodecVTbl** c) { for(*c = codecs; *c; *c = (*c)->next) { diff --git a/source/lib/tex/tex_codec.h b/source/lib/tex/tex_codec.h index 625a180ee6..1e8f46bf6d 100644 --- a/source/lib/tex/tex_codec.h +++ b/source/lib/tex/tex_codec.h @@ -96,7 +96,7 @@ struct TexCodecVTbl * @param extension (including '.') * @return bool **/ - bool (*is_ext)(const NativePath& extension); + bool (*is_ext)(const OsPath& extension); /** * return size of the file header supported by this codec. @@ -170,7 +170,7 @@ extern int tex_codec_register(TexCodecVTbl* c); * called by tex_is_known_extension) if no codec indicates they can * handle the given extension. **/ -extern LibError tex_codec_for_filename(const NativePath& extension, const TexCodecVTbl** c); +extern LibError tex_codec_for_filename(const OsPath& extension, const TexCodecVTbl** c); /** * find codec that recognizes the header's magic field. diff --git a/source/lib/tex/tex_dds.cpp b/source/lib/tex/tex_dds.cpp index d9d5375a71..18959fee7d 100644 --- a/source/lib/tex/tex_dds.cpp +++ b/source/lib/tex/tex_dds.cpp @@ -579,9 +579,9 @@ static bool dds_is_hdr(const u8* file) } -static bool dds_is_ext(const NativePath& extension) +static bool dds_is_ext(const OsPath& extension) { - return !wcscasecmp(extension.c_str(), L".dds"); + return extension == L".dds"; } diff --git a/source/lib/tex/tex_jpg.cpp b/source/lib/tex/tex_jpg.cpp index 66aea58d0e..d8bf479b94 100644 --- a/source/lib/tex/tex_jpg.cpp +++ b/source/lib/tex/tex_jpg.cpp @@ -573,9 +573,9 @@ static bool jpg_is_hdr(const u8* file) } -static bool jpg_is_ext(const NativePath& extension) +static bool jpg_is_ext(const OsPath& extension) { - return !wcscasecmp(extension.c_str(), L".jpg") || !wcscasecmp(extension.c_str(), L".jpeg"); + return extension == L".jpg" || extension == L".jpeg"; } diff --git a/source/lib/tex/tex_png.cpp b/source/lib/tex/tex_png.cpp index 9e078dd557..f121cfa81d 100644 --- a/source/lib/tex/tex_png.cpp +++ b/source/lib/tex/tex_png.cpp @@ -183,9 +183,9 @@ static bool png_is_hdr(const u8* file) } -static bool png_is_ext(const NativePath& extension) +static bool png_is_ext(const OsPath& extension) { - return !wcscasecmp(extension.c_str(), L".png"); + return extension == L".png"; } diff --git a/source/lib/tex/tex_tga.cpp b/source/lib/tex/tex_tga.cpp index 0c2819996c..f179736d12 100644 --- a/source/lib/tex/tex_tga.cpp +++ b/source/lib/tex/tex_tga.cpp @@ -93,9 +93,9 @@ static bool tga_is_hdr(const u8* file) } -static bool tga_is_ext(const NativePath& extension) +static bool tga_is_ext(const OsPath& extension) { - return !wcscasecmp(extension.c_str(), L".tga"); + return extension == L".tga"; } diff --git a/source/main.cpp b/source/main.cpp index 2a8c19c49a..1d3205926c 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -437,7 +437,7 @@ static void RunGameOrAtlas(int argc, const char* argv[]) Paths paths(args); g_VFS = CreateVfs(20 * MiB); g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE); - g_VFS->Mount(L"", Path::Join(paths.RData(), "mods/public"), VFS_MOUNT_MUST_EXIST); + g_VFS->Mount(L"", paths.RData()/"mods/public", VFS_MOUNT_MUST_EXIST); { CReplayPlayer replay; @@ -456,12 +456,12 @@ static void RunGameOrAtlas(int argc, const char* argv[]) { Paths paths(args); - NativePath mod = NativePathFromString(args.Get("archivebuild")); - NativePath zip; + OsPath mod(args.Get("archivebuild")); + OsPath zip; if (args.Has("archivebuild-output")) - zip = NativePathFromString(args.Get("archivebuild-output")); + zip = args.Get("archivebuild-output"); else - zip = Path::Filename(mod)+L".zip"; + zip = mod.Filename().ChangeExtension(L".zip"); CArchiveBuilder builder(mod, paths.Cache()); builder.Build(zip); diff --git a/source/network/NetTurnManager.cpp b/source/network/NetTurnManager.cpp index c5725fc7e8..97406ec30c 100644 --- a/source/network/NetTurnManager.cpp +++ b/source/network/NetTurnManager.cpp @@ -182,8 +182,8 @@ void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash) bool ok = m_Simulation2.ComputeStateHash(hash, quick); debug_assert(ok); - NativePath path = Path::Join(psLogDir(), "oos_dump.txt"); - std::ofstream file (StringFromNativePath(path).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath path = psLogDir()/"oos_dump.txt"; + std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); m_Simulation2.DumpDebugState(file); file.close(); diff --git a/source/network/tests/test_Net.h b/source/network/tests/test_Net.h index f2998e7e65..fde56bea68 100644 --- a/source/network/tests/test_Net.h +++ b/source/network/tests/test_Net.h @@ -38,8 +38,8 @@ public: void setUp() { g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/public"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/public", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache")); CXeromyces::Startup(); // Need some stuff for terrain movement costs: @@ -60,7 +60,7 @@ public: CXeromyces::Terminate(); g_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } bool clients_are_all(const std::vector& clients, uint state) diff --git a/source/ps/ArchiveBuilder.cpp b/source/ps/ArchiveBuilder.cpp index cf81c4ce08..bc7f09bb67 100644 --- a/source/ps/ArchiveBuilder.cpp +++ b/source/ps/ArchiveBuilder.cpp @@ -32,18 +32,18 @@ #include -CArchiveBuilder::CArchiveBuilder(const std::wstring& mod, const NativePath& tempdir) : +CArchiveBuilder::CArchiveBuilder(const OsPath& mod, const OsPath& tempdir) : m_TempDir(tempdir) { tex_codec_register_all(); m_VFS = CreateVfs(20*MiB); - DeleteDirectory(Path::Join(m_TempDir, "_archivecache")); // clean up in case the last run failed + DeleteDirectory(m_TempDir/"_archivecache"); // clean up in case the last run failed - m_VFS->Mount(L"cache/", Path::Join(m_TempDir, "_archivecache/")); + m_VFS->Mount(L"cache/", m_TempDir/"_archivecache/"); - m_VFS->Mount(L"", Path::AddSlash(mod), VFS_MOUNT_MUST_EXIST); + m_VFS->Mount(L"", mod/"", VFS_MOUNT_MUST_EXIST); // Collect the list of files before loading any base mods fs_util::ForEachFile(m_VFS, L"", &CollectFileCB, (uintptr_t)static_cast(this), 0, fs_util::DIR_RECURSIVE); @@ -53,17 +53,17 @@ CArchiveBuilder::~CArchiveBuilder() { m_VFS.reset(); - DeleteDirectory(Path::Join(m_TempDir, "_archivecache")); + DeleteDirectory(m_TempDir/"_archivecache"); tex_codec_unregister_all(); } -void CArchiveBuilder::AddBaseMod(const NativePath& mod) +void CArchiveBuilder::AddBaseMod(const OsPath& mod) { - m_VFS->Mount(L"", Path::AddSlash(mod), VFS_MOUNT_MUST_EXIST); + m_VFS->Mount(L"", mod/"", VFS_MOUNT_MUST_EXIST); } -void CArchiveBuilder::Build(const NativePath& archive) +void CArchiveBuilder::Build(const OsPath& archive) { // Disable zip compression because it significantly hurts download size // for releases (which re-compress all files with better compression @@ -84,25 +84,26 @@ void CArchiveBuilder::Build(const NativePath& archive) { LibError ret; - NativePath realPath; - ret = m_VFS->GetRealPath(m_Files[i], realPath); + const VfsPath path = m_Files[i]; + OsPath realPath; + ret = m_VFS->GetRealPath(path, realPath); debug_assert(ret == INFO::OK); // Compress textures and store the new cached version instead of the original - if (boost::algorithm::starts_with(m_Files[i], L"art/textures/") && + if (boost::algorithm::starts_with(path.string(), L"art/textures/") && tex_is_known_extension(m_Files[i]) && // Skip some subdirectories where the engine doesn't use CTextureManager yet: - !boost::algorithm::starts_with(m_Files[i], L"art/textures/cursors/") && - !boost::algorithm::starts_with(m_Files[i], L"art/textures/terrain/alphamaps/") + !boost::algorithm::starts_with(path.string(), L"art/textures/cursors/") && + !boost::algorithm::starts_with(path.string(), L"art/textures/terrain/alphamaps/") ) { VfsPath cachedPath; - debug_printf(L"Converting texture %ls\n", realPath.c_str()); - bool ok = texman.GenerateCachedTexture(m_Files[i], cachedPath); + debug_printf(L"Converting texture %ls\n", realPath.string().c_str()); + bool ok = texman.GenerateCachedTexture(path, cachedPath); debug_assert(ok); - std::wstring cachedRealPath; - ret = m_VFS->GetRealPath(Path::Join("cache", cachedPath), cachedRealPath); + OsPath cachedRealPath; + ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath); debug_assert(ret == INFO::OK); writer->AddFile(cachedRealPath, cachedPath); @@ -114,19 +115,19 @@ void CArchiveBuilder::Build(const NativePath& archive) // TODO: should cache DAE->PMD and DAE->PSA conversions too - debug_printf(L"Adding %ls\n", realPath.c_str()); - writer->AddFile(realPath, m_Files[i]); + debug_printf(L"Adding %ls\n", realPath.string().c_str()); + writer->AddFile(realPath, path); // Also cache XMB versions of all XML files - if (Path::Extension(m_Files[i]) == L".xml") + if (m_Files[i].Extension() == L".xml") { VfsPath cachedPath; - debug_printf(L"Converting XML file %ls\n", realPath.c_str()); - bool ok = xero.GenerateCachedXMB(m_VFS, m_Files[i], cachedPath); + debug_printf(L"Converting XML file %ls\n", realPath.string().c_str()); + bool ok = xero.GenerateCachedXMB(m_VFS, path, cachedPath); debug_assert(ok); - NativePath cachedRealPath; - ret = m_VFS->GetRealPath(Path::Join("cache", cachedPath), cachedRealPath); + OsPath cachedRealPath; + ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath); debug_assert(ret == INFO::OK); writer->AddFile(cachedRealPath, cachedPath); diff --git a/source/ps/ArchiveBuilder.h b/source/ps/ArchiveBuilder.h index 7d57141ad6..b4671ce39a 100644 --- a/source/ps/ArchiveBuilder.h +++ b/source/ps/ArchiveBuilder.h @@ -36,7 +36,7 @@ public: * @param mod path to data/mods/foo directory, containing files for conversion * @param tempdir path to a writable directory for temporary files */ - CArchiveBuilder(const std::wstring& mod, const NativePath& tempdir); + CArchiveBuilder(const OsPath& mod, const OsPath& tempdir); ~CArchiveBuilder(); @@ -47,20 +47,20 @@ public: * a user's mod. * @param mod path to data/mods/foo directory, containing files for loading */ - void AddBaseMod(const NativePath& mod); + void AddBaseMod(const OsPath& mod); /** * Do all the processing and packing of files into the archive. * @param archive path of .zip file to generate (will be overwritten if it exists) */ - void Build(const NativePath& archive); + void Build(const OsPath& archive); private: static LibError CollectFileCB(const VfsPath& pathname, const FileInfo& fileInfo, const uintptr_t cbData); PIVFS m_VFS; std::vector m_Files; - NativePath m_TempDir; + OsPath m_TempDir; }; #endif // INCLUDED_ARCHIVEBUILDER diff --git a/source/ps/CLogger.cpp b/source/ps/CLogger.cpp index 87b1877c85..7ee985bbf3 100644 --- a/source/ps/CLogger.cpp +++ b/source/ps/CLogger.cpp @@ -75,11 +75,11 @@ const char* html_header1 = "\n"; CLogger::CLogger() { - NativePath mainlogPath(Path::Join(psLogDir(), "mainlog.html")); - m_MainLog = new std::ofstream(StringFromNativePath(mainlogPath).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath mainlogPath(psLogDir()/"mainlog.html"); + m_MainLog = new std::ofstream(OsString(mainlogPath).c_str(), std::ofstream::out | std::ofstream::trunc); - NativePath interestinglogPath(Path::Join(psLogDir(), "interestinglog.html")); - m_InterestingLog = new std::ofstream(StringFromNativePath(interestinglogPath).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath interestinglogPath(psLogDir()/"interestinglog.html"); + m_InterestingLog = new std::ofstream(OsString(interestinglogPath).c_str(), std::ofstream::out | std::ofstream::trunc); m_OwnsStreams = true; m_UseDebugPrintf = true; diff --git a/source/ps/CacheLoader.cpp b/source/ps/CacheLoader.cpp index 98eb6d9dcd..99c33c3e41 100644 --- a/source/ps/CacheLoader.cpp +++ b/source/ps/CacheLoader.cpp @@ -45,7 +45,7 @@ LibError CCacheLoader::TryLoadingCached(const VfsPath& sourcePath, const MD5& in LibError err = m_VFS->GetFileInfo(sourcePath, NULL); if (err < 0) { - LOGERROR(L"Failed to find file: \"%ls\"", sourcePath.c_str()); + LOGERROR(L"Failed to find file: \"%ls\"", sourcePath.string().c_str()); return err; } @@ -109,7 +109,7 @@ bool CCacheLoader::CanUseArchiveCache(const VfsPath& sourcePath, const VfsPath& VfsPath CCacheLoader::ArchiveCachePath(const VfsPath& sourcePath) { - return Path::ChangeExtension(sourcePath, Path::Extension(sourcePath) + L".cached" + m_FileExtension); + return sourcePath.ChangeExtension(sourcePath.Extension().string() + L".cached" + m_FileExtension); } VfsPath CCacheLoader::LooseCachePath(const VfsPath& sourcePath, const MD5& initialHash, u32 version) @@ -142,7 +142,7 @@ VfsPath CCacheLoader::LooseCachePath(const VfsPath& sourcePath, const MD5& initi digestPrefix << std::setfill(L'0') << std::setw(2) << (int)digest[i]; // Construct the final path - return Path::Join("cache", Path::ChangeExtension(sourcePath, Path::Extension(sourcePath) + std::wstring(L".") + digestPrefix.str() + m_FileExtension)); + return VfsPath("cache") /sourcePath.ChangeExtension(sourcePath.Extension().string() + L"." + digestPrefix.str() + m_FileExtension); // TODO: we should probably include the mod name, once that's possible (http://trac.wildfiregames.com/ticket/564) } diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp index 8de114709c..cf321fa9a9 100644 --- a/source/ps/ConfigDB.cpp +++ b/source/ps/ConfigDB.cpp @@ -341,16 +341,16 @@ bool CConfigDB::Reload(EConfigNamespace ns) // Handle missing files quietly if (g_VFS->GetFileInfo(m_ConfigFile[ns], NULL) < 0) { - LOGMESSAGE(L"Cannot find config file \"%ls\" - ignoring", m_ConfigFile[ns].c_str()); + LOGMESSAGE(L"Cannot find config file \"%ls\" - ignoring", m_ConfigFile[ns].string().c_str()); return false; } else { - LOGMESSAGE(L"Loading config file \"%ls\"", m_ConfigFile[ns].c_str()); + LOGMESSAGE(L"Loading config file \"%ls\"", m_ConfigFile[ns].string().c_str()); LibError ret = g_VFS->LoadFile(m_ConfigFile[ns], buffer, buflen); if (ret != INFO::OK) { - LOGERROR(L"CConfigDB::Reload(): vfs_load for \"%ls\" failed: return was %ld", m_ConfigFile[ns].c_str(), ret); + LOGERROR(L"CConfigDB::Reload(): vfs_load for \"%ls\" failed: return was %ld", m_ConfigFile[ns].string().c_str(), ret); return false; } } @@ -437,7 +437,7 @@ bool CConfigDB::WriteFile(EConfigNamespace ns, const VfsPath& path) LibError ret = g_VFS->CreateFile(path, buf, len); if(ret < 0) { - LOGERROR(L"CConfigDB::WriteFile(): CreateFile \"%ls\" failed (error: %d)", path.c_str(), (int)ret); + LOGERROR(L"CConfigDB::WriteFile(): CreateFile \"%ls\" failed (error: %d)", path.string().c_str(), (int)ret); return false; } diff --git a/source/ps/Filesystem.cpp b/source/ps/Filesystem.cpp index bc82f8058d..86b94ed667 100644 --- a/source/ps/Filesystem.cpp +++ b/source/ps/Filesystem.cpp @@ -53,17 +53,17 @@ void UnregisterFileReloadFunc(FileReloadFunc func, void* obj) static bool CanIgnore(const DirWatchNotification& notification) { // ignore directories - const NativePath& pathname = notification.Pathname(); - if(Path::IsDirectory(pathname)) + const OsPath& pathname = notification.Pathname(); + if(pathname.IsDirectory()) return true; // ignore uninteresting file types (e.g. temp files, or the // hundreds of XMB files that are generated from XML) - const std::wstring extension = Path::Extension(pathname); + const OsPath extension = pathname.Extension(); const wchar_t* extensionsToIgnore[] = { L".xmb", L".tmp" }; for(size_t i = 0; i < ARRAY_SIZE(extensionsToIgnore); i++) { - if(!wcscasecmp(extension.c_str(), extensionsToIgnore[i])) + if(extension == extensionsToIgnore[i]) return true; } @@ -116,7 +116,7 @@ PSRETURN CVFSFile::Load(const PIVFS& vfs, const VfsPath& filename) LibError ret = vfs->LoadFile(filename, m_Buffer, m_BufferSize); if (ret != INFO::OK) { - LOGERROR(L"CVFSFile: file %ls couldn't be opened (vfs_load: %ld)", filename.c_str(), ret); + LOGERROR(L"CVFSFile: file %ls couldn't be opened (vfs_load: %ld)", filename.string().c_str(), ret); return PSRETURN_CVFSFile_LoadFailed; } diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 926926767a..75e436a17b 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -438,7 +438,7 @@ static void InitVfs(const CmdLineArgs& args) const Paths paths(args); - NativePath logs(paths.Logs()); + OsPath logs(paths.Logs()); CreateDirectories(logs, 0700); psSetLogDir(logs); @@ -453,8 +453,8 @@ static void InitVfs(const CmdLineArgs& args) const size_t cacheSize = ChooseCacheSize(); g_VFS = CreateVfs(cacheSize); - g_VFS->Mount(L"screenshots/", Path::Join(paths.Data(), "screenshots/")); - const NativePath readonlyConfig = Path::Join(paths.RData(), "config/"); + g_VFS->Mount(L"screenshots/", paths.Data()/"screenshots/"); + const OsPath readonlyConfig = paths.RData()/"config/"; g_VFS->Mount(L"config/", readonlyConfig); if(readonlyConfig != paths.Config()) g_VFS->Mount(L"config/", paths.Config()); @@ -465,15 +465,15 @@ static void InitVfs(const CmdLineArgs& args) if(!args.Has("onlyPublicFiles")) mods.push_back("internal"); - NativePath modArchivePath = Path::Join(paths.Cache(), "mods"); - NativePath modLoosePath = Path::Join(paths.RData(), "mods"); + OsPath modArchivePath = paths.Cache()/"mods"; + OsPath modLoosePath = paths.RData()/"mods"; for (size_t i = 0; i < mods.size(); ++i) { size_t priority = i; size_t flags = VFS_MOUNT_WATCH|VFS_MOUNT_ARCHIVABLE|VFS_MOUNT_MUST_EXIST; - NativePath modName(NativePathFromString(mods[i])); - g_VFS->Mount(L"", Path::AddSlash(Path::Join(modLoosePath, modName)), flags, priority); - g_VFS->Mount(L"", Path::AddSlash(Path::Join(modArchivePath, modName)), flags, priority); + OsPath modName(mods[i]); + g_VFS->Mount(L"", modLoosePath / modName/"", flags, priority); + g_VFS->Mount(L"", modArchivePath / modName/"", flags, priority); } // note: don't bother with g_VFS->TextRepresentation - directories diff --git a/source/ps/GameSetup/Paths.cpp b/source/ps/GameSetup/Paths.cpp index 3e1da9f92e..1a2ffeb2c6 100644 --- a/source/ps/GameSetup/Paths.cpp +++ b/source/ps/GameSetup/Paths.cpp @@ -19,7 +19,7 @@ #include "Paths.h" #include "lib/path_util.h" -#include "lib/sysdep/filesystem.h" // wrealpath +#include "lib/file/file_system_util.h" #include "lib/sysdep/sysdep.h" // sys_get_executable_name #if OS_WIN # include "lib/sysdep/os/win/wutil.h" // wutil_AppdataPath @@ -28,12 +28,12 @@ Paths::Paths(const CmdLineArgs& args) { - m_root = Root(NativePathFromString(args.GetArg0())); + m_root = Root(args.GetArg0()); #ifdef INSTALLED_DATADIR m_rdata = WIDEN(STRINGIZE(INSTALLED_DATADIR)) L"/"; #else - m_rdata = Path::Join(m_root, "data/"); + m_rdata = m_root/"data/"; #endif const char* subdirectoryName = args.Has("writableRoot")? 0 : "0ad"; @@ -42,68 +42,67 @@ Paths::Paths(const CmdLineArgs& args) if(!subdirectoryName) { m_data = m_rdata; - m_config = Path::Join(m_data, "config/"); - m_cache = Path::Join(m_data, "cache/"); - m_logs = Path::Join(m_root, "logs/"); + m_config = m_data/"config/"; + m_cache = m_data/"cache/"; + m_logs = m_root/"logs/"; } else { #if OS_WIN - const NativePath appdata = Path::AddSlash(Path::Join(wutil_AppdataPath(), subdirectoryName)); - m_data = Path::Join(appdata, "data/"); - m_config = Path::Join(appdata, "config/"); - m_cache = Path::Join(appdata, "cache/"); - m_logs = Path::Join(appdata, "logs/"); + const OsPath appdata = wutil_AppdataPath() / subdirectoryName/""; + m_data = appdata/"data/"; + m_config = appdata/"config/"; + m_cache = appdata/"cache/"; + m_logs = appdata/"logs/"; #else const char* envHome = getenv("HOME"); debug_assert(envHome); - const NativePath home(NativePathFromString(envHome)); - const NativePath xdgData = Path::Join(XDG_Path("XDG_DATA_HOME", home, Path::Join(home, ".local/share/")), subdirectoryName); - const NativePath xdgConfig = Path::Join(XDG_Path("XDG_CONFIG_HOME", home, Path::Join(home, ".config/")), subdirectoryName); - const NativePath xdgCache = Path::Join(XDG_Path("XDG_CACHE_HOME", home, Path::Join(home, ".cache/")), subdirectoryName); - m_data = Path::AddSlash(xdgData); - m_cache = Path::AddSlash(xdgCache); - m_config = Path::AddSlash(Path::Join(xdgConfig, "config")); - m_logs = Path::AddSlash(Path::Join(xdgConfig, "logs")); + const OsPath home(envHome); + const OsPath xdgData = XDG_Path("XDG_DATA_HOME", home, home/".local/share/") / subdirectoryName; + const OsPath xdgConfig = XDG_Path("XDG_CONFIG_HOME", home, home/".config/" ) / subdirectoryName; + const OsPath xdgCache = XDG_Path("XDG_CACHE_HOME", home, home/".cache/" ) / subdirectoryName; + m_data = xdgData/""; + m_cache = xdgCache/""; + m_config = xdgConfig/"config/"; + m_logs = xdgConfig/"logs/"; #endif } } -/*static*/ NativePath Paths::Root(const NativePath& argv0) +/*static*/ OsPath Paths::Root(const OsPath& argv0) { // get full path to executable - NativePath pathname; + OsPath pathname; // .. first try safe, but system-dependent version if(sys_get_executable_name(pathname) != INFO::OK) { // .. failed; use argv[0] - wchar_t pathname_buf[PATH_MAX]; errno = 0; - if(!wrealpath(argv0.c_str(), pathname_buf)) + pathname = wrealpath(argv0); + if(pathname.empty()) WARN_ERR(LibError_from_errno(false)); - pathname = pathname_buf; } // make sure it's valid - if(!FileExists(pathname)) + if(!fs_util::FileExists(pathname)) WARN_ERR(LibError_from_errno(false)); - fs::wpath components = pathname; + fs::wpath components = pathname.string(); for(size_t i = 0; i < 3; i++) // remove "system/name.exe" components.remove_leaf(); return components.string(); } -/*static*/ NativePath Paths::XDG_Path(const char* envname, const NativePath& home, const NativePath& defaultPath) +/*static*/ OsPath Paths::XDG_Path(const char* envname, const OsPath& home, const OsPath& defaultPath) { const char* path = getenv(envname); if(path) { if(path[0] != '/') // relative to $HOME - return Path::AddSlash(Path::Join(home, NativePathFromString(path))); - return Path::AddSlash(NativePathFromString(path)); + return home / path/""; + return OsPath(path)/""; } - return Path::AddSlash(defaultPath); + return defaultPath/""; } diff --git a/source/ps/GameSetup/Paths.h b/source/ps/GameSetup/Paths.h index 29df46f76f..d284691703 100644 --- a/source/ps/GameSetup/Paths.h +++ b/source/ps/GameSetup/Paths.h @@ -26,49 +26,49 @@ class Paths public: Paths(const CmdLineArgs& args); - const NativePath& Root() const + const OsPath& Root() const { return m_root; } - const NativePath& RData() const + const OsPath& RData() const { return m_rdata; } - const NativePath& Data() const + const OsPath& Data() const { return m_data; } - const NativePath& Config() const + const OsPath& Config() const { return m_config; } - const NativePath& Cache() const + const OsPath& Cache() const { return m_cache; } - const NativePath& Logs() const + const OsPath& Logs() const { return m_logs; } private: - static NativePath Root(const NativePath& argv0); - static NativePath XDG_Path(const char* envname, const NativePath& home, const NativePath& defaultPath); + static OsPath Root(const OsPath& argv0); + static OsPath XDG_Path(const char* envname, const OsPath& home, const OsPath& defaultPath); // read-only directories, fixed paths relative to executable - NativePath m_root; - NativePath m_rdata; + OsPath m_root; + OsPath m_rdata; // writable directories - NativePath m_data; - NativePath m_config; - NativePath m_cache; - NativePath m_logs; // special-cased in single-root-folder installations + OsPath m_data; + OsPath m_config; + OsPath m_cache; + OsPath m_logs; // special-cased in single-root-folder installations }; #endif // #ifndef INCLUDED_PS_GAMESETUP_PATHS diff --git a/source/ps/ProfileViewer.cpp b/source/ps/ProfileViewer.cpp index 50a31bd1a4..c1d91fc463 100644 --- a/source/ps/ProfileViewer.cpp +++ b/source/ps/ProfileViewer.cpp @@ -525,8 +525,8 @@ void CProfileViewer::SaveToFile() { // Open the file. (It will be closed when the CProfileViewer // destructor is called.) - NativePath path = Path::Join(psLogDir(), "profile.txt"); - m->outputStream.open(StringFromNativePath(path).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath path = psLogDir()/"profile.txt"; + m->outputStream.open(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); if (m->outputStream.fail()) { diff --git a/source/ps/Pyrogenesis.cpp b/source/ps/Pyrogenesis.cpp index 4277db7e5b..556f61ca23 100644 --- a/source/ps/Pyrogenesis.cpp +++ b/source/ps/Pyrogenesis.cpp @@ -46,11 +46,10 @@ void psTranslateFree(const wchar_t* text) // convert contents of file from char to wchar_t and // append to file. -static void AppendAsciiFile(FILE* out, const NativePath& pathname) +static void AppendAsciiFile(FILE* out, const OsPath& pathname) { - FILE* in; - errno_t err = _wfopen_s(&in, pathname.c_str(), L"rb"); - if(err != 0) + FILE* in = sys_OpenFile(pathname, "rb"); + if(!in) { fwprintf(out, L"(unavailable)"); return; @@ -77,25 +76,25 @@ void psBundleLogs(FILE* f) fwprintf(f, L"SVN Revision: %ls\n\n", svn_revision); fwprintf(f, L"System info:\n\n"); - NativePath path1 = Path::Join(psLogDir(), "system_info.txt"); + OsPath path1 = psLogDir()/"system_info.txt"; AppendAsciiFile(f, path1); fwprintf(f, L"\n\n====================================\n\n"); fwprintf(f, L"Main log:\n\n"); - NativePath path2 = Path::Join(psLogDir(), "mainlog.html"); + OsPath path2 = psLogDir()/"mainlog.html"; AppendAsciiFile(f, path2); fwprintf(f, L"\n\n====================================\n\n"); } -static NativePath logDir; +static OsPath logDir; -void psSetLogDir(const NativePath& newLogDir) +void psSetLogDir(const OsPath& newLogDir) { logDir = newLogDir; } -const NativePath& psLogDir() +const OsPath& psLogDir() { return logDir; } diff --git a/source/ps/Pyrogenesis.h b/source/ps/Pyrogenesis.h index 8a65fa2a0d..3efdbab90d 100644 --- a/source/ps/Pyrogenesis.h +++ b/source/ps/Pyrogenesis.h @@ -31,7 +31,7 @@ extern const wchar_t* psTranslate(const wchar_t* text); extern void psTranslateFree(const wchar_t* text); extern void psBundleLogs(FILE* f); -extern void psSetLogDir(const NativePath& logDir); // set during InitVfs -extern const NativePath& psLogDir(); // used by AppHooks and engine code when reporting errors +extern void psSetLogDir(const OsPath& logDir); // set during InitVfs +extern const OsPath& psLogDir(); // used by AppHooks and engine code when reporting errors #endif diff --git a/source/ps/Replay.cpp b/source/ps/Replay.cpp index 10286a209b..1416c2aa0b 100644 --- a/source/ps/Replay.cpp +++ b/source/ps/Replay.cpp @@ -68,9 +68,9 @@ CReplayLogger::CReplayLogger(ScriptInterface& scriptInterface) : name << L"/commands.txt"; - NativePath path = Path::Join(psLogDir(), NativePath(name.str())); - CreateDirectories(Path::Path(path), 0700); - m_Stream = new std::ofstream(StringFromNativePath(path).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath path = psLogDir() / name.str(); + CreateDirectories(path.Parent(), 0700); + m_Stream = new std::ofstream(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); } CReplayLogger::~CReplayLogger() diff --git a/source/ps/Util.cpp b/source/ps/Util.cpp index ffd89e405d..fd4fc5470b 100644 --- a/source/ps/Util.cpp +++ b/source/ps/Util.cpp @@ -25,6 +25,7 @@ #include "lib/timer.h" #include "lib/bits.h" // round_up #include "lib/allocators/shared_ptr.h" +#include "lib/sysdep/sysdep.h" // sys_OpenFile #include "lib/sysdep/gfx.h" #include "lib/sysdep/snd.h" #include "lib/sysdep/cpu.h" @@ -78,10 +79,9 @@ void WriteSystemInfo() struct utsname un; uname(&un); - NativePath pathname = Path::Join(psLogDir(), "system_info.txt"); - FILE* f; - errno_t err = _wfopen_s(&f, pathname.c_str(), L"w"); - if(err != 0) + OsPath pathname = psLogDir()/"system_info.txt"; + FILE* f = sys_OpenFile(pathname, "w"); + if(!f) return; // current timestamp (redundant WRT OS timestamp, but that is not @@ -196,10 +196,8 @@ const wchar_t* ErrorString(int err) // transformed to write it out in the format determined by 's extension. LibError tex_write(Tex* t, const VfsPath& filename) { - const std::wstring extension = Path::Extension(filename); - DynArray da; - RETURN_ERR(tex_encode(t, extension, &da)); + RETURN_ERR(tex_encode(t, filename.Extension(), &da)); // write to disk LibError ret = INFO::OK; @@ -223,12 +221,12 @@ static size_t s_nextScreenshotNumber; // identifies the file format that is to be written // (case-insensitive). examples: "bmp", "png", "jpg". // BMP is good for quick output at the expense of large files. -void WriteScreenshot(const std::wstring& extension) +void WriteScreenshot(const VfsPath& extension) { // get next available numbered filename // note: %04d -> always 4 digits, so sorting by filename works correctly. const VfsPath basenameFormat(L"screenshots/screenshot%04d"); - const VfsPath filenameFormat = Path::ChangeExtension(basenameFormat, extension); + const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension); VfsPath filename; fs_util::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename); @@ -238,7 +236,7 @@ void WriteScreenshot(const std::wstring& extension) int flags = TEX_BOTTOM_UP; // we want writing BMP to be as fast as possible, // so read data from OpenGL in BMP format to obviate conversion. - if(!wcscasecmp(extension.c_str(), L".bmp")) + if(extension == L".bmp") { fmt = GL_BGR; flags |= TEX_BGR; @@ -260,12 +258,12 @@ void WriteScreenshot(const std::wstring& extension) if (tex_write(&t, filename) == INFO::OK) { - NativePath realPath; + OsPath realPath; g_VFS->GetRealPath(filename, realPath); - LOGMESSAGERENDER(L"Screenshot written to '%ls'", realPath.c_str()); + LOGMESSAGERENDER(L"Screenshot written to '%ls'", realPath.string().c_str()); } else - LOGERROR(L"Error writing screenshot to '%ls'", filename.c_str()); + LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str()); tex_free(&t); } @@ -273,7 +271,7 @@ void WriteScreenshot(const std::wstring& extension) // Similar to WriteScreenshot, but generates an image of size 640*tiles x 480*tiles. -void WriteBigScreenshot(const std::wstring& extension, int tiles) +void WriteBigScreenshot(const VfsPath& extension, int tiles) { // If the game hasn't started yet then use WriteScreenshot to generate the image. if(g_Game == NULL){ WriteScreenshot(L".bmp"); return; } @@ -281,7 +279,7 @@ void WriteBigScreenshot(const std::wstring& extension, int tiles) // get next available numbered filename // note: %04d -> always 4 digits, so sorting by filename works correctly. const VfsPath basenameFormat(L"screenshots/screenshot%04d"); - const VfsPath filenameFormat = Path::ChangeExtension(basenameFormat, extension); + const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension); VfsPath filename; fs_util::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename); @@ -296,7 +294,7 @@ void WriteBigScreenshot(const std::wstring& extension, int tiles) int flags = TEX_BOTTOM_UP; // we want writing BMP to be as fast as possible, // so read data from OpenGL in BMP format to obviate conversion. - if(!wcscasecmp(extension.c_str(), L".bmp")) + if(extension == L".bmp") { fmt = GL_BGR; flags |= TEX_BGR; @@ -386,12 +384,12 @@ void WriteBigScreenshot(const std::wstring& extension, int tiles) if (tex_write(&t, filename) == INFO::OK) { - NativePath realPath; + OsPath realPath; g_VFS->GetRealPath(filename, realPath); - LOGMESSAGERENDER(L"Screenshot written to '%ls'", realPath.c_str()); + LOGMESSAGERENDER(L"Screenshot written to '%ls'", realPath.string().c_str()); } else - LOGERROR(L"Error writing screenshot to '%ls'", filename.c_str()); + LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str()); tex_free(&t); free(tile_data); diff --git a/source/ps/Util.h b/source/ps/Util.h index fa0b6694f2..73b20d078b 100644 --- a/source/ps/Util.h +++ b/source/ps/Util.h @@ -26,8 +26,8 @@ extern void WriteSystemInfo(); extern const wchar_t* ErrorString(int err); -extern void WriteScreenshot(const std::wstring& extension); -extern void WriteBigScreenshot(const std::wstring& extension, int tiles); +extern void WriteScreenshot(const VfsPath& extension); +extern void WriteBigScreenshot(const VfsPath& extension, int tiles); extern LibError tex_write(Tex* t, const VfsPath& filename); diff --git a/source/ps/World.cpp b/source/ps/World.cpp index 96e1f34794..bec3cb4678 100644 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -70,7 +70,7 @@ void CWorld::RegisterInit(const CStrW& mapFile, int playerID) // Load the map, if one was specified if (mapFile.length()) { - VfsPath mapfilename(Path::Join("maps/scenarios", NativePath(mapFile + L".pmp"))); + VfsPath mapfilename(VfsPath("maps/scenarios") / (mapFile + L".pmp")); CMapReader* reader = 0; try @@ -88,7 +88,7 @@ void CWorld::RegisterInit(const CStrW& mapFile, int playerID) catch (PSERROR_File& err) { delete reader; - LOGERROR(L"Failed to load map %ls: %hs", mapfilename.c_str(), err.what()); + LOGERROR(L"Failed to load map %ls: %hs", mapfilename.string().c_str(), err.what()); throw PSERROR_Game_World_MapLoadFailed(); } } diff --git a/source/ps/XML/Xeromyces.cpp b/source/ps/XML/Xeromyces.cpp index a8424d6d27..9f20e11260 100644 --- a/source/ps/XML/Xeromyces.cpp +++ b/source/ps/XML/Xeromyces.cpp @@ -118,7 +118,7 @@ bool CXeromyces::GenerateCachedXMB(const PIVFS& vfs, const VfsPath& sourcePath, archiveCachePath = cacheLoader.ArchiveCachePath(sourcePath); - return (ConvertFile(vfs, sourcePath, Path::Join("cache", archiveCachePath)) == PSRETURN_OK); + return (ConvertFile(vfs, sourcePath, VfsPath("cache") / archiveCachePath) == PSRETURN_OK); } PSRETURN CXeromyces::ConvertFile(const PIVFS& vfs, const VfsPath& filename, const VfsPath& xmbPath) @@ -126,16 +126,16 @@ PSRETURN CXeromyces::ConvertFile(const PIVFS& vfs, const VfsPath& filename, cons CVFSFile input; if (input.Load(vfs, filename)) { - LOGERROR(L"CXeromyces: Failed to open XML file %ls", filename.c_str()); + LOGERROR(L"CXeromyces: Failed to open XML file %ls", filename.string().c_str()); return PSRETURN_Xeromyces_XMLOpenFailed; } - CStr8 filename8(CStrW(filename).ToUTF8()); + CStr8 filename8(CStrW(filename.string()).ToUTF8()); xmlDocPtr doc = xmlReadMemory((const char*)input.GetBuffer(), (int)input.GetBufferSize(), filename8.c_str(), NULL, XML_PARSE_NONET|XML_PARSE_NOCDATA); if (! doc) { - LOGERROR(L"CXeromyces: Failed to parse XML file %ls", filename.c_str()); + LOGERROR(L"CXeromyces: Failed to parse XML file %ls", filename.string().c_str()); return PSRETURN_Xeromyces_XMLParseError; } diff --git a/source/ps/scripting/JSInterface_VFS.cpp b/source/ps/scripting/JSInterface_VFS.cpp index 7f10ae1235..76d649b105 100644 --- a/source/ps/scripting/JSInterface_VFS.cpp +++ b/source/ps/scripting/JSInterface_VFS.cpp @@ -69,7 +69,7 @@ static LibError BuildDirEntListCB(const VfsPath& pathname, const FileInfo& UNUSE { BuildDirEntListState* s = (BuildDirEntListState*)cbData; - jsval val = ToJSVal( CStrW(pathname) ); + jsval val = ToJSVal( CStrW(pathname.string()) ); JS_SetElement(s->cx, s->filename_array, s->cur_idx++, &val); return INFO::CB_CONTINUE; } diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index f50677e135..57b264d3a4 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -80,7 +80,7 @@ void ModelRenderer::BuildPositionAndNormals( // some broken situations if (numVertices && vertices[0].m_Blend.m_Bone[0] == 0xff) { - LOGERROR(L"Model %ls is boned with unboned animation", mdef->GetName().c_str()); + LOGERROR(L"Model %ls is boned with unboned animation", mdef->GetName().string().c_str()); return; } diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 543380028d..924c3a698c 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -1624,7 +1624,7 @@ int CRenderer::LoadAlphaMaps() { // note: these individual textures can be discarded afterwards; // we cache the composite. - textures[i] = ogl_tex_load(g_VFS, Path::Join(path, VfsPath(fnames[i]))); + textures[i] = ogl_tex_load(g_VFS, path / fnames[i]); RETURN_ERR(textures[i]); // get its size and make sure they are all equal. @@ -1720,7 +1720,7 @@ LibError CRenderer::ReloadChangedFileCB(void* param, const VfsPath& path) CRenderer* renderer = static_cast(param); // If an alpha map changed, and we already loaded them, then reload them - if (boost::algorithm::starts_with(path, L"art/textures/terrain/alphamaps/")) + if (boost::algorithm::starts_with(path.string(), L"art/textures/terrain/alphamaps/")) { if (renderer->m_hCompositeAlphaMap) { diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index c687ebae71..e4af1fddfd 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -75,7 +75,7 @@ void SkyManager::LoadSkyTextures() { for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i) { - VfsPath path = Path::Join("art/textures/skies", Path::Join(VfsPath(m_SkySet), VfsPath(s_imageNames[i])+L".dds")); + VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds"); CTextureProperties textureProps(path); textureProps.SetWrap(GL_CLAMP_TO_EDGE); @@ -109,12 +109,12 @@ std::vector SkyManager::GetSkySets() const DirectoryNames subdirectories; if(g_VFS->GetDirectoryEntries(path, 0, &subdirectories) < 0) { - LOGERROR(L"Error opening directory '%ls'", path.c_str()); + LOGERROR(L"Error opening directory '%ls'", path.string().c_str()); return std::vector(1, GetSkySet()); // just return what we currently have } for(size_t i = 0; i < subdirectories.size(); i++) - skies.push_back(subdirectories[i]); + skies.push_back(subdirectories[i].string()); sort(skies.begin(), skies.end()); return skies; diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 35fcff4b7d..51e6595532 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -37,6 +37,7 @@ #include "lib/svn_revision.h" #include "lib/timer.h" #include "lib/utf8.h" +#include "lib/sysdep/sysdep.h" // sys_OpenFile #include "maths/scripting/JSInterface_Vector3D.h" #include "network/NetServer.h" #include "ps/CConsole.h" @@ -279,13 +280,8 @@ void DumpHeap(const char* basename, int idx, JSContext* cx) { char filename[64]; sprintf_s(filename, ARRAY_SIZE(filename), "%s.%03d.txt", basename, idx); - NativePath pathname = Path::Join(psLogDir(), filename); -#if OS_WIN - FILE* f = _wfopen(pathname.c_str(), L"w"); -#else - std::string pathname8 = StringFromNativePath(pathname); - FILE* f = fopen(pathname8.c_str(), "w"); -#endif + OsPath pathname = psLogDir() / filename; + FILE* f = sys_OpenFile(pathname, "w"); debug_assert(f); JS_DumpHeap(cx, f, NULL, 0, NULL, (size_t)-1, NULL); fclose(f); diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index afe64fa790..c9841f4368 100644 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -94,7 +94,7 @@ void ScriptingHost::RunScript(const VfsPath& pathname, JSObject* globalObject) jsval rval; JSBool ok = JS_EvaluateUCScript(m_Context, globalObject, reinterpret_cast(script.c_str()), (uintN)script.size(), - CStrW(pathname).ToUTF8().c_str(), 1, &rval); + utf8_from_wstring(pathname.string()).c_str(), 1, &rval); if (ok == JS_FALSE) throw PSERROR_Scripting_LoadFile_EvalErrors(); diff --git a/source/scriptinterface/ScriptConversions.cpp b/source/scriptinterface/ScriptConversions.cpp index f69f1d1e4b..ba9060ffc2 100644 --- a/source/scriptinterface/ScriptConversions.cpp +++ b/source/scriptinterface/ScriptConversions.cpp @@ -120,6 +120,15 @@ template<> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, return true; } +template<> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, Path& out) +{ + std::wstring string; + if(!FromJSVal(cx, v, string)) + return false; + out = string; + return true; +} + template<> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, std::string& out) { WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions @@ -242,6 +251,11 @@ template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const std return JSVAL_VOID; } +template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const Path& val) +{ + return ToJSVal(cx, val.string()); +} + template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const std::string& val) { JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length()); diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index f29012f1af..9e380be4b7 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -768,9 +768,9 @@ bool ScriptInterface::FreezeObject(jsval obj, bool deep) return JS_FreezeObject(m->m_cx, JSVAL_TO_OBJECT(obj)) ? true : false; } -bool ScriptInterface::LoadScript(const std::wstring& filename, const std::wstring& code) +bool ScriptInterface::LoadScript(const VfsPath& filename, const std::wstring& code) { - std::string fnAscii(filename.begin(), filename.end()); + std::string fnAscii = utf8_from_wstring(filename.string()); // Compile the code in strict mode, to encourage better coding practices and // to possibly help SpiderMonkey with optimisations @@ -792,7 +792,7 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) { if (!VfsFileExists(g_VFS, path)) { - LOGERROR(L"File '%ls' does not exist", path.c_str()); + LOGERROR(L"File '%ls' does not exist", path.string().c_str()); return false; } @@ -802,14 +802,14 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) if (ret != PSRETURN_OK) { - LOGERROR(L"Failed to load file '%ls': %hs", path.c_str(), GetErrorString(ret)); + LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret)); return false; } std::string content(file.GetBuffer(), file.GetBuffer() + file.GetBufferSize()); std::wstring code = wstring_from_utf8(content); - std::string fnAscii(path.begin(), path.end()); + std::string fnAscii = utf8_from_wstring(path.string()); // Compile the code in strict mode, to encourage better coding practices and // to possibly help SpiderMonkey with optimisations @@ -877,7 +877,7 @@ CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path) { if (!VfsFileExists(g_VFS, path)) { - LOGERROR(L"File '%ls' does not exist", path.c_str()); + LOGERROR(L"File '%ls' does not exist", path.string().c_str()); return CScriptValRooted(); } @@ -887,7 +887,7 @@ CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path) if (ret != PSRETURN_OK) { - LOGERROR(L"Failed to load file '%ls': %hs", path.c_str(), GetErrorString(ret)); + LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret)); return CScriptValRooted(); } diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index 0d44d19fc9..5c44625622 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -235,7 +235,7 @@ public: * @param code JS code to execute * @return true on successful compilation and execution; false otherwise */ - bool LoadScript(const std::wstring& filename, const std::wstring& code); + bool LoadScript(const VfsPath& filename, const std::wstring& code); /** * Load and execute the given script in the global scope. diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index f8c34fc45e..09e4b922b3 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -151,7 +151,7 @@ bool CSimulation2Impl::LoadScripts(const VfsPath& path) { VfsPath filename = *it; m_LoadedScripts.insert(filename); - LOGMESSAGE(L"Loading simulation script '%ls'", filename.c_str()); + LOGMESSAGE(L"Loading simulation script '%ls'", filename.string().c_str()); if (! m_ComponentManager.LoadScript(filename)) ok = false; } @@ -172,7 +172,7 @@ LibError CSimulation2Impl::ReloadChangedFile(const VfsPath& path) if (!VfsFileExists(path)) return INFO::OK; - LOGMESSAGE(L"Reloading simulation script '%ls'", filename.c_str()); + LOGMESSAGE(L"Reloading simulation script '%ls'", filename.string().c_str()); if (!m_ComponentManager.LoadScript(filename, true)) return ERR::FAIL; @@ -289,9 +289,9 @@ void CSimulation2Impl::DumpState() std::wstringstream name; name << L"sim_log/" << getpid() << L"/" << std::setw(5) << std::setfill(L'0') << m_TurnNumber << L".txt"; - NativePath path = Path::Join(psLogDir(), NativePath(name.str())); - CreateDirectories(Path::Path(path), 0700); - std::ofstream file (StringFromNativePath(path).c_str(), std::ofstream::out | std::ofstream::trunc); + OsPath path = psLogDir() / name.str(); + CreateDirectories(path.Parent(), 0700); + std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); file << "State hash: " << std::hex; std::string hashRaw; @@ -304,7 +304,7 @@ void CSimulation2Impl::DumpState() m_ComponentManager.DumpDebugState(file); - std::ofstream binfile (StringFromNativePath(Path::ChangeExtension(path, L".dat")).c_str(), std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); + std::ofstream binfile (OsString(path.ChangeExtension(L".dat")).c_str(), std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); m_ComponentManager.SerializeState(binfile); } diff --git a/source/simulation2/components/CCmpAIManager.cpp b/source/simulation2/components/CCmpAIManager.cpp index 2ce4aaa1f0..c27bac1355 100644 --- a/source/simulation2/components/CCmpAIManager.cpp +++ b/source/simulation2/components/CCmpAIManager.cpp @@ -159,7 +159,7 @@ private: { if (!m_ScriptInterface.LoadGlobalScriptFile(*it)) { - LOGERROR(L"Failed to load script %ls", it->c_str()); + LOGERROR(L"Failed to load script %ls", it->string().c_str()); return false; } } @@ -172,11 +172,11 @@ private: if (!LoadScripts(m_AIName)) return false; - NativePath path = L"simulation/ai/" + m_AIName + L"/data.json"; + OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; CScriptValRooted metadata = m_Worker.LoadMetadata(path); if (metadata.uninitialised()) { - LOGERROR(L"Failed to create AI player: can't find %ls", path.c_str()); + LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str()); return false; } @@ -184,7 +184,7 @@ private: std::string constructor; if (!m_ScriptInterface.GetProperty(metadata.get(), "constructor", constructor)) { - LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.c_str()); + LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); return false; } @@ -193,7 +193,7 @@ private: if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor) || ctor.undefined()) { - LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.c_str(), constructor.c_str()); + LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } @@ -218,7 +218,7 @@ private: if (obj.undefined()) { - LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.c_str(), constructor.c_str()); + LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } diff --git a/source/simulation2/components/CCmpTemplateManager.cpp b/source/simulation2/components/CCmpTemplateManager.cpp index f7653f9881..2c5e83c0c7 100644 --- a/source/simulation2/components/CCmpTemplateManager.cpp +++ b/source/simulation2/components/CCmpTemplateManager.cpp @@ -320,7 +320,7 @@ bool CCmpTemplateManager::LoadTemplateFile(const std::string& templateName, int // Normal case: templateName is an XML file: - VfsPath path = Path::Join(VfsPath(TEMPLATE_ROOT), wstring_from_utf8(templateName + ".xml")); + VfsPath path = VfsPath(TEMPLATE_ROOT) / wstring_from_utf8(templateName + ".xml"); CXeromyces xero; PSRETURN ok = xero.Load(g_VFS, path); if (ok != PSRETURN_OK) @@ -381,9 +381,9 @@ static LibError AddToTemplates(const VfsPath& pathname, const FileInfo& UNUSED(f std::vector& templates = *(std::vector*)cbData; // Strip the .xml extension - VfsPath pathstem = Path::ChangeExtension(pathname, L""); + VfsPath pathstem = pathname.ChangeExtension(L""); // Strip the root from the path - std::wstring name = pathstem.substr(ARRAY_SIZE(TEMPLATE_ROOT)-1); + std::wstring name = pathstem.string().substr(ARRAY_SIZE(TEMPLATE_ROOT)-1); // We want to ignore template_*.xml templates, since they should never be built in the editor if (name.substr(0, 9) == L"template_") @@ -398,7 +398,7 @@ static LibError AddActorToTemplates(const VfsPath& pathname, const FileInfo& UNU std::vector& templates = *(std::vector*)cbData; // Strip the root from the path - std::wstring name = pathname.substr(ARRAY_SIZE(ACTOR_ROOT)-1); + std::wstring name = pathname.string().substr(ARRAY_SIZE(ACTOR_ROOT)-1); templates.push_back("actor|" + std::string(name.begin(), name.end())); return INFO::OK; diff --git a/source/simulation2/components/ICmpAIManager.cpp b/source/simulation2/components/ICmpAIManager.cpp index 4c4cbeeb0d..bb04a34e80 100644 --- a/source/simulation2/components/ICmpAIManager.cpp +++ b/source/simulation2/components/ICmpAIManager.cpp @@ -50,7 +50,7 @@ public: GetAIsHelper* self = (GetAIsHelper*)cbData; // Extract the 3rd component of the path (i.e. the directory after simulation/ai/) - fs::wpath components = pathname; + fs::wpath components = pathname.string(); fs::wpath::iterator it = components.begin(); std::advance(it, 2); std::wstring dirname = *it; diff --git a/source/simulation2/components/ICmpOverlayRenderer.cpp b/source/simulation2/components/ICmpOverlayRenderer.cpp index 898cc85ff3..233b316cbd 100644 --- a/source/simulation2/components/ICmpOverlayRenderer.cpp +++ b/source/simulation2/components/ICmpOverlayRenderer.cpp @@ -23,5 +23,5 @@ BEGIN_INTERFACE_WRAPPER(OverlayRenderer) DEFINE_INTERFACE_METHOD_0("Reset", void, ICmpOverlayRenderer, Reset) -DEFINE_INTERFACE_METHOD_4("AddSprite", void, ICmpOverlayRenderer, AddSprite, std::wstring, CFixedVector2D, CFixedVector2D, CFixedVector3D) +DEFINE_INTERFACE_METHOD_4("AddSprite", void, ICmpOverlayRenderer, AddSprite, VfsPath, CFixedVector2D, CFixedVector2D, CFixedVector3D) END_INTERFACE_WRAPPER(OverlayRenderer) diff --git a/source/simulation2/components/tests/test_Pathfinder.h b/source/simulation2/components/tests/test_Pathfinder.h index 2360655602..cb4c7dad50 100644 --- a/source/simulation2/components/tests/test_Pathfinder.h +++ b/source/simulation2/components/tests/test_Pathfinder.h @@ -36,8 +36,8 @@ public: CXeromyces::Startup(); g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/public"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache/", Path::Join(DataDir(), "cache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/public", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache/", DataDir()/"cache")); // Need some stuff for terrain movement costs: // (TODO: this ought to be independent of any graphics code) diff --git a/source/simulation2/components/tests/test_scripts.h b/source/simulation2/components/tests/test_scripts.h index b0a867d0d8..8872f3cdc6 100644 --- a/source/simulation2/components/tests/test_scripts.h +++ b/source/simulation2/components/tests/test_scripts.h @@ -25,7 +25,7 @@ public: void setUp() { g_VFS = CreateVfs(20 * MiB); - g_VFS->Mount(L"", Path::Join(DataDir(), "mods/public"), VFS_MOUNT_MUST_EXIST); // ignore directory-not-found errors + g_VFS->Mount(L"", DataDir()/"mods/public", VFS_MOUNT_MUST_EXIST); // ignore directory-not-found errors CXeromyces::Startup(); } @@ -35,26 +35,25 @@ public: g_VFS.reset(); } - static void load_script(ScriptInterface& scriptInterface, const VfsPath& path) + static void load_script(ScriptInterface& scriptInterface, const VfsPath& pathname) { - std::wstring name = path; CVFSFile file; - TS_ASSERT_EQUALS(file.Load(g_VFS, path), PSRETURN_OK); + TS_ASSERT_EQUALS(file.Load(g_VFS, pathname), PSRETURN_OK); CStr content = file.GetAsString(); std::wstring wcontent(content.begin(), content.end()); - TSM_ASSERT(L"Running script "+name, scriptInterface.LoadScript(name, wcontent)); + TSM_ASSERT(L"Running script "+pathname.string(), scriptInterface.LoadScript(pathname, wcontent)); } - static void Script_LoadComponentScript(void* cbdata, VfsPath name) + static void Script_LoadComponentScript(void* cbdata, VfsPath pathname) { CComponentManager* componentManager = static_cast (cbdata); - TS_ASSERT(componentManager->LoadScript(L"simulation/components/"+name)); + TS_ASSERT(componentManager->LoadScript(VfsPath(L"simulation/components") / pathname)); } - static void Script_LoadHelperScript(void* cbdata, VfsPath name) + static void Script_LoadHelperScript(void* cbdata, VfsPath pathname) { CComponentManager* componentManager = static_cast (cbdata); - TS_ASSERT(componentManager->LoadScript(L"simulation/helpers/"+name)); + TS_ASSERT(componentManager->LoadScript(VfsPath(L"simulation/helpers") / pathname)); } void test_scripts() diff --git a/source/simulation2/system/ComponentManager.cpp b/source/simulation2/system/ComponentManager.cpp index 2b46d31aa0..c868214c35 100644 --- a/source/simulation2/system/ComponentManager.cpp +++ b/source/simulation2/system/ComponentManager.cpp @@ -940,7 +940,7 @@ CScriptVal CComponentManager::Script_ReadJSONFile(void* cbdata, std::wstring fil { CComponentManager* componentManager = static_cast (cbdata); - VfsPath path = Path::Join("simulation/data", fileName); + VfsPath path = VfsPath("simulation/data") / fileName; return componentManager->GetScriptInterface().ReadJSONFile(path).get(); } diff --git a/source/simulation2/tests/test_CmpTemplateManager.h b/source/simulation2/tests/test_CmpTemplateManager.h index 7c4cedcc3c..2d105406db 100644 --- a/source/simulation2/tests/test_CmpTemplateManager.h +++ b/source/simulation2/tests/test_CmpTemplateManager.h @@ -37,8 +37,8 @@ public: void setUp() { g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/_test.sim"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/_test.sim", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache")); CXeromyces::Startup(); } @@ -46,7 +46,7 @@ public: { CXeromyces::Terminate(); g_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } void test_LoadTemplate() @@ -223,8 +223,8 @@ public: void setUp() { g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/public"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/public", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache")); CXeromyces::Startup(); } @@ -232,7 +232,7 @@ public: { CXeromyces::Terminate(); g_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } // This just attempts loading every public entity, to check there's no validation errors diff --git a/source/simulation2/tests/test_ComponentManager.h b/source/simulation2/tests/test_ComponentManager.h index 67992f0cbb..df8ad66fb8 100644 --- a/source/simulation2/tests/test_ComponentManager.h +++ b/source/simulation2/tests/test_ComponentManager.h @@ -44,8 +44,8 @@ public: void setUp() { g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/_test.sim"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/_test.sim", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache")); CXeromyces::Startup(); } @@ -53,7 +53,7 @@ public: { CXeromyces::Terminate(); g_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } void test_Load() diff --git a/source/simulation2/tests/test_Serializer.h b/source/simulation2/tests/test_Serializer.h index e016269566..9284d57d2d 100644 --- a/source/simulation2/tests/test_Serializer.h +++ b/source/simulation2/tests/test_Serializer.h @@ -487,8 +487,8 @@ public: CXeromyces::Startup(); g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/public"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache/", Path::Join(DataDir(), "cache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/public", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache/", DataDir()/"cache")); CTerrain terrain; diff --git a/source/simulation2/tests/test_Simulation2.h b/source/simulation2/tests/test_Simulation2.h index b1d2e8461c..08a9cdf528 100644 --- a/source/simulation2/tests/test_Simulation2.h +++ b/source/simulation2/tests/test_Simulation2.h @@ -42,8 +42,8 @@ public: void setUp() { g_VFS = CreateVfs(20 * MiB); - TS_ASSERT_OK(g_VFS->Mount(L"", Path::Join(DataDir(), "mods/_test.sim"), VFS_MOUNT_MUST_EXIST)); - TS_ASSERT_OK(g_VFS->Mount(L"cache", Path::Join(DataDir(), "_testcache"))); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods/_test.sim", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache")); CXeromyces::Startup(); } @@ -51,7 +51,7 @@ public: { CXeromyces::Terminate(); g_VFS.reset(); - DeleteDirectory(Path::Join(DataDir(), "_testcache")); + DeleteDirectory(DataDir()/"_testcache"); } void test_AddEntity() @@ -130,7 +130,7 @@ public: { CSimulation2 sim(NULL, &m_Terrain); - TS_ASSERT_OK(CreateDirectories(Path::Join(DataDir(), "mods/_test.sim/simulation/components/hotload/"), 0700)); + TS_ASSERT_OK(CreateDirectories(DataDir()/"mods/_test.sim/simulation/components/hotload/", 0700)); copyFile(L"simulation/components/test-hotload1.js", L"simulation/components/hotload/hotload.js"); TS_ASSERT_OK(g_VFS->Invalidate(L"simulation/components/hotload/hotload.js")); @@ -155,7 +155,7 @@ public: TS_ASSERT_EQUALS(static_cast (sim.QueryInterface(ent, IID_Test1))->GetX(), 1000); - TS_ASSERT_OK(DeleteDirectory(Path::Join(DataDir(), "mods/_test.sim/simulation/components/hotload/"))); + TS_ASSERT_OK(DeleteDirectory(DataDir()/"mods/_test.sim/simulation/components/hotload/")); TS_ASSERT_OK(g_VFS->Invalidate(L"simulation/components/hotload/hotload.js")); TS_ASSERT_OK(sim.ReloadChangedFile(L"simulation/components/hotload/hotload.js")); diff --git a/source/sound/JSI_Sound.cpp b/source/sound/JSI_Sound.cpp index 7d346abc1a..c3d580ef3b 100644 --- a/source/sound/JSI_Sound.cpp +++ b/source/sound/JSI_Sound.cpp @@ -19,6 +19,7 @@ #include "JSI_Sound.h" #include "maths/Vector3D.h" +#include "lib/utf8.h" #include "lib/res/sound/snd_mgr.h" #include "lib/res/h_mgr.h" // h_filename #include "ps/Filesystem.h" @@ -180,7 +181,7 @@ void JSI_Sound::ScriptingInit() CStr JSI_Sound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv)) { - return "[object Sound: " + (m_Handle ? CStrW(h_filename(m_Handle)).ToUTF8() : "(null)") + "]"; + return "[object Sound: " + (m_Handle ? utf8_from_wstring(h_filename(m_Handle).string()) : "(null)") + "]"; } JSBool JSI_Sound::Construct(JSContext* cx, uintN argc, jsval* vp) diff --git a/source/sound/SoundGroup.cpp b/source/sound/SoundGroup.cpp index efb41ff83a..735cc61427 100644 --- a/source/sound/SoundGroup.cpp +++ b/source/sound/SoundGroup.cpp @@ -121,7 +121,7 @@ static void HandleError(const std::wstring& message, const VfsPath& pathname, Li { if(err == ERR::AGAIN) return; // open failed because sound is disabled (don't log this) - LOGERROR(L"%ls: pathname=%ls, error=%ld", message.c_str(), pathname.c_str(), err); + LOGERROR(L"%ls: pathname=%ls, error=%ld", message.c_str(), pathname.string().c_str(), err); } void CSoundGroup::PlayNext(const CVector3D& position) @@ -131,7 +131,7 @@ void CSoundGroup::PlayNext(const CVector3D& position) if(!snd_is_playing(m_hReplacement)) { // load up replacement file - const VfsPath pathname(Path::Join(m_filepath, m_intensity_file)); + const VfsPath pathname(m_filepath / m_intensity_file); m_hReplacement = snd_open(g_VFS, pathname); if(m_hReplacement < 0) { @@ -152,7 +152,7 @@ void CSoundGroup::PlayNext(const CVector3D& position) if(TestFlag(eRandOrder)) m_index = (size_t)rand(0, (size_t)filenames.size()); // (note: previously snd_group[m_index] was used in place of hs) - const VfsPath pathname(Path::Join(m_filepath, filenames[m_index])); + const VfsPath pathname(m_filepath / filenames[m_index]); Handle hs = snd_open(g_VFS, pathname); if(hs < 0) { diff --git a/source/test_setup.cpp b/source/test_setup.cpp index c6a11ac2ba..d971c99f43 100644 --- a/source/test_setup.cpp +++ b/source/test_setup.cpp @@ -92,11 +92,11 @@ bool ts_str_contains(const std::wstring& str1, const std::wstring& str2) // contains input files (it is assumed that developer's machines have // write access to those directories). note that argv0 isn't // available, so we use sys_get_executable_name. -NativePath DataDir() +OsPath DataDir() { - NativePath path; + OsPath path; TS_ASSERT_OK(sys_get_executable_name(path)); - return Path::Join(Path::Path(path), "../data"); + return path.Parent()/"../data"; } // Script-based testing setup: @@ -115,8 +115,8 @@ void ScriptTestSetup(ScriptInterface& ifc) // Load the TS_* function definitions // (We don't use VFS because tests might not have the normal VFS paths loaded) - NativePath path = Path::Join(DataDir(), "tests/test_setup.js"); - std::ifstream ifs(StringFromNativePath(path).c_str()); + OsPath path = DataDir()/"tests/test_setup.js"; + std::ifstream ifs(OsString(path).c_str()); debug_assert(ifs.good()); std::string content((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); std::wstring wcontent(content.begin(), content.end()); diff --git a/source/tools/atlas/GameInterface/GameLoop.cpp b/source/tools/atlas/GameInterface/GameLoop.cpp index 7d4113a24a..2501ef3f49 100644 --- a/source/tools/atlas/GameInterface/GameLoop.cpp +++ b/source/tools/atlas/GameInterface/GameLoop.cpp @@ -145,7 +145,7 @@ bool BeginAtlas(const CmdLineArgs& args, const DllLoader& dll) // Tell Atlas the location of the data directory const Paths paths(args); - Atlas_SetDataDirectory(paths.RData().c_str()); + Atlas_SetDataDirectory(paths.RData().string().c_str()); // Register all the handlers for message which might be passed back RegisterHandlers(); diff --git a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp index 1abda44aa0..6fe7865d47 100644 --- a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -100,7 +100,7 @@ MESSAGEHANDLER(LoadMap) MESSAGEHANDLER(SaveMap) { CMapWriter writer; - const VfsPath pathname = Path::Join("maps/scenarios", *msg->filename); + const VfsPath pathname = VfsPath("maps/scenarios") / *msg->filename; writer.SaveMap(pathname, g_Game->GetWorld()->GetTerrain(), g_Renderer.GetWaterManager(), g_Renderer.GetSkyManager(),