Vendoring OpenVR

This commit is contained in:
dsc 2021-04-05 13:36:39 +02:00
parent 96034902d1
commit aad58b1c83
32 changed files with 38364 additions and 0 deletions

View file

@ -0,0 +1,101 @@
//========= Copyright Valve Corporation ============//
#include <vrcommon/dirtools_public.h>
#include <vrcommon/strtools_public.h>
#include <vrcommon/pathtools_public.h>
#include <errno.h>
#include <string.h>
#ifdef _WIN32
#include "windows.h"
#else
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#if defined( OSX )
#include <sys/syslimits.h>
#endif
//-----------------------------------------------------------------------------
// Purpose: utility function to create dirs & subdirs
//-----------------------------------------------------------------------------
bool BCreateDirectoryRecursive( const char *pchPath )
{
// Does it already exist?
if ( Path_IsDirectory( pchPath ) )
return true;
// copy the path into something we can munge
int len = (int)strlen( pchPath );
char *path = (char *)malloc( len + 1 );
strcpy( path, pchPath );
// Walk backwards to first non-existing dir that we find
char *s = path + len - 1;
const char slash = Path_GetSlash();
while ( s > path )
{
if ( *s == slash )
{
*s = '\0';
bool bExists = Path_IsDirectory( path );
*s = slash;
if ( bExists )
{
++s;
break;
}
}
--s;
}
// and then move forwards from there
while ( *s )
{
if ( *s == slash )
{
*s = '\0';
BCreateDirectory( path );
*s = slash;
}
s++;
}
bool bRetVal = BCreateDirectory( path );
free( path );
return bRetVal;
}
//-----------------------------------------------------------------------------
// Purpose: Creates the directory, returning true if it is created, or if it already existed
//-----------------------------------------------------------------------------
bool BCreateDirectory( const char *pchPath )
{
#ifdef WIN32
std::wstring wPath = UTF8to16( pchPath );
if ( ::CreateDirectoryW( wPath.c_str(), NULL ) )
return true;
if ( ::GetLastError() == ERROR_ALREADY_EXISTS )
return true;
return false;
#else
int i = mkdir( pchPath, S_IRWXU | S_IRWXG | S_IRWXO );
if ( i == 0 )
return true;
if ( errno == EEXIST )
return true;
return false;
#endif
}

View file

@ -0,0 +1,17 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <stdint.h>
#include <string>
#if !defined(_WIN32)
#include <sys/types.h>
#include <sys/stat.h>
#endif
extern bool BCreateDirectoryRecursive( const char *pchPath );
extern bool BCreateDirectory( const char *pchPath );

View file

@ -0,0 +1,88 @@
//========= Copyright Valve Corporation ============//
#include <vrcommon/envvartools_public.h>
#include <vrcommon/strtools_public.h>
#include <stdlib.h>
#include <string>
#include <cctype>
#if defined(_WIN32)
#include <windows.h>
#undef GetEnvironmentVariable
#undef SetEnvironmentVariable
#endif
std::string GetEnvironmentVariable( const char *pchVarName )
{
#if defined(_WIN32)
char rchValue[32767]; // max size for an env var on Windows
DWORD cChars = GetEnvironmentVariableA( pchVarName, rchValue, sizeof( rchValue ) );
if( cChars == 0 )
return "";
else
return rchValue;
#elif defined(POSIX)
char *pchValue = getenv( pchVarName );
if( pchValue )
return pchValue;
else
return "";
#else
#error "Unsupported Platform"
#endif
}
bool GetEnvironmentVariableAsBool( const char *pchVarName, bool bDefault )
{
std::string sValue = GetEnvironmentVariable( pchVarName );
if ( sValue.empty() )
{
return bDefault;
}
sValue = StringToLower( sValue );
std::string sYesValues[] = { "y", "yes", "true" };
std::string sNoValues[] = { "n", "no", "false" };
for ( std::string &sMatch : sYesValues )
{
if ( sMatch == sValue )
{
return true;
}
}
for ( std::string &sMatch : sNoValues )
{
if ( sMatch == sValue )
{
return false;
}
}
if ( std::isdigit( sValue.at(0) ) )
{
return atoi( sValue.c_str() ) != 0;
}
fprintf( stderr,
"GetEnvironmentVariableAsBool(%s): Unable to parse value '%s', using default %d\n",
pchVarName, sValue.c_str(), bDefault );
return bDefault;
}
bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue )
{
#if defined(_WIN32)
return 0 != SetEnvironmentVariableA( pchVarName, pchVarValue );
#elif defined(POSIX)
if( pchVarValue == NULL )
return 0 == unsetenv( pchVarName );
else
return 0 == setenv( pchVarName, pchVarValue, 1 );
#else
#error "Unsupported Platform"
#endif
}

View file

@ -0,0 +1,8 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
std::string GetEnvironmentVariable( const char *pchVarName );
bool GetEnvironmentVariableAsBool( const char *pchVarName, bool bDefault );
bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue );

View file

