[sdk]: fixed compilation of public openvr api
[sdk]: update with latest from main
Copying using vr_steamvr_main_to_sdk_release

[git-p4: depot-paths = "//vr/steamvr/sdk_release/": change = 7680507]
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 29b69c5..b83710a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -8,7 +8,7 @@
 if(APPLE)
   set(CMAKE_MACOSX_RPATH 1)
   if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
-    set_source_files_properties(vrcommon/pathtools_public.cpp vrcommon/vrpathregistry_public.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++")
+    set_source_files_properties(vrcore/pathtools_public.cpp vrcore/vrpathregistry_public.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++")
   endif()
   if(BUILD_SHARED OR BUILD_FRAMEWORK)
     find_library(FOUNDATION_FRAMEWORK Foundation)
@@ -23,7 +23,7 @@
 endif()
 
 # Add include folders.
-include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../headers ${CMAKE_CURRENT_SOURCE_DIR}/vrcommon)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../headers ${CMAKE_CURRENT_SOURCE_DIR}/vrcore)
 
 if(USE_CUSTOM_LIBCXX)
 	link_directories(
@@ -36,19 +36,21 @@
 	openvr_api_public.cpp
 	jsoncpp.cpp
 )
-set(VRCOMMON_FILES
-	vrcommon/dirtools_public.cpp
-	vrcommon/envvartools_public.cpp
-	vrcommon/pathtools_public.cpp
-	vrcommon/sharedlibtools_public.cpp
-	vrcommon/hmderrors_public.cpp
-	vrcommon/vrpathregistry_public.cpp
-	vrcommon/strtools_public.cpp
+set(VRCORE_FILES
+	vrcore/dirtools_public.cpp
+	vrcore/envvartools_public.cpp
+	vrcore/pathtools_public.cpp
+	vrcore/sharedlibtools_public.cpp
+	vrcore/hmderrors_public.cpp
+	vrcore/vrpathregistry_public.cpp
+	vrcore/strtools_public.cpp
 )
 
+add_compile_definitions(VRCORE_NO_PLATFORM)
+
 set(SOURCE_FILES
 	${CORE_FILES}
-	${VRCOMMON_FILES}
+	${VRCORE_FILES}
 )
 
 set(PUBLIC_HEADER_FILES
@@ -61,8 +63,8 @@
 	${CORE_FILES}
 )
 
-source_group("VRCommon" FILES
-	${VRCOMMON_FILES}
+source_group("VRCore" FILES
+	${VRCORE_FILES}
 )
 
 # Build the library.
diff --git a/src/openvr_api_public.cpp b/src/openvr_api_public.cpp
index 98ba762..973f291 100644
--- a/src/openvr_api_public.cpp
+++ b/src/openvr_api_public.cpp
@@ -127,10 +127,10 @@
 
 	// Because we don't have a way to select debug vs. release yet we'll just
 	// use debug if it's there
-#if defined( LINUX64 ) || defined( LINUXARM64 )
-	std::string sTestPath = Path_Join( sRuntimePath, "bin", PLATSUBDIR );
-#else
+#if defined( WIN32 ) || defined( LINUX32 )
 	std::string sTestPath = Path_Join( sRuntimePath, "bin" );
+#else
+	std::string sTestPath = Path_Join( sRuntimePath, "bin", PLATSUBDIR );
 #endif
 	if( !Path_IsDirectory( sTestPath ) )
 	{
diff --git a/src/vrcommon/dirtools_public.cpp b/src/vrcommon/dirtools_public.cpp
deleted file mode 100644
index e5fccc1..0000000
--- a/src/vrcommon/dirtools_public.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-//========= Copyright Valve Corporation ============//
-#include <vrcore/dirtools_public.h>
-#include <vrcore/strtools_public.h>
-#include <vrcore/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
-}
-
diff --git a/src/vrcommon/dirtools_public.h b/src/vrcommon/dirtools_public.h
deleted file mode 100644
index b048b41..0000000
--- a/src/vrcommon/dirtools_public.h
+++ /dev/null
@@ -1,17 +0,0 @@
-//========= 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 );
-
-
diff --git a/src/vrcore/dirtools_public.cpp b/src/vrcore/dirtools_public.cpp
new file mode 100644
index 0000000..2339e88
--- /dev/null
+++ b/src/vrcore/dirtools_public.cpp
@@ -0,0 +1,639 @@
+//========= Copyright Valve Corporation ============//
+#include <vrcore/dirtools_public.h>
+#include <vrcore/strtools_public.h>
+#include <vrcore/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
+
+#define HMD_INVALID_HANDLE_VALUE ( ( HMDHANDLE )( LONG_PTR )-1 )
+
+//-----------------------------------------------------------------------------
+// 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
+}
+
+#if !defined( VRCORE_NO_PLATFORM )
+
+#include <vrcore/log.h>
+
+//-----------------------------------------------------------------------------
+CDirIterator::CDirIterator( const char *pchPath, const char *pchPattern )
+{
+	m_pFindData = NULL;
+
+	// put in the path
+	if ( pchPath )
+	{
+		std::string sPathAndPattern = Path_Join( pchPath, pchPattern );
+
+		Init( sPathAndPattern.c_str() );
+	}
+	else
+	{
+		m_bNoFiles = true;
+		m_bUsedFirstFile = true;
+
+#if defined( _WIN32 )
+		m_hFind = HMD_INVALID_HANDLE_VALUE;
+		m_pFindData = new WIN32_FIND_DATAW;
+#else
+		m_hFind = -1;
+		m_pFindData = new _finddata_t;
+#endif
+		memset( m_pFindData, 0, sizeof( *m_pFindData ) );
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize iteration structure
+//-----------------------------------------------------------------------------
+void CDirIterator::Init( const std::string &sPathAndPattern )
+{
+#if defined( _WIN32 )
+	m_pFindData = new WIN32_FIND_DATAW;
+	memset( m_pFindData, 0, sizeof( *m_pFindData ) );
+
+	std::wstring sWPathAndPattern = UTF8to16( sPathAndPattern.c_str() );
+
+	m_hFind = FindFirstFileW( sWPathAndPattern.c_str(), m_pFindData );
+	bool bSuccess = ( m_hFind != HMD_INVALID_HANDLE_VALUE );
+	// Conversion should never fail with valid filenames...
+	if ( bSuccess )
+	{
+		m_sFilename = UTF16to8( m_pFindData->cFileName );
+	}
+#else
+	m_pFindData = new _finddata_t;
+	memset( m_pFindData, 0, sizeof( *m_pFindData ) );
+
+	m_hFind = _findfirst( sPathAndPattern.c_str(), m_pFindData );
+	bool bSuccess = ( m_hFind != -1 );
+#endif
+
+	if ( !bSuccess )
+	{
+		m_bNoFiles = true;
+		m_bUsedFirstFile = true;
+	}
+	else
+	{
+		m_bNoFiles = false;
+		// if we're pointing at . or .., set it as used
+		// so we'll look for the next item when BNextFile() is called
+		m_bUsedFirstFile = !BValidFilename();
+	}
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDirIterator::~CDirIterator()
+{
+#if defined( _WIN32 )
+	if ( m_hFind != HMD_INVALID_HANDLE_VALUE )
+	{
+		FindClose( m_hFind );
+	}
+	delete m_pFindData;
+#else
+	if ( m_hFind != -1 )
+	{
+		_findclose( m_hFind );
+	}
+	if ( m_pFindData )
+	{
+		for ( int i = 0; i < m_pFindData->numNames; i++ )
+		{
+			// scandir allocates with malloc, so free with free
+			free( m_pFindData->namelist[ i ] );
+		}
+		free( m_pFindData->namelist );
+		delete m_pFindData;
+	}
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Check for successful construction
+//-----------------------------------------------------------------------------
+bool CDirIterator::IsValid() const
+{
+#if defined( _WIN32 )
+	return m_hFind != HMD_INVALID_HANDLE_VALUE;
+#else
+	return m_hFind != -1;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Filter out . and ..
+//-----------------------------------------------------------------------------
+bool CDirIterator::BValidFilename()
+{
+#if defined( _WIN32 )
+	const char *pch = m_sFilename.c_str();
+#else
+	const char *pch = m_pFindData->name;
+#endif
+
+	if ( ( pch[ 0 ] == '.' && pch[ 1 ] == 0 ) || ( pch[ 0 ] == '.' && pch[ 1 ] == '.' && pch[ 2 ] == 0 ) )
+		return false;
+
+	return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if there is a file to read
+//-----------------------------------------------------------------------------
+bool CDirIterator::BNextFile()
+{
+	if ( m_bNoFiles )
+		return false;
+
+	// use the first result
+	if ( !m_bUsedFirstFile )
+	{
+		m_bUsedFirstFile = true;
+		return true;
+	}
+
+	// find the next item
+	for ( ;; )
+	{
+#if defined( _WIN32 )
+		bool bFound = ( FindNextFileW( m_hFind, m_pFindData ) != FALSE );
+		// Conversion should never fail with valid filenames...
+		if ( bFound )
+		{
+			m_sFilename = UTF16to8( m_pFindData->cFileName );
+		}
+#else
+		bool bFound = ( _findnext( m_hFind, m_pFindData ) == 0 );
+#endif
+
+		if ( !bFound )
+		{
+			// done
+			m_bNoFiles = true;
+			return false;
+		}
+
+		// skip over the '.' and '..' paths
+		if ( !BValidFilename() )
+			continue;
+
+		break;
+	}
+
+	// have one more file
+	return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns name (filename portion only) of the current file.
+// Name is emitted in UTF-8 encoding.
+// NOTE: This method returns a pointer into a static buffer, either a member
+// or the buffer inside the _finddata_t.
+//-----------------------------------------------------------------------------
+std::string CDirIterator::CurrentFileName()
+{
+#if defined( _WIN32 )
+	return m_sFilename;
+#else
+	return m_pFindData->name;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns size of the file
+//-----------------------------------------------------------------------------
+int64_t CDirIterator::CurrentFileLength() const
+{
+#if defined( _WIN32 )
+	LARGE_INTEGER li = { { m_pFindData->nFileSizeLow, ( LONG )m_pFindData->nFileSizeHigh } };
+	return li.QuadPart;
+#else
+	return ( int64_t )m_pFindData->size;
+#endif
+}
+
+#if defined( _WIN32 )
+//-----------------------------------------------------------------------------
+// Purpose: utility for converting a regular time to a system filetime
+//-----------------------------------------------------------------------------
+FILETIME UnixTimeToFileTime( int64_t t )
+{
+	FILETIME retf;
+	long long int ll;
+	ll = ( ( long long )t * 10000000LL );
+	ll += 116444736000000000LL;
+	retf.dwHighDateTime = ll >> 32;
+	retf.dwLowDateTime = ll & 0x00000000FFFFFFFF;
+	return retf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: utility for converting a system filetime to a regular time
+//-----------------------------------------------------------------------------
+int64_t FileTimeToUnixTime( FILETIME filetime )
+{
+	long long int t = filetime.dwHighDateTime;
+	t <<= 32;
+	t += ( unsigned long )filetime.dwLowDateTime;
+	t -= 116444736000000000LL;
+	return t / 10000000;
+}
+#endif // _WIN32
+
+//-----------------------------------------------------------------------------
+// Purpose: returns last write time of the file
+//-----------------------------------------------------------------------------
+int64_t CDirIterator::CurrentFileWriteTime() const
+{
+#if defined( _WIN32 )
+	return FileTimeToUnixTime( m_pFindData->ftLastWriteTime );
+#else
+	return m_pFindData->time_write;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the creation time of the file
+//-----------------------------------------------------------------------------
+int64_t CDirIterator::CurrentFileCreateTime() const
+{
+#if defined( _WIN32 )
+	return FileTimeToUnixTime( m_pFindData->ftCreationTime );
+#else
+	return m_pFindData->time_create;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether current item under examination is a directory
+//-----------------------------------------------------------------------------
+bool CDirIterator::BCurrentIsDir() const
+{
+#if defined( _WIN32 )
+	return ( m_pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0;
+#else
+	return ( m_pFindData->attrib & _A_SUBDIR ? true : false );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether current item under examination is a hidden file
+//-----------------------------------------------------------------------------
+bool CDirIterator::BCurrentIsHidden() const
+{
+#if defined( _WIN32 )
+	return ( m_pFindData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) != 0;
+#else
+	return ( m_pFindData->attrib & _A_HIDDEN ? true : false );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether current item under examination is read-only
+//-----------------------------------------------------------------------------
+bool CDirIterator::BCurrentIsReadOnly() const
+{
+#if defined( _WIN32 )
+	return ( m_pFindData->dwFileAttributes & FILE_ATTRIBUTE_READONLY ) != 0;
+#else
+	return ( m_pFindData->attrib & _A_RDONLY ? true : false );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether current item under examination is marked as a system file
+//-----------------------------------------------------------------------------
+bool CDirIterator::BCurrentIsSystem() const
+{
+#if defined( _WIN32 )
+	return ( m_pFindData->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ) != 0;
+#else
+	return ( m_pFindData->attrib & _A_SYSTEM ? true : false );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether current item under examination is marked for archiving
+//-----------------------------------------------------------------------------
+bool CDirIterator::BCurrentIsMarkedForArchive() const
+{
+#if defined( _WIN32 )
+	return ( m_pFindData->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE ) != 0;
+#else
+	return ( m_pFindData->attrib & _A_ARCH ? true : false );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// A huge pile of stuff from fileio.cpp in steam/tier1
+//
+//-----------------------------------------------------------------------------
+
+#if !defined( _WIN32 )
+// findfirst/findnext implementation from filesystem/linux_support.[h|cpp]
+
+static char selectBuf[ PATH_MAX ];
+
+#if defined( OSX ) && !defined( __MAC_10_8 )
+static int FileSelect( direntBig_t *ent )
+#elif defined( LINUX ) || defined( OSX )
+static int FileSelect( const direntBig_t *ent )
+#else
+#error
+#endif
+{
+	const char *mask = selectBuf;
+	const char *name = ent->d_name;
+
+	return FileSelect( name, mask );
+}
+
+static int FileSelect( const char *name, const char *mask )
+{
+	// printf("Test:%s %s\n",mask,name);
+
+	if ( !strcmp( name, "." ) || !strcmp( name, ".." ) )
+		return 0;
+
+	if ( !strcmp( mask, "*.*" ) || !strcmp( mask, "*" ) )
+		return 1;
+
+	while ( *mask && *name )
+	{
+		if ( *mask == '*' )
+		{
+			mask++;		  // move to the next char in the mask
+			if ( !*mask ) // if this is the end of the mask its a match
+			{
+				return 1;
+			}
+			while ( *name && toupper( *name ) != toupper( *mask ) )
+			{ // while the two don't meet up again
+				name++;
+			}
+			if ( !*name )
+			{ // end of the name
+				break;
+			}
+		}
+		else if ( *mask != '?' )
+		{
+			if ( toupper( *mask ) != toupper( *name ) )
+			{ // mismatched!
+				return 0;
+			}
+			else
+			{
+				mask++;
+				name++;
+				if ( !*mask && !*name )
+				{ // if its at the end of the buffer
+					return 1;
+				}
+			}
+		}
+		else /* mask is "?", we don't care*/
+		{
+			mask++;
+			name++;
+		}
+	}
+
+	return ( !*mask && !*name ); // both of the strings are at the end
+}
+
+int FillDataStruct( _finddata_t *dat )
+{
+	statBig_t fileStat;
+
+	if ( dat->curName >= dat->numNames )
+		return -1;
+
+	strncpy( dat->name, dat->namelist[ dat->curName ]->d_name, sizeof( dat->name ) );
+	char szFullPath[ MAX_PATH ];
+	int nWriteSize = snprintf( szFullPath, sizeof( szFullPath ), "%s%c%s", dat->dirBase, Path_GetSlash(), dat->name );
+	if ( nWriteSize >= sizeof( szFullPath ) )
+	{
+		Log( LogError, "File path truncated\n" );
+	}
+	if ( statBig( szFullPath, &fileStat ) == 0 )
+	{
+		dat->attrib = fileStat.st_mode;
+		dat->size = fileStat.st_size;
+		dat->time_write = fileStat.st_mtime;
+		dat->time_create = fileStat.st_ctime;
+	}
+	else
+	{
+		dat->attrib = 0;
+		dat->size = 0;
+		dat->time_write = 0;
+		dat->time_create = 0;
+	}
+	free( dat->namelist[ dat->curName ] );
+	dat->namelist[ dat->curName ] = NULL;
+	dat->curName++;
+	return 1;
+}
+
+int _findfirst( const char *fileName, _finddata_t *dat )
+{
+	char nameStore[ MAX_PATH ];
+	char *dir = NULL;
+	int n, iret = -1;
+
+	strncpy( nameStore, fileName, sizeof( nameStore ) );
+
+	if ( strrchr( nameStore, '/' ) )
+	{
+		dir = nameStore;
+		while ( strrchr( dir, '/' ) )
+		{
+			statBig_t dirChk;
+
+			// zero this with the dir name
+			dir = strrchr( nameStore, '/' );
+			*dir = '\0';
+			if ( dir == nameStore )
+			{
+				strcpy( nameStore, "/" ); // C++11 would prefer no `dir = "/";`
+			}
+			else
+			{
+				dir = nameStore;
+			}
+
+			if ( statBig( dir, &dirChk ) == 0 && S_ISDIR( dirChk.st_mode ) )
+			{
+				break;
+			}
+		}
+	}
+	else
+	{
+		// couldn't find a dir separator...
+		return -1;
+	}
+
+	if ( strlen( dir ) > 0 )
+	{
+		if ( strlen( dir ) == 1 )
+			strncpy( selectBuf, fileName + 1, sizeof( selectBuf ) );
+		else
+			strncpy( selectBuf, fileName + strlen( dir ) + 1, sizeof( selectBuf ) );
+
+		n = scandirBig( dir, &dat->namelist, FileSelect, alphasortBig );
+		if ( n < 0 )
+		{
+			// silently return, nothing interesting
+		}
+		else
+		{
+			dat->curName = 0;
+			dat->numNames = n; // n is the number of matches
+			strncpy( dat->dirBase, dir, sizeof( dat->dirBase ) );
+			iret = FillDataStruct( dat );
+			if ( iret < 0 )
+			{
+				free( dat->namelist );
+				dat->namelist = NULL;
+				dat->curName = 0;
+				dat->numNames = 0;
+			}
+		}
+	}
+
+	//  printf("Returning: %i \n",iret);
+	return iret;
+}
+
+int _findnext( int64_t handle, _finddata_t *dat )
+{
+	if ( dat->curName >= dat->numNames )
+	{
+		free( dat->namelist );
+		dat->namelist = NULL;
+		dat->curName = 0;
+		dat->numNames = 0;
+		return -1; // no matches left
+	}
+
+	FillDataStruct( dat );
+	return 0;
+}
+
+bool _findclose( int64_t handle )
+{
+	return true;
+}
+
+#endif // !defined( _WIN32 )
+
+#endif // VRCORE_NO_PLATFORM
\ No newline at end of file
diff --git a/src/vrcore/dirtools_public.h b/src/vrcore/dirtools_public.h
new file mode 100644
index 0000000..3b3575e
--- /dev/null
+++ b/src/vrcore/dirtools_public.h
@@ -0,0 +1,83 @@
+//========= 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 );
+
+
+#if !defined( VRCORE_NO_PLATFORM )
+
+// for finddata_t
+#include <vrcore/platform.h>
+
+typedef void *HMDHANDLE;
+
+// iterator class, initialize with the path & pattern you want to want files/dirs for.
+//
+// all string setters and accessors use UTF-8 encoding.
+class CDirIterator
+{
+public:
+	CDirIterator( const char *pchPath, const char *pchPattern );
+	~CDirIterator();
+
+	bool IsValid() const;
+
+	// fetch the next file
+	bool BNextFile();
+
+	// name of the current file - file portion only, not full path
+	std::string CurrentFileName();
+
+	// size of the current file
+	int64_t CurrentFileLength() const;
+
+	// creation time of the current file
+	int64_t CurrentFileCreateTime() const;
+
+	// mod time of the current file
+	int64_t CurrentFileWriteTime() const;
+
+	// mode/type checks:
+
+	// is the current file actually a directory?
+	bool BCurrentIsDir() const;
+
+	// is the current file hidden?
+	bool BCurrentIsHidden() const;
+
+	// is the current file read-only?
+	bool BCurrentIsReadOnly() const;
+
+	// is the current file a system file?
+	bool BCurrentIsSystem() const;
+
+	// is the current file's archive bit set?
+	bool BCurrentIsMarkedForArchive() const;
+
+private:
+	void Init( const std::string &sPathAndPattern );
+	bool BValidFilename();
+	bool m_bNoFiles, m_bUsedFirstFile;
+
+#if defined( _WIN32 )
+	HMDHANDLE m_hFind;
+	struct _WIN32_FIND_DATAW *m_pFindData;
+	std::string m_sFilename;
+#else
+	int64_t m_hFind;
+	struct _finddata_t *m_pFindData;
+#endif
+};
+
+#endif // VRCORE_NO_PLATFORM
\ No newline at end of file
diff --git a/src/vrcommon/envvartools_public.cpp b/src/vrcore/envvartools_public.cpp
similarity index 100%
rename from src/vrcommon/envvartools_public.cpp
rename to src/vrcore/envvartools_public.cpp
diff --git a/src/vrcommon/envvartools_public.h b/src/vrcore/envvartools_public.h
similarity index 100%
rename from src/vrcommon/envvartools_public.h
rename to src/vrcore/envvartools_public.h
diff --git a/src/vrcommon/hmderrors_public.cpp b/src/vrcore/hmderrors_public.cpp
similarity index 90%
rename from src/vrcommon/hmderrors_public.cpp
rename to src/vrcore/hmderrors_public.cpp
index 6f44d3a..cf89eb2 100644
--- a/src/vrcommon/hmderrors_public.cpp
+++ b/src/vrcore/hmderrors_public.cpp
@@ -56,6 +56,14 @@
 	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_Init_VRDashboardServicePending:	return "VR Dashboard startup failed, vrservice was pending for too long (160)";
+	case VRInitError_Init_VRDashboardServiceTimeout:	return "VR Dashboard startup failed, attempt to communicate with vrservice timed out (161)";
+	case VRInitError_Init_VRDashboardServiceStopped:	return "VR Dashboard startup failed, vrservice was stopped (162)";
+	case VRInitError_Init_VRDashboardAlreadyStarted:	return "VR Dashboard startup failed, vrdashboard was already running (163)";
+	case VRInitError_Init_VRDashboardCopyFailed:		return "VR Dashboard startup failed, required files did not copy correctly (164)";
+	case VRInitError_Init_VRDashboardTokenFailure:		return "VR Dashboard startup failed, unable to create appropriate token (165)";
+	case VRInitError_Init_VRDashboardEnvironmentFailure:	return "VR Dashboard startup failed, unable to create appropriate environment (166)";
+	case VRInitError_Init_VRDashboardPathFailure:		return "VR Dashboard startup failed, path error (167)";
 
 	case VRInitError_Driver_Failed:							return "Driver Failed (200)";
 	case VRInitError_Driver_Unknown:						return "Driver Not Known (201)";
@@ -109,6 +117,7 @@
 	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_VendorSpecific_HmdFound_UnexpectedConfiguration_1:		return "HMD found, but problems with the data (1115)";
 
 	case VRInitError_Steam_SteamInstallationNotFound: return "Unable to find Steam installation (2000)";
 
@@ -180,8 +189,20 @@
 		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_PrismClientInitFailed );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_PrismClientStartFailed );
 		RETURN_ENUM_AS_STRING( VRInitError_Init_PrismExitedUnexpectedly );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_BadLuid );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NoServerForAppContainer );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_DuplicateBootstrapper );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardServicePending );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardServiceTimeout );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardServiceStopped );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardAlreadyStarted );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardCopyFailed );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardTokenFailure );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardEnvironmentFailure );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRDashboardPathFailure );
 
 		RETURN_ENUM_AS_STRING( VRInitError_Driver_Failed );
 		RETURN_ENUM_AS_STRING( VRInitError_Driver_Unknown );
@@ -197,6 +218,8 @@
 		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_Driver_PeerDriverNotInstalled );
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_WirelessHmdNotConnected );
 
 		RETURN_ENUM_AS_STRING( VRInitError_IPC_ServerInitFailed);
 		RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailed);
@@ -304,10 +327,13 @@
 		RETURN_ENUM_AS_STRING( VRInitError_Compositor_WindowInterfaceIsNull );
 		RETURN_ENUM_AS_STRING( VRInitError_Compositor_SystemLayerCreateInstance );
 		RETURN_ENUM_AS_STRING( VRInitError_Compositor_SystemLayerCreateSession );
+		RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateInverseDistortUVs );
+		RETURN_ENUM_AS_STRING( VRInitError_Compositor_CreateBackbufferDepth );
 
 		// Vendor-specific errors
 		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_UnableToConnectToOculusRuntime);
 		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_WindowsNotInDevMode );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_OculusLinkNotEnabled );
 		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_OculusRuntimeBadInstall );
 
 		// Lighthouse
