Apply clang-format-all.sh using the _clang-format file through all the cpp/.h files. make sure not to apply it to certain serialization structures, since some parser expects the * as part of the name, instead of type. This commit contains no other changes aside from adding and applying clang-format-all.sh
799 lines
20 KiB
C++
799 lines
20 KiB
C++
//========= Copyright Valve Corporation ============//
|
|
#include "compat.h"
|
|
#include "strtools.h"
|
|
#include "pathtools.h"
|
|
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#include <shobjidl.h>
|
|
#include <knownfolders.h>
|
|
#include <shlobj.h>
|
|
#include <share.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
|
|
}
|