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.
280 lines
5.5 KiB
280 lines
5.5 KiB
![]()
4 years ago
|
//========= 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;
|
||
|
}
|