@@ -324,6 +350,7 @@
 		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_VendorSpecific_HmdFound_UnexpectedConfiguration_1 );
 
 		RETURN_ENUM_AS_STRING( VRInitError_Steam_SteamInstallationNotFound );
 
diff --git a/src/vrcommon/hmderrors_public.h b/src/vrcore/hmderrors_public.h
similarity index 100%
rename from src/vrcommon/hmderrors_public.h
rename to src/vrcore/hmderrors_public.h
diff --git a/src/vrcommon/pathtools_public.cpp b/src/vrcore/pathtools_public.cpp
similarity index 91%
rename from src/vrcommon/pathtools_public.cpp
rename to src/vrcore/pathtools_public.cpp
index 2503ec6..a29154f 100644
--- a/src/vrcommon/pathtools_public.cpp
+++ b/src/vrcore/pathtools_public.cpp
@@ -111,7 +111,7 @@
 	const char *pchTmpDir = getenv( "TMPDIR" );
 	if ( pchTmpDir == NULL )
 	{
-		return "";
+		return "/tmp";
 	}
 	return pchTmpDir;
 #endif
@@ -608,15 +608,18 @@
 	{
 		fseek( f, 0, SEEK_END );
 		int size = ftell( f );
-		fseek( f, 0, SEEK_SET );
+		if ( size > 0 )
+		{
+			fseek( f, 0, SEEK_SET );
 
-		vecFileContents.resize( size );
-		if ( fread( &vecFileContents[ 0 ], size, 1, f ) == 1 )
-		{
-		}
-		else
-		{
-			vecFileContents.clear();
+			vecFileContents.resize( size );
+			if ( fread( &vecFileContents[ 0 ], size, 1, f ) == 1 )
+			{
+			}
+			else
+			{
+				vecFileContents.clear();
+			}
 		}
 
 		fclose( f );
@@ -643,18 +646,21 @@
 	{
 		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 ( size > 0 )
 		{
-			if (pSize)
-				*pSize = size;
-		}
-		else
-		{
-			delete[] buf;
-			buf = 0;
+			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);
@@ -682,18 +688,22 @@
 	if ( f != NULL )
 	{
 		fseek( f, 0, SEEK_END );
-		uint32_t size = (uint32_t)ftell( f );
-		fseek( f, 0, SEEK_SET );
+		int nSize = ftell( f );
+		if ( nSize > 0 )
+		{
+			uint32_t size = (uint32_t) nSize;
+			fseek( f, 0, SEEK_SET );
 
-		if ( size > unSize || !pBuffer )
-		{
-			unSizeToReturn = (uint32_t)size;
-		}
-		else
-		{
-			if ( fread( pBuffer, size, 1, f ) == 1 )
+			if ( size > unSize || !pBuffer )
 			{
-				unSizeToReturn = (uint32_t)size;
+				unSizeToReturn = size;
+			}
+			else
+			{
+				if ( fread( pBuffer, size, 1, f ) == 1 )
+				{
+					unSizeToReturn = size;
+				}
 			}
 		}
 
@@ -986,3 +996,67 @@
 
 	return sFixed;
 }
+
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes a directory and any contents, including subdirectories.
+//-----------------------------------------------------------------------------
+bool Path_DeleteDirectory( const std::string &sDirectoryPath, bool bDeleteSubdirectories )
+{
+#if defined( _WIN32 )
+	std::wstring wsDirectoryPath = UTF8to16( sDirectoryPath.c_str() );
+	std::wstring wsDirectoryPattern = wsDirectoryPath + L"\\*.*";
+	WIN32_FIND_DATAW findData;
+	HANDLE hFindFile = FindFirstFileW( wsDirectoryPattern.c_str(), &findData );
+	if ( hFindFile == INVALID_HANDLE_VALUE )
+		return false;
+
+	do
+	{
+		if ( findData.cFileName[ 0 ] == '.' )
+			continue;
+
+		std::wstring wsFilePath = wsDirectoryPath + L"\\" + findData.cFileName;
+
+		if ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+		{
+			if ( !bDeleteSubdirectories )
+			{
+				FindClose( hFindFile );
+				return false;
+			}
+			else if ( !Path_DeleteDirectory( UTF16to8( wsFilePath ), bDeleteSubdirectories ) )
+			{
+				FindClose( hFindFile );
+				return false;
+			}
+		}
+
+		if ( !SetFileAttributesW( wsFilePath.c_str(), FILE_ATTRIBUTE_NORMAL ) )
+		{
+			FindClose( hFindFile );
+			return false;
+		}
+
+		if ( !DeleteFileW( wsFilePath.c_str() ) )
+		{
+			FindClose( hFindFile );
+			return false;
+		}
+	} while ( FindNextFileW( hFindFile, &findData ) );
+
+	if ( !FindClose( hFindFile ) )
+		return false;
+
+	if ( !SetFileAttributesW( wsDirectoryPath.c_str(), FILE_ATTRIBUTE_NORMAL ) )
+		return false;
+
+	if ( !RemoveDirectoryW( wsDirectoryPath.c_str() ) )
+		return false;
+
+	return true;
+#else
+	return false;
+#endif
+}
+
diff --git a/src/vrcommon/pathtools_public.h b/src/vrcore/pathtools_public.h
similarity index 97%
rename from src/vrcommon/pathtools_public.h
rename to src/vrcore/pathtools_public.h
index 8bad50a..6edd3e3 100644
--- a/src/vrcommon/pathtools_public.h
+++ b/src/vrcore/pathtools_public.h
@@ -114,6 +114,8 @@
 
 std::string Path_SanitizeFilename( const std::string& sFilename );
 
+bool Path_DeleteDirectory( const std::string& sDirectoryPath, bool bDeleteSubdirectories = false );
+
 #ifndef MAX_UNICODE_PATH
 	#define MAX_UNICODE_PATH 32767
 #endif
@@ -140,6 +142,8 @@
 #define PROGRAM_EXT ""
 #if defined( LINUX32 )
 #define PLATSUBDIR	"linux32"
+#elif defined( ANDROIDARM32 )
+#define PLATSUBDIR	"androidarm32" 
 #elif defined( ANDROIDARM64 )
 #define PLATSUBDIR	"androidarm64" 
 #elif defined( LINUXARM64 )
diff --git a/src/vrcommon/sharedlibtools_public.cpp b/src/vrcore/sharedlibtools_public.cpp
similarity index 63%
rename from src/vrcommon/sharedlibtools_public.cpp
rename to src/vrcore/sharedlibtools_public.cpp
index cce1528..069c6b4 100644
--- a/src/vrcommon/sharedlibtools_public.cpp
+++ b/src/vrcore/sharedlibtools_public.cpp
@@ -10,30 +10,29 @@
 #include <dlfcn.h>
 #endif
 
-
-SharedLibHandle SharedLib_Load( const char *pchPath, uint32_t *pErrorCode )
+SharedLibHandle SharedLib_Load( const char *pchPath, std::string *pErrStr )
 {
 	SharedLibHandle pHandle = nullptr;
 #if defined( _WIN32)
 	pHandle = ( SharedLibHandle )LoadLibraryEx( pchPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
+#elif defined(LINUXARM64)	
+	pHandle = (SharedLibHandle) dlopen( pchPath, RTLD_LOCAL|RTLD_DEEPBIND|RTLD_NOW );
 #elif defined(POSIX)
-	pHandle = (SharedLibHandle) dlopen(pchPath, RTLD_LOCAL|RTLD_NOW);
+	pHandle = (SharedLibHandle) dlopen( pchPath, RTLD_LOCAL|RTLD_NOW );
 #endif
 
-	if ( pErrorCode )
+	if ( pHandle == nullptr && pErrStr )
 	{
-		if ( pHandle == nullptr )
-		{
 #if defined( _WIN32)
-			*pErrorCode = ( uint32_t ) GetLastError();
+		// TODO: Consider using FormatMessage to get an error string for this error code
+		*pErrStr =  std::to_string( GetLastError() );
 #elif defined(POSIX)
-			*pErrorCode = 1;
-#endif
-		}
-		else
+		char * pErr = dlerror();
+		if ( pErr )
 		{
-			*pErrorCode = 0;
+			*pErrStr = std::string ( pErr );
 		}
+#endif
 	}
 
 	return pHandle;
diff --git a/src/vrcommon/sharedlibtools_public.h b/src/vrcore/sharedlibtools_public.h
similarity index 70%
rename from src/vrcommon/sharedlibtools_public.h
rename to src/vrcore/sharedlibtools_public.h
index 38e7c29..ba8b75d 100644
--- a/src/vrcommon/sharedlibtools_public.h
+++ b/src/vrcore/sharedlibtools_public.h
@@ -2,10 +2,11 @@
 #pragma once
 
 #include <stdint.h>
+#include <string>
 
 typedef void *SharedLibHandle;
 
-SharedLibHandle SharedLib_Load( const char *pchPath, uint32_t *pErrorCode = nullptr );
+SharedLibHandle SharedLib_Load( const char *pchPath, std::string *pErrStr = nullptr );
 void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName);
 void SharedLib_Unload( SharedLibHandle lib );
 
diff --git a/src/vrcommon/strtools_public.cpp b/src/vrcore/strtools_public.cpp
similarity index 94%
rename from src/vrcommon/strtools_public.cpp
rename to src/vrcore/strtools_public.cpp
index 343ec42..03aec14 100644
--- a/src/vrcommon/strtools_public.cpp
+++ b/src/vrcore/strtools_public.cpp
@@ -9,7 +9,13 @@
 #include <functional>
 #include <locale>
 #include <codecvt>
+#include <cstdarg>
+
+#if !defined( VRCORE_NO_PLATFORM )
 #include <vrcore/assert.h>
+#else
+#define AssertMsg( cond, ... )
+#endif
 
 #if defined( _WIN32 )
 #include <windows.h>
@@ -604,3 +610,37 @@
 {
 	return RepairUTF8( sInputUtf8.data(), sInputUtf8.data() + sInputUtf8.size(), sOutputUtf8 );
 }
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Trims trailing CR, LF, Tab, and Space characters
+//-----------------------------------------------------------------------------
+std::string TrimTrailingWhitespace( const std::string& in )
+{
+	// trim string at the point where a non-whitespace character occurs -- often at the end of the string
+	size_t endpos = in.find_last_not_of( " \t\n\r" );
+	if ( std::string::npos != endpos )
+	{
+		return in.substr( 0, endpos + 1 );
+	}
+	else
+	{
+		return in;
+	}
+}
+
+/** Returns an IP address as a string */
+std::string IpToString( uint32_t unIpH )
+{
+	uint8_t *ip = ( uint8_t * )&unIpH;
+	return Format( "%d.%d.%d.%d", ip[ 3 ], ip[ 2 ], ip[ 1 ], ip[ 0 ] );
+}
+
+/** Returns an IP address and port as a string */
+std::string IpAndPortToString( uint32_t unIpH, uint16_t usPortH )
+{
+	uint8_t *ip = ( uint8_t * )&unIpH;
+	return Format( "%d.%d.%d.%d:%u", ip[ 3 ], ip[ 2 ], ip[ 1 ], ip[ 0 ], usPortH );
+}
+
+
diff --git a/src/vrcommon/strtools_public.h b/src/vrcore/strtools_public.h
similarity index 94%
rename from src/vrcommon/strtools_public.h
rename to src/vrcore/strtools_public.h
index 0e8e349..d65130c 100644
--- a/src/vrcommon/strtools_public.h
+++ b/src/vrcore/strtools_public.h
@@ -31,6 +31,9 @@
 bool RepairUTF8( const char *begin, const char *end, std::string & sOutputUtf8 );
 bool RepairUTF8( const std::string & sInputUtf8, std::string & sOutputUtf8 );
 
+/** Trims trailing CR, LF, Tab, and Space characters */
+std::string TrimTrailingWhitespace( const std::string& in );
+
 /** safely copy a string into a buffer */
 void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource );
 template< size_t bufferSize >
@@ -149,6 +152,12 @@
 //-----------------------------------------------------------------------------
 void V_StripExtension( std::string &in );
 
+/** Returns an IP address as a string */
+std::string IpToString( uint32_t unIpH );
+
+/** Returns an IP address and port as a string */
+std::string IpAndPortToString( uint32_t unIpH, uint16_t usPortH );
+
 
 /** Tokenizes a string into a vector of strings */
 std::vector<std::string> TokenizeString( const std::string & sString, char cToken );
diff --git a/src/vrcommon/vrpathregistry_public.cpp b/src/vrcore/vrpathregistry_public.cpp
similarity index 97%
rename from src/vrcommon/vrpathregistry_public.cpp
rename to src/vrcore/vrpathregistry_public.cpp
index 2746bdb..0fbff25 100644
--- a/src/vrcommon/vrpathregistry_public.cpp
+++ b/src/vrcore/vrpathregistry_public.cpp
@@ -481,3 +481,10 @@
 	return nSteamAppId;
 }
 
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRPathRegistry_Public::IsChildOfVRServer()
+{
+	std::string app_key = GetEnvironmentVariable( "STEAMVR_APPKEY" );
+	return app_key == "openvr.component.vrserver";
+}
\ No newline at end of file
diff --git a/src/vrcommon/vrpathregistry_public.h b/src/vrcore/vrpathregistry_public.h
similarity index 97%
rename from src/vrcommon/vrpathregistry_public.h
rename to src/vrcore/vrpathregistry_public.h
index 6563286..df61a60 100644
--- a/src/vrcommon/vrpathregistry_public.h
+++ b/src/vrcore/vrpathregistry_public.h
@@ -21,7 +21,7 @@
 	static uint32_t GetSteamAppId();
 	static bool IsSteamVRMain();
 	static uint32_t InitSteamAppId();
-
+	static bool IsChildOfVRServer();
 public:
 	CVRPathRegistry_Public();