@ -0,0 +1,338 @@
//========= Copyright Valve Corporation ============//
#include "openvr.h"
#include "hmderrors_public.h"
#include <stdio.h>
#include <algorithm>
using namespace vr;
#define RETURN_ENUM_AS_STRING(enumValue) case enumValue: return #enumValue;
const char *GetEnglishStringForHmdError( vr::EVRInitError eError )
{
switch( eError )
{
case VRInitError_None: return "No Error (0)";
case VRInitError_Init_InstallationNotFound: return "Installation Not Found (100)";
case VRInitError_Init_InstallationCorrupt: return "Installation Corrupt (101)";
case VRInitError_Init_VRClientDLLNotFound: return "vrclient Shared Lib Not Found (102)";
case VRInitError_Init_FileNotFound: return "File Not Found (103)";
case VRInitError_Init_FactoryNotFound: return "Factory Function Not Found (104)";
case VRInitError_Init_InterfaceNotFound: return "Interface Not Found (105)";
case VRInitError_Init_InvalidInterface: return "Invalid Interface (106)";
case VRInitError_Init_UserConfigDirectoryInvalid: return "User Config Directory Invalid (107)";
case VRInitError_Init_HmdNotFound: return "Hmd Not Found (108)";
case VRInitError_Init_NotInitialized: return "Not Initialized (109)";
case VRInitError_Init_PathRegistryNotFound: return "Installation path could not be located (110)";
case VRInitError_Init_NoConfigPath: return "Config path could not be located (111)";
case VRInitError_Init_NoLogPath: return "Log path could not be located (112)";
case VRInitError_Init_PathRegistryNotWritable: return "Unable to write path registry (113)";
case VRInitError_Init_AppInfoInitFailed: return "App info manager init failed (114)";
case VRInitError_Init_Retry: return "Internal Retry (115)";
case VRInitError_Init_InitCanceledByUser: return "User Canceled Init (116)";
case VRInitError_Init_AnotherAppLaunching: return "Another app was already launching (117)";
case VRInitError_Init_SettingsInitFailed: return "Settings manager init failed (118)";
case VRInitError_Init_ShuttingDown: return "VR system shutting down (119)";
case VRInitError_Init_TooManyObjects: return "Too many tracked objects (120)";
case VRInitError_Init_NoServerForBackgroundApp: return "Not starting vrserver for background app (121)";
case VRInitError_Init_NotSupportedWithCompositor: return "The requested interface is incompatible with the compositor and the compositor is running (122)";
case VRInitError_Init_NotAvailableToUtilityApps: return "This interface is not available to utility applications (123)";
case VRInitError_Init_Internal: return "vrserver internal error (124)";
case VRInitError_Init_HmdDriverIdIsNone: return "Hmd DriverId is invalid (125)";
case VRInitError_Init_HmdNotFoundPresenceFailed: return "Hmd Not Found Presence Failed (126)";
case VRInitError_Init_VRMonitorNotFound: return "VR Monitor Not Found (127)";
case VRInitError_Init_VRMonitorStartupFailed: return "VR Monitor startup failed (128)";
case VRInitError_Init_LowPowerWatchdogNotSupported: return "Low Power Watchdog Not Supported (129)";
case VRInitError_Init_InvalidApplicationType: return "Invalid Application Type (130)";
case VRInitError_Init_NotAvailableToWatchdogApps: return "Not available to watchdog apps (131)";
case VRInitError_Init_WatchdogDisabledInSettings: return "Watchdog disabled in settings (132)";
case VRInitError_Init_VRDashboardNotFound: return "VR Dashboard Not Found (133)";
case VRInitError_Init_VRDashboardStartupFailed: return "VR Dashboard startup failed (134)";
case VRInitError_Init_VRHomeNotFound: return "VR Home Not Found (135)";
case VRInitError_Init_VRHomeStartupFailed: return "VR home startup failed (136)";
case VRInitError_Init_RebootingBusy: return "Rebooting In Progress (137)";
case VRInitError_Init_FirmwareUpdateBusy: return "Firmware Update In Progress (138)";
case VRInitError_Init_FirmwareRecoveryBusy: return "Firmware Recovery In Progress (139)";
case VRInitError_Init_USBServiceBusy: return "USB Service Busy (140)";
case VRInitError_Driver_Failed: return "Driver Failed (200)";
case VRInitError_Driver_Unknown: return "Driver Not Known (201)";
case VRInitError_Driver_HmdUnknown: return "HMD Not Known (202)";
case VRInitError_Driver_NotLoaded: return "Driver Not Loaded (203)";
case VRInitError_Driver_RuntimeOutOfDate: return "Driver runtime is out of date (204)";
case VRInitError_Driver_HmdInUse: return "HMD already in use by another application (205)";
case VRInitError_Driver_NotCalibrated: return "Device is not calibrated (206)";
case VRInitError_Driver_CalibrationInvalid: return "Device Calibration is invalid (207)";
case VRInitError_Driver_HmdDisplayNotFound: return "HMD detected over USB, but Monitor not found (208)";
case VRInitError_Driver_TrackedDeviceInterfaceUnknown: return "Driver Tracked Device Interface unknown (209)";
// case VRInitError_Driver_HmdDisplayNotFoundAfterFix: return "HMD detected over USB, but Monitor not found after attempt to fix (210)"; // taken out upon Ben's request: He thinks that there is no need to separate that error from 208
case VRInitError_Driver_HmdDriverIdOutOfBounds: return "Hmd DriverId is our of bounds (211)";
case VRInitError_Driver_HmdDisplayMirrored: return "HMD detected over USB, but Monitor may be mirrored instead of extended (212)";
case VRInitError_Driver_HmdDisplayNotFoundLaptop: return "On laptop, HMD detected over USB, but Monitor not found (213)";
case VRInitError_IPC_ServerInitFailed: return "VR Server Init Failed (300)";
case VRInitError_IPC_ConnectFailed: return "Connect to VR Server Failed (301)";
case VRInitError_IPC_SharedStateInitFailed: return "Shared IPC State Init Failed (302)";
case VRInitError_IPC_CompositorInitFailed: return "Shared IPC Compositor Init Failed (303)";
case VRInitError_IPC_MutexInitFailed: return "Shared IPC Mutex Init Failed (304)";
case VRInitError_IPC_Failed: return "Shared IPC Failed (305)";
case VRInitError_IPC_CompositorConnectFailed: return "Shared IPC Compositor Connect Failed (306)";
case VRInitError_IPC_CompositorInvalidConnectResponse: return "Shared IPC Compositor Invalid Connect Response (307)";
case VRInitError_IPC_ConnectFailedAfterMultipleAttempts: return "Shared IPC Connect Failed After Multiple Attempts (308)";
case VRInitError_IPC_ConnectFailedAfterTargetExited: return "Shared IPC Connect Failed After Target Exited (309)";
case VRInitError_IPC_NamespaceUnavailable: return "Shared IPC Namespace Unavailable (310)";
case VRInitError_Compositor_Failed: return "Compositor failed to initialize (400)";
case VRInitError_Compositor_D3D11HardwareRequired: return "Compositor failed to find DX11 hardware (401)";
case VRInitError_Compositor_FirmwareRequiresUpdate: return "Compositor requires mandatory firmware update (402)";
case VRInitError_Compositor_OverlayInitFailed: return "Compositor initialization succeeded, but overlay init failed (403)";
case VRInitError_Compositor_ScreenshotsInitFailed: return "Compositor initialization succeeded, but screenshot init failed (404)";
case VRInitError_Compositor_UnableToCreateDevice: return "Compositor unable to create graphics device (405)";
// Oculus
case VRInitError_VendorSpecific_UnableToConnectToOculusRuntime: return "Unable to connect to Oculus Runtime (1000)";
case VRInitError_VendorSpecific_OculusRuntimeBadInstall: return "Unable to connect to Oculus Runtime, possible bad install (1114)";
// Lighthouse
case VRInitError_VendorSpecific_HmdFound_CantOpenDevice: return "HMD found, but can not open device (1101)";
case VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart: return "HMD found, but unable to request config (1102)";
case VRInitError_VendorSpecific_HmdFound_NoStoredConfig: return "HMD found, but no stored config (1103)";
case VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck: return "HMD found, but failed configuration check (1113)";
case VRInitError_VendorSpecific_HmdFound_ConfigTooBig: return "HMD found, but config too big (1104)";
case VRInitError_VendorSpecific_HmdFound_ConfigTooSmall: return "HMD found, but config too small (1105)";
case VRInitError_VendorSpecific_HmdFound_UnableToInitZLib: return "HMD found, but unable to init ZLib (1106)";
case VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion: return "HMD found, but problems with the data (1107)";
case VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart: return "HMD found, but problems with the data (1108)";
case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart: return "HMD found, but problems with the data (1109)";
case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext: return "HMD found, but problems with the data (1110)";
case VRInitError_VendorSpecific_HmdFound_UserDataAddressRange: return "HMD found, but problems with the data (1111)";
case VRInitError_VendorSpecific_HmdFound_UserDataError: return "HMD found, but problems with the data (1112)";
case VRInitError_Steam_SteamInstallationNotFound: return "Unable to find Steam installation (2000)";
default:
return GetIDForVRInitError( eError );
}
}
const char *GetIDForVRInitError( vr::EVRInitError eError )
{
switch( eError )
{
RETURN_ENUM_AS_STRING( VRInitError_None );
RETURN_ENUM_AS_STRING( VRInitError_Unknown );
RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationCorrupt );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRClientDLLNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_FileNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_FactoryNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_InterfaceNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidInterface );
RETURN_ENUM_AS_STRING( VRInitError_Init_UserConfigDirectoryInvalid );
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotInitialized );
RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_NoConfigPath );
RETURN_ENUM_AS_STRING( VRInitError_Init_NoLogPath );
RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotWritable );
RETURN_ENUM_AS_STRING( VRInitError_Init_AppInfoInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_Retry );
RETURN_ENUM_AS_STRING( VRInitError_Init_InitCanceledByUser );
RETURN_ENUM_AS_STRING( VRInitError_Init_AnotherAppLaunching );
RETURN_ENUM_AS_STRING( VRInitError_Init_SettingsInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_ShuttingDown );
RETURN_ENUM_AS_STRING( VRInitError_Init_TooManyObjects );
RETURN_ENUM_AS_STRING( VRInitError_Init_NoServerForBackgroundApp );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotSupportedWithCompositor );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToUtilityApps );
RETURN_ENUM_AS_STRING( VRInitError_Init_Internal );
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdDriverIdIsNone );
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFoundPresenceFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorStartupFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_LowPowerWatchdogNotSupported );
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidApplicationType );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToWatchdogApps );
RETURN_ENUM_AS_STRING( VRInitError_Init_WatchdogDisabledInSettings );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardStartupFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRHomeNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRHomeStartupFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_RebootingBusy );
RETURN_ENUM_AS_STRING( VRInitError_Init_FirmwareUpdateBusy );
RETURN_ENUM_AS_STRING( VRInitError_Init_FirmwareRecoveryBusy );
RETURN_ENUM_AS_STRING( VRInitError_Init_USBServiceBusy );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRWebHelperStartupFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_TrackerManagerInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_AlreadyRunning );
RETURN_ENUM_AS_STRING( VRInitError_Init_FailedForVrMonitor);
RETURN_ENUM_AS_STRING( VRInitError_Init_PropertyManagerInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_WebServerFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_IllegalTypeTransition );
RETURN_ENUM_AS_STRING( VRInitError_Init_MismatchedRuntimes );
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidProcessId );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRServiceStartupFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_PrismNeedsNewDrivers );
RETURN_ENUM_AS_STRING( VRInitError_Init_PrismStartupTimedOut );
RETURN_ENUM_AS_STRING( VRInitError_Init_CouldNotStartPrism );
RETURN_ENUM_AS_STRING( VRInitError_Init_CreateDriverDirectDeviceFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_PrismExitedUnexpectedly );
RETURN_ENUM_AS_STRING( VRInitError_Driver_Failed );
RETURN_ENUM_AS_STRING( VRInitError_Driver_Unknown );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdUnknown);
RETURN_ENUM_AS_STRING( VRInitError_Driver_NotLoaded);
RETURN_ENUM_AS_STRING( VRInitError_Driver_RuntimeOutOfDate);
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdInUse);
RETURN_ENUM_AS_STRING( VRInitError_Driver_NotCalibrated);
RETURN_ENUM_AS_STRING( VRInitError_Driver_CalibrationInvalid);
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFound);
RETURN_ENUM_AS_STRING( VRInitError_Driver_TrackedDeviceInterfaceUnknown );
// RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFoundAfterFix );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDriverIdOutOfBounds );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayMirrored );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFoundLaptop );
RETURN_ENUM_AS_STRING( VRInitError_IPC_ServerInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_SharedStateInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_MutexInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_Failed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorConnectFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInvalidConnectResponse);
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailedAfterMultipleAttempts );
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailedAfterTargetExited );
RETURN_ENUM_AS_STRING( VRInitError_IPC_NamespaceUnavailable );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_Failed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_D3D11HardwareRequired );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FirmwareRequiresUpdate );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_OverlayInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_ScreenshotsInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_UnableToCreateDevice );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SharedStateIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_NotificationManagerIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_ResourceManagerClientIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_MessageOverlaySharedStateInitFailure );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_PropertiesInterfaceIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFullscreenWindowFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SettingsInterfaceIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToShowWindow );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DistortInterfaceIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DisplayFrequencyFailure );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_RendererInitializationFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DXGIFactoryInterfaceIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DXGIFactoryCreateFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DXGIFactoryQueryFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidAdapterDesktop );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidHmdAttachment );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidOutputDesktop );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidDeviceProvided );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_D3D11RendererInitializationFailed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToFindDisplayMode );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateSwapChain );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToGetBackBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateRenderTarget );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateDXGI2SwapChain );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedtoGetDXGI2BackBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateDXGI2RenderTarget );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToGetDXGIDeviceInterface );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SelectDisplayMode );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateNvAPIRenderTargets );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_NvAPISetDisplayMode );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateDirectModeDisplay );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_InvalidHmdPropertyContainer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_UpdateDisplayFrequency );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateRasterizerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateWireframeRasterizerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateSamplerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateClampToBorderSamplerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateAnisoSamplerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlaySamplerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreatePanoramaSamplerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFontSamplerState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateNoBlendState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateAlphaBlendState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendStateMaskR );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendStateMaskG );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBlendStateMaskB );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDepthStencilState );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDepthStencilStateNoWrite );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDepthStencilStateNoDepth );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFlushTexture );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDistortionSurfaces );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateHmdPoseConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateHmdPoseStagingConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateSharedFrameInfoConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateSceneTextureIndexConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateReadableSceneTextureIndexConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLayerGraphicsTextureIndexConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLayerComputeTextureIndexConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLayerComputeSceneTextureIndexConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateComputeHmdPoseConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateGeomConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreatePanelMaskConstantBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreatePixelSimUBO );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateMSAARenderTextures );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateResolveRenderTextures );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateComputeResolveRenderTextures );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateDriverDirectModeResolveTextures );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_OpenDriverDirectModeResolveTextures );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateFallbackSyncTexture );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_ShareFallbackSyncTexture );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayIndexBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayVertexBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateTextVertexBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateTextIndexBuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateMirrorTextures );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateLastFrameRenderTexture );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateMirrorOverlay );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateVirtualDisplayBackbuffer );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_DisplayModeNotSupported );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayInvalidCall );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateOverlayAlreadyInitialized );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FailedToCreateMailbox );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_WindowInterfaceIsNull );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SystemLayerCreateInstance );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_SystemLayerCreateSession );
// Vendor-specific errors
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_UnableToConnectToOculusRuntime);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_WindowsNotInDevMode );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_OculusRuntimeBadInstall );
// Lighthouse
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantOpenDevice);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_NoStoredConfig);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooBig );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooSmall );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToInitZLib );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataAddressRange );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataError );
RETURN_ENUM_AS_STRING( VRInitError_Steam_SteamInstallationNotFound );
default:
{
static char buf[128];
sprintf( buf, "Unknown error (%d)", eError );
return buf;
}
}
}

