summaryrefslogtreecommitdiff
path: root/utils/scenemanager/scenemanager_tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/scenemanager/scenemanager_tools.cpp')
-rw-r--r--utils/scenemanager/scenemanager_tools.cpp846
1 files changed, 846 insertions, 0 deletions
diff --git a/utils/scenemanager/scenemanager_tools.cpp b/utils/scenemanager/scenemanager_tools.cpp
new file mode 100644
index 0000000..884ee49
--- /dev/null
+++ b/utils/scenemanager/scenemanager_tools.cpp
@@ -0,0 +1,846 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+#include "cbase.h"
+#include "StatusWindow.h"
+#include "cmdlib.h"
+#include <sys/stat.h>
+#include "workspace.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+#include "tier2/riff.h"
+#include "sentence.h"
+#include "utlbuffer.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include <KeyValues.h>
+#include "MultipleRequest.h"
+
+bool SceneManager_HasWindowStyle( mxWindow *w, int bits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ return ( style & bits ) ? true : false;
+}
+
+bool SceneManager_HasWindowExStyle( mxWindow *w, int bits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_EXSTYLE );
+ return ( style & bits ) ? true : false;
+}
+
+void SceneManager_AddWindowStyle( mxWindow *w, int addbits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ style |= addbits;
+ SetWindowLong( wnd, GWL_STYLE, style );
+}
+
+void SceneManager_AddWindowExStyle( mxWindow *w, int addbits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_EXSTYLE );
+ style |= addbits;
+ SetWindowLong( wnd, GWL_EXSTYLE, style );
+}
+
+void SceneManager_RemoveWindowStyle( mxWindow *w, int removebits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ style &= ~removebits;
+ SetWindowLong( wnd, GWL_STYLE, style );
+}
+
+void SceneManager_RemoveWindowExStyle( mxWindow *w, int removebits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_EXSTYLE );
+ style &= ~removebits;
+ SetWindowLong( wnd, GWL_EXSTYLE, style );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *w -
+//-----------------------------------------------------------------------------
+void SceneManager_MakeToolWindow( mxWindow *w, bool smallcaption )
+{
+ SceneManager_AddWindowStyle( w, WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+
+ if ( smallcaption )
+ {
+ SceneManager_AddWindowExStyle( w, WS_EX_OVERLAPPEDWINDOW );
+ SceneManager_AddWindowExStyle( w, WS_EX_TOOLWINDOW );
+ }
+ else
+ {
+ SceneManager_RemoveWindowStyle( w, WS_SYSMENU );
+ }
+}
+
+char *va( const char *fmt, ... )
+{
+ va_list args;
+ static char output[4][1024];
+ static int outbuffer = 0;
+
+ outbuffer++;
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output[ outbuffer & 3 ], fmt, args );
+ return output[ outbuffer & 3 ];
+}
+
+void Con_Overprintf( const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ if ( !g_pStatusWindow )
+ {
+ return;
+ }
+
+ g_pStatusWindow->StatusPrint( CONSOLE_R, CONSOLE_G, CONSOLE_B, true, output );
+}
+
+void Con_Printf( const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+// vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+ va_end( args );
+
+ if ( !g_pStatusWindow )
+ {
+ return;
+ }
+
+ g_pStatusWindow->StatusPrint( CONSOLE_R, CONSOLE_G, CONSOLE_B, false, output );
+}
+
+void Con_ColorPrintf( int r, int g, int b, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ if ( !g_pStatusWindow )
+ {
+ return;
+ }
+
+ g_pStatusWindow->StatusPrint( r, g, b, false, output );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pname -
+// Output : char
+//-----------------------------------------------------------------------------
+char *SceneManager_MakeWindowsSlashes( char *pname )
+{
+ static char returnString[ 4096 ];
+ strcpy( returnString, pname );
+ pname = returnString;
+
+ while ( *pname ) {
+ if ( *pname == '/' )
+ *pname = '\\';
+ pname++;
+ }
+
+ return returnString;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *SceneManager_GetGameDirectory( void )
+{
+ // Todo: Make SceneManager only use the filesystem read/write paths.
+ return gamedir;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Takes a full path and determines if the file exists on the disk
+// Input : *filename -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool SceneManager_FullpathFileExists( const char *filename )
+{
+ // Should be a full path
+ Assert( strchr( filename, ':' ) );
+
+ struct _stat buf;
+ int result = _stat( filename, &buf );
+ if ( result != -1 )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: converts an english string to unicode
+//-----------------------------------------------------------------------------
+int ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSize)
+{
+ return ::MultiByteToWideChar(CP_ACP, 0, ansi, -1, unicode, unicodeBufferSize);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: converts an unicode string to an english string
+//-----------------------------------------------------------------------------
+int ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize)
+{
+ return ::WideCharToMultiByte(CP_ACP, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL);
+}
+
+int Sys_Exec( const char *pProgName, const char *pCmdLine, bool verbose )
+{
+#if 0
+ int count = 0;
+ char cmdLine[1024];
+ STARTUPINFO si;
+
+ memset( &si, 0, sizeof(si) );
+ si.cb = sizeof(si);
+ //GetStartupInfo( &si );
+
+ sprintf( cmdLine, "%s %s", pProgName, pCmdLine );
+
+ PROCESS_INFORMATION pi;
+ memset( &pi, 0, sizeof( pi ) );
+
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ if ( CreateProcess( NULL, cmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi ) )
+ {
+ WaitForSingleObject( pi.hProcess, INFINITE );
+ /*
+ do
+ {
+ WaitForInputIdle( pi.hProcess, 100 );
+ count++;
+ } while ( count < 100 );
+ */
+
+ /*
+ DWORD exitCode = STILL_ACTIVE;
+ do
+ {
+ BOOL ok = GetExitCodeProcess( pi.hProcess, &exitCode );
+ if ( !ok )
+ break;
+ Sleep( 100 );
+ } while ( exitCode == STILL_ACTIVE );
+ */
+
+ DWORD exitCode;
+
+ GetExitCodeProcess( pi.hProcess, &exitCode );
+
+ Con_Printf( "Finished\n" );
+
+ CloseHandle( pi.hProcess );
+ return (int)exitCode;
+ }
+ else
+ {
+ char *lpMsgBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ Con_Printf( "error %s\n", lpMsgBuf );
+
+ LocalFree( (HLOCAL)lpMsgBuf );
+ }
+
+ return false;
+#else
+ char tmp[1024];
+ sprintf( tmp, "%s %s\n", pProgName, pCmdLine );
+
+ _strlwr( tmp );
+
+ int iret = system( tmp );
+ if ( iret != 0 && verbose )
+ {
+ Con_Printf( "Execution failed: %s\n", tmp );
+ }
+
+ return iret;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Checks it out/ checks it in baby
+//-----------------------------------------------------------------------------
+
+static void SceneManager_VSSCheckout( char const *pUserName, char const *pProjectDir,
+ char const* pRelativeDir, char const* pDestPath, char const* pFileNameWithExtension )
+{
+ char buf[1024];
+
+ // Check for the existence of the file in source safe...
+ sprintf( buf, "filetype %s/%s%s -O- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pUserName );
+ int retVal = Sys_Exec( "ss.exe", buf, false );
+ if (retVal != 0 )
+ {
+ Con_Printf( "File %s missing from VSS\n", pFileNameWithExtension );
+ return;
+ }
+
+ // It's there, try to check it out
+ sprintf( buf, "checkout %s/%s%s -GL%s -GWA -O- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pDestPath, pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+}
+
+//-----------------------------------------------------------------------------
+// Checks it out/ checks it in baby
+//-----------------------------------------------------------------------------
+
+static void SceneManager_VSSCheckin( char const *pUserName, char const *pProjectDir,
+ char const* pRelativeDir, char const* pDestPath, char const* pFileNameWithExtension )
+{
+ char buf[1024];
+
+ // Check for the existence of the file on disk. If it's not there, don't bother
+ sprintf( buf, "%s%s", pDestPath, pFileNameWithExtension );
+ struct _stat statbuf;
+ int result = _stat( buf, &statbuf );
+ if (result != 0)
+ return;
+
+ // Check for the existence of the file in source safe...
+ sprintf( buf, "filetype %s/%s%s -O- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pUserName );
+ int retVal = Sys_Exec( "ss.exe", buf, false );
+ if (retVal != 0)
+ {
+ sprintf( buf, "Cp %s -O- -y%s\n",
+ pProjectDir ,
+ pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+
+ // Try to add the file to source safe...
+ sprintf( buf, "add %s%s -GL%s -O- -I- -y%s\n",
+ pRelativeDir, pFileNameWithExtension,
+ pDestPath, pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+ }
+ else
+ {
+ // It's there, just check it in
+ sprintf( buf, "checkin %s/%s%s -GL%s -O- -I- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pDestPath, pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+ }
+}
+
+void SplitFileName( char const *in, char *path, int maxpath, char *filename, int maxfilename )
+{
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+
+ _splitpath( in, drive, dir, fname, ext );
+
+ if ( dir[0] )
+ {
+ Q_snprintf( path, maxpath, "\\%s", dir );
+ }
+ else
+ {
+ path[0] = 0;
+ }
+ Q_snprintf( filename, maxfilename, "%s%s", fname, ext );
+}
+
+
+void VSS_Checkout( char const *name, bool updatestaticons /*= true*/ )
+{
+ CWorkspace *ws = GetWorkspaceManager()->GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ if ( filesystem->IsFileWritable( name ) )
+ {
+ return;
+ }
+
+ char path[ 256 ];
+ char filename[ 256 ];
+
+ SplitFileName( name, path, sizeof( path ), filename, sizeof( filename ) );
+
+ Con_ColorPrintf( 200, 200, 100, "VSS Checkout: '%s'\n", name );
+
+ SceneManager_VSSCheckout(
+ ws->GetVSSUserName(),
+ ws->GetVSSProject(),
+ path,
+ va( "%s%s", gamedir, path ),
+ filename );
+
+ if ( updatestaticons )
+ {
+ GetWorkspaceManager()->RefreshBrowsers();
+ }
+}
+
+void VSS_Checkin( char const *name, bool updatestaticons /*= true*/ )
+{
+ CWorkspace *ws = GetWorkspaceManager()->GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ if ( !filesystem->IsFileWritable( name ) )
+ {
+ return;
+ }
+
+ char path[ 256 ];
+ char filename[ 256 ];
+
+ SplitFileName( name, path, sizeof( path ), filename, sizeof( filename ) );
+
+ Con_ColorPrintf( 200, 200, 100, "VSS Checkin: '%s'\n", name );
+
+ SceneManager_VSSCheckin(
+ ws->GetVSSUserName(),
+ ws->GetVSSProject(),
+ path,
+ va( "%s%s", gamedir, path ),
+ filename );
+
+ if ( updatestaticons )
+ {
+ GetWorkspaceManager()->RefreshBrowsers();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements the RIFF i/o interface on stdio
+//-----------------------------------------------------------------------------
+class StdIOReadBinary : public IFileReadBinary
+{
+public:
+ int open( const char *pFileName )
+ {
+ return (int)filesystem->Open( pFileName, "rb" );
+ }
+
+ int read( void *pOutput, int size, int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Read( pOutput, size, (FileHandle_t)file );
+ }
+
+ void seek( int file, int pos )
+ {
+ if ( !file )
+ return;
+
+ filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
+ }
+
+ unsigned int tell( int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Tell( (FileHandle_t)file );
+ }
+
+ unsigned int size( int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Size( (FileHandle_t)file );
+ }
+
+ void close( int file )
+ {
+ if ( !file )
+ return;
+
+ filesystem->Close( (FileHandle_t)file );
+ }
+};
+
+class StdIOWriteBinary : public IFileWriteBinary
+{
+public:
+ int create( const char *pFileName )
+ {
+ return (int)filesystem->Open( pFileName, "wb" );
+ }
+
+ int write( void *pData, int size, int file )
+ {
+ return filesystem->Write( pData, size, (FileHandle_t)file );
+ }
+
+ void close( int file )
+ {
+ filesystem->Close( (FileHandle_t)file );
+ }
+
+ void seek( int file, int pos )
+ {
+ filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
+ }
+
+ unsigned int tell( int file )
+ {
+ return filesystem->Tell( (FileHandle_t)file );
+ }
+};
+
+static StdIOReadBinary io_in;
+static StdIOWriteBinary io_out;
+
+#define RIFF_WAVE MAKEID('W','A','V','E')
+#define WAVE_FMT MAKEID('f','m','t',' ')
+#define WAVE_DATA MAKEID('d','a','t','a')
+#define WAVE_FACT MAKEID('f','a','c','t')
+#define WAVE_CUE MAKEID('c','u','e',' ')
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &walk -
+//-----------------------------------------------------------------------------
+static void SceneManager_ParseSentence( CSentence& sentence, IterateRIFF &walk )
+{
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.EnsureCapacity( walk.ChunkSize() );
+ walk.ChunkRead( buf.Base() );
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, walk.ChunkSize() );
+
+ sentence.InitFromDataChunk( buf.Base(), buf.TellPut() );
+}
+
+bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io )
+{
+ sentence.Reset();
+
+ InFileRIFF riff( wavfile, io );
+
+ // UNDONE: Don't use printf to handle errors
+ if ( riff.RIFFName() != RIFF_WAVE )
+ {
+ return false;
+ }
+
+ // set up the iterator for the whole file (root RIFF is a chunk)
+ IterateRIFF walk( riff, riff.RIFFSize() );
+
+ // This chunk must be first as it contains the wave's format
+ // break out when we've parsed it
+ bool found = false;
+ while ( walk.ChunkAvailable() && !found )
+ {
+ switch( walk.ChunkName() )
+ {
+ case WAVE_VALVEDATA:
+ {
+ found = true;
+ SceneManager_ParseSentence( sentence, walk );
+ }
+ break;
+ }
+ walk.ChunkNext();
+ }
+
+ return true;
+}
+
+bool SceneManager_LoadSentenceFromWavFile( char const *wavfile, CSentence& sentence )
+{
+ return SceneManager_LoadSentenceFromWavFileUsingIO( wavfile, sentence, io_in );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : store -
+//-----------------------------------------------------------------------------
+static void SceneManager_StoreValveDataChunk( CSentence& sentence, IterateOutputRIFF& store )
+{
+ // Buffer and dump data
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ sentence.SaveToBuffer( buf );
+
+ // Copy into store
+ store.ChunkWriteData( buf.Base(), buf.TellPut() );
+}
+
+bool SceneManager_SaveSentenceToWavFile( char const *wavfile, CSentence& sentence )
+{
+ char tempfile[ 512 ];
+
+ Q_StripExtension( wavfile, tempfile, sizeof( tempfile ) );
+ Q_DefaultExtension( tempfile, ".tmp", sizeof( tempfile ) );
+
+ if ( filesystem->FileExists( tempfile, "GAME" ) )
+ {
+ filesystem->RemoveFile( tempfile, "GAME" );
+ }
+
+ if ( !filesystem->IsFileWritable( wavfile ) )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", wavfile ) );
+ if ( retval != 0 )
+ return false;
+
+ VSS_Checkout( wavfile );
+ }
+
+ if ( !filesystem->IsFileWritable( wavfile ) )
+ {
+ Con_Printf( "%s is not writable, can't save sentence data to file\n", wavfile );
+ return false;
+ }
+
+ // Rename original wavfile to temp
+ filesystem->RenameFile( wavfile, tempfile, "GAME" );
+
+ // NOTE: Put this in it's own scope so that the destructor for outfileRFF actually closes the file!!!!
+ {
+ // Read from Temp
+ InFileRIFF riff( tempfile, io_in );
+ Assert( riff.RIFFName() == RIFF_WAVE );
+
+ // set up the iterator for the whole file (root RIFF is a chunk)
+ IterateRIFF walk( riff, riff.RIFFSize() );
+
+ // And put data back into original wavfile by name
+ OutFileRIFF riffout( wavfile, io_out );
+
+ IterateOutputRIFF store( riffout );
+
+ bool wordtrackwritten = false;
+
+ // Walk input chunks and copy to output
+ while ( walk.ChunkAvailable() )
+ {
+ store.ChunkStart( walk.ChunkName() );
+
+ switch ( walk.ChunkName() )
+ {
+ case WAVE_VALVEDATA:
+ {
+ // Overwrite data
+ SceneManager_StoreValveDataChunk( sentence, store );
+ wordtrackwritten = true;
+ }
+ break;
+ default:
+ store.CopyChunkData( walk );
+ break;
+ }
+
+ store.ChunkFinish();
+
+ walk.ChunkNext();
+ }
+
+ // If we didn't write it above, write it now
+ if ( !wordtrackwritten )
+ {
+ store.ChunkStart( WAVE_VALVEDATA );
+ SceneManager_StoreValveDataChunk( sentence, store );
+ store.ChunkFinish();
+ }
+ }
+
+ // Remove temp file
+ filesystem->RemoveFile( tempfile, NULL );
+
+ return true;
+}
+
+
+void SceneManager_LoadWindowPositions( KeyValues *kv, mxWindow *wnd )
+{
+ bool zoomed = kv->GetInt( "zoomed", 0 ) ? true : false;
+ int x = kv->GetInt( "x", 0 );
+ int y = kv->GetInt( "y", 0 );
+ int w = kv->GetInt( "w", 400 );
+ int h = kv->GetInt( "h", 300 );
+
+ wnd->setBounds( x, y, w, h );
+ if ( zoomed )
+ {
+ ShowWindow( (HWND)wnd->getHandle(), SW_SHOWMAXIMIZED );
+ }
+}
+
+static void Indent( CUtlBuffer& buf, int numtabs )
+{
+ for ( int i = 0 ; i < numtabs; i++ )
+ {
+ buf.Printf( "\t" );
+ }
+}
+
+void SceneManager_SaveWindowPositions( CUtlBuffer& buf, int indent, mxWindow *wnd )
+{
+ int x, y, w, h;
+
+ x = wnd->x();
+ y = wnd->y();
+ w = wnd->w();
+ h = wnd->h();
+
+ // xpos and ypos are screen space
+ POINT pt;
+ pt.x = x;
+ pt.y = y;
+
+ // Convert from screen space to relative to client area of parent window so
+ // the setBounds == MoveWindow call will offset to the same location
+ if ( wnd->getParent() )
+ {
+ ScreenToClient( (HWND)wnd->getParent()->getHandle(), &pt );
+ x = (short)pt.x;
+ y = (short)pt.y;
+ }
+
+
+ Indent( buf, indent );
+ buf.Printf( "\"x\"\t\"%i\"\n", x );
+
+ Indent( buf, indent );
+ buf.Printf( "\"y\"\t\"%i\"\n", y );
+
+ Indent( buf, indent );
+ buf.Printf( "\"w\"\t\"%i\"\n", w );
+
+ Indent( buf, indent );
+ buf.Printf( "\"h\"\t\"%i\"\n", h );
+
+ bool zoomed = IsZoomed( (HWND)wnd->getHandle() ) ? true : false;
+
+ Indent( buf, indent );
+ buf.Printf( "\"zoomed\"\t\"%i\"\n", zoomed ? 1 : 0 );
+
+}
+#if defined( _WIN32 ) || defined( WIN32 )
+#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
+#else //_WIN32
+#define PATHSEPARATOR(c) ((c) == '/')
+#endif //_WIN32
+
+static bool charsmatch( char c1, char c2 )
+{
+ if ( tolower( c1 ) == tolower( c2 ) )
+ return true;
+ if ( PATHSEPARATOR( c1 ) && PATHSEPARATOR( c2 ) )
+ return true;
+ return false;
+}
+
+
+char *Q_stristr_slash( char const *pStr, char const *pSearch )
+{
+ AssertValidStringPtr(pStr);
+ AssertValidStringPtr(pSearch);
+
+ if (!pStr || !pSearch)
+ return 0;
+
+ char const* pLetter = pStr;
+
+ // Check the entire string
+ while (*pLetter != 0)
+ {
+ // Skip over non-matches
+ if ( charsmatch( *pLetter, *pSearch ) )
+ {
+ // Check for match
+ char const* pMatch = pLetter + 1;
+ char const* pTest = pSearch + 1;
+ while (*pTest != 0)
+ {
+ // We've run off the end; don't bother.
+ if (*pMatch == 0)
+ return 0;
+
+ if ( !charsmatch( *pMatch, *pTest ) )
+ break;
+
+ ++pMatch;
+ ++pTest;
+ }
+
+ // Found a match!
+ if (*pTest == 0)
+ return (char *)pLetter;
+ }
+
+ ++pLetter;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *filename -
+//-----------------------------------------------------------------------------
+void MakeFileWriteable( const char *filename )
+{
+ Assert( filesystem );
+ char fullpath[ 512 ];
+ if (filesystem->GetLocalPath( filename, fullpath, sizeof(fullpath) ))
+ {
+ Q_FixSlashes( fullpath );
+ SetFileAttributes( fullpath, FILE_ATTRIBUTE_NORMAL );
+ }
+} \ No newline at end of file