diff options
Diffstat (limited to 'utils/vmtcheck/vmtcheck.cpp')
| -rw-r--r-- | utils/vmtcheck/vmtcheck.cpp | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/utils/vmtcheck/vmtcheck.cpp b/utils/vmtcheck/vmtcheck.cpp new file mode 100644 index 0000000..241a1d0 --- /dev/null +++ b/utils/vmtcheck/vmtcheck.cpp @@ -0,0 +1,279 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "stdafx.h" +#include <stdio.h> +#include <windows.h> +#include "vmtcheck_util.h" +#include "tier0/dbg.h" +#include "utldict.h" +#include "filesystem.h" +#include "FileSystem_Tools.h" +#include "KeyValues.h" +#include "cmdlib.h" + +bool uselogfile = false; + +struct AnalysisData +{ + CUtlSymbolTable symbols; +}; + +static AnalysisData g_Analysis; + + +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: +//----------------------------------------------------------------------------- +void printusage( void ) +{ + vprint( 0, "usage: vmtcheck <materials/.vmt root directory>\n\ + \t-v = verbose output\n\ + \t-l = log to file log.txt\n\ + \ne.g.: vmtcheck -l u:/hl2/hl2/materials\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 ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE ) + return; + + int extlen = strlen( extension ); + + do + { + 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 .vmt files\n", files.Count() ); + } + } + } + } + } while ( FindNextFile( ff, &wfd ) ); +} + +void BuildFileList( CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension ) +{ + files.RemoveAll(); + BuildFileList_R( files, rootdir, extension ); +} + +bool ValidateVMTFile( char const *vmtname, int offset ) +{ + bool valid = true; + + KeyValues *kv = new KeyValues( "Test" ); + if ( kv->LoadFromFile( g_pFileSystem, &vmtname[offset] ) ) + { + // Do any custom checking here... + } + else + { + valid = false; + } + kv->deleteThis(); + + return valid; +} + +void ProcessMaterialsDirectory( char const *basedir ) +{ + vprint( 0, "building .vmt list\n" ); + + CUtlVector< CUtlSymbol > vmts; + + BuildFileList( vmts, basedir, ".vmt" ); + + vprint( 0, "found %i .vmt files\n\n", vmts.Count() ); + + int offset = strlen( basedir ) + 1; + offset -= strlen( "materials/" ); + if ( offset < 0 ) + { + Error( "Bogus offset\n" ); + } + + // Now iterate vmts and load into memory, etc. + + int c = vmts.Count(); + int valid = 0; + for ( int i = 0; i < c; i++ ) + { + CUtlSymbol& sym = vmts[ i ]; + + char const *vmtfile = g_Analysis.symbols.String( sym ); + + if ( verbose ) + { + vprint( 0, "checking %i .vmt %s\n", i, vmtfile ); + } + + spewed = false; + if ( ValidateVMTFile( vmtfile, offset ) ) + { + if ( !spewed ) + { + valid++; + } + } + + if ( i > 0 && !( i % 1000 ) ) + { + vprint( 0, "Analyzed %i .vmt files (%.2f %%%%)\n", i, 100.0f * (float)i/(float)c ); + } + } + + int ecount = c - valid; + vprint( 0, "\nSummary: found %i/%i (%.2f percent) .vmt errors\n", ecount, c, 100.0 * ecount / max( c, 1 ) ); + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CheckLogFile( void ) +{ + if ( uselogfile ) + { + _unlink( "log.txt" ); + vprint( 0, " Outputting to log.txt\n" ); + } +} + +void PrintHeader() +{ + vprint( 0, "Valve Software - vmtcheck.exe (%s)\n", __DATE__ ); + vprint( 0, "--- VMT File Consistency Checker ---\n" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : argc - +// argv[] - +// Output : int +//----------------------------------------------------------------------------- +int main( int argc, char* argv[] ) +{ + SpewOutputFunc( SpewFunc ); + SpewActivate( "vmtcheck", 2 ); + + int i=1; + for ( i ; i<argc ; i++) + { + if ( argv[ i ][ 0 ] == '-' ) + { + switch( argv[ i ][ 1 ] ) + { + case 'l': + uselogfile = true; + break; + case 'v': + verbose = true; + break; + default: + printusage(); + break; + } + } + } + + if ( argc < 2 || ( i != argc ) ) + { + PrintHeader(); + printusage(); + } + + CheckLogFile(); + + PrintHeader(); + + vprint( 0, " Looking for messed up .vmt files...\n" ); + + char vmtdir[ 256 ]; + strcpy( vmtdir, argv[ i - 1 ] ); + + if ( !strstr( vmtdir, "materials" ) ) + { + vprint( 0, "Materials dir %s looks invalid (format: u:/tf2/hl2/materials)\n", vmtdir ); + + return 0; + } + + char workingdir[ 256 ]; + workingdir[0] = 0; + Q_getwd( workingdir, sizeof( workingdir ) ); + + // If they didn't specify -game on the command line, use VPROJECT. + CmdLib_InitFileSystem( workingdir ); + + vprint( 0, "game dir %s\nmaterials dir %s\n\n", + gamedir, + vmtdir ); + + Q_StripTrailingSlash( vmtdir ); + ProcessMaterialsDirectory( vmtdir ); + + FileSystem_Term(); + + return 0; +} |