View file

@ -0,0 +1,6 @@
//========= Copyright Valve Corporation ============//
#pragma once
const char *GetEnglishStringForHmdError( vr::EVRInitError eError );
const char *GetIDForVRInitError( vr::EVRInitError eError );

View file

@ -0,0 +1,988 @@
//========= Copyright Valve Corporation ============//
#include <vrcommon/strtools_public.h>
#include <vrcommon/pathtools_public.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>
#include <alloca.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;
}
/** Gets the path to a temporary directory. */
std::string Path_GetTemporaryDirectory()
{
#if defined( _WIN32 )
wchar_t buf[MAX_UNICODE_PATH];
if ( GetTempPathW( MAX_UNICODE_PATH, buf ) == 0 )
return Path_GetWorkingDirectory();
return UTF16to8( buf );
#else
const char *pchTmpDir = getenv( "TMPDIR" );
if ( pchTmpDir == NULL )
{
return "";
}
return pchTmpDir;
#endif
}
/** 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 )
{
if( Path_IsAbsolute( sRelativePath ) )
return Path_Compact( sRelativePath );
else
{
if( !Path_IsAbsolute( sBasePath ) )
return "";
std::string sCompacted = Path_Compact( Path_Join( sBasePath, sRelativePath ) );
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();
//Not sure why the following line of code was used for a while. It causes problems with strlen.
//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 true if these two paths are the same without respect for internal . or ..
* sequences, slash type, or case (on case-insensitive platforms). */
bool Path_IsSamePath( const std::string & sPath1, const std::string & sPath2 )
{
std::string sCompact1 = Path_Compact( sPath1 );
std::string sCompact2 = Path_Compact( sPath2 );
#if defined(WIN32)
return !stricmp( sCompact1.c_str(), sCompact2.c_str() );
#else
return !strcmp( sCompact1.c_str(), sCompact2.c_str() );
#endif
}
/** 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)
@autoreleasepool {
NSBundle *bundle = [ NSBundle bundleWithPath: [ NSString stringWithUTF8String:sPath.c_str() ] ];
bool bisAppBundle = ( nullptr != bundle );
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
//-----------------------------------------------------------------------------
std::vector<uint8_t> Path_ReadBinaryFile( const std::string & strFilename )
{
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
std::vector<uint8_t> vecFileContents;
if ( f != NULL )
{
fseek( f, 0, SEEK_END );
int size = ftell( f );
fseek( f, 0, SEEK_SET );
vecFileContents.resize( size );
if ( fread( &vecFileContents[ 0 ], size, 1, f ) == 1 )
{
}
else
{
vecFileContents.clear();
}
fclose( f );
}
return vecFileContents ;
}
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_MakeWritable( const std::string &strFilename )
{
#if defined ( _WIN32 )
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
DWORD dwAttrs = GetFileAttributesW( wstrFilename.c_str() );
if ( dwAttrs != INVALID_FILE_ATTRIBUTES && ( dwAttrs & FILE_ATTRIBUTE_READONLY ) )
{
return SetFileAttributesW( wstrFilename.c_str(), dwAttrs & ~FILE_ATTRIBUTE_READONLY );
}
#else
struct stat sb;
if ( stat( strFilename.c_str(), &sb ) == 0 && !( sb.st_mode & S_IWUSR ) )
{
return ( chmod( strFilename.c_str(), sb.st_mode | S_IWUSR ) == 0 );
}
#endif
return true;
}
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 ( StringHasPrefix( sRelativePath, "http://" )
|| StringHasPrefix( sRelativePath, "https://" )
|| StringHasPrefix( sRelativePath, "vr-input-workshop://" )
|| StringHasPrefix( sRelativePath, "file://" )
)
{
return sRelativePath;
}
else
{
std::string sAbsolute = Path_MakeAbsolute( sRelativePath, sBasePath );
if ( sAbsolute.empty() )
return sAbsolute;
sAbsolute = Path_FixSlashes( sAbsolute, '/' );
size_t unBufferSize = sAbsolute.length() * 3;
char *pchBuffer = (char *)alloca( unBufferSize );
V_URLEncodeFullPath( pchBuffer, (int)unBufferSize, sAbsolute.c_str(), (int)sAbsolute.length() );
return std::string( FILE_URL_PREFIX ) + pchBuffer;
}
}
// -----------------------------------------------------------------------------------------------------
// 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 ) ) )
{
char *pchBuffer = (char *)alloca( sFileUrl.length() );
V_URLDecodeNoPlusForSpace( pchBuffer, (int)sFileUrl.length(),
sFileUrl.c_str() + strlen( FILE_URL_PREFIX ), (int)( sFileUrl.length() - strlen( FILE_URL_PREFIX ) ) );
return Path_FixSlashes( pchBuffer );
}
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
}
// -----------------------------------------------------------------------------------------------------
// Purpose: deletes / unlinks a single file
// -----------------------------------------------------------------------------------------------------
bool Path_UnlinkFile( const std::string &strFilename )
{
#if defined( WIN32 )
std::wstring wsFilename = UTF8to16( strFilename.c_str() );
return ( 0 != DeleteFileW( wsFilename.c_str() ) );
#else
return ( 0 == unlink( strFilename.c_str() ) );
#endif
}
// -----------------------------------------------------------------------------------------------------
// Limits the set of characters that are allowed in filenames
// -----------------------------------------------------------------------------------------------------
std::string Path_SanitizeFilename( const std::string& sFilename )
{
std::string sFixed = sFilename;
std::string::iterator iLastDot = sFixed.end();
for ( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ )
{
if ( *i == '.' )
{
iLastDot = i;
}
// path-related characters are forbidden (except the last period)
switch ( *i )
{
case '\0':
case '.':
case '\\':
case '/':
case ':':
case '|':
case '?':
case '>':
case '<':
case '&':
case '%':
case '@':
case '$':
case '*':
case '\"':
*i = '_';
break;
default:
if ( *i < 32 )
{
*i = '_';
}
break;
}
}
if ( iLastDot != sFixed.end() && iLastDot != sFixed.begin()
&& iLastDot+1 != sFixed.end() )
{
*iLastDot = '.';
}
return sFixed;
}

View file

@ -0,0 +1,153 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
#include <vector>
#include <stdint.h>
/** Returns the path (including filename) to the current executable */
std::string Path_GetExecutablePath();
/** Returns the path of the current working directory */
std::string Path_GetWorkingDirectory();
/** Sets the path of the current working directory. Returns true if this was successful. */
bool Path_SetWorkingDirectory( const std::string & sPath );
/** Gets the path to a temporary directory. */
std::string Path_GetTemporaryDirectory();
/** returns the path (including filename) of the current shared lib or DLL */
std::string Path_GetThisModulePath();
/** Returns the specified path without its filename.
* If slash is unspecified the native path separator of the current platform
* will be used. */
std::string Path_StripFilename( const std::string & sPath, char slash = 0 );
/** returns just the filename from the provided full or relative path. */
std::string Path_StripDirectory( const std::string & sPath, char slash = 0 );
/** 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 );
/** returns just extension of the provided filename (if any). */
std::string Path_GetExtension( const std::string & sPath );
/** Returns true if the path is absolute */
bool Path_IsAbsolute( const std::string & sPath );
/** Makes an absolute path from a relative path and a base path */
std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath );
/** Fixes the directory separators for the current platform.
* If slash is unspecified the native path separator of the current platform
* will be used. */
std::string Path_FixSlashes( const std::string & sPath, char slash = 0 );
/** Returns the path separator for the current platform */
char Path_GetSlash();
/** Jams two paths together with the right kind of slash */
std::string Path_Join( const std::string & first, const std::string & second, char slash = 0 );
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash = 0 );
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash = 0 );
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 = 0 );
/** 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.
* If slash is unspecified the native path separator of the current platform
* will be used. */
std::string Path_Compact( const std::string & sRawPath, char slash = 0 );
/** Returns true if these two paths are the same without respect for internal . or ..
* sequences, slash type, or case (on case-insensitive platforms). */
bool Path_IsSamePath( const std::string & sPath1, const std::string & sPath2 );
//** Removed trailing slashes */
std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash = 0 );
/** returns true if the specified path exists and is a directory */
bool Path_IsDirectory( const std::string & sPath );
/** returns true if the specified path represents an app bundle */
bool Path_IsAppBundle( const std::string & sPath );
/** returns true if the the path exists */
bool Path_Exists( const std::string & sPath );
/** Helper functions to find parent directories or subdirectories of parent directories */
std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
/** Make a text file writable. */
bool Path_MakeWritable( const std::string &strFilename );
/** Path operations to read or write text/binary files */
unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize );
uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize );
std::vector<uint8_t> Path_ReadBinaryFile( const std::string & strFilename );
bool Path_WriteBinaryFile( const std::string &strFilename, unsigned char *pData, unsigned nSize );
std::string Path_ReadTextFile( const std::string &strFilename );
bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData );
bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData );
/** Returns a file:// url for paths, or an http or https url if that's what was provided */
std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath );
/** 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 );
/** Returns the root of the directory the system wants us to store user documents in */
std::string GetUserDocumentsPath();
/** deletes / unlinks a single file */
bool Path_UnlinkFile( const std::string &strFilename );
std::string Path_SanitizeFilename( const std::string& sFilename );
#ifndef MAX_UNICODE_PATH
#define MAX_UNICODE_PATH 32767
#endif
#ifndef MAX_UNICODE_PATH_IN_UTF8
#define MAX_UNICODE_PATH_IN_UTF8 (MAX_UNICODE_PATH * 4)
#endif
//-----------------------------------------------------------------------------
#if defined(WIN32)
#define DYNAMIC_LIB_EXT ".dll"
#define PROGRAM_EXT ".exe"
#ifdef _WIN64
#define PLATSUBDIR "win64"
#else
#define PLATSUBDIR "win32"
#endif
#elif defined(OSX)
#define DYNAMIC_LIB_EXT ".dylib"
#define PLATSUBDIR "osx32"
#define PROGRAM_EXT ""
#elif defined(LINUX)
#define DYNAMIC_LIB_EXT ".so"
#define PROGRAM_EXT ""
#if defined( LINUX32 )
#define PLATSUBDIR "linux32"
#elif defined( ANDROIDARM64 )
#define PLATSUBDIR "androidarm64"
#elif defined( LINUXARM64 )
#define PLATSUBDIR "linuxarm64"
#else
#define PLATSUBDIR "linux64"
#endif
#else
#warning "Unknown platform for PLATSUBDIR"
#define PLATSUBDIR "unknown_platform"
#endif

