Team Fortress 2 Source Code as on 22/4/2020
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.

279 lines
5.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include <stdio.h>
  9. #include <windows.h>
  10. #include "vmtcheck_util.h"
  11. #include "tier0/dbg.h"
  12. #include "utldict.h"
  13. #include "filesystem.h"
  14. #include "FileSystem_Tools.h"
  15. #include "KeyValues.h"
  16. #include "cmdlib.h"
  17. bool uselogfile = false;
  18. struct AnalysisData
  19. {
  20. CUtlSymbolTable symbols;
  21. };
  22. static AnalysisData g_Analysis;
  23. static bool spewed = false;
  24. SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
  25. {
  26. spewed = true;
  27. printf( "%s", pMsg );
  28. OutputDebugString( pMsg );
  29. if ( type == SPEW_ERROR )
  30. {
  31. printf( "\n" );
  32. OutputDebugString( "\n" );
  33. }
  34. return SPEW_CONTINUE;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. //-----------------------------------------------------------------------------
  39. void printusage( void )
  40. {
  41. vprint( 0, "usage: vmtcheck <materials/.vmt root directory>\n\
  42. \t-v = verbose output\n\
  43. \t-l = log to file log.txt\n\
  44. \ne.g.: vmtcheck -l u:/hl2/hl2/materials\n" );
  45. // Exit app
  46. exit( 1 );
  47. }
  48. void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension )
  49. {
  50. WIN32_FIND_DATA wfd;
  51. char directory[ 256 ];
  52. char filename[ 256 ];
  53. HANDLE ff;
  54. sprintf( directory, "%s\\*.*", dir );
  55. if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
  56. return;
  57. int extlen = strlen( extension );
  58. do
  59. {
  60. if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  61. {
  62. if ( wfd.cFileName[ 0 ] == '.' )
  63. continue;
  64. // Recurse down directory
  65. sprintf( filename, "%s\\%s", dir, wfd.cFileName );
  66. BuildFileList_R( files, filename, extension );
  67. }
  68. else
  69. {
  70. int len = strlen( wfd.cFileName );
  71. if ( len > extlen )
  72. {
  73. if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) )
  74. {
  75. char filename[ MAX_PATH ];
  76. Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName );
  77. _strlwr( filename );
  78. Q_FixSlashes( filename );
  79. CUtlSymbol sym = g_Analysis.symbols.AddString( filename );
  80. files.AddToTail( sym );
  81. if ( !( files.Count() % 3000 ) )
  82. {
  83. vprint( 0, "...found %i .vmt files\n", files.Count() );
  84. }
  85. }
  86. }
  87. }
  88. } while ( FindNextFile( ff, &wfd ) );
  89. }
  90. void BuildFileList( CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension )
  91. {
  92. files.RemoveAll();
  93. BuildFileList_R( files, rootdir, extension );
  94. }
  95. bool ValidateVMTFile( char const *vmtname, int offset )
  96. {
  97. bool valid = true;
  98. KeyValues *kv = new KeyValues( "Test" );
  99. if ( kv->LoadFromFile( g_pFileSystem, &vmtname[offset] ) )
  100. {
  101. // Do any custom checking here...
  102. }
  103. else
  104. {
  105. valid = false;
  106. }
  107. kv->deleteThis();
  108. return valid;
  109. }
  110. void ProcessMaterialsDirectory( char const *basedir )
  111. {
  112. vprint( 0, "building .vmt list\n" );
  113. CUtlVector< CUtlSymbol > vmts;
  114. BuildFileList( vmts, basedir, ".vmt" );
  115. vprint( 0, "found %i .vmt files\n\n", vmts.Count() );
  116. int offset = strlen( basedir ) + 1;
  117. offset -= strlen( "materials/" );
  118. if ( offset < 0 )
  119. {
  120. Error( "Bogus offset\n" );
  121. }
  122. // Now iterate vmts and load into memory, etc.
  123. int c = vmts.Count();
  124. int valid = 0;
  125. for ( int i = 0; i < c; i++ )
  126. {
  127. CUtlSymbol& sym = vmts[ i ];
  128. char const *vmtfile = g_Analysis.symbols.String( sym );
  129. if ( verbose )
  130. {
  131. vprint( 0, "checking %i .vmt %s\n", i, vmtfile );
  132. }
  133. spewed = false;
  134. if ( ValidateVMTFile( vmtfile, offset ) )
  135. {
  136. if ( !spewed )
  137. {
  138. valid++;
  139. }
  140. }
  141. if ( i > 0 && !( i % 1000 ) )
  142. {
  143. vprint( 0, "Analyzed %i .vmt files (%.2f %%%%)\n", i, 100.0f * (float)i/(float)c );
  144. }
  145. }
  146. int ecount = c - valid;
  147. vprint( 0, "\nSummary: found %i/%i (%.2f percent) .vmt errors\n", ecount, c, 100.0 * ecount / max( c, 1 ) );
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose:
  151. //-----------------------------------------------------------------------------
  152. void CheckLogFile( void )
  153. {
  154. if ( uselogfile )
  155. {
  156. _unlink( "log.txt" );
  157. vprint( 0, " Outputting to log.txt\n" );
  158. }
  159. }
  160. void PrintHeader()
  161. {
  162. vprint( 0, "Valve Software - vmtcheck.exe (%s)\n", __DATE__ );
  163. vprint( 0, "--- VMT File Consistency Checker ---\n" );
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose:
  167. // Input : argc -
  168. // argv[] -
  169. // Output : int
  170. //-----------------------------------------------------------------------------
  171. int main( int argc, char* argv[] )
  172. {
  173. SpewOutputFunc( SpewFunc );
  174. SpewActivate( "vmtcheck", 2 );
  175. int i=1;
  176. for ( i ; i<argc ; i++)
  177. {
  178. if ( argv[ i ][ 0 ] == '-' )
  179. {
  180. switch( argv[ i ][ 1 ] )
  181. {
  182. case 'l':
  183. uselogfile = true;
  184. break;
  185. case 'v':
  186. verbose = true;
  187. break;
  188. default:
  189. printusage();
  190. break;
  191. }
  192. }
  193. }
  194. if ( argc < 2 || ( i != argc ) )
  195. {
  196. PrintHeader();
  197. printusage();
  198. }
  199. CheckLogFile();
  200. PrintHeader();
  201. vprint( 0, " Looking for messed up .vmt files...\n" );
  202. char vmtdir[ 256 ];
  203. strcpy( vmtdir, argv[ i - 1 ] );
  204. if ( !strstr( vmtdir, "materials" ) )
  205. {
  206. vprint( 0, "Materials dir %s looks invalid (format: u:/tf2/hl2/materials)\n", vmtdir );
  207. return 0;
  208. }
  209. char workingdir[ 256 ];
  210. workingdir[0] = 0;
  211. Q_getwd( workingdir, sizeof( workingdir ) );
  212. // If they didn't specify -game on the command line, use VPROJECT.
  213. CmdLib_InitFileSystem( workingdir );
  214. vprint( 0, "game dir %s\nmaterials dir %s\n\n",
  215. gamedir,
  216. vmtdir );
  217. Q_StripTrailingSlash( vmtdir );
  218. ProcessMaterialsDirectory( vmtdir );
  219. FileSystem_Term();
  220. return 0;
  221. }