//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: vcd_sound_check.cpp : Defines the entry point for the console application. // //=============================================================================// #include #include #include "tier0/dbg.h" #include "tier1/utldict.h" #include "filesystem.h" #include "FileSystem_Tools.h" #include "tier1/KeyValues.h" #include "cmdlib.h" #include "scriplib.h" #include "vstdlib/random.h" #include "tier1/UtlBuffer.h" #include "pacifier.h" #include "appframework/appframework.h" #include "tier0/icommandline.h" #include "keyvaluescompiler.h" #include "tier2/keyvaluesmacros.h" #include "kvc_paintkit.h" #include "tier0/fasttimer.h" // #define TESTING 1 bool uselogfile = false; bool timing = false; qboolean verbose = false; struct AnalysisData { CUtlSymbolTable symbols; }; static AnalysisData g_Analysis; IBaseFileSystem *filesystem = NULL; //IFileSystem *g_pFullFileSystem = NULL; static bool spewed = false; SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg ) { spewed = true; printf( "%s", pMsg ); OutputDebugString( pMsg ); if ( type == SPEW_ERROR ) { printf( "\n" ); OutputDebugString( "\n" ); } return SPEW_CONTINUE; } //----------------------------------------------------------------------------- // Purpose: // Input : depth - // *fmt - // ... - //----------------------------------------------------------------------------- void vprint( int depth, const char *fmt, ... ) { char string[ 8192 ]; va_list va; va_start( va, fmt ); vsprintf( string, fmt, va ); va_end( va ); FILE *fp = NULL; if ( uselogfile ) { fp = fopen( "log.txt", "ab" ); } while ( depth-- > 0 ) { printf( " " ); OutputDebugString( " " ); if ( fp ) { fprintf( fp, " " ); } } ::printf( "%s", string ); OutputDebugString( string ); if ( fp ) { char *p = string; while ( *p ) { if ( *p == '\n' ) { fputc( '\r', fp ); } fputc( *p, fp ); p++; } fclose( fp ); } } void logprint( char const *logfile, const char *fmt, ... ) { char string[ 8192 ]; va_list va; va_start( va, fmt ); vsprintf( string, fmt, va ); va_end( va ); FILE *fp = NULL; static bool first = true; if ( first ) { first = false; fp = fopen( logfile, "wb" ); } else { fp = fopen( logfile, "ab" ); } if ( fp ) { char *p = string; while ( *p ) { if ( *p == '\n' ) { fputc( '\r', fp ); } fputc( *p, fp ); p++; } fclose( fp ); } } void Con_Printf( const char *fmt, ... ) { va_list args; static char output[1024]; va_start( args, fmt ); vprintf( fmt, args ); vsprintf( output, fmt, args ); vprint( 0, output ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void printusage( void ) { vprint( 0, "usage: kvc [] \n\ \n\ -v = verbose output\n\ -l = log to file log.txt\n\ -t = perform load timing tests\n\ -p = perform paint kit macro expansion\n\ in this mode if no output file is specified,\n\ the input file is copied to _bak and is overwritten\n\ with -p, each file specified is processed separately without wildcards\n\ -f = With -p, output is to _fix and is unchanged\n\ \n\ e.g.: kvc -l u:/xbox/game/hl2x/materials/*.vmt u:/xbox/game/hl2x/kvc/vmt.kv\n\ \n\ kvc -v -p americanpastoral_rocketlauncher.paintkit\n\ \n" ); // Exit app exit( 1 ); } void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension ) { WIN32_FIND_DATA wfd; char directory[ 256 ]; char filename[ 256 ]; HANDLE ff; sprintf( directory, "%s\\*.*", dir ); #if defined( TESTING ) if ( files.Count() > 100 ) return; #endif if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE ) return; int extlen = strlen( extension ); do { #if defined( TESTING ) if ( files.Count() > 100 ) return; #endif if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { if ( wfd.cFileName[ 0 ] == '.' ) continue; // Recurse down directory sprintf( filename, "%s\\%s", dir, wfd.cFileName ); BuildFileList_R( files, filename, extension ); } else { int len = strlen( wfd.cFileName ); if ( len > extlen ) { if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) ) { char filename[ MAX_PATH ]; Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName ); _strlwr( filename ); Q_FixSlashes( filename ); CUtlSymbol sym = g_Analysis.symbols.AddString( filename ); files.AddToTail( sym ); if ( !( files.Count() % 3000 ) ) { vprint( 0, "...found %i .%s files\n", files.Count(), extension ); } } } } } while ( FindNextFile( ff, &wfd ) ); } void BuildFileList( CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension ) { files.RemoveAll(); BuildFileList_R( files, rootdir, extension ); } void BuildFileListWildcard_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *wildcard ) { // Match files in current directory againsxt the wildcard char filesearch[ 256 ]; WIN32_FIND_DATA filedata; HANDLE h; Q_snprintf( filesearch, sizeof( filesearch ), "%s\\%s", dir, wildcard ); if ( ( h = FindFirstFile( filesearch, &filedata ) ) != INVALID_HANDLE_VALUE ) { do { #if defined( TESTING ) if ( files.Count() > 100 ) return; #endif if ( filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { continue; } char filename[ MAX_PATH ]; Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, filedata.cFileName ); _strlwr( filename ); Q_FixSlashes( filename ); CUtlSymbol sym = g_Analysis.symbols.AddString( filename ); files.AddToTail( sym ); if ( !( files.Count() % 3000 ) ) { vprint( 0, "...found %i files\n", files.Count() ); } } while ( FindNextFile( h, &filedata ) ); } // Now iterate the subdirectories and try them, too WIN32_FIND_DATA wfd; char directory[ 256 ]; char filename[ 256 ]; HANDLE ff; sprintf( directory, "%s\\*.*", dir ); #if defined( TESTING ) if ( files.Count() > 100 ) return; #endif if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE ) return; do { #if defined( TESTING ) if ( files.Count() > 100 ) return; #endif if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { if ( wfd.cFileName[ 0 ] == '.' ) continue; // Recurse down directory sprintf( filename, "%s\\%s", dir, wfd.cFileName ); BuildFileListWildcard_R( files, filename, wildcard ); } } while ( FindNextFile( ff, &wfd ) ); } void BuildFileListFromWildcard( CUtlVector< CUtlSymbol >& files, char const *search ) { char basepath[ 512 ]; char wildcard[ 512 ]; Q_ExtractFilePath( search, basepath, sizeof( basepath ) ); Q_StripTrailingSlash( basepath ); Q_strncpy( wildcard, &search[ Q_strlen( basepath ) + 1 ], sizeof( wildcard ) ); BuildFileListWildcard_R( files, basepath, wildcard ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CheckLogFile( void ) { if ( uselogfile ) { _unlink( "log.txt" ); vprint( 0, " Outputting to log.txt\n" ); } } void PrintHeader() { vprint( 0, "Valve Software - kvc.exe (%s)\n", __DATE__ ); vprint( 0, "--- KeyValues File compiler ---\n" ); } void CompileKeyValuesFiles( CUtlVector< CUtlSymbol >& scriptFiles, CCompiledKeyValuesWriter& writer ) { CUtlVector< CUtlSymbol > disposition; StartPacifier( "CompileKeyValuesFiles" ); int i; int c = scriptFiles.Count(); for ( i = 0 ; i < c; ++i ) { UpdatePacifier( (float)i / (float)c ); char filename[ 512 ]; Q_strncpy( filename, g_Analysis.symbols.String( scriptFiles[ i ] ), sizeof( filename ) ); writer.AppendKeyValuesFile( &filename[ Q_strlen( gamedir ) ] ); } EndPacifier(); } void DescribeKV( int depth, KeyValues *parent, KeyValues *kv ) { switch ( kv->GetDataType() ) { default: case KeyValues::TYPE_NONE: vprint( depth, "%s\n", kv->GetName() ); break; case KeyValues::TYPE_STRING: case KeyValues::TYPE_INT: case KeyValues::TYPE_FLOAT: case KeyValues::TYPE_PTR: case KeyValues::TYPE_WSTRING: case KeyValues::TYPE_COLOR: { vprint( depth, "%s = %s\n", kv->GetName(), kv->GetString() ); } break; } // Describe children for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) { DescribeKV( depth + 1, kv, sub ); } // Then add peers if ( !parent && kv->GetNextKey() ) { DescribeKV( depth, NULL, kv->GetNextKey() ); } } void ExamineKVFile( char const *filename ) { int i; CCompiledKeyValuesReader reader; CFastTimer timer; CFastTimer timer2; CFastTimer timer3; CUtlDict< KeyValues *, unsigned short > results; timer.Start(); reader.LoadFile( filename ); timer.End(); timer2.Start(); // Now get the actual files for ( i = reader.First(); i != reader.InvalidIndex(); i = reader.Next( i ) ) { char fn[ 256 ]; reader.GetFileName( i, fn, sizeof( fn ) ); // Instance keyvalues KeyValues *kv = reader.Instance( fn ); results.Insert( fn, kv ); } timer2.End(); timer3.Start(); KeyValues *foo = new KeyValues( "bar" ); // Now get the actual files for ( i = reader.First(); i != reader.InvalidIndex(); i = reader.Next( i ) ) { foo->Clear(); char fn[ 256 ]; reader.GetFileName( i, fn, sizeof( fn ) ); // Instance keyvalues reader.InstanceInPlace( *foo, fn ); } foo->deleteThis(); timer3.End(); /* for ( i = results.First(); i != results.InvalidIndex(); i = results.Next( i ) ) { vprint( 1, "%s\n", results.GetElementName( i ) ); KeyValues *kv = results[ i ]; DescribeKV( 1, NULL, kv ); } */ vprint( 0, "loading of %d elements took %.3f msec, create %.3f in-place %.3f\n", results.Count(), (float)timer.GetDuration().GetMillisecondsF(), (float)timer2.GetDuration().GetMillisecondsF(), (float)timer3.GetDuration().GetMillisecondsF()); CUtlVector< KeyValues * > test; // Now load them the hard way CFastTimer kvt; kvt.Start(); for ( i = results.First(); i != results.InvalidIndex(); i = results.Next( i ) ) { KeyValues *kv = new KeyValues( results.GetElementName( i ) ); kv->LoadFromFile( filesystem, results.GetElementName( i ) ); test.AddToTail( kv ); } kvt.End(); // Clean up int c = test.Count(); for ( i = 0; i < c; ++i ) { test[ i ]->deleteThis(); } for ( i = results.First(); i != results.InvalidIndex(); i = results.Next( i ) ) { results[ i ]->deleteThis(); } vprint( 0, "parsing of %d elements took %.3f msec\n", results.Count(), (float)kvt.GetDuration().GetMillisecondsF() ); } //----------------------------------------------------------------------------- // The application object //----------------------------------------------------------------------------- class CCompileKeyValuesApp : public CSteamAppSystemGroup { typedef CSteamAppSystemGroup BaseClass; public: // Methods of IApplication virtual bool Create(); virtual bool PreInit(); virtual int Main(); virtual void PostShutdown(); virtual void Destroy(); private: // Sets up the search paths bool SetupSearchPaths(); }; bool CCompileKeyValuesApp::Create() { SpewOutputFunc( SpewFunc ); SpewActivate( "kvc", 2 ); AppSystemInfo_t appSystems[] = { { "", "" } // Required to terminate the list }; if ( !AddSystems( appSystems ) ) return false; g_pFullFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); g_pFileSystem = filesystem = g_pFullFileSystem; if ( !filesystem ) { Error("Unable to load required library interface!\n"); } return true; } void CCompileKeyValuesApp::Destroy() { g_pFullFileSystem = NULL; g_pFileSystem = filesystem = NULL; } //----------------------------------------------------------------------------- // Sets up the game path //----------------------------------------------------------------------------- bool CCompileKeyValuesApp::SetupSearchPaths() { if ( !BaseClass::SetupSearchPaths( NULL, false, true ) ) return false; // Set gamedir. Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), GetGameInfoPath() ); Q_AppendSlash( gamedir, sizeof( gamedir ) ); return true; } //----------------------------------------------------------------------------- // Init, shutdown //----------------------------------------------------------------------------- bool CCompileKeyValuesApp::PreInit( ) { // MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); g_pFullFileSystem->SetWarningFunc( Warning ); // Add paths... if ( !SetupSearchPaths() ) return false; return true; } void CCompileKeyValuesApp::PostShutdown() { } //----------------------------------------------------------------------------- // main application //----------------------------------------------------------------------------- int CCompileKeyValuesApp::Main() { bool bOptPaintKit = false; CUtlVector< CUtlSymbol > worklist; int i; for ( i=1 ; iParmCount() ; i++ ) { if ( CommandLine()->GetParm( i )[ 0 ] == '-' ) { switch( CommandLine()->GetParm( i )[ 1 ] ) { case 'l': uselogfile = true; break; case 'v': verbose = true; break; case 'g': // -game ++i; break; case 't': timing = true; break; case 'p': bOptPaintKit = true; break; case 'f': // -f is valid when -p is specified break; default: printusage(); break; } } else if ( i != 0 ) { CUtlSymbol sym; sym = CommandLine()->GetParm( i ); worklist.AddToTail( sym ); } } if ( bOptPaintKit ) { if ( CommandLine()->ParmCount() < 2 || ( i != CommandLine()->ParmCount() ) || ( worklist.Count() < 1 ) ) { PrintHeader(); printusage(); // This exits app } ProcessPaintKitKeyValuesFiles( worklist ); return 0; } if ( CommandLine()->ParmCount() < 2 || ( i != CommandLine()->ParmCount() ) || worklist.Count() < 2 ) { PrintHeader(); printusage(); } CheckLogFile(); PrintHeader(); char binaries[MAX_PATH]; Q_strncpy( binaries, gamedir, MAX_PATH ); Q_StripTrailingSlash( binaries ); Q_strncat( binaries, "/../bin", MAX_PATH, MAX_PATH ); char outfile[ 512 ]; Q_strncpy( outfile, worklist[ worklist.Count() - 1 ].String() , sizeof( outfile ) ); g_pFullFileSystem->AddSearchPath( binaries, "EXECUTABLE_PATH"); vprint( 0, " Compiling keyvalues files...\n" ); CUtlVector< CUtlSymbol > diskfiles; for ( i = 0; i < worklist.Count() - 1; ++i ) { char workdir[ 256 ]; Q_snprintf( workdir, sizeof( workdir ), "%s", worklist[ i ].String() ); Q_StripTrailingSlash( workdir ); vprint( 0, "Processing '%s'\n", workdir ); int oldc = diskfiles.Count(); BuildFileListFromWildcard( diskfiles, workdir ); int added = diskfiles.Count() - oldc; vprint( 0, "found %i files\n\n", added ); } { CCompiledKeyValuesWriter writer; CompileKeyValuesFiles( diskfiles, writer ); vprint( 0, "Writing compiled file '%s'\n", outfile ); writer.WriteFile( outfile ); } if ( timing ) { ExamineKVFile( outfile ); } return 0; } //----------------------------------------------------------------------------- // Purpose: // Input : argc - // argv[] - // Output : int //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { CommandLine()->CreateCmdLine( argc, argv ); CCompileKeyValuesApp kvCompiler; CSteamApplication steamApplication( &kvCompiler ); int nRetVal = steamApplication.Run(); return nRetVal; }