aboutsummaryrefslogtreecommitdiff
path: root/mp/src/tier1/fileio.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/tier1/fileio.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/tier1/fileio.cpp')
-rw-r--r--mp/src/tier1/fileio.cpp992
1 files changed, 496 insertions, 496 deletions
diff --git a/mp/src/tier1/fileio.cpp b/mp/src/tier1/fileio.cpp
index 0b00fb43..3a909983 100644
--- a/mp/src/tier1/fileio.cpp
+++ b/mp/src/tier1/fileio.cpp
@@ -1,497 +1,497 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: A collection of utility classes to simplify file I/O, and
-// as much as possible contain portability problems. Here avoiding
-// including windows.h.
-//
-//=============================================================================
-
-#if defined(_WIN32)
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0502 // ReadDirectoryChangesW
-#endif
-
-#if defined(OSX)
-#include <CoreServices/CoreServices.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <sys/time.h>
-#endif
-
-#define ASYNC_FILEIO
-#if defined( LINUX )
-// Linux hasn't got a good AIO library that we have found yet, so lets punt for now
-#undef ASYNC_FILEIO
-#endif
-
-#if defined(_WIN32)
-//#include <direct.h>
-#include <io.h>
-// unset to force to use stdio implementation
-#define WIN32_FILEIO
-
-#if defined(ASYNC_FILEIO)
-#if defined(_WIN32) && !defined(WIN32_FILEIO)
-#error "trying to use async io without win32 filesystem API usage, that isn't doable"
-#endif
-#endif
-
-#else /* not defined (_WIN32) */
-#include <utime.h>
-#include <dirent.h>
-#include <unistd.h> // for unlink
-#include <limits.h> // defines PATH_MAX
-#include <alloca.h> // 'cause we like smashing the stack
-#if defined( _PS3 )
-#include <fcntl.h>
-#else
-#include <sys/fcntl.h>
-#include <sys/statvfs.h>
-#endif
-#include <sched.h>
-#define int64 int64_t
-
-#define _A_SUBDIR S_IFDIR
-
-// FUTURE map _A_HIDDEN via checking filename against .*
-#define _A_HIDDEN 0
-
-// FUTURE check 'read only' by checking mode against S_IRUSR
-#define _A_RDONLY 0
-
-// no files under posix are 'system' or 'archive'
-#define _A_SYSTEM 0
-#define _A_ARCH 0
-
-#endif
-
-#include "tier1/fileio.h"
-#include "tier1/utlbuffer.h"
-#include "tier1/strtools.h"
-#include <errno.h>
-
-#if defined( WIN32_FILEIO )
-#include "winlite.h"
-#endif
-
-#if defined( ASYNC_FILEIO )
-#ifdef _WIN32
-#include "winlite.h"
-#elif defined(_PS3)
-// bugbug ps3 - see some aio files under libfs.. skipping for the moment
-#elif defined(POSIX)
-#include <aio.h>
-#else
-#error "aio please"
-#endif
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor from UTF8
-//-----------------------------------------------------------------------------
-CPathString::CPathString( const char *pchUTF8Path )
-{
- // Need to first turn into an absolute path, so \\?\ pre-pended paths will be ok
- m_pchUTF8Path = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
- m_pwchWideCharPathPrepended = NULL;
-
- // First, convert to absolute path, which also does Q_FixSlashes for us.
- Q_MakeAbsolutePath( m_pchUTF8Path, MAX_UNICODE_PATH * 4, pchUTF8Path );
-
- // Second, fix any double slashes
- V_FixDoubleSlashes( m_pchUTF8Path );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-//-----------------------------------------------------------------------------
-CPathString::~CPathString()
-{
- if ( m_pwchWideCharPathPrepended )
- {
- delete[] m_pwchWideCharPathPrepended;
- m_pwchWideCharPathPrepended = NULL;
- }
-
- if ( m_pchUTF8Path )
- {
- delete[] m_pchUTF8Path;
- m_pchUTF8Path = NULL;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Access UTF8 path
-//-----------------------------------------------------------------------------
-const char * CPathString::GetUTF8Path()
-{
- return m_pchUTF8Path;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets wchar_t based path, with \\?\ pre-pended (allowing long paths
-// on Win32, should only be used with unicode extended path aware filesystem calls)
-//-----------------------------------------------------------------------------
-const wchar_t *CPathString::GetWCharPathPrePended()
-{
- PopulateWCharPath();
- return m_pwchWideCharPathPrepended;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Builds wchar path string
-//-----------------------------------------------------------------------------
-void CPathString::PopulateWCharPath()
-{
- if ( m_pwchWideCharPathPrepended )
- return;
-
- // Check if the UTF8 path starts with \\, which on Win32 means it's a UNC path, and then needs a different prefix
- if ( m_pchUTF8Path[0] == '\\' && m_pchUTF8Path[1] == '\\' )
- {
- m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+8];
- Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\UNC\\", 8*sizeof(wchar_t) );
-#ifdef DBGFLAG_ASSERT
- int cchResult =
-#endif
- Q_UTF8ToUnicode( m_pchUTF8Path+2, m_pwchWideCharPathPrepended+8, MAX_UNICODE_PATH*sizeof(wchar_t) );
- Assert( cchResult );
-
- // Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
- m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+7] = 0;
- }
- else
- {
- m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+4];
- Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\", 4*sizeof(wchar_t) );
-#ifdef DBGFLAG_ASSERT
- int cchResult =
-#endif
- Q_UTF8ToUnicode( m_pchUTF8Path, m_pwchWideCharPathPrepended+4, MAX_UNICODE_PATH*sizeof(wchar_t) );
- Assert( cchResult );
-
- // Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
- m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+3] = 0;
- }
-}
-
-#ifdef WIN32
-struct DirWatcherOverlapped : public OVERLAPPED
-{
- CDirWatcher *m_pDirWatcher;
-};
-#endif
-
-#if !defined(_PS3) && !defined(_X360)
-// a buffer full of file names
-static const int k_cubDirWatchBufferSize = 8 * 1024;
-
-//-----------------------------------------------------------------------------
-// Purpose: directory watching
-//-----------------------------------------------------------------------------
-CDirWatcher::CDirWatcher()
-{
- m_hFile = NULL;
- m_pOverlapped = NULL;
- m_pFileInfo = NULL;
-#ifdef OSX
- m_WatcherStream = 0;
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: directory watching
-//-----------------------------------------------------------------------------
-CDirWatcher::~CDirWatcher()
-{
-#ifdef WIN32
- if ( m_pOverlapped )
- {
- // mark the overlapped structure as gone
- DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
- pDirWatcherOverlapped->m_pDirWatcher = NULL;
- }
-
- if ( m_hFile )
- {
- // make sure we flush any pending I/O's on the handle
- ::CancelIo( m_hFile );
- ::SleepEx( 0, TRUE );
- // close the handle
- ::CloseHandle( m_hFile );
- }
-#elif defined(OSX)
- if ( m_WatcherStream )
- {
- FSEventStreamStop( (FSEventStreamRef)m_WatcherStream );
- FSEventStreamInvalidate( (FSEventStreamRef)m_WatcherStream );
- FSEventStreamRelease( (FSEventStreamRef)m_WatcherStream );
- m_WatcherStream = 0;
- }
-#endif
- if ( m_pFileInfo )
- {
- free( m_pFileInfo );
- }
- if ( m_pOverlapped )
- {
- free( m_pOverlapped );
- }
-}
-
-
-#ifdef WIN32
-//-----------------------------------------------------------------------------
-// Purpose: callback watch
-// gets called on the same thread whenever a SleepEx() occurs
-//-----------------------------------------------------------------------------
-class CDirWatcherFriend
-{
-public:
- static void WINAPI DirWatchCallback( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *pOverlapped )
- {
- DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)pOverlapped;
-
- // see if we've been cancelled
- if ( !pDirWatcherOverlapped->m_pDirWatcher )
- return;
-
- // parse and pass back
- if ( dwNumberOfBytesTransfered > sizeof(FILE_NOTIFY_INFORMATION) )
- {
- FILE_NOTIFY_INFORMATION *pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)pDirWatcherOverlapped->m_pDirWatcher->m_pFileInfo;
- do
- {
- // null terminate the string and turn it to UTF-8
- int cNumWChars = pFileNotifyInformation->FileNameLength / sizeof(wchar_t);
- wchar_t *pwchT = new wchar_t[cNumWChars + 1];
- memcpy( pwchT, pFileNotifyInformation->FileName, pFileNotifyInformation->FileNameLength );
- pwchT[cNumWChars] = 0;
- CStrAutoEncode strAutoEncode( pwchT );
-
- // add it to our list
- pDirWatcherOverlapped->m_pDirWatcher->AddFileToChangeList( strAutoEncode.ToString() );
- delete[] pwchT;
- if ( pFileNotifyInformation->NextEntryOffset == 0 )
- break;
-
- // move to the next file
- pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)(((byte*)pFileNotifyInformation) + pFileNotifyInformation->NextEntryOffset);
- } while ( 1 );
- }
-
-
- // watch again
- pDirWatcherOverlapped->m_pDirWatcher->PostDirWatch();
- }
-};
-#elif defined(OSX)
-void CheckDirectoryForChanges( const char *path_buff, CDirWatcher *pDirWatch, bool bRecurse )
-{
- DIR *dir = opendir(path_buff);
- char fullpath[MAX_PATH];
- struct dirent *dirent;
- struct timespec ts = { 0, 0 };
- bool bTimeSet = false;
-
- while ( (dirent = readdir(dir)) != NULL )
- {
- if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
- continue;
-
- snprintf( fullpath, PATH_MAX, "%s/%s", path_buff, dirent->d_name );
-
- struct stat st;
- if (lstat(fullpath, &st) != 0)
- continue;
-
- if ( S_ISDIR(st.st_mode) && bRecurse )
- {
- CheckDirectoryForChanges( fullpath, pDirWatch, bRecurse );
- }
- else if ( st.st_mtimespec.tv_sec > pDirWatch->m_modTime.tv_sec ||
- ( st.st_mtimespec.tv_sec == pDirWatch->m_modTime.tv_sec && st.st_mtimespec.tv_nsec > pDirWatch->m_modTime.tv_nsec ) )
- {
- ts = st.st_mtimespec;
- bTimeSet = true;
- // the win32 size only sends up the dir relative to the watching dir, so replicate that here
- pDirWatch->AddFileToChangeList( fullpath + pDirWatch->m_BaseDir.Length() + 1 );
- }
- }
-
- if ( bTimeSet )
- pDirWatch->m_modTime = ts;
- closedir(dir);
-}
-
-static void fsevents_callback( ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,void *eventPaths,
- const FSEventStreamEventFlags eventMasks[], const FSEventStreamEventId eventIDs[] )
-{
- char path_buff[PATH_MAX];
- for (int i=0; i < numEvents; i++)
- {
- char **paths = (char **)eventPaths;
-
- strcpy(path_buff, paths[i]);
- int len = strlen(path_buff);
- if (path_buff[len-1] == '/')
- {
- // chop off a trailing slash
- path_buff[--len] = '\0';
- }
-
- bool bRecurse = false;
-
- if (eventMasks[i] & kFSEventStreamEventFlagMustScanSubDirs
- || eventMasks[i] & kFSEventStreamEventFlagUserDropped
- || eventMasks[i] & kFSEventStreamEventFlagKernelDropped)
- {
- bRecurse = true;
- }
-
- CDirWatcher *pDirWatch = (CDirWatcher *)clientCallBackInfo;
- // make sure its in our subdir
- if ( !V_strnicmp( path_buff, pDirWatch->m_BaseDir.String(), pDirWatch->m_BaseDir.Length() ) )
- CheckDirectoryForChanges( path_buff, pDirWatch, bRecurse );
- }
-}
-
-
-
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: only one directory can be watched at a time
-//-----------------------------------------------------------------------------
-void CDirWatcher::SetDirToWatch( const char *pchDir )
-{
- if ( !pchDir || !*pchDir )
- return;
-
- CPathString strPath( pchDir );
-#ifdef WIN32
- // open the directory
- m_hFile = ::CreateFileW( strPath.GetWCharPathPrePended(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, NULL );
-
- // create our buffers
- m_pFileInfo = malloc( k_cubDirWatchBufferSize );
- m_pOverlapped = malloc( sizeof( DirWatcherOverlapped ) );
-
- // post a watch
- PostDirWatch();
-#elif defined(OSX)
- CFStringRef mypath = CFStringCreateWithCString( NULL, strPath.GetUTF8Path(), kCFStringEncodingMacRoman );
- if ( !mypath )
- {
- Assert( !"Failed to CFStringCreateWithCString watcher path" );
- return;
- }
-
- CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
- FSEventStreamContext callbackInfo = {0, this, NULL, NULL, NULL};
- CFAbsoluteTime latency = 1.0; // Latency in seconds
-
- m_WatcherStream = (void *)FSEventStreamCreate(NULL,
- &fsevents_callback,
- &callbackInfo,
- pathsToWatch,
- kFSEventStreamEventIdSinceNow,
- latency,
- kFSEventStreamCreateFlagNoDefer
- );
-
- FSEventStreamScheduleWithRunLoop( (FSEventStreamRef)m_WatcherStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- CFRelease(pathsToWatch );
- CFRelease( mypath );
-
- FSEventStreamStart( (FSEventStreamRef)m_WatcherStream );
-
- char szFullPath[MAX_PATH];
- Q_MakeAbsolutePath( szFullPath, sizeof(szFullPath), pchDir );
- m_BaseDir = szFullPath;
-
- struct timeval tv;
- gettimeofday( &tv, NULL );
- TIMEVAL_TO_TIMESPEC( &tv, &m_modTime );
-
-#else
- Assert( !"Impl me" );
-#endif
-}
-
-
-#ifdef WIN32
-//-----------------------------------------------------------------------------
-// Purpose: used by callback functions to push a file onto the list
-//-----------------------------------------------------------------------------
-void CDirWatcher::PostDirWatch()
-{
- memset( m_pOverlapped, 0, sizeof(DirWatcherOverlapped) );
- DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
- pDirWatcherOverlapped->m_pDirWatcher = this;
-
- DWORD dwBytes;
- ::ReadDirectoryChangesW( m_hFile, m_pFileInfo, k_cubDirWatchBufferSize, TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytes, (OVERLAPPED *)m_pOverlapped, &CDirWatcherFriend::DirWatchCallback );
-}
-#endif
-
-
-//-----------------------------------------------------------------------------
-// Purpose: used by callback functions to push a file onto the list
-//-----------------------------------------------------------------------------
-void CDirWatcher::AddFileToChangeList( const char *pchFile )
-{
- // make sure it isn't already in the list
- FOR_EACH_LL( m_listChangedFiles, i )
- {
- if ( !Q_stricmp( m_listChangedFiles[i], pchFile ) )
- return;
- }
-
- m_listChangedFiles.AddToTail( pchFile );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: retrieve any changes
-//-----------------------------------------------------------------------------
-bool CDirWatcher::GetChangedFile( CUtlString *psFile )
-{
-#ifdef WIN32
- // this will trigger any pending directory reads
- // this does get hit other places in the code; so the callback can happen at any time
- ::SleepEx( 0, TRUE );
-#endif
-
- if ( !m_listChangedFiles.Count() )
- return false;
-
- *psFile = m_listChangedFiles[m_listChangedFiles.Head()];
- m_listChangedFiles.Remove( m_listChangedFiles.Head() );
- return true;
-}
-
-
-
-#ifdef DBGFLAG_VALIDATE
-void CDirWatcher::Validate( CValidator &validator, const char *pchName )
-{
- VALIDATE_SCOPE();
-
- validator.ClaimMemory( m_pOverlapped );
- validator.ClaimMemory( m_pFileInfo );
- ValidateObj( m_listChangedFiles );
- FOR_EACH_LL( m_listChangedFiles, i )
- {
- ValidateObj( m_listChangedFiles[i] );
- }
-}
-#endif
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A collection of utility classes to simplify file I/O, and
+// as much as possible contain portability problems. Here avoiding
+// including windows.h.
+//
+//=============================================================================
+
+#if defined(_WIN32)
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0502 // ReadDirectoryChangesW
+#endif
+
+#if defined(OSX)
+#include <CoreServices/CoreServices.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#endif
+
+#define ASYNC_FILEIO
+#if defined( LINUX )
+// Linux hasn't got a good AIO library that we have found yet, so lets punt for now
+#undef ASYNC_FILEIO
+#endif
+
+#if defined(_WIN32)
+//#include <direct.h>
+#include <io.h>
+// unset to force to use stdio implementation
+#define WIN32_FILEIO
+
+#if defined(ASYNC_FILEIO)
+#if defined(_WIN32) && !defined(WIN32_FILEIO)
+#error "trying to use async io without win32 filesystem API usage, that isn't doable"
+#endif
+#endif
+
+#else /* not defined (_WIN32) */
+#include <utime.h>
+#include <dirent.h>
+#include <unistd.h> // for unlink
+#include <limits.h> // defines PATH_MAX
+#include <alloca.h> // 'cause we like smashing the stack
+#if defined( _PS3 )
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#include <sys/statvfs.h>
+#endif
+#include <sched.h>
+#define int64 int64_t
+
+#define _A_SUBDIR S_IFDIR
+
+// FUTURE map _A_HIDDEN via checking filename against .*
+#define _A_HIDDEN 0
+
+// FUTURE check 'read only' by checking mode against S_IRUSR
+#define _A_RDONLY 0
+
+// no files under posix are 'system' or 'archive'
+#define _A_SYSTEM 0
+#define _A_ARCH 0
+
+#endif
+
+#include "tier1/fileio.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/strtools.h"
+#include <errno.h>
+
+#if defined( WIN32_FILEIO )
+#include "winlite.h"
+#endif
+
+#if defined( ASYNC_FILEIO )
+#ifdef _WIN32
+#include "winlite.h"
+#elif defined(_PS3)
+// bugbug ps3 - see some aio files under libfs.. skipping for the moment
+#elif defined(POSIX)
+#include <aio.h>
+#else
+#error "aio please"
+#endif
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor from UTF8
+//-----------------------------------------------------------------------------
+CPathString::CPathString( const char *pchUTF8Path )
+{
+ // Need to first turn into an absolute path, so \\?\ pre-pended paths will be ok
+ m_pchUTF8Path = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
+ m_pwchWideCharPathPrepended = NULL;
+
+ // First, convert to absolute path, which also does Q_FixSlashes for us.
+ Q_MakeAbsolutePath( m_pchUTF8Path, MAX_UNICODE_PATH * 4, pchUTF8Path );
+
+ // Second, fix any double slashes
+ V_FixDoubleSlashes( m_pchUTF8Path );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CPathString::~CPathString()
+{
+ if ( m_pwchWideCharPathPrepended )
+ {
+ delete[] m_pwchWideCharPathPrepended;
+ m_pwchWideCharPathPrepended = NULL;
+ }
+
+ if ( m_pchUTF8Path )
+ {
+ delete[] m_pchUTF8Path;
+ m_pchUTF8Path = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Access UTF8 path
+//-----------------------------------------------------------------------------
+const char * CPathString::GetUTF8Path()
+{
+ return m_pchUTF8Path;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets wchar_t based path, with \\?\ pre-pended (allowing long paths
+// on Win32, should only be used with unicode extended path aware filesystem calls)
+//-----------------------------------------------------------------------------
+const wchar_t *CPathString::GetWCharPathPrePended()
+{
+ PopulateWCharPath();
+ return m_pwchWideCharPathPrepended;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Builds wchar path string
+//-----------------------------------------------------------------------------
+void CPathString::PopulateWCharPath()
+{
+ if ( m_pwchWideCharPathPrepended )
+ return;
+
+ // Check if the UTF8 path starts with \\, which on Win32 means it's a UNC path, and then needs a different prefix
+ if ( m_pchUTF8Path[0] == '\\' && m_pchUTF8Path[1] == '\\' )
+ {
+ m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+8];
+ Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\UNC\\", 8*sizeof(wchar_t) );
+#ifdef DBGFLAG_ASSERT
+ int cchResult =
+#endif
+ Q_UTF8ToUnicode( m_pchUTF8Path+2, m_pwchWideCharPathPrepended+8, MAX_UNICODE_PATH*sizeof(wchar_t) );
+ Assert( cchResult );
+
+ // Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
+ m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+7] = 0;
+ }
+ else
+ {
+ m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+4];
+ Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\", 4*sizeof(wchar_t) );
+#ifdef DBGFLAG_ASSERT
+ int cchResult =
+#endif
+ Q_UTF8ToUnicode( m_pchUTF8Path, m_pwchWideCharPathPrepended+4, MAX_UNICODE_PATH*sizeof(wchar_t) );
+ Assert( cchResult );
+
+ // Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
+ m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+3] = 0;
+ }
+}
+
+#ifdef WIN32
+struct DirWatcherOverlapped : public OVERLAPPED
+{
+ CDirWatcher *m_pDirWatcher;
+};
+#endif
+
+#if !defined(_PS3) && !defined(_X360)
+// a buffer full of file names
+static const int k_cubDirWatchBufferSize = 8 * 1024;
+
+//-----------------------------------------------------------------------------
+// Purpose: directory watching
+//-----------------------------------------------------------------------------
+CDirWatcher::CDirWatcher()
+{
+ m_hFile = NULL;
+ m_pOverlapped = NULL;
+ m_pFileInfo = NULL;
+#ifdef OSX
+ m_WatcherStream = 0;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: directory watching
+//-----------------------------------------------------------------------------
+CDirWatcher::~CDirWatcher()
+{
+#ifdef WIN32
+ if ( m_pOverlapped )
+ {
+ // mark the overlapped structure as gone
+ DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
+ pDirWatcherOverlapped->m_pDirWatcher = NULL;
+ }
+
+ if ( m_hFile )
+ {
+ // make sure we flush any pending I/O's on the handle
+ ::CancelIo( m_hFile );
+ ::SleepEx( 0, TRUE );
+ // close the handle
+ ::CloseHandle( m_hFile );
+ }
+#elif defined(OSX)
+ if ( m_WatcherStream )
+ {
+ FSEventStreamStop( (FSEventStreamRef)m_WatcherStream );
+ FSEventStreamInvalidate( (FSEventStreamRef)m_WatcherStream );
+ FSEventStreamRelease( (FSEventStreamRef)m_WatcherStream );
+ m_WatcherStream = 0;
+ }
+#endif
+ if ( m_pFileInfo )
+ {
+ free( m_pFileInfo );
+ }
+ if ( m_pOverlapped )
+ {
+ free( m_pOverlapped );
+ }
+}
+
+
+#ifdef WIN32
+//-----------------------------------------------------------------------------
+// Purpose: callback watch
+// gets called on the same thread whenever a SleepEx() occurs
+//-----------------------------------------------------------------------------
+class CDirWatcherFriend
+{
+public:
+ static void WINAPI DirWatchCallback( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *pOverlapped )
+ {
+ DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)pOverlapped;
+
+ // see if we've been cancelled
+ if ( !pDirWatcherOverlapped->m_pDirWatcher )
+ return;
+
+ // parse and pass back
+ if ( dwNumberOfBytesTransfered > sizeof(FILE_NOTIFY_INFORMATION) )
+ {
+ FILE_NOTIFY_INFORMATION *pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)pDirWatcherOverlapped->m_pDirWatcher->m_pFileInfo;
+ do
+ {
+ // null terminate the string and turn it to UTF-8
+ int cNumWChars = pFileNotifyInformation->FileNameLength / sizeof(wchar_t);
+ wchar_t *pwchT = new wchar_t[cNumWChars + 1];
+ memcpy( pwchT, pFileNotifyInformation->FileName, pFileNotifyInformation->FileNameLength );
+ pwchT[cNumWChars] = 0;
+ CStrAutoEncode strAutoEncode( pwchT );
+
+ // add it to our list
+ pDirWatcherOverlapped->m_pDirWatcher->AddFileToChangeList( strAutoEncode.ToString() );
+ delete[] pwchT;
+ if ( pFileNotifyInformation->NextEntryOffset == 0 )
+ break;
+
+ // move to the next file
+ pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)(((byte*)pFileNotifyInformation) + pFileNotifyInformation->NextEntryOffset);
+ } while ( 1 );
+ }
+
+
+ // watch again
+ pDirWatcherOverlapped->m_pDirWatcher->PostDirWatch();
+ }
+};
+#elif defined(OSX)
+void CheckDirectoryForChanges( const char *path_buff, CDirWatcher *pDirWatch, bool bRecurse )
+{
+ DIR *dir = opendir(path_buff);
+ char fullpath[MAX_PATH];
+ struct dirent *dirent;
+ struct timespec ts = { 0, 0 };
+ bool bTimeSet = false;
+
+ while ( (dirent = readdir(dir)) != NULL )
+ {
+ if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
+ continue;
+
+ snprintf( fullpath, PATH_MAX, "%s/%s", path_buff, dirent->d_name );
+
+ struct stat st;
+ if (lstat(fullpath, &st) != 0)
+ continue;
+
+ if ( S_ISDIR(st.st_mode) && bRecurse )
+ {
+ CheckDirectoryForChanges( fullpath, pDirWatch, bRecurse );
+ }
+ else if ( st.st_mtimespec.tv_sec > pDirWatch->m_modTime.tv_sec ||
+ ( st.st_mtimespec.tv_sec == pDirWatch->m_modTime.tv_sec && st.st_mtimespec.tv_nsec > pDirWatch->m_modTime.tv_nsec ) )
+ {
+ ts = st.st_mtimespec;
+ bTimeSet = true;
+ // the win32 size only sends up the dir relative to the watching dir, so replicate that here
+ pDirWatch->AddFileToChangeList( fullpath + pDirWatch->m_BaseDir.Length() + 1 );
+ }
+ }
+
+ if ( bTimeSet )
+ pDirWatch->m_modTime = ts;
+ closedir(dir);
+}
+
+static void fsevents_callback( ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,void *eventPaths,
+ const FSEventStreamEventFlags eventMasks[], const FSEventStreamEventId eventIDs[] )
+{
+ char path_buff[PATH_MAX];
+ for (int i=0; i < numEvents; i++)
+ {
+ char **paths = (char **)eventPaths;
+
+ strcpy(path_buff, paths[i]);
+ int len = strlen(path_buff);
+ if (path_buff[len-1] == '/')
+ {
+ // chop off a trailing slash
+ path_buff[--len] = '\0';
+ }
+
+ bool bRecurse = false;
+
+ if (eventMasks[i] & kFSEventStreamEventFlagMustScanSubDirs
+ || eventMasks[i] & kFSEventStreamEventFlagUserDropped
+ || eventMasks[i] & kFSEventStreamEventFlagKernelDropped)
+ {
+ bRecurse = true;
+ }
+
+ CDirWatcher *pDirWatch = (CDirWatcher *)clientCallBackInfo;
+ // make sure its in our subdir
+ if ( !V_strnicmp( path_buff, pDirWatch->m_BaseDir.String(), pDirWatch->m_BaseDir.Length() ) )
+ CheckDirectoryForChanges( path_buff, pDirWatch, bRecurse );
+ }
+}
+
+
+
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: only one directory can be watched at a time
+//-----------------------------------------------------------------------------
+void CDirWatcher::SetDirToWatch( const char *pchDir )
+{
+ if ( !pchDir || !*pchDir )
+ return;
+
+ CPathString strPath( pchDir );
+#ifdef WIN32
+ // open the directory
+ m_hFile = ::CreateFileW( strPath.GetWCharPathPrePended(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, NULL );
+
+ // create our buffers
+ m_pFileInfo = malloc( k_cubDirWatchBufferSize );
+ m_pOverlapped = malloc( sizeof( DirWatcherOverlapped ) );
+
+ // post a watch
+ PostDirWatch();
+#elif defined(OSX)
+ CFStringRef mypath = CFStringCreateWithCString( NULL, strPath.GetUTF8Path(), kCFStringEncodingMacRoman );
+ if ( !mypath )
+ {
+ Assert( !"Failed to CFStringCreateWithCString watcher path" );
+ return;
+ }
+
+ CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
+ FSEventStreamContext callbackInfo = {0, this, NULL, NULL, NULL};
+ CFAbsoluteTime latency = 1.0; // Latency in seconds
+
+ m_WatcherStream = (void *)FSEventStreamCreate(NULL,
+ &fsevents_callback,
+ &callbackInfo,
+ pathsToWatch,
+ kFSEventStreamEventIdSinceNow,
+ latency,
+ kFSEventStreamCreateFlagNoDefer
+ );
+
+ FSEventStreamScheduleWithRunLoop( (FSEventStreamRef)m_WatcherStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ CFRelease(pathsToWatch );
+ CFRelease( mypath );
+
+ FSEventStreamStart( (FSEventStreamRef)m_WatcherStream );
+
+ char szFullPath[MAX_PATH];
+ Q_MakeAbsolutePath( szFullPath, sizeof(szFullPath), pchDir );
+ m_BaseDir = szFullPath;
+
+ struct timeval tv;
+ gettimeofday( &tv, NULL );
+ TIMEVAL_TO_TIMESPEC( &tv, &m_modTime );
+
+#else
+ Assert( !"Impl me" );
+#endif
+}
+
+
+#ifdef WIN32
+//-----------------------------------------------------------------------------
+// Purpose: used by callback functions to push a file onto the list
+//-----------------------------------------------------------------------------
+void CDirWatcher::PostDirWatch()
+{
+ memset( m_pOverlapped, 0, sizeof(DirWatcherOverlapped) );
+ DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
+ pDirWatcherOverlapped->m_pDirWatcher = this;
+
+ DWORD dwBytes;
+ ::ReadDirectoryChangesW( m_hFile, m_pFileInfo, k_cubDirWatchBufferSize, TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytes, (OVERLAPPED *)m_pOverlapped, &CDirWatcherFriend::DirWatchCallback );
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: used by callback functions to push a file onto the list
+//-----------------------------------------------------------------------------
+void CDirWatcher::AddFileToChangeList( const char *pchFile )
+{
+ // make sure it isn't already in the list
+ FOR_EACH_LL( m_listChangedFiles, i )
+ {
+ if ( !Q_stricmp( m_listChangedFiles[i], pchFile ) )
+ return;
+ }
+
+ m_listChangedFiles.AddToTail( pchFile );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: retrieve any changes
+//-----------------------------------------------------------------------------
+bool CDirWatcher::GetChangedFile( CUtlString *psFile )
+{
+#ifdef WIN32
+ // this will trigger any pending directory reads
+ // this does get hit other places in the code; so the callback can happen at any time
+ ::SleepEx( 0, TRUE );
+#endif
+
+ if ( !m_listChangedFiles.Count() )
+ return false;
+
+ *psFile = m_listChangedFiles[m_listChangedFiles.Head()];
+ m_listChangedFiles.Remove( m_listChangedFiles.Head() );
+ return true;
+}
+
+
+
+#ifdef DBGFLAG_VALIDATE
+void CDirWatcher::Validate( CValidator &validator, const char *pchName )
+{
+ VALIDATE_SCOPE();
+
+ validator.ClaimMemory( m_pOverlapped );
+ validator.ClaimMemory( m_pFileInfo );
+ ValidateObj( m_listChangedFiles );
+ FOR_EACH_LL( m_listChangedFiles, i )
+ {
+ ValidateObj( m_listChangedFiles[i] );
+ }
+}
+#endif
+
#endif // _PS3 || _X360 \ No newline at end of file