View file

@ -0,0 +1,63 @@
//========= Copyright Valve Corporation ============//
#include <vrcommon/sharedlibtools_public.h>
#include <string.h>
#if defined(_WIN32)
#include <windows.h>
#endif
#if defined(POSIX)
#include <dlfcn.h>
#endif
SharedLibHandle SharedLib_Load( const char *pchPath, uint32_t *pErrorCode )
{
SharedLibHandle pHandle = nullptr;
#if defined( _WIN32)
pHandle = ( SharedLibHandle )LoadLibraryEx( pchPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
#elif defined(POSIX)
pHandle = (SharedLibHandle) dlopen(pchPath, RTLD_LOCAL|RTLD_NOW);
#endif
if ( pErrorCode )
{
if ( pHandle == nullptr )
{
#if defined( _WIN32)
*pErrorCode = ( uint32_t ) GetLastError();
#elif defined(POSIX)
*pErrorCode = 1;
#endif
}
else
{
*pErrorCode = 0;
}
}
return pHandle;
}
void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName)
{
#if defined( _WIN32)
return (void*)GetProcAddress( (HMODULE)lib, pchFunctionName );
#elif defined(POSIX)
return dlsym( lib, pchFunctionName );
#endif
}
void SharedLib_Unload( SharedLibHandle lib )
{
if ( !lib )
return;
#if defined( _WIN32)
FreeLibrary( (HMODULE)lib );
#elif defined(POSIX)
dlclose( lib );
#endif
}

