tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vrpathregistry_public.cpp (12070B)


      1 //========= Copyright Valve Corporation ============//
      2 
      3 #include "vrpathregistry_public.h"
      4 #include "json/json.h"
      5 #include "pathtools_public.h"
      6 #include "envvartools_public.h"
      7 #include "strtools_public.h"
      8 #include "dirtools_public.h"
      9 
     10 #if defined( WIN32 )
     11 #include <windows.h>
     12 #include <shlobj.h>
     13 
     14 #undef GetEnvironmentVariable
     15 #elif defined OSX
     16 #include <Foundation/Foundation.h>
     17 #include <AppKit/AppKit.h>
     18 #elif defined(LINUX)
     19 #include <dlfcn.h>
     20 #include <stdio.h>
     21 #endif
     22 
     23 #include <algorithm>
     24 
     25 #ifndef VRLog
     26 #if defined( __MINGW32__ )
     27 	#define VRLog(args...)		fprintf(stderr, args)
     28 #elif defined( WIN32 )
     29 	#define VRLog(fmt, ...)		fprintf(stderr, fmt, __VA_ARGS__)
     30 #else
     31 	#define VRLog(args...)		fprintf(stderr, args)
     32 #endif
     33 #endif
     34 
     35 /** Returns the root of the directory the system wants us to store user config data in */
     36 static std::string GetAppSettingsPath()
     37 {
     38 #if defined( WIN32 )
     39 WCHAR rwchPath[MAX_PATH];
     40 
     41 if( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
     42 {
     43 	return "";
     44 }
     45 
     46 // Convert the path to UTF-8 and store in the output
     47 std::string sUserPath = UTF16to8( rwchPath );
     48 
     49 return sUserPath;
     50 #elif defined( OSX )
     51 std::string sSettingsDir;
     52 @autoreleasepool {
     53 	// Search for the path
     54 	NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
     55 	if ( [paths count] == 0 )
     56 	{
     57 		return "";
     58 	}
     59 	
     60 	NSString *resolvedPath = [paths objectAtIndex:0];
     61 	resolvedPath = [resolvedPath stringByAppendingPathComponent: @"OpenVR"];
     62 	
     63 	if ( ![[NSFileManager defaultManager] createDirectoryAtPath: resolvedPath withIntermediateDirectories:YES attributes:nil error:nil] )
     64 	{
     65 		return "";
     66 	}
     67 	
     68 	sSettingsDir.assign( [resolvedPath UTF8String] );
     69 }
     70 return sSettingsDir;
     71 #elif defined( LINUX )
     72 
     73 // As defined by XDG Base Directory Specification 
     74 // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
     75 
     76 const char *pchHome = getenv("XDG_CONFIG_HOME");
     77 if ( ( pchHome != NULL) && ( pchHome[0] != '\0' ) )
     78 {
     79 	return pchHome;
     80 }
     81 
     82 //
     83 // XDG_CONFIG_HOME is not defined, use ~/.config instead
     84 // 
     85 pchHome = getenv( "HOME" );
     86 if ( pchHome == NULL )
     87 {
     88 	return "";
     89 }
     90 
     91 std::string sUserPath( pchHome );
     92 sUserPath = Path_Join( sUserPath, ".config" );
     93 return sUserPath;
     94 #else
     95 #warning "Unsupported platform"
     96 #endif
     97 }
     98 
     99 
    100 // ---------------------------------------------------------------------------
    101 // Purpose: Constructor
    102 // ---------------------------------------------------------------------------
    103 CVRPathRegistry_Public::CVRPathRegistry_Public()
    104 {
    105 
    106 }
    107 
    108 // ---------------------------------------------------------------------------
    109 // Purpose: Computes the registry filename
    110 // ---------------------------------------------------------------------------
    111 std::string CVRPathRegistry_Public::GetOpenVRConfigPath()
    112 {
    113 std::string sConfigPath = GetAppSettingsPath();
    114 if( sConfigPath.empty() )
    115 	return "";
    116 
    117 #if defined( _WIN32 ) || defined( LINUX )
    118 sConfigPath = Path_Join( sConfigPath, "openvr" );
    119 #elif defined ( OSX ) 
    120 sConfigPath = Path_Join( sConfigPath, ".openvr" );
    121 #else
    122 #warning "Unsupported platform"
    123 #endif
    124 sConfigPath = Path_FixSlashes( sConfigPath );
    125 return sConfigPath;
    126 }
    127 
    128 
    129 
    130 //-----------------------------------------------------------------------------
    131 // Purpose:
    132 //-----------------------------------------------------------------------------
    133 std::string CVRPathRegistry_Public::GetVRPathRegistryFilename()
    134 {
    135 std::string sOverridePath = GetEnvironmentVariable( "VR_PATHREG_OVERRIDE" );
    136 if ( !sOverridePath.empty() )
    137 	return sOverridePath;
    138 
    139 std::string sPath = GetOpenVRConfigPath();
    140 if ( sPath.empty() )
    141 	return "";
    142 
    143 #if defined( _WIN32 )
    144 sPath = Path_Join( sPath, "openvrpaths.vrpath" );
    145 #elif defined ( POSIX ) 
    146 sPath = Path_Join( sPath, "openvrpaths.vrpath" );
    147 #else
    148 #error "Unsupported platform"
    149 #endif
    150 sPath = Path_FixSlashes( sPath );
    151 return sPath;
    152 }
    153 
    154 
    155 // ---------------------------------------------------------------------------
    156 // Purpose: Converts JSON to a history array
    157 // ---------------------------------------------------------------------------
    158 static void ParseStringListFromJson( std::vector< std::string > *pvecHistory, const Json::Value & root, const char *pchArrayName )
    159 {
    160 if( !root.isMember( pchArrayName ) )
    161 	return;
    162 
    163 const Json::Value & arrayNode = root[ pchArrayName ];
    164 if( !arrayNode )
    165 {
    166 	VRLog( "VR Path Registry node %s is not an array\n", pchArrayName );
    167 	return;
    168 }
    169 
    170 pvecHistory->clear();
    171 pvecHistory->reserve( arrayNode.size() );
    172 for( uint32_t unIndex = 0; unIndex < arrayNode.size(); unIndex++ )
    173 {
    174 	std::string sPath( arrayNode[ unIndex ].asString() );
    175 	pvecHistory->push_back( sPath );
    176 }
    177 }
    178 
    179 
    180 // ---------------------------------------------------------------------------
    181 // Purpose: Converts a history array to JSON
    182 // ---------------------------------------------------------------------------
    183 static void StringListToJson( const std::vector< std::string > & vecHistory, Json::Value & root, const char *pchArrayName )
    184 {
    185 Json::Value & arrayNode = root[ pchArrayName ];
    186 for( auto i = vecHistory.begin(); i != vecHistory.end(); i++ )
    187 {
    188 	arrayNode.append( *i );
    189 }
    190 }
    191 
    192 
    193 //-----------------------------------------------------------------------------
    194 // Purpose:
    195 //-----------------------------------------------------------------------------
    196 bool CVRPathRegistry_Public::ToJsonString( std::string &sJsonString )
    197 {
    198 std::string sRegPath = GetVRPathRegistryFilename();
    199 if( sRegPath.empty() )
    200 	return false;
    201 
    202 std::string sRegistryContents = Path_ReadTextFile( sRegPath );
    203 if( sRegistryContents.empty() )
    204 	return false;
    205 
    206 sJsonString = sRegistryContents;
    207 
    208 return true;
    209 }
    210 
    211 // Mozilla: see mozilla.patch for more details
    212 // ---------------------------------------------------------------------------
    213 // Purpose: Loads the config file from its well known location
    214 // ---------------------------------------------------------------------------
    215 bool CVRPathRegistry_Public::BLoadFromFile( std::string *psLoadError )
    216 {
    217 std::string sRegPath = GetVRPathRegistryFilename();
    218 if( sRegPath.empty() )
    219 {
    220 	if ( psLoadError )
    221 	{
    222 		*psLoadError = "Unable to determine VR Path Registry filename";
    223 	}
    224 	return false;
    225 }
    226 
    227 std::string sRegistryContents = Path_ReadTextFile( sRegPath );
    228 if( sRegistryContents.empty() )
    229 {
    230 	if ( psLoadError )
    231 	{
    232 		*psLoadError = "Unable to read VR Path Registry from " + sRegPath;
    233 	}
    234 	return false;
    235 }
    236 
    237 Json::Value root;
    238 Json::CharReaderBuilder builder;
    239 std::istringstream istream( sRegistryContents );
    240 std::string sErrors;
    241 
    242 // try
    243 {
    244 	if ( !parseFromStream( builder, istream, &root, &sErrors ) )
    245 	{
    246 		if ( psLoadError )
    247 		{
    248 			*psLoadError = "Unable to parse " + sRegPath + ": " + sErrors;
    249 		}
    250 		return false;
    251 	}
    252 
    253 	ParseStringListFromJson( &m_vecRuntimePath, root, "runtime" );
    254 	ParseStringListFromJson( &m_vecConfigPath, root, "config" );
    255 	ParseStringListFromJson( &m_vecLogPath, root, "log" );
    256 	if ( root.isMember( "external_drivers" ) && root["external_drivers"].isArray() )
    257 	{
    258 		ParseStringListFromJson( &m_vecExternalDrivers, root, "external_drivers" );
    259 	}
    260 }
    261 // catch ( ... )
    262 // {
    263 // 	if ( psLoadError )
    264 // 	{
    265 // 		*psLoadError = "Unable to parse " + sRegPath + ": exception thrown in JSON library";
    266 // 	}
    267 // 	return false;
    268 // }
    269 
    270 return true;
    271 }
    272 
    273 
    274 // ---------------------------------------------------------------------------
    275 // Purpose: Saves the config file to its well known location
    276 // ---------------------------------------------------------------------------
    277 bool CVRPathRegistry_Public::BSaveToFile() const
    278 {
    279 std::string sRegPath = GetVRPathRegistryFilename();
    280 if( sRegPath.empty() )
    281 	return false;
    282 
    283 Json::Value root;
    284 
    285 root[ "version" ] = 1;
    286 root[ "jsonid" ] = "vrpathreg";
    287 
    288 StringListToJson( m_vecRuntimePath, root, "runtime" );
    289 StringListToJson( m_vecConfigPath, root, "config" );
    290 StringListToJson( m_vecLogPath, root, "log" );
    291 StringListToJson( m_vecExternalDrivers, root, "external_drivers" );
    292 
    293 Json::StreamWriterBuilder builder;
    294 std::string sRegistryContents = Json::writeString( builder, root );
    295 
    296 // make sure the directory we're writing into actually exists
    297 std::string sRegDirectory = Path_StripFilename( sRegPath );
    298 if( !BCreateDirectoryRecursive( sRegDirectory.c_str() ) )
    299 {
    300 	VRLog( "Unable to create path registry directory %s\n", sRegDirectory.c_str() );
    301 	return false;
    302 }
    303 
    304 if( !Path_WriteStringToTextFile( sRegPath, sRegistryContents.c_str() ) )
    305 {
    306 	VRLog( "Unable to write VR path registry to %s\n", sRegPath.c_str() );
    307 	return false;
    308 }
    309 
    310 return true;
    311 }
    312 
    313 
    314 // ---------------------------------------------------------------------------
    315 // Purpose: Returns the current runtime path or NULL if no path is configured.
    316 // ---------------------------------------------------------------------------
    317 std::string CVRPathRegistry_Public::GetRuntimePath() const
    318 {
    319 if( m_vecRuntimePath.empty() )
    320 	return "";
    321 else
    322 	return m_vecRuntimePath.front().c_str();
    323 }
    324 
    325 
    326 // ---------------------------------------------------------------------------
    327 // Purpose: Returns the current config path or NULL if no path is configured.
    328 // ---------------------------------------------------------------------------
    329 std::string CVRPathRegistry_Public::GetConfigPath() const
    330 {
    331 if( m_vecConfigPath.empty() )
    332 	return "";
    333 else
    334 	return m_vecConfigPath.front().c_str();
    335 }
    336 
    337 
    338 // ---------------------------------------------------------------------------
    339 // Purpose: Returns the current log path or NULL if no path is configured.
    340 // ---------------------------------------------------------------------------
    341 std::string CVRPathRegistry_Public::GetLogPath() const
    342 {
    343 if( m_vecLogPath.empty() )
    344 	return "";
    345 else
    346 	return m_vecLogPath.front().c_str();
    347 }
    348 
    349 
    350 
    351 // ---------------------------------------------------------------------------
    352 // Purpose: Returns paths using the path registry and the provided override 
    353 //			values. Pass NULL for any paths you don't care about.
    354 // ---------------------------------------------------------------------------
    355 bool CVRPathRegistry_Public::GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers )
    356 {
    357 std::string sLoadError;
    358 CVRPathRegistry_Public pathReg;
    359 bool bLoadedRegistry = pathReg.BLoadFromFile( &sLoadError );
    360 int nCountEnvironmentVariables = 0;
    361 int nRequestedPaths = 0;
    362 
    363 if( psRuntimePath )
    364 {
    365 	nRequestedPaths++;
    366 	if ( GetEnvironmentVariable( k_pchRuntimeOverrideVar ).length() != 0 )
    367 	{
    368 		*psRuntimePath = GetEnvironmentVariable( k_pchRuntimeOverrideVar );
    369 		nCountEnvironmentVariables++;
    370 	}
    371 	else if( !pathReg.GetRuntimePath().empty() )
    372 	{
    373 		*psRuntimePath = pathReg.GetRuntimePath();
    374 	}
    375 	else
    376 	{
    377 		*psRuntimePath = "";
    378 	}
    379 }
    380 
    381 if( psConfigPath )
    382 {
    383 	nRequestedPaths++;
    384 	if ( GetEnvironmentVariable( k_pchConfigOverrideVar ).length() != 0 )
    385 	{
    386 		*psConfigPath = GetEnvironmentVariable( k_pchConfigOverrideVar );
    387 		nCountEnvironmentVariables++;
    388 	}
    389 	else if( pchConfigPathOverride )
    390 	{
    391 		*psConfigPath = pchConfigPathOverride;
    392 	}
    393 	else if( !pathReg.GetConfigPath().empty() )
    394 	{
    395 		*psConfigPath = pathReg.GetConfigPath();
    396 	}
    397 	else
    398 	{
    399 		*psConfigPath = "";
    400 	}
    401 }
    402 
    403 if( psLogPath )
    404 {
    405 	nRequestedPaths++;
    406 	if ( GetEnvironmentVariable( k_pchLogOverrideVar ).length() != 0 )
    407 	{
    408 		*psLogPath = GetEnvironmentVariable( k_pchLogOverrideVar );
    409 		nCountEnvironmentVariables++;
    410 	}
    411 	else if( pchLogPathOverride )
    412 	{
    413 		*psLogPath = pchLogPathOverride;
    414 	}
    415 	else if( !pathReg.GetLogPath().empty() )
    416 	{
    417 		*psLogPath = pathReg.GetLogPath();
    418 	}
    419 	else
    420 	{
    421 		*psLogPath = "";
    422 	}
    423 }
    424 
    425 if ( pvecExternalDrivers )
    426 {
    427 	*pvecExternalDrivers = pathReg.m_vecExternalDrivers;
    428 }
    429 
    430 if ( nCountEnvironmentVariables == nRequestedPaths )
    431 {
    432 	// all three environment variables were set, so we don't need the physical file
    433 	return true;
    434 }
    435 else if( !bLoadedRegistry )
    436 {
    437 	VRLog( "%s\n", sLoadError.c_str() );
    438 }
    439 
    440 return bLoadedRegistry;
    441 }