Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

782 lines
18 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "pch_tier0.h"
  8. #include <time.h>
  9. #if defined(_WIN32) && !defined(_X360)
  10. #define WINDOWS_LEAN_AND_MEAN
  11. #define _WIN32_WINNT 0x0403
  12. #include <windows.h>
  13. #include <direct.h>
  14. #include <io.h>
  15. #endif
  16. #include <errno.h>
  17. #include <assert.h>
  18. #include "tier0/platform.h"
  19. #if defined( _X360 )
  20. #include "xbox/xbox_console.h"
  21. #endif
  22. #include "tier0/threadtools.h"
  23. #include "tier0/minidump.h"
  24. #include "tier0/memalloc.h"
  25. #if defined( _PS3 )
  26. #include <cell/fios/fios_common.h>
  27. #include <cell/fios/fios_memory.h>
  28. #include <cell/fios/fios_configuration.h>
  29. #include <sys/process.h>
  30. #include <sysutil/sysutil_common.h>
  31. #include <sysutil/sysutil_sysparam.h>
  32. #include <sys/time.h>
  33. #include "tls_ps3.h"
  34. #if !defined(_CERT)
  35. #include "sn/LibSN.h"
  36. #endif
  37. /*
  38. #include <sys/types.h>
  39. #include <sys/process.h>
  40. #include <sys/prx.h>
  41. #include <sysutil/sysutil_syscache.h>
  42. #include <cell/sysmodule.h>
  43. */
  44. #include <cell/fios/fios_time.h>
  45. #endif // _PS3
  46. // memdbgon must be the last include file in a .cpp file!!!
  47. #include "tier0/memdbgon.h"
  48. // Benchmark mode uses this heavy-handed method
  49. static bool g_bBenchmarkMode = false;
  50. #ifdef _WIN32
  51. static double g_FakeBenchmarkTime = 0;
  52. static double g_FakeBenchmarkTimeInc = 1.0 / 66.0;
  53. #endif
  54. static CThreadFastMutex g_LocalTimeMutex;
  55. //our global error callback function. Note that this is not initialized, but static space guarantees this is NULL at app start.
  56. //If you initialize, it will set to zero again when the CPP runs its static initializers, which could stomp the value if another
  57. //CPP sets this value while initializing its static space
  58. static ExitProcessWithErrorCBFn g_pfnExitProcessWithErrorCB; //= NULL
  59. bool Plat_IsInBenchmarkMode()
  60. {
  61. return g_bBenchmarkMode;
  62. }
  63. void Plat_SetBenchmarkMode( bool bBenchmark )
  64. {
  65. g_bBenchmarkMode = bBenchmark;
  66. }
  67. #if defined( PLATFORM_WINDOWS )
  68. static LARGE_INTEGER g_PerformanceFrequency;
  69. static double g_PerformanceCounterToS;
  70. static double g_PerformanceCounterToMS;
  71. static double g_PerformanceCounterToUS;
  72. static LARGE_INTEGER g_ClockStart;
  73. static bool s_bTimeInitted;
  74. static void InitTime()
  75. {
  76. if( !s_bTimeInitted )
  77. {
  78. s_bTimeInitted = true;
  79. QueryPerformanceFrequency(&g_PerformanceFrequency);
  80. g_PerformanceCounterToS = 1.0 / g_PerformanceFrequency.QuadPart;
  81. g_PerformanceCounterToMS = 1e3 / g_PerformanceFrequency.QuadPart;
  82. g_PerformanceCounterToUS = 1e6 / g_PerformanceFrequency.QuadPart;
  83. QueryPerformanceCounter(&g_ClockStart);
  84. }
  85. }
  86. double Plat_FloatTime()
  87. {
  88. if (! s_bTimeInitted )
  89. InitTime();
  90. if ( g_bBenchmarkMode )
  91. {
  92. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  93. return g_FakeBenchmarkTime;
  94. }
  95. LARGE_INTEGER CurrentTime;
  96. QueryPerformanceCounter( &CurrentTime );
  97. double fRawSeconds = (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToS;
  98. return fRawSeconds;
  99. }
  100. uint32 Plat_MSTime()
  101. {
  102. if (! s_bTimeInitted )
  103. InitTime();
  104. if ( g_bBenchmarkMode )
  105. {
  106. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  107. return (uint32)(g_FakeBenchmarkTime * 1000.0);
  108. }
  109. LARGE_INTEGER CurrentTime;
  110. QueryPerformanceCounter( &CurrentTime );
  111. return (uint32) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToMS );
  112. }
  113. uint64 Plat_USTime()
  114. {
  115. if (! s_bTimeInitted )
  116. InitTime();
  117. if ( g_bBenchmarkMode )
  118. {
  119. g_FakeBenchmarkTime += g_FakeBenchmarkTimeInc;
  120. return (uint64)(g_FakeBenchmarkTime * 1e6);
  121. }
  122. LARGE_INTEGER CurrentTime;
  123. QueryPerformanceCounter( &CurrentTime );
  124. return (uint64) ( ( CurrentTime.QuadPart - g_ClockStart.QuadPart ) * g_PerformanceCounterToUS );
  125. }
  126. uint64 Plat_GetClockStart()
  127. {
  128. if ( !s_bTimeInitted )
  129. InitTime();
  130. return g_ClockStart.QuadPart;
  131. }
  132. #elif defined( PLATFORM_PS3 )
  133. cell::fios::abstime_t g_fiosLaunchTime = 0;
  134. double Plat_FloatTime()
  135. {
  136. return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime ) * 1e-6;
  137. }
  138. uint32 Plat_MSTime()
  139. {
  140. return (uint32) cell::fios::FIOSAbstimeToMilliseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime );
  141. }
  142. uint64 Plat_USTime()
  143. {
  144. return cell::fios::FIOSAbstimeToMicroseconds( cell::fios::FIOSGetCurrentTime() - g_fiosLaunchTime );
  145. }
  146. uint64 Plat_GetClockStart()
  147. {
  148. return g_fiosLaunchTime;
  149. }
  150. #endif // PLATFORM_WINDOWS/PLATFORM_PS3
  151. uint64 Plat_GetTime()
  152. {
  153. // We just provide a wrapper on this function so we can protect access to time() everywhere.
  154. time_t ltime;
  155. time( &ltime );
  156. return ltime;
  157. }
  158. void Plat_GetLocalTime( struct tm *pNow )
  159. {
  160. // We just provide a wrapper on this function so we can protect access to time() everywhere.
  161. time_t ltime;
  162. time( &ltime );
  163. Plat_ConvertToLocalTime( ltime, pNow );
  164. }
  165. void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow )
  166. {
  167. // Since localtime() returns a global, we need to protect against multiple threads stomping it.
  168. g_LocalTimeMutex.Lock();
  169. time_t ltime = (time_t)nTime;
  170. tm *pTime = localtime( &ltime );
  171. if ( pTime )
  172. *pNow = *pTime;
  173. else
  174. memset( pNow, 0, sizeof( *pNow ) );
  175. g_LocalTimeMutex.Unlock();
  176. }
  177. void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes )
  178. {
  179. g_LocalTimeMutex.Lock();
  180. char *pStr = asctime( pTime );
  181. strncpy( pOut, pStr, nMaxBytes );
  182. pOut[nMaxBytes-1] = 0;
  183. g_LocalTimeMutex.Unlock();
  184. }
  185. /*
  186. // timezone
  187. int32 Plat_timezone( void )
  188. {
  189. #ifdef _PS3
  190. g_LocalTimeMutex.Lock();
  191. int timezone = 0;
  192. if ( cellSysutilGetSystemParamInt (CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE, &timezone ) < CELL_OK ) // Not Threadsafe
  193. timezone = 0;
  194. g_LocalTimeMutex.Unlock();
  195. return timezone;
  196. #else
  197. return timezone;
  198. #endif
  199. }
  200. // daylight savings
  201. int32 Plat_daylight( void )
  202. {
  203. #ifdef _PS3
  204. g_LocalTimeMutex.Lock();
  205. int32 daylight = 0;
  206. if ( cellSysutilGetSystemParamInt (CELL_SYSUTIL_SYSTEMPARAM_ID_SUMMERTIME, &daylight ) < CELL_OK )
  207. daylight = 0;
  208. g_LocalTimeMutex.Unlock();
  209. return daylight;
  210. #else
  211. return daylight;
  212. #endif
  213. }
  214. */
  215. void Platform_gmtime( uint64 nTime, struct tm *pTime )
  216. {
  217. time_t tmtTime = nTime;
  218. #ifdef _PS3
  219. struct tm * tmp = gmtime( &tmtTime );
  220. * pTime = * tmp;
  221. #else
  222. gmtime_s( pTime, &tmtTime );
  223. #endif
  224. }
  225. time_t Plat_timegm( struct tm *timeptr )
  226. {
  227. #ifndef _GAMECONSOLE
  228. return _mkgmtime( timeptr );
  229. #else
  230. int *pnCrashHereBecauseConsolesDontSupportMkGmTime = 0;
  231. *pnCrashHereBecauseConsolesDontSupportMkGmTime = 0;
  232. return 0;
  233. #endif
  234. }
  235. void Plat_GetModuleFilename( char *pOut, int nMaxBytes )
  236. {
  237. #ifdef PLATFORM_WINDOWS_PC
  238. SetLastError( ERROR_SUCCESS ); // clear the error code
  239. GetModuleFileName( NULL, pOut, nMaxBytes );
  240. if ( GetLastError() != ERROR_SUCCESS )
  241. Error( "Plat_GetModuleFilename: The buffer given is too small (%d bytes).", nMaxBytes );
  242. #elif PLATFORM_X360
  243. pOut[0] = 0x00; // return null string on Xbox 360
  244. #else
  245. // We shouldn't need this on POSIX.
  246. Assert( false );
  247. pOut[0] = 0x00; // Null the returned string in release builds
  248. #endif
  249. }
  250. void Plat_ExitProcess( int nCode )
  251. {
  252. #if defined( _WIN32 ) && !defined( _X360 )
  253. // We don't want global destructors in our process OR in any DLL to get executed.
  254. // _exit() avoids calling global destructors in our module, but not in other DLLs.
  255. const char *pchCmdLineA = Plat_GetCommandLineA();
  256. if ( nCode || ( strstr( pchCmdLineA, "gc.exe" ) && strstr( pchCmdLineA, "gc.dll" ) && strstr( pchCmdLineA, "-gc" ) ) )
  257. {
  258. int *x = NULL; *x = 1; // cause a hard crash, GC is not allowed to exit voluntarily from gc.dll
  259. }
  260. TerminateProcess( GetCurrentProcess(), nCode );
  261. #elif defined(_PS3)
  262. // We do not use this path to exit on PS3 (naturally), rather we want a clear crash:
  263. int *x = NULL; *x = 1;
  264. #else
  265. _exit( nCode );
  266. #endif
  267. }
  268. void Plat_ExitProcessWithError( int nCode, bool bGenerateMinidump )
  269. {
  270. //try to delegate out if they have registered a callback
  271. if( g_pfnExitProcessWithErrorCB )
  272. {
  273. if( g_pfnExitProcessWithErrorCB( nCode ) )
  274. return;
  275. }
  276. //handle default behavior
  277. if( bGenerateMinidump )
  278. {
  279. //don't generate mini dumps in the debugger
  280. if( !Plat_IsInDebugSession() )
  281. {
  282. WriteMiniDump();
  283. }
  284. }
  285. //and exit our process
  286. Plat_ExitProcess( nCode );
  287. }
  288. void Plat_SetExitProcessWithErrorCB( ExitProcessWithErrorCBFn pfnCB )
  289. {
  290. g_pfnExitProcessWithErrorCB = pfnCB;
  291. }
  292. void GetCurrentDate( int *pDay, int *pMonth, int *pYear )
  293. {
  294. struct tm long_time;
  295. Plat_GetLocalTime( &long_time );
  296. *pDay = long_time.tm_mday;
  297. *pMonth = long_time.tm_mon + 1;
  298. *pYear = long_time.tm_year + 1900;
  299. }
  300. // Wraps the thread-safe versions of asctime. buf must be at least 26 bytes
  301. char *Plat_asctime( const struct tm *tm, char *buf, size_t bufsize )
  302. {
  303. #ifdef _PS3
  304. snprintf( buf, bufsize, "%s", asctime(tm) );
  305. return buf;
  306. #else
  307. if ( EINVAL == asctime_s( buf, bufsize, tm ) )
  308. return NULL;
  309. else
  310. return buf;
  311. #endif
  312. }
  313. // Wraps the thread-safe versions of ctime. buf must be at least 26 bytes
  314. char *Plat_ctime( const time_t *timep, char *buf, size_t bufsize )
  315. {
  316. #ifdef _PS3
  317. snprintf( buf, bufsize, "%s", ctime( timep ) );
  318. return buf;
  319. #else
  320. if ( EINVAL == ctime_s( buf, bufsize, timep ) )
  321. return NULL;
  322. else
  323. return buf;
  324. #endif
  325. }
  326. // Wraps the thread-safe versions of gmtime
  327. struct tm *Platform_gmtime( const time_t *timep, struct tm *result )
  328. {
  329. #ifdef _PS3
  330. *result = *gmtime( timep );
  331. return result;
  332. #else
  333. if ( EINVAL == gmtime_s( result, timep ) )
  334. return NULL;
  335. else
  336. return result;
  337. #endif
  338. }
  339. // Wraps the thread-safe versions of localtime
  340. struct tm *Plat_localtime( const time_t *timep, struct tm *result )
  341. {
  342. #ifdef _PS3
  343. *result = *localtime( timep );
  344. return result;
  345. #else
  346. if ( EINVAL == localtime_s( result, timep ) )
  347. return NULL;
  348. else
  349. return result;
  350. #endif
  351. }
  352. bool vtune( bool resume )
  353. {
  354. #if IS_WINDOWS_PC
  355. static bool bInitialized = false;
  356. static void (__cdecl *VTResume)(void) = NULL;
  357. static void (__cdecl *VTPause) (void) = NULL;
  358. // Grab the Pause and Resume function pointers from the VTune DLL the first time through:
  359. if( !bInitialized )
  360. {
  361. bInitialized = true;
  362. HINSTANCE pVTuneDLL = LoadLibrary( "vtuneapi.dll" );
  363. if( pVTuneDLL )
  364. {
  365. VTResume = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTResume" );
  366. VTPause = (void(__cdecl *)())GetProcAddress( pVTuneDLL, "VTPause" );
  367. }
  368. }
  369. // Call the appropriate function, as indicated by the argument:
  370. if( resume && VTResume )
  371. {
  372. VTResume();
  373. return true;
  374. }
  375. else if( !resume && VTPause )
  376. {
  377. VTPause();
  378. return true;
  379. }
  380. #endif
  381. return false;
  382. }
  383. bool Plat_IsInDebugSession()
  384. {
  385. #if defined( _X360 )
  386. return (XBX_IsDebuggerPresent() != 0);
  387. #elif defined( _WIN32 )
  388. return (IsDebuggerPresent() != 0);
  389. #elif defined( _PS3 ) && !defined(_CERT)
  390. return snIsDebuggerPresent();
  391. #else
  392. return false;
  393. #endif
  394. }
  395. void Plat_DebugString( const char * psz )
  396. {
  397. #ifdef _CERT
  398. return; // do nothing!
  399. #endif
  400. #if defined( _X360 )
  401. XBX_OutputDebugString( psz );
  402. #elif defined( _WIN32 )
  403. ::OutputDebugStringA( psz );
  404. #elif defined(_PS3)
  405. printf("%s",psz);
  406. #else
  407. // do nothing?
  408. #endif
  409. }
  410. #if defined( PLATFORM_WINDOWS_PC )
  411. void Plat_MessageBox( const char *pTitle, const char *pMessage )
  412. {
  413. MessageBox( NULL, pMessage, pTitle, MB_OK );
  414. }
  415. #endif
  416. PlatOSVersion_t Plat_GetOSVersion()
  417. {
  418. #ifdef PLATFORM_WINDOWS_PC
  419. OSVERSIONINFO info;
  420. info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  421. if ( GetVersionEx( &info ) )
  422. {
  423. if ( info.dwMajorVersion > 24 )
  424. info.dwMajorVersion = 24; // clamp to fit the version in single byte
  425. return PlatOSVersion_t( ( info.dwMajorVersion*10 ) + ( info.dwMinorVersion%10 ) );
  426. }
  427. return PLAT_OS_VERSION_UNKNOWN;
  428. #elif defined( PLATFORM_X360 )
  429. return PLAT_OS_VERSION_XBOX360;
  430. #else
  431. return PLAT_OS_VERSION_UNKNOWN;
  432. #endif
  433. }
  434. #if defined( PLATFORM_PS3 )
  435. //copied from platform_posix.cpp
  436. static char g_CmdLine[ 2048 ] = "";
  437. PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine )
  438. {
  439. strncpy( g_CmdLine, cmdLine, sizeof(g_CmdLine) );
  440. g_CmdLine[ sizeof(g_CmdLine) -1 ] = 0;
  441. }
  442. #endif
  443. PLATFORM_INTERFACE const tchar *Plat_GetCommandLine()
  444. {
  445. #if defined( _PS3 )
  446. #pragma message("Plat_GetCommandLine() not implemented on PS3") // ****
  447. return g_CmdLine;
  448. #elif defined( TCHAR_IS_WCHAR )
  449. return GetCommandLineW();
  450. #else
  451. return GetCommandLine();
  452. #endif
  453. }
  454. PLATFORM_INTERFACE const char *Plat_GetCommandLineA()
  455. {
  456. #if defined( _PS3 )
  457. #pragma message("Plat_GetCommandLineA() not implemented on PS3") // ****
  458. return g_CmdLine;
  459. #else
  460. return GetCommandLineA();
  461. #endif
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Dynamically load a function
  465. //-----------------------------------------------------------------------------
  466. #ifdef PLATFORM_WINDOWS
  467. void *Plat_GetProcAddress( const char *pszModule, const char *pszName )
  468. {
  469. HMODULE hModule = ::LoadLibrary( pszModule );
  470. return ( hModule ) ? ::GetProcAddress( hModule, pszName ) : NULL;
  471. }
  472. #endif
  473. // -------------------------------------------------------------------------------------------------- //
  474. // Memory stuff.
  475. //
  476. // DEPRECATED. Still here to support binary back compatability of tier0.dll
  477. //
  478. // -------------------------------------------------------------------------------------------------- //
  479. #ifndef _X360
  480. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  481. typedef void (*Plat_AllocErrorFn)( unsigned long size );
  482. void Plat_DefaultAllocErrorFn( unsigned long size )
  483. {
  484. }
  485. Plat_AllocErrorFn g_AllocError = Plat_DefaultAllocErrorFn;
  486. #endif
  487. #if !defined( _X360 ) && !defined( _PS3 )
  488. CRITICAL_SECTION g_AllocCS;
  489. class CAllocCSInit
  490. {
  491. public:
  492. CAllocCSInit()
  493. {
  494. InitializeCriticalSection( &g_AllocCS );
  495. }
  496. } g_AllocCSInit;
  497. PLATFORM_INTERFACE void* Plat_Alloc( unsigned long size )
  498. {
  499. EnterCriticalSection( &g_AllocCS );
  500. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  501. void *pRet = MemAlloc_Alloc( size );
  502. #else
  503. void *pRet = malloc( size );
  504. #endif
  505. LeaveCriticalSection( &g_AllocCS );
  506. if ( pRet )
  507. {
  508. return pRet;
  509. }
  510. else
  511. {
  512. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  513. g_AllocError( size );
  514. #endif
  515. return 0;
  516. }
  517. }
  518. PLATFORM_INTERFACE void* Plat_Realloc( void *ptr, unsigned long size )
  519. {
  520. EnterCriticalSection( &g_AllocCS );
  521. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  522. void *pRet = g_pMemAlloc->Realloc( ptr, size );
  523. #else
  524. void *pRet = realloc( ptr, size );
  525. #endif
  526. LeaveCriticalSection( &g_AllocCS );
  527. if ( pRet )
  528. {
  529. return pRet;
  530. }
  531. else
  532. {
  533. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  534. g_AllocError( size );
  535. #endif
  536. return 0;
  537. }
  538. }
  539. PLATFORM_INTERFACE void Plat_Free( void *ptr )
  540. {
  541. EnterCriticalSection( &g_AllocCS );
  542. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  543. g_pMemAlloc->Free( ptr );
  544. #else
  545. free( ptr );
  546. #endif
  547. LeaveCriticalSection( &g_AllocCS );
  548. }
  549. #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
  550. PLATFORM_INTERFACE void Plat_SetAllocErrorFn( Plat_AllocErrorFn fn )
  551. {
  552. g_AllocError = fn;
  553. }
  554. #endif
  555. #endif
  556. #endif
  557. void Plat_getwd( char *pWorkingDirectory, size_t nBufLen )
  558. {
  559. #if defined( PLATFORM_X360 )
  560. V_tier0_strncpy( pWorkingDirectory, s_pWorkingDir, nBufLen );
  561. #elif defined( PLATFORM_WINDOWS )
  562. _getcwd( pWorkingDirectory, ( int )nBufLen );
  563. V_tier0_strncat( pWorkingDirectory, "\\", ( int )nBufLen );
  564. #else // PLATFORM_X360/PLATFORM_WINDOWS
  565. if ( getcwd( pWorkingDirectory, nBufLen ) )
  566. {
  567. V_tier0_strncat( pWorkingDirectory, "/", ( int )nBufLen );
  568. }
  569. else
  570. {
  571. V_tier0_strncpy( pWorkingDirectory, "./", ( int )nBufLen );
  572. }
  573. #endif // PLATFORM_X360/PLATFORM_WINDOWS
  574. }
  575. void Plat_chdir( const char *pDir )
  576. {
  577. #if !defined( PLATFORM_X360 )
  578. int nErr = _chdir( pDir );
  579. NOTE_UNUSED( nErr );
  580. #else // PLATFORM_X360
  581. V_tier0_strncpy( s_pWorkingDir, pDir, sizeof( s_pWorkingDir ) );
  582. #endif // PLATFORM_X360
  583. }
  584. char const * Plat_GetEnv(char const *pEnvVarName)
  585. {
  586. return getenv(pEnvVarName);
  587. }
  588. bool Plat_GetExecutablePath(char *pBuff, size_t nBuff)
  589. {
  590. return ::GetModuleFileNameA(NULL, pBuff, (DWORD)nBuff) > 0;
  591. }
  592. int Plat_chmod(const char *filename, int pmode)
  593. {
  594. #if defined( PLATFORM_WINDOWS )
  595. return _chmod(filename, pmode);
  596. #else
  597. return chmod(filename, pmode);
  598. #endif
  599. }
  600. bool Plat_FileExists(const char *pFileName)
  601. {
  602. #if defined( PLATFORM_WINDOWS )
  603. // VS2015 CRT _stat on Windows XP always returns -1 (lol)
  604. // https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
  605. DWORD dwResult = GetFileAttributes(pFileName);
  606. return (dwResult != INVALID_FILE_ATTRIBUTES);
  607. #else
  608. struct _stat fileInfo;
  609. return (_stat(pFileName, &fileInfo) != -1);
  610. #endif
  611. }
  612. size_t Plat_FileSize(const char *pFileName)
  613. {
  614. #if defined( PLATFORM_WINDOWS )
  615. // VS2015 CRT _stat on Windows XP always returns -1 (lol)
  616. // https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
  617. WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
  618. BOOL bSuccess = GetFileAttributesEx(pFileName, GetFileExInfoStandard, &fileAttributes);
  619. if (!bSuccess)
  620. return 0;
  621. uint64 ulFileSize;
  622. ulFileSize = fileAttributes.nFileSizeHigh;
  623. ulFileSize <<= 32;
  624. ulFileSize |= fileAttributes.nFileSizeLow;
  625. return (size_t)ulFileSize;
  626. #else
  627. struct _stat fileInfo;
  628. if (_stat(pFileName, &fileInfo) == -1)
  629. return 0;
  630. return fileInfo.st_size;
  631. #endif
  632. }
  633. bool Plat_IsDirectory(const char *pFilepath)
  634. {
  635. #if defined( PLATFORM_WINDOWS )
  636. // VS2015 CRT _stat on Windows XP always returns -1 (lol)
  637. // https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
  638. DWORD dwResult = GetFileAttributes(pFilepath);
  639. if (dwResult == INVALID_FILE_ATTRIBUTES)
  640. return false;
  641. return (dwResult & FILE_ATTRIBUTE_DIRECTORY) != 0;
  642. #else
  643. struct _stat fileInfo;
  644. if (_stat(pFilepath, &fileInfo) == -1)
  645. return false;
  646. return ((fileInfo.st_mode & _S_IFDIR) != 0);
  647. #endif
  648. }
  649. bool Plat_FileIsReadOnly(const char *pFileName)
  650. {
  651. #if defined( PLATFORM_WINDOWS )
  652. // VS2015 CRT _stat on Windows XP always returns -1 (lol)
  653. // https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always
  654. DWORD dwResult = GetFileAttributes(pFileName);
  655. if (dwResult == INVALID_FILE_ATTRIBUTES)
  656. return false; // See below.
  657. return (dwResult & FILE_ATTRIBUTE_READONLY) != 0;
  658. #else
  659. struct _stat fileInfo;
  660. if (_stat(pFileName, &fileInfo) == -1)
  661. return false; //for the purposes of this test, a nonexistent file is more writable than it is readable.
  662. return ((fileInfo.st_mode & _S_IWRITE) == 0);
  663. #endif
  664. }