View file

@ -0,0 +1,12 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <stdint.h>
typedef void *SharedLibHandle;
SharedLibHandle SharedLib_Load( const char *pchPath, uint32_t *pErrorCode = nullptr );
void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName);
void SharedLib_Unload( SharedLibHandle lib );

View file

@ -0,0 +1,606 @@
//========= Copyright Valve Corporation ============//
#include <vrcommon/strtools_public.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <codecvt>
#include <iostream>
#include <functional>
#include <locale>
#include <codecvt>
#include <stdarg.h>
#if defined( _WIN32 )
#include <windows.h>
#endif
#if defined( OSX ) || defined( LINUX )
//-----------------------------------------------------------------------------
// Purpose: stricmp -> strcasecmp bridge
//-----------------------------------------------------------------------------
int stricmp( const char *pStr1, const char *pStr2 )
{
return strcasecmp( pStr1, pStr2 );
}
//-----------------------------------------------------------------------------
// Purpose: strincmp -> strncasecmp bridge
//-----------------------------------------------------------------------------
int strnicmp( const char *pStr1, const char *pStr2, size_t unBufferLen )
{
return strncasecmp( pStr1, pStr2, unBufferLen );
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool StringHasPrefix( const std::string & sString, const std::string & sPrefix )
{
return 0 == strnicmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
}
bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix )
{
return 0 == strncmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
}
bool StringHasSuffix( const std::string &sString, const std::string &sSuffix )
{
size_t cStrLen = sString.length();
size_t cSuffixLen = sSuffix.length();
if ( cSuffixLen > cStrLen )
return false;
std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
return 0 == stricmp( sStringSuffix.c_str(), sSuffix.c_str() );
}
bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix )
{
size_t cStrLen = sString.length();
size_t cSuffixLen = sSuffix.length();
if ( cSuffixLen > cStrLen )
return false;
std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
return 0 == strncmp( sStringSuffix.c_str(), sSuffix.c_str(),cSuffixLen );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
typedef std::codecvt_utf8< wchar_t > convert_type;
std::string UTF16to8(const wchar_t * in)
{
static std::wstring_convert< convert_type, wchar_t > s_converter; // construction of this can be expensive (or even serialized) depending on locale
try
{
return s_converter.to_bytes( in );
}
catch ( ... )
{
return std::string();
}
}
std::string UTF16to8( const std::wstring & in ) { return UTF16to8( in.c_str() ); }
std::wstring UTF8to16(const char * in)
{
static std::wstring_convert< convert_type, wchar_t > s_converter; // construction of this can be expensive (or even serialized) depending on locale
try
{
return s_converter.from_bytes( in );
}
catch ( ... )
{
return std::wstring();
}
}
std::wstring UTF8to16( const std::string & in ) { return UTF8to16( in.c_str() ); }
//-----------------------------------------------------------------------------
// Purpose: Format string to std::string converter
//-----------------------------------------------------------------------------
std::string Format( const char *pchFormat, ... )
{
static constexpr size_t k_ulMaxStackString = 4096;
va_list args;
char pchBuffer[k_ulMaxStackString];
va_start( args, pchFormat );
int unSize = vsnprintf( pchBuffer, sizeof( pchBuffer ), pchFormat, args );
va_end( args );
// Something went fairly wrong
if ( unSize < 0 )
{
//AssertMsg( false, "Format string parse failure" );
return "";
}
// Processing on the stack worked, success
if ( unSize < k_ulMaxStackString )
{
return pchBuffer;
}
// If processing on the stack failed, fallback to a dynamic allocation
std::vector< char > vecChar{};
vecChar.resize( unSize + 1 );
va_start( args, pchFormat );
unSize = vsnprintf( vecChar.data(), vecChar.size(), pchFormat, args );
va_end( args );
// Double check, just in case
if ( unSize < 0 )
{
//AssertMsg( false, "Format string parse failure" );
return "";
}
return vecChar.data();
}
#if defined( _WIN32 )
//-----------------------------------------------------------------------------
// Purpose: Convert LPSTR in the default CodePage to UTF8
//-----------------------------------------------------------------------------
std::string DefaultACPtoUTF8( const char *pszStr )
{
if ( GetACP() == CP_UTF8 )
{
return pszStr;
}
else
{
std::vector<wchar_t> vecBuf( strlen( pszStr ) + 1 ); // should be guaranteed to be enough
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszStr, -1, vecBuf.data(), (int) vecBuf.size() );
return UTF16to8( vecBuf.data() );
}
}
#endif
// --------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------
void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource )
{
strncpy( pchBuffer, pchSource, unBufferSizeBytes - 1 );
pchBuffer[unBufferSizeBytes - 1] = '\0';
}
// --------------------------------------------------------------------
// Purpose: converts a string to upper case
// --------------------------------------------------------------------
std::string StringToUpper( const std::string & sString )
{
std::string sOut;
sOut.reserve( sString.size() + 1 );
for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
{
sOut.push_back( (char)toupper( *i ) );
}
return sOut;
}
// --------------------------------------------------------------------
// Purpose: converts a string to lower case
// --------------------------------------------------------------------
std::string StringToLower( const std::string & sString )
{
std::string sOut;
sOut.reserve( sString.size() + 1 );
for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
{
sOut.push_back( (char)tolower( *i ) );
}
return sOut;
}
uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen )
{
uint32_t unLen = (uint32_t)sValue.length() + 1;
if( !pchBuffer || !unBufferLen )
return unLen;
if( unBufferLen < unLen )
{
pchBuffer[0] = '\0';
}
else
{
memcpy( pchBuffer, sValue.c_str(), unLen );
}
return unLen;
}
/** Returns a std::string from a uint64_t */
std::string Uint64ToString( uint64_t ulValue )
{
char buf[ 22 ];
#if defined( _WIN32 )
sprintf_s( buf, "%llu", ulValue );
#else
snprintf( buf, sizeof( buf ), "%llu", (long long unsigned int ) ulValue );
#endif
return buf;
}
/** returns a uint64_t from a string */
uint64_t StringToUint64( const std::string & sValue )
{
return strtoull( sValue.c_str(), NULL, 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15.
//-----------------------------------------------------------------------------
char cIntToHexDigit( int nValue )
{
//Assert( nValue >= 0 && nValue <= 15 );
return "0123456789ABCDEF"[ nValue & 15 ];
}
//-----------------------------------------------------------------------------
// Purpose: Helper for converting a hex char value to numeric, return -1 if the char
// is not a valid hex digit.
//-----------------------------------------------------------------------------
int iHexCharToInt( char cValue )
{
int32_t iValue = cValue;
if ( (uint32_t)( iValue - '0' ) < 10 )
return iValue - '0';
iValue |= 0x20;
if ( (uint32_t)( iValue - 'a' ) < 6 )
return iValue - 'a' + 10;
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: These define the set of characters to filter for components (which
// need all the escaping we can muster) vs. paths (which don't want
// / and : escaped so we don't break less compliant URL handling code.
//-----------------------------------------------------------------------------
static bool CharNeedsEscape_Component( const char c )
{
return (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')
&& c != '-' && c != '_' && c != '.');
}
static bool CharNeedsEscape_FullPath( const char c )
{
return (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')
&& c != '-' && c != '_' && c != '.' && c != '/' && c != ':' );
}
//-----------------------------------------------------------------------------
// Purpose: Internal implementation of encode, works in the strict RFC manner, or
// with spaces turned to + like HTML form encoding.
//-----------------------------------------------------------------------------
void V_URLEncodeInternal( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen,
bool bUsePlusForSpace, std::function< bool(const char)> fnNeedsEscape )
{
//AssertMsg( nDestLen > 3*nSourceLen, "Target buffer for V_URLEncode should be 3x source length, plus one for terminating null\n" );
int iDestPos = 0;
for ( int i=0; i < nSourceLen; ++i )
{
// worst case we need 3 additional chars
if( (iDestPos+3) > nDestLen )
{
pchDest[0] = '\0';
// AssertMsg( false, "Target buffer too short\n" );
return;
}
// We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped.
// These are the characters allowed by both the original RFC 1738 and the latest RFC 3986.
// Current specs also allow '~', but that is forbidden under original RFC 1738.
if ( fnNeedsEscape( pchSource[i] ) )
{
if ( bUsePlusForSpace && pchSource[i] == ' ' )
{
pchDest[iDestPos++] = '+';
}
else
{
pchDest[iDestPos++] = '%';
uint8_t iValue = pchSource[i];
if ( iValue == 0 )
{
pchDest[iDestPos++] = '0';
pchDest[iDestPos++] = '0';
}
else
{
char cHexDigit1 = cIntToHexDigit( iValue % 16 );
iValue /= 16;
char cHexDigit2 = cIntToHexDigit( iValue );
pchDest[iDestPos++] = cHexDigit2;
pchDest[iDestPos++] = cHexDigit1;
}
}
}
else
{
pchDest[iDestPos++] = pchSource[i];
}
}
if( (iDestPos+1) > nDestLen )
{
pchDest[0] = '\0';
//AssertMsg( false, "Target buffer too short to terminate\n" );
return;
}
// Null terminate
pchDest[iDestPos++] = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Internal implementation of decode, works in the strict RFC manner, or
// with spaces turned to + like HTML form encoding.
//
// Returns the amount of space used in the output buffer.
//-----------------------------------------------------------------------------
size_t V_URLDecodeInternal( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace )
{
if ( nDecodeDestLen < nEncodedSourceLen )
{
//AssertMsg( false, "V_URLDecode needs a dest buffer at least as large as the source" );
return 0;
}
int iDestPos = 0;
for( int i=0; i < nEncodedSourceLen; ++i )
{
if ( bUsePlusForSpace && pchEncodedSource[i] == '+' )
{
pchDecodeDest[ iDestPos++ ] = ' ';
}
else if ( pchEncodedSource[i] == '%' )
{
// Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that
// First make sure we have 2 more chars
if ( i < nEncodedSourceLen - 2 )
{
char cHexDigit1 = pchEncodedSource[i+1];
char cHexDigit2 = pchEncodedSource[i+2];
// Turn the chars into a hex value, if they are not valid, then we'll
// just place the % and the following two chars direct into the string,
// even though this really shouldn't happen, who knows what bad clients
// may do with encoding.
bool bValid = false;
int iValue = iHexCharToInt( cHexDigit1 );
if ( iValue != -1 )
{
iValue *= 16;
int iValue2 = iHexCharToInt( cHexDigit2 );
if ( iValue2 != -1 )
{
iValue += iValue2;
pchDecodeDest[ iDestPos++ ] = (char)iValue;
bValid = true;
}
}
if ( !bValid )
{
pchDecodeDest[ iDestPos++ ] = '%';
pchDecodeDest[ iDestPos++ ] = cHexDigit1;
pchDecodeDest[ iDestPos++ ] = cHexDigit2;
}
}
// Skip ahead
i += 2;
}
else
{
pchDecodeDest[ iDestPos++ ] = pchEncodedSource[i];
}
}
// We may not have extra room to NULL terminate, since this can be used on raw data, but if we do
// go ahead and do it as this can avoid bugs.
if ( iDestPos < nDecodeDestLen )
{
pchDecodeDest[iDestPos] = 0;
}
return (size_t)iDestPos;
}
//-----------------------------------------------------------------------------
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
//-----------------------------------------------------------------------------
void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
{
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, true, CharNeedsEscape_Component );
}
void V_URLEncodeNoPlusForSpace( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
{
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, false, CharNeedsEscape_Component );
}
void V_URLEncodeFullPath( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
{
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, false, CharNeedsEscape_FullPath );
}
//-----------------------------------------------------------------------------
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
//-----------------------------------------------------------------------------
size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen )
{
return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true );
}
size_t V_URLDecodeNoPlusForSpace( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen )
{
return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, false );
}
//-----------------------------------------------------------------------------
void V_StripExtension( std::string &in )
{
// Find the last dot. If it's followed by a dot or a slash, then it's part of a
// directory specifier like ../../somedir/./blah.
std::string::size_type test = in.rfind( '.' );
if ( test != std::string::npos )
{
// This handles things like ".\blah" or "c:\my@email.com\abc\def\geh"
// Which would otherwise wind up with "" and "c:\my@email", respectively.
if ( in.rfind( '\\' ) < test && in.rfind( '/' ) < test )
{
in.resize( test );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Tokenizes a string into a vector of strings
//-----------------------------------------------------------------------------
std::vector<std::string> TokenizeString( const std::string & sString, char cToken )
{
std::vector<std::string> vecStrings;
std::istringstream stream( sString );
std::string s;
while ( std::getline( stream, s, cToken ) )
{
vecStrings.push_back( s );
}
if ( !sString.empty() && sString.back() == cToken )
{
vecStrings.push_back( "" );
}
return vecStrings;
}
//-----------------------------------------------------------------------------
// Purpose: Repairs a should-be-UTF-8 string to a for-sure-is-UTF-8 string, plus return boolean if we subbed in '?' somewhere
//-----------------------------------------------------------------------------
bool RepairUTF8( const char *pbegin, const char *pend, std::string & sOutputUtf8 )
{
typedef std::codecvt_utf8<char32_t> facet_type;
facet_type myfacet;
std::mbstate_t mystate = std::mbstate_t();
sOutputUtf8.clear();
sOutputUtf8.reserve( pend - pbegin );
bool bSqueakyClean = true;
const char *pmid = pbegin;
while ( pmid != pend )
{
bool bHasError = false;
bool bHasValidData = false;
char32_t out = 0xdeadbeef, *pout;
pbegin = pmid;
switch ( myfacet.in( mystate, pbegin, pend, pmid, &out, &out + 1, pout ) )
{
case facet_type::ok:
bHasValidData = true;
break;
case facet_type::noconv:
// unexpected! always converting type
bSqueakyClean = false;
break;
case facet_type::partial:
bHasError = pbegin == pmid;
if ( bHasError )
{
bSqueakyClean = false;
}
else
{
bHasValidData = true;
}
break;
case facet_type::error:
bHasError = true;
bSqueakyClean = false;
break;
}
if ( bHasValidData )
{
// could convert back, but no need
for ( const char *p = pbegin; p != pmid; ++p )
{
sOutputUtf8 += *p;
}
}
if ( bHasError )
{
sOutputUtf8 += '?';
}
if ( pmid == pbegin )
{
pmid++;
}
}
return bSqueakyClean;
}
//-----------------------------------------------------------------------------
// Purpose: Repairs a should-be-UTF-8 string to a for-sure-is-UTF-8 string, plus return boolean if we subbed in '?' somewhere
//-----------------------------------------------------------------------------
bool RepairUTF8( const std::string & sInputUtf8, std::string & sOutputUtf8 )
{
return RepairUTF8( sInputUtf8.data(), sInputUtf8.data() + sInputUtf8.size(), sOutputUtf8 );
}

View file

@ -0,0 +1,154 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
#include <stdint.h>
#include <sys/types.h>
#include <vector>
/** returns true if the string has the prefix */
bool StringHasPrefix( const std::string & sString, const std::string & sPrefix );
bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix );
/** returns if the string has the suffix */
bool StringHasSuffix( const std::string &sString, const std::string &sSuffix );
bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix );
/** converts a UTF-16 string to a UTF-8 string */
std::string UTF16to8( const wchar_t * in );
std::string UTF16to8( const std::wstring & in );
/** converts a UTF-8 string to a UTF-16 string */
std::wstring UTF8to16(const char * in);
std::wstring UTF8to16( const std::string & in );
#define Utf16FromUtf8 UTF8to16
#if defined( _WIN32 )
std::string DefaultACPtoUTF8( const char *pszStr );
#endif
/** Repairs a should-be-UTF-8 string to a for-sure-is-UTF-8 string, plus return boolean if we subbed in '?' somewhere */
bool RepairUTF8( const char *begin, const char *end, std::string & sOutputUtf8 );
bool RepairUTF8( const std::string & sInputUtf8, std::string & sOutputUtf8 );
/** safely copy a string into a buffer */
void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource );
template< size_t bufferSize >
void strcpy_safe( char (& buffer) [ bufferSize ], const char *pchSource )
{
strcpy_safe( buffer, bufferSize, pchSource );
}
/** Turns printf-style format args into a std::string */
std::string Format( const char *pchFormat, ... );
/** converts a string to upper case */
std::string StringToUpper( const std::string & sString );
/** converts a string to lower case */
std::string StringToLower( const std::string & sString );
// we stricmp (from WIN) but it isn't POSIX - OSX/LINUX have strcasecmp so just inline bridge to it
#if defined( OSX ) || defined( LINUX )
int stricmp(const char *pStr1, const char *pStr2);
#ifndef _stricmp
#define _stricmp stricmp
#endif
int strnicmp( const char *pStr1, const char *pStr2, size_t unBufferLen );
#ifndef _strnicmp
#define _strnicmp strnicmp
#endif
#ifndef _vsnprintf_s
#define _vsnprintf_s vsnprintf
#endif
#define _TRUNCATE ((size_t)-1)
#endif
#if defined( OSX )
// behaviors ensure NULL-termination at least as well as _TRUNCATE does, but
// wcsncpy_s/strncpy_s can non-NULL-terminate, wcslcpy/strlcpy can not.
inline errno_t wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
{
return wcslcpy(strDest, strSource, numberOfElements);
}
inline errno_t strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
{
return strlcpy(strDest, strSource, numberOfElements);
}
#endif
#if defined( LINUX )
// this implementation does not return whether or not the destination was
// truncated, but that is straightforward to fix if anybody actually needs the
// return code.
#include "string.h"
inline void wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
{
wcsncpy(strDest, strSource, numberOfElements);
strDest[numberOfElements-1] = '\0';
}
inline void strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
{
strncpy(strDest, strSource, numberOfElements);
strDest[numberOfElements-1] = '\0';
}
#endif
#if defined( _WIN32 ) && _MSC_VER < 1800
inline uint64_t strtoull(const char *str, char **endptr, int base) { return _strtoui64( str, endptr, base ); }
#endif
/* Handles copying a std::string into a buffer as would be provided in an API */
uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen );
/** Returns a std::string from a uint64_t */
std::string Uint64ToString( uint64_t ulValue );
/** returns a uint64_t from a string */
uint64_t StringToUint64( const std::string & sValue );
//-----------------------------------------------------------------------------
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
//-----------------------------------------------------------------------------
void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
/** Same as V_URLEncode, but without plus for space. */
void V_URLEncodeNoPlusForSpace( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
/** Same as V_URLEncodeNoPlusForSpace, but without escaping / and : */
void V_URLEncodeFullPath( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
//-----------------------------------------------------------------------------
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
//-----------------------------------------------------------------------------
size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
/** Same as V_URLDecode, but without plus for space. */
size_t V_URLDecodeNoPlusForSpace( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
//-----------------------------------------------------------------------------
// Purpose: strip extension from a path
//-----------------------------------------------------------------------------
void V_StripExtension( std::string &in );
/** Tokenizes a string into a vector of strings */
std::vector<std::string> TokenizeString( const std::string & sString, char cToken );

View file

@ -0,0 +1,483 @@
//========= Copyright Valve Corporation ============//
#include <vrcommon/vrpathregistry_public.h>
#include <json/json.h>
#include <vrcommon/pathtools_public.h>
#include <vrcommon/envvartools_public.h>
#include <vrcommon/strtools_public.h>
#include <vrcommon/dirtools_public.h>
#if defined( WIN32 )
#include <windows.h>
#include <shlobj.h>
#undef GetEnvironmentVariable
#elif defined OSX
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#elif defined(LINUX)
#include <dlfcn.h>
#include <stdio.h>
#endif
#include <algorithm>
#include <sstream>
#ifndef VRLog
#if defined( __MINGW32__ )
#define VRLog(args...) fprintf(stderr, args)
#elif defined( WIN32 )
#define VRLog(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#else
#define VRLog(args...) fprintf(stderr, args)
#endif
#endif
/** Returns the root of the directory the system wants us to store user config data in */
static std::string GetAppSettingsPath()
{
#if defined( WIN32 )
WCHAR rwchPath[MAX_PATH];
if( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_LOCAL_APPDATA | 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 )
std::string sSettingsDir;
@autoreleasepool {
// Search for the path
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
if ( [paths count] == 0 )
{
return "";
}
NSString *resolvedPath = [paths objectAtIndex:0];
resolvedPath = [resolvedPath stringByAppendingPathComponent: @"OpenVR"];
if ( ![[NSFileManager defaultManager] createDirectoryAtPath: resolvedPath withIntermediateDirectories:YES attributes:nil error:nil] )
{
return "";
}
sSettingsDir.assign( [resolvedPath UTF8String] );
}
return sSettingsDir;
#elif defined( LINUX )
// As defined by XDG Base Directory Specification
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
const char *pchHome = getenv("XDG_CONFIG_HOME");
if ( ( pchHome != NULL) && ( pchHome[0] != '\0' ) )
{
return pchHome;
}
//
// XDG_CONFIG_HOME is not defined, use ~/.config instead
//
pchHome = getenv( "HOME" );
if ( pchHome == NULL )
{
return "";
}
std::string sUserPath( pchHome );
sUserPath = Path_Join( sUserPath, ".config" );
return sUserPath;
#else
#warning "Unsupported platform"
#endif
}
// ---------------------------------------------------------------------------
// Purpose: Constructor
// ---------------------------------------------------------------------------
CVRPathRegistry_Public::CVRPathRegistry_Public()
{
}
// ---------------------------------------------------------------------------
// Purpose: Computes the registry filename
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetOpenVRConfigPath()
{
std::string sConfigPath = GetAppSettingsPath();
if( sConfigPath.empty() )
return "";
#if defined( _WIN32 ) || defined( LINUX )
sConfigPath = Path_Join( sConfigPath, "openvr" );
#elif defined ( OSX )
sConfigPath = Path_Join( sConfigPath, ".openvr" );
#else
#warning "Unsupported platform"
#endif
sConfigPath = Path_FixSlashes( sConfigPath );
return sConfigPath;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetVRPathRegistryFilename()
{
std::string sOverridePath = GetEnvironmentVariable( "VR_PATHREG_OVERRIDE" );
if ( !sOverridePath.empty() )
return sOverridePath;
std::string sPath = GetOpenVRConfigPath();
if ( sPath.empty() )
return "";
#if defined( _WIN32 )
sPath = Path_Join( sPath, "openvrpaths.vrpath" );
#elif defined ( POSIX )
sPath = Path_Join( sPath, "openvrpaths.vrpath" );
#else
#error "Unsupported platform"
#endif
sPath = Path_FixSlashes( sPath );
return sPath;
}
// ---------------------------------------------------------------------------
// Purpose: Converts JSON to a history array
// ---------------------------------------------------------------------------
static void ParseStringListFromJson( std::vector< std::string > *pvecHistory, const Json::Value & root, const char *pchArrayName )
{
if( !root.isMember( pchArrayName ) )
return;
const Json::Value & arrayNode = root[ pchArrayName ];
if( !arrayNode )
{
VRLog( "VR Path Registry node %s is not an array\n", pchArrayName );
return;
}
pvecHistory->clear();
pvecHistory->reserve( arrayNode.size() );
for( uint32_t unIndex = 0; unIndex < arrayNode.size(); unIndex++ )
{
std::string sPath( arrayNode[ unIndex ].asString() );
pvecHistory->push_back( sPath );
}
}
// ---------------------------------------------------------------------------
// Purpose: Converts a history array to JSON
// ---------------------------------------------------------------------------
static void StringListToJson( const std::vector< std::string > & vecHistory, Json::Value & root, const char *pchArrayName )
{
Json::Value & arrayNode = root[ pchArrayName ];
for( auto i = vecHistory.begin(); i != vecHistory.end(); i++ )
{
arrayNode.append( *i );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CVRPathRegistry_Public::ToJsonString( std::string &sJsonString )
{
std::string sRegPath = GetVRPathRegistryFilename();
if( sRegPath.empty() )
return false;
std::string sRegistryContents = Path_ReadTextFile( sRegPath );
if( sRegistryContents.empty() )
return false;
sJsonString = sRegistryContents;
return true;
}
// ---------------------------------------------------------------------------
// Purpose: Loads the config file from its well known location
// ---------------------------------------------------------------------------
bool CVRPathRegistry_Public::BLoadFromFile( std::string *psLoadError )
{
std::string sRegPath = GetVRPathRegistryFilename();
if( sRegPath.empty() )
{
if ( psLoadError )
{
*psLoadError = "Unable to determine VR Path Registry filename";
}
return false;
}
std::string sRegistryContents = Path_ReadTextFile( sRegPath );
if( sRegistryContents.empty() )
{
if ( psLoadError )
{
*psLoadError = "Unable to read VR Path Registry from " + sRegPath;
}
return false;
}
Json::Value root;
Json::CharReaderBuilder builder;
std::istringstream istream( sRegistryContents );
std::string sErrors;
try {
if ( !parseFromStream( builder, istream, &root, &sErrors ) )
{
if ( psLoadError )
{
*psLoadError = "Unable to parse " + sRegPath + ": " + sErrors;
}
return false;
}
ParseStringListFromJson( &m_vecRuntimePath, root, "runtime" );
ParseStringListFromJson( &m_vecConfigPath, root, "config" );
ParseStringListFromJson( &m_vecLogPath, root, "log" );
if ( root.isMember( "external_drivers" ) && root["external_drivers"].isArray() )
{
ParseStringListFromJson( &m_vecExternalDrivers, root, "external_drivers" );
}
}
catch ( ... )
{
if ( psLoadError )
{
*psLoadError = "Unable to parse " + sRegPath + ": exception thrown in JSON library";
}
return false;
}
return true;
}
// ---------------------------------------------------------------------------
// Purpose: Saves the config file to its well known location
// ---------------------------------------------------------------------------
bool CVRPathRegistry_Public::BSaveToFile() const
{
std::string sRegPath = GetVRPathRegistryFilename();
if( sRegPath.empty() )
return false;
Json::Value root;
root[ "version" ] = 1;
root[ "jsonid" ] = "vrpathreg";
StringListToJson( m_vecRuntimePath, root, "runtime" );
StringListToJson( m_vecConfigPath, root, "config" );
StringListToJson( m_vecLogPath, root, "log" );
StringListToJson( m_vecExternalDrivers, root, "external_drivers" );
Json::StreamWriterBuilder builder;
std::string sRegistryContents = Json::writeString( builder, root );
// make sure the directory we're writing into actually exists
std::string sRegDirectory = Path_StripFilename( sRegPath );
if( !BCreateDirectoryRecursive( sRegDirectory.c_str() ) )
{
VRLog( "Unable to create path registry directory %s\n", sRegDirectory.c_str() );
return false;
}
if( !Path_WriteStringToTextFile( sRegPath, sRegistryContents.c_str() ) )
{
VRLog( "Unable to write VR path registry to %s\n", sRegPath.c_str() );
return false;
}
return true;
}
// ---------------------------------------------------------------------------
// Purpose: Returns the current runtime path or NULL if no path is configured.
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetRuntimePath() const
{
if( m_vecRuntimePath.empty() )
return "";
else
return m_vecRuntimePath.front().c_str();
}
// ---------------------------------------------------------------------------
// Purpose: Returns the current config path or NULL if no path is configured.
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetConfigPath() const
{
if( m_vecConfigPath.empty() )
return "";
else
return m_vecConfigPath.front().c_str();
}
// ---------------------------------------------------------------------------
// Purpose: Returns the current log path or NULL if no path is configured.
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetLogPath() const
{
if( m_vecLogPath.empty() )
return "";
else
return m_vecLogPath.front().c_str();
}
// ---------------------------------------------------------------------------
// Purpose: Returns paths using the path registry and the provided override
// values. Pass NULL for any paths you don't care about.
// ---------------------------------------------------------------------------
bool CVRPathRegistry_Public::GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers )
{
std::string sLoadError;
CVRPathRegistry_Public pathReg;
bool bLoadedRegistry = pathReg.BLoadFromFile( &sLoadError );
int nCountEnvironmentVariables = 0;
int nRequestedPaths = 0;
if( psRuntimePath )
{
nRequestedPaths++;
if ( GetEnvironmentVariable( k_pchRuntimeOverrideVar ).length() != 0 )
{
*psRuntimePath = GetEnvironmentVariable( k_pchRuntimeOverrideVar );
nCountEnvironmentVariables++;
}
else if( !pathReg.GetRuntimePath().empty() )
{
*psRuntimePath = pathReg.GetRuntimePath();
}
else
{
*psRuntimePath = "";
}
}
if( psConfigPath )
{
nRequestedPaths++;
if ( GetEnvironmentVariable( k_pchConfigOverrideVar ).length() != 0 )
{
*psConfigPath = GetEnvironmentVariable( k_pchConfigOverrideVar );
nCountEnvironmentVariables++;
}
else if( pchConfigPathOverride )
{
*psConfigPath = pchConfigPathOverride;
}
else if( !pathReg.GetConfigPath().empty() )
{
*psConfigPath = pathReg.GetConfigPath();
}
else
{
*psConfigPath = "";
}
}
if( psLogPath )
{
nRequestedPaths++;
if ( GetEnvironmentVariable( k_pchLogOverrideVar ).length() != 0 )
{
*psLogPath = GetEnvironmentVariable( k_pchLogOverrideVar );
nCountEnvironmentVariables++;
}
else if( pchLogPathOverride )
{
*psLogPath = pchLogPathOverride;
}
else if( !pathReg.GetLogPath().empty() )
{
*psLogPath = pathReg.GetLogPath();
}
else
{
*psLogPath = "";
}
}
if ( pvecExternalDrivers )
{
*pvecExternalDrivers = pathReg.m_vecExternalDrivers;
}
if ( nCountEnvironmentVariables == nRequestedPaths )
{
// all three environment variables were set, so we don't need the physical file
return true;
}
else if( !bLoadedRegistry )
{
VRLog( "%s\n", sLoadError.c_str() );
}
return bLoadedRegistry;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
uint32_t CVRPathRegistry_Public::GetSteamAppId()
{
#if !defined( REL_BRANCH_ONLY )
uint32_t nSteamAppId = k_unSteamVRMainAppId;
#else
uint32_t nSteamAppId = k_unSteamVRAppId;
#endif
return nSteamAppId;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CVRPathRegistry_Public::IsSteamVRMain()
{
#if defined( REL_BRANCH_ONLY )
return false;
#else
return true;
#endif
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
uint32_t CVRPathRegistry_Public::InitSteamAppId()
{
uint32_t nSteamAppId = CVRPathRegistry_Public::GetSteamAppId();
// Forcefully setting to what it should be before SteamAPI_Init() since SteamVR is more often
// started as child processes of the game app and otherwise Steam then considers us as the
// wrong app id.
SetEnvironmentVariable( "SteamAppId", std::to_string( nSteamAppId ).c_str() );
SetEnvironmentVariable( "SteamGameId", std::to_string( nSteamAppId ).c_str() );
return nSteamAppId;
}

View file

@ -0,0 +1,52 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
#include <vector>
#include <stdint.h>
static const char *k_pchRuntimeOverrideVar = "VR_OVERRIDE";
static const char *k_pchConfigOverrideVar = "VR_CONFIG_PATH";
static const char *k_pchLogOverrideVar = "VR_LOG_PATH";
static const uint32_t k_unSteamVRAppId = 250820;
static const uint32_t k_unSteamVRMainAppId = 330050;
class CVRPathRegistry_Public
{
public:
static std::string GetVRPathRegistryFilename();
static std::string GetOpenVRConfigPath();
static uint32_t GetSteamAppId();
static bool IsSteamVRMain();
static uint32_t InitSteamAppId();
public:
CVRPathRegistry_Public();
/** Returns paths using the path registry and the provided override values. Pass NULL for any paths you don't care about.
* Returns false if the path registry could not be read. Valid paths might still be returned based on environment variables. */
static bool GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers = NULL );
bool BLoadFromFile( std::string *psError = nullptr );
bool BSaveToFile() const;
bool ToJsonString( std::string &sJsonString );
// methods to get the current values
std::string GetRuntimePath() const;
std::string GetConfigPath() const;
std::string GetLogPath() const;
protected:
typedef std::vector< std::string > StringVector_t;
// index 0 is the current setting
StringVector_t m_vecRuntimePath;
StringVector_t m_vecLogPath;
StringVector_t m_vecConfigPath;
// full list of external drivers
StringVector_t m_vecExternalDrivers;
};