Index: third_party/openvr/src/src/vrcommon/pathtools_public.cpp |
diff --git a/third_party/openvr/src/src/vrcommon/pathtools_public.cpp b/third_party/openvr/src/src/vrcommon/pathtools_public.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f43a006db1d9306d54f65555cd59aadd8b588c1e |
--- /dev/null |
+++ b/third_party/openvr/src/src/vrcommon/pathtools_public.cpp |
@@ -0,0 +1,818 @@ |
+//========= Copyright Valve Corporation ============// |
+#include "strtools_public.h" |
+#include "pathtools_public.h" |
+ |
+#if defined( _WIN32) |
+#include <Windows.h> |
+#include <direct.h> |
+#include <Shobjidl.h> |
+#include <KnownFolders.h> |
+#include <Shlobj.h> |
+ |
+#undef GetEnvironmentVariable |
+#else |
+#include <dlfcn.h> |
+#include <stdio.h> |
+#include <unistd.h> |
+#include <stdlib.h> |
+#endif |
+#if defined OSX |
+#include <Foundation/Foundation.h> |
+#include <AppKit/AppKit.h> |
+#include <mach-o/dyld.h> |
+#define _S_IFDIR S_IFDIR // really from tier0/platform.h which we dont have yet |
+#endif |
+ |
+#include <sys/stat.h> |
+ |
+#include <algorithm> |
+ |
+/** Returns the path (including filename) to the current executable */ |
+std::string Path_GetExecutablePath() |
+{ |
+#if defined( _WIN32 ) |
+ wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH]; |
+ char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8]; |
+ ::GetModuleFileNameW( NULL, pwchPath, MAX_UNICODE_PATH ); |
+ WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL ); |
+ delete[] pwchPath; |
+ |
+ std::string sPath = pchPath; |
+ delete[] pchPath; |
+ return sPath; |
+#elif defined( OSX ) |
+ char rchPath[1024]; |
+ uint32_t nBuff = sizeof( rchPath ); |
+ bool bSuccess = _NSGetExecutablePath(rchPath, &nBuff) == 0; |
+ rchPath[nBuff-1] = '\0'; |
+ if( bSuccess ) |
+ return rchPath; |
+ else |
+ return ""; |
+#elif defined LINUX |
+ char rchPath[1024]; |
+ size_t nBuff = sizeof( rchPath ); |
+ ssize_t nRead = readlink("/proc/self/exe", rchPath, nBuff-1 ); |
+ if ( nRead != -1 ) |
+ { |
+ rchPath[ nRead ] = 0; |
+ return rchPath; |
+ } |
+ else |
+ { |
+ return ""; |
+ } |
+#else |
+ AssertMsg( false, "Implement Plat_GetExecutablePath" ); |
+ return ""; |
+#endif |
+ |
+} |
+ |
+/** Returns the path of the current working directory */ |
+std::string Path_GetWorkingDirectory() |
+{ |
+ std::string sPath; |
+#if defined( _WIN32 ) |
+ wchar_t buf[MAX_UNICODE_PATH]; |
+ sPath = UTF16to8( _wgetcwd( buf, MAX_UNICODE_PATH ) ); |
+#else |
+ char buf[ 1024 ]; |
+ sPath = getcwd( buf, sizeof( buf ) ); |
+#endif |
+ return sPath; |
+} |
+ |
+/** Sets the path of the current working directory. Returns true if this was successful. */ |
+bool Path_SetWorkingDirectory( const std::string & sPath ) |
+{ |
+ bool bSuccess; |
+#if defined( _WIN32 ) |
+ std::wstring wsPath = UTF8to16( sPath.c_str() ); |
+ bSuccess = 0 == _wchdir( wsPath.c_str() ); |
+#else |
+ bSuccess = 0 == chdir( sPath.c_str() ); |
+#endif |
+ return bSuccess; |
+} |
+ |
+/** Returns the specified path without its filename */ |
+std::string Path_StripFilename( const std::string & sPath, char slash ) |
+{ |
+ if( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ std::string::size_type n = sPath.find_last_of( slash ); |
+ if( n == std::string::npos ) |
+ return sPath; |
+ else |
+ return std::string( sPath.begin(), sPath.begin() + n ); |
+} |
+ |
+/** returns just the filename from the provided full or relative path. */ |
+std::string Path_StripDirectory( const std::string & sPath, char slash ) |
+{ |
+ if( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ std::string::size_type n = sPath.find_last_of( slash ); |
+ if( n == std::string::npos ) |
+ return sPath; |
+ else |
+ return std::string( sPath.begin() + n + 1, sPath.end() ); |
+} |
+ |
+/** returns just the filename with no extension of the provided filename. |
+* If there is a path the path is left intact. */ |
+std::string Path_StripExtension( const std::string & sPath ) |
+{ |
+ for( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ ) |
+ { |
+ if( *i == '.' ) |
+ { |
+ return std::string( sPath.begin(), i.base() - 1 ); |
+ } |
+ |
+ // if we find a slash there is no extension |
+ if( *i == '\\' || *i == '/' ) |
+ break; |
+ } |
+ |
+ // we didn't find an extension |
+ return sPath; |
+} |
+ |
+/** returns just extension of the provided filename (if any). */ |
+std::string Path_GetExtension( const std::string & sPath ) |
+{ |
+ for ( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ ) |
+ { |
+ if ( *i == '.' ) |
+ { |
+ return std::string( i.base(), sPath.end() ); |
+ } |
+ |
+ // if we find a slash there is no extension |
+ if ( *i == '\\' || *i == '/' ) |
+ break; |
+ } |
+ |
+ // we didn't find an extension |
+ return ""; |
+} |
+ |
+bool Path_IsAbsolute( const std::string & sPath ) |
+{ |
+ if( sPath.empty() ) |
+ return false; |
+ |
+#if defined( WIN32 ) |
+ if ( sPath.size() < 3 ) // must be c:\x or \\x at least |
+ return false; |
+ |
+ if ( sPath[1] == ':' ) // drive letter plus slash, but must test both slash cases |
+ { |
+ if ( sPath[2] == '\\' || sPath[2] == '/' ) |
+ return true; |
+ } |
+ else if ( sPath[0] == '\\' && sPath[1] == '\\' ) // UNC path |
+ return true; |
+#else |
+ if( sPath[0] == '\\' || sPath[0] == '/' ) // any leading slash |
+ return true; |
+#endif |
+ |
+ return false; |
+} |
+ |
+ |
+/** Makes an absolute path from a relative path and a base path */ |
+std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath, char slash ) |
+{ |
+ if( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ if( Path_IsAbsolute( sRelativePath ) ) |
+ return sRelativePath; |
+ else |
+ { |
+ if( !Path_IsAbsolute( sBasePath ) ) |
+ return ""; |
+ |
+ std::string sCompacted = Path_Compact( Path_Join( sBasePath, sRelativePath, slash ), slash ); |
+ if( Path_IsAbsolute( sCompacted ) ) |
+ return sCompacted; |
+ else |
+ return ""; |
+ } |
+} |
+ |
+ |
+/** Fixes the directory separators for the current platform */ |
+std::string Path_FixSlashes( const std::string & sPath, char slash ) |
+{ |
+ if( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ std::string sFixed = sPath; |
+ for( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ ) |
+ { |
+ if( *i == '/' || *i == '\\' ) |
+ *i = slash; |
+ } |
+ |
+ return sFixed; |
+} |
+ |
+ |
+char Path_GetSlash() |
+{ |
+#if defined(_WIN32) |
+ return '\\'; |
+#else |
+ return '/'; |
+#endif |
+} |
+ |
+/** Jams two paths together with the right kind of slash */ |
+std::string Path_Join( const std::string & first, const std::string & second, char slash ) |
+{ |
+ if( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ // only insert a slash if we don't already have one |
+ std::string::size_type nLen = first.length(); |
+ if( !nLen ) |
+ return second; |
+#if defined(_WIN32) |
+ if( first.back() == '\\' || first.back() == '/' ) |
+ nLen--; |
+#else |
+ char last_char = first[first.length()-1]; |
+ if (last_char == '\\' || last_char == '/') |
+ nLen--; |
+#endif |
+ |
+ return first.substr( 0, nLen ) + std::string( 1, slash ) + second; |
+} |
+ |
+ |
+std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash ) |
+{ |
+ return Path_Join( Path_Join( first, second, slash ), third, slash ); |
+} |
+ |
+std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash ) |
+{ |
+ return Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash ); |
+} |
+ |
+std::string Path_Join( |
+ const std::string & first, |
+ const std::string & second, |
+ const std::string & third, |
+ const std::string & fourth, |
+ const std::string & fifth, |
+ char slash ) |
+{ |
+ return Path_Join( Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash ), fifth, slash ); |
+} |
+ |
+ |
+std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash ) |
+{ |
+ if ( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ std::string sPath = sRawPath; |
+ std::string::size_type nCurrent = sRawPath.length(); |
+ if ( nCurrent == 0 ) |
+ return sPath; |
+ |
+ int nLastFound = -1; |
+ nCurrent--; |
+ while( nCurrent != 0 ) |
+ { |
+ if ( sRawPath[ nCurrent ] == slash ) |
+ { |
+ nLastFound = (int)nCurrent; |
+ nCurrent--; |
+ } |
+ else |
+ { |
+ break; |
+ } |
+ } |
+ |
+ if ( nLastFound >= 0 ) |
+ { |
+ sPath.erase( nLastFound, std::string::npos ); |
+ } |
+ |
+ return sPath; |
+} |
+ |
+ |
+/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the |
+* specified path has a broken number of directories for its number of ..s */ |
+std::string Path_Compact( const std::string & sRawPath, char slash ) |
+{ |
+ if( slash == 0 ) |
+ slash = Path_GetSlash(); |
+ |
+ std::string sPath = Path_FixSlashes( sRawPath, slash ); |
+ std::string sSlashString( 1, slash ); |
+ |
+ // strip out all /./ |
+ for( std::string::size_type i = 0; (i + 3) < sPath.length(); ) |
+ { |
+ if( sPath[ i ] == slash && sPath[ i+1 ] == '.' && sPath[ i+2 ] == slash ) |
+ { |
+ sPath.replace( i, 3, sSlashString ); |
+ } |
+ else |
+ { |
+ ++i; |
+ } |
+ } |
+ |
+ |
+ // get rid of trailing /. but leave the path separator |
+ if( sPath.length() > 2 ) |
+ { |
+ std::string::size_type len = sPath.length(); |
+ if( sPath[ len-1 ] == '.' && sPath[ len-2 ] == slash ) |
+ { |
+ // sPath.pop_back(); |
+ sPath[len-1] = 0; // for now, at least |
+ } |
+ } |
+ |
+ // get rid of leading ./ |
+ if( sPath.length() > 2 ) |
+ { |
+ if( sPath[ 0 ] == '.' && sPath[ 1 ] == slash ) |
+ { |
+ sPath.replace( 0, 2, "" ); |
+ } |
+ } |
+ |
+ // each time we encounter .. back up until we've found the previous directory name |
+ // then get rid of both |
+ std::string::size_type i = 0; |
+ while( i < sPath.length() ) |
+ { |
+ if( i > 0 && sPath.length() - i >= 2 |
+ && sPath[i] == '.' |
+ && sPath[i+1] == '.' |
+ && ( i + 2 == sPath.length() || sPath[ i+2 ] == slash ) |
+ && sPath[ i-1 ] == slash ) |
+ { |
+ // check if we've hit the start of the string and have a bogus path |
+ if( i == 1 ) |
+ return ""; |
+ |
+ // find the separator before i-1 |
+ std::string::size_type iDirStart = i-2; |
+ while( iDirStart > 0 && sPath[ iDirStart - 1 ] != slash ) |
+ --iDirStart; |
+ |
+ // remove everything from iDirStart to i+2 |
+ sPath.replace( iDirStart, (i - iDirStart) + 3, "" ); |
+ |
+ // start over |
+ i = 0; |
+ } |
+ else |
+ { |
+ ++i; |
+ } |
+ } |
+ |
+ return sPath; |
+} |
+ |
+ |
+/** Returns the path to the current DLL or exe */ |
+std::string Path_GetThisModulePath() |
+{ |
+ // gets the path of vrclient.dll itself |
+#ifdef WIN32 |
+ HMODULE hmodule = NULL; |
+ |
+ ::GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCTSTR>(Path_GetThisModulePath), &hmodule ); |
+ |
+ wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH]; |
+ char *pchPath = new char[ MAX_UNICODE_PATH_IN_UTF8 ]; |
+ ::GetModuleFileNameW( hmodule, pwchPath, MAX_UNICODE_PATH ); |
+ WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL ); |
+ delete[] pwchPath; |
+ |
+ std::string sPath = pchPath; |
+ delete [] pchPath; |
+ return sPath; |
+ |
+#elif defined( OSX ) || defined( LINUX ) |
+ // get the addr of a function in vrclient.so and then ask the dlopen system about it |
+ Dl_info info; |
+ dladdr( (void *)Path_GetThisModulePath, &info ); |
+ return info.dli_fname; |
+#endif |
+ |
+} |
+ |
+ |
+/** returns true if the specified path exists and is a directory */ |
+bool Path_IsDirectory( const std::string & sPath ) |
+{ |
+ std::string sFixedPath = Path_FixSlashes( sPath ); |
+ if( sFixedPath.empty() ) |
+ return false; |
+ char cLast = sFixedPath[ sFixedPath.length() - 1 ]; |
+ if( cLast == '/' || cLast == '\\' ) |
+ sFixedPath.erase( sFixedPath.end() - 1, sFixedPath.end() ); |
+ |
+ // see if the specified path actually exists. |
+ |
+#if defined(POSIX) |
+ struct stat buf; |
+ if ( stat( sFixedPath.c_str(), &buf ) == -1 ) |
+ { |
+ return false; |
+ } |
+ |
+#if defined( LINUX ) || defined( OSX ) |
+ return S_ISDIR( buf.st_mode ); |
+#else |
+ return (buf.st_mode & _S_IFDIR) != 0; |
+#endif |
+ |
+#else |
+ struct _stat buf; |
+ std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() ); |
+ if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 ) |
+ { |
+ return false; |
+ } |
+ |
+ return (buf.st_mode & _S_IFDIR) != 0; |
+#endif |
+} |
+ |
+/** returns true if the specified path represents an app bundle */ |
+bool Path_IsAppBundle( const std::string & sPath ) |
+{ |
+#if defined(OSX) |
+ NSBundle *bundle = [ NSBundle bundleWithPath: [ NSString stringWithUTF8String:sPath.c_str() ] ]; |
+ bool bisAppBundle = ( nullptr != bundle ); |
+ [ bundle release ]; |
+ return bisAppBundle; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+//----------------------------------------------------------------------------- |
+// Purpose: returns true if the the path exists |
+//----------------------------------------------------------------------------- |
+bool Path_Exists( const std::string & sPath ) |
+{ |
+ std::string sFixedPath = Path_FixSlashes( sPath ); |
+ if( sFixedPath.empty() ) |
+ return false; |
+ |
+#if defined( WIN32 ) |
+ struct _stat buf; |
+ std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() ); |
+ if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 ) |
+ { |
+ return false; |
+ } |
+#else |
+ struct stat buf; |
+ if ( stat ( sFixedPath.c_str(), &buf ) == -1) |
+ { |
+ return false; |
+ } |
+#endif |
+ |
+ return true; |
+} |
+ |
+ |
+//----------------------------------------------------------------------------- |
+// Purpose: helper to find a directory upstream from a given path |
+//----------------------------------------------------------------------------- |
+std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName ) |
+{ |
+ std::string strFoundPath = ""; |
+ std::string strCurrentPath = Path_FixSlashes( strStartDirectory ); |
+ if ( strCurrentPath.length() == 0 ) |
+ return ""; |
+ |
+ bool bExists = Path_Exists( strCurrentPath ); |
+ std::string strCurrentDirectoryName = Path_StripDirectory( strCurrentPath ); |
+ if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 ) |
+ return strCurrentPath; |
+ |
+ while( bExists && strCurrentPath.length() != 0 ) |
+ { |
+ strCurrentPath = Path_StripFilename( strCurrentPath ); |
+ strCurrentDirectoryName = Path_StripDirectory( strCurrentPath ); |
+ bExists = Path_Exists( strCurrentPath ); |
+ if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 ) |
+ return strCurrentPath; |
+ } |
+ |
+ return ""; |
+} |
+ |
+ |
+//----------------------------------------------------------------------------- |
+// Purpose: helper to find a subdirectory upstream from a given path |
+//----------------------------------------------------------------------------- |
+std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName ) |
+{ |
+ std::string strFoundPath = ""; |
+ std::string strCurrentPath = Path_FixSlashes( strStartDirectory ); |
+ if ( strCurrentPath.length() == 0 ) |
+ return ""; |
+ |
+ bool bExists = Path_Exists( strCurrentPath ); |
+ while( bExists && strCurrentPath.length() != 0 ) |
+ { |
+ strCurrentPath = Path_StripFilename( strCurrentPath ); |
+ bExists = Path_Exists( strCurrentPath ); |
+ |
+ if( Path_Exists( Path_Join( strCurrentPath, strDirectoryName ) ) ) |
+ { |
+ strFoundPath = Path_Join( strCurrentPath, strDirectoryName ); |
+ break; |
+ } |
+ } |
+ return strFoundPath; |
+} |
+ |
+ |
+//----------------------------------------------------------------------------- |
+// Purpose: reading and writing files in the vortex directory |
+//----------------------------------------------------------------------------- |
+unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize ) |
+{ |
+ FILE *f; |
+#if defined( POSIX ) |
+ f = fopen( strFilename.c_str(), "rb" ); |
+#else |
+ std::wstring wstrFilename = UTF8to16( strFilename.c_str() ); |
+ // the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s |
+ f = _wfsopen( wstrFilename.c_str(), L"rb", _SH_DENYNO ); |
+#endif |
+ |
+ unsigned char* buf = NULL; |
+ |
+ if ( f != NULL ) |
+ { |
+ fseek(f, 0, SEEK_END); |
+ int size = ftell(f); |
+ fseek(f, 0, SEEK_SET); |
+ |
+ buf = new unsigned char[size]; |
+ if (buf && fread(buf, size, 1, f) == 1) |
+ { |
+ if (pSize) |
+ *pSize = size; |
+ } |
+ else |
+ { |
+ delete[] buf; |
+ buf = 0; |
+ } |
+ |
+ fclose(f); |
+ } |
+ |
+ return buf; |
+} |
+ |
+uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize ) |
+{ |
+ FILE *f; |
+#if defined( POSIX ) |
+ f = fopen( strFilename.c_str(), "rb" ); |
+#else |
+ std::wstring wstrFilename = UTF8to16( strFilename.c_str() ); |
+ errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"rb" ); |
+ if ( err != 0 ) |
+ { |
+ f = NULL; |
+ } |
+#endif |
+ |
+ uint32_t unSizeToReturn = 0; |
+ |
+ if ( f != NULL ) |
+ { |
+ fseek( f, 0, SEEK_END ); |
+ uint32_t size = (uint32_t)ftell( f ); |
+ fseek( f, 0, SEEK_SET ); |
+ |
+ if ( size > unSize || !pBuffer ) |
+ { |
+ unSizeToReturn = (uint32_t)size; |
+ } |
+ else |
+ { |
+ if ( fread( pBuffer, size, 1, f ) == 1 ) |
+ { |
+ unSizeToReturn = (uint32_t)size; |
+ } |
+ } |
+ |
+ fclose( f ); |
+ } |
+ |
+ return unSizeToReturn; |
+} |
+ |
+bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize) |
+{ |
+ FILE *f; |
+#if defined( POSIX ) |
+ f = fopen(strFilename.c_str(), "wb"); |
+#else |
+ std::wstring wstrFilename = UTF8to16( strFilename.c_str() ); |
+ errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"wb" ); |
+ if (err != 0) |
+ { |
+ f = NULL; |
+ } |
+#endif |
+ |
+ size_t written = 0; |
+ if (f != NULL) { |
+ written = fwrite(pData, sizeof(unsigned char), nSize, f); |
+ fclose(f); |
+ } |
+ |
+ return written = nSize ? true : false; |
+} |
+ |
+std::string Path_ReadTextFile( const std::string &strFilename ) |
+{ |
+ // doing it this way seems backwards, but I don't |
+ // see an easy way to do this with C/C++ style IO |
+ // that isn't worse... |
+ int size; |
+ unsigned char* buf = Path_ReadBinaryFile( strFilename, &size ); |
+ if (!buf) |
+ return ""; |
+ |
+ // convert CRLF -> LF |
+ size_t outsize = 1; |
+ for (int i=1; i < size; i++) |
+ { |
+ if (buf[i] == '\n' && buf[i-1] == '\r') // CRLF |
+ buf[outsize-1] = '\n'; // ->LF |
+ else |
+ buf[outsize++] = buf[i]; // just copy |
+ } |
+ |
+ std::string ret((char *)buf, outsize); |
+ delete[] buf; |
+ return ret; |
+} |
+ |
+ |
+bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData ) |
+{ |
+ FILE *f; |
+#if defined( POSIX ) |
+ f = fopen( strFilename.c_str(), "w" ); |
+#else |
+ std::wstring wstrFilename = UTF8to16( strFilename.c_str() ); |
+ errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"w" ); |
+ if ( err != 0 ) |
+ { |
+ f = NULL; |
+ } |
+#endif |
+ |
+ bool ok = false; |
+ |
+ if ( f != NULL ) |
+ { |
+ ok = fputs( pchData, f) >= 0; |
+ fclose(f); |
+ } |
+ |
+ return ok; |
+} |
+ |
+bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData ) |
+{ |
+ std::string strTmpFilename = strFilename + ".tmp"; |
+ |
+ if ( !Path_WriteStringToTextFile( strTmpFilename, pchData ) ) |
+ return false; |
+ |
+ // Platform specific atomic file replacement |
+#if defined( _WIN32 ) |
+ std::wstring wsFilename = UTF8to16( strFilename.c_str() ); |
+ std::wstring wsTmpFilename = UTF8to16( strTmpFilename.c_str() ); |
+ if ( !::ReplaceFileW( wsFilename.c_str(), wsTmpFilename.c_str(), nullptr, 0, 0, 0 ) ) |
+ { |
+ // if we couldn't ReplaceFile, try a non-atomic write as a fallback |
+ if ( !Path_WriteStringToTextFile( strFilename, pchData ) ) |
+ return false; |
+ } |
+#elif defined( POSIX ) |
+ if ( rename( strTmpFilename.c_str(), strFilename.c_str() ) == -1 ) |
+ return false; |
+#else |
+#error Do not know how to write atomic file |
+#endif |
+ |
+ return true; |
+} |
+ |
+ |
+#if defined(WIN32) |
+#define FILE_URL_PREFIX "file:///" |
+#else |
+#define FILE_URL_PREFIX "file://" |
+#endif |
+ |
+// ---------------------------------------------------------------------------------------------------------------------------- |
+// Purpose: Turns a path to a file on disk into a URL (or just returns the value if it's already a URL) |
+// ---------------------------------------------------------------------------------------------------------------------------- |
+std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath ) |
+{ |
+ if ( !strnicmp( sRelativePath.c_str(), "http://", 7 ) |
+ || !strnicmp( sRelativePath.c_str(), "https://", 8 ) |
+ || !strnicmp( sRelativePath.c_str(), "file://", 7 ) ) |
+ { |
+ return sRelativePath; |
+ } |
+ else |
+ { |
+ std::string sAbsolute = Path_MakeAbsolute( sRelativePath, sBasePath ); |
+ if ( sAbsolute.empty() ) |
+ return sAbsolute; |
+ return std::string( FILE_URL_PREFIX ) + sAbsolute; |
+ } |
+} |
+ |
+// ----------------------------------------------------------------------------------------------------- |
+// Purpose: Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned |
+// ----------------------------------------------------------------------------------------------------- |
+std::string Path_UrlToFilePath( const std::string & sFileUrl ) |
+{ |
+ if ( !strnicmp( sFileUrl.c_str(), FILE_URL_PREFIX, strlen( FILE_URL_PREFIX ) ) ) |
+ { |
+ return sFileUrl.c_str() + strlen( FILE_URL_PREFIX ); |
+ } |
+ else |
+ { |
+ return ""; |
+ } |
+} |
+ |
+ |
+// ----------------------------------------------------------------------------------------------------- |
+// Purpose: Returns the root of the directory the system wants us to store user documents in |
+// ----------------------------------------------------------------------------------------------------- |
+std::string GetUserDocumentsPath() |
+{ |
+#if defined( WIN32 ) |
+ WCHAR rwchPath[MAX_PATH]; |
+ |
+ if ( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) ) |
+ { |
+ return ""; |
+ } |
+ |
+ // Convert the path to UTF-8 and store in the output |
+ std::string sUserPath = UTF16to8( rwchPath ); |
+ |
+ return sUserPath; |
+#elif defined( OSX ) |
+ @autoreleasepool { |
+ NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES ); |
+ if ( [paths count] == 0 ) |
+ { |
+ return ""; |
+ } |
+ |
+ return [[paths objectAtIndex:0] UTF8String]; |
+ } |
+#elif defined( LINUX ) |
+ // @todo: not solved/changed as part of OSX - still not real - just removed old class based steam cut and paste |
+ const char *pchHome = getenv( "HOME" ); |
+ if ( pchHome == NULL ) |
+ { |
+ return ""; |
+ } |
+ return pchHome; |
+#endif |
+} |
+ |