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.

709 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: vcd_sound_check.cpp : Defines the entry point for the console application.
  4. //
  5. //=============================================================================//
  6. #include <stdio.h>
  7. #include <windows.h>
  8. #include "tier0/dbg.h"
  9. #include "tier1/utldict.h"
  10. #include "filesystem.h"
  11. #include "FileSystem_Tools.h"
  12. #include "tier1/KeyValues.h"
  13. #include "cmdlib.h"
  14. #include "scriplib.h"
  15. #include "vstdlib/random.h"
  16. #include "tier1/UtlBuffer.h"
  17. #include "pacifier.h"
  18. #include "appframework/appframework.h"
  19. #include "tier0/icommandline.h"
  20. #include "keyvaluescompiler.h"
  21. #include "tier2/keyvaluesmacros.h"
  22. #include "kvc_paintkit.h"
  23. #include "tier0/fasttimer.h"
  24. // #define TESTING 1
  25. bool uselogfile = false;
  26. bool timing = false;
  27. qboolean verbose = false;
  28. struct AnalysisData
  29. {
  30. CUtlSymbolTable symbols;
  31. };
  32. static AnalysisData g_Analysis;
  33. IBaseFileSystem *filesystem = NULL;
  34. //IFileSystem *g_pFullFileSystem = NULL;
  35. static bool spewed = false;
  36. SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
  37. {
  38. spewed = true;
  39. printf( "%s", pMsg );
  40. OutputDebugString( pMsg );
  41. if ( type == SPEW_ERROR )
  42. {
  43. printf( "\n" );
  44. OutputDebugString( "\n" );
  45. }
  46. return SPEW_CONTINUE;
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose:
  50. // Input : depth -
  51. // *fmt -
  52. // ... -
  53. //-----------------------------------------------------------------------------
  54. void vprint( int depth, const char *fmt, ... )
  55. {
  56. char string[ 8192 ];
  57. va_list va;
  58. va_start( va, fmt );
  59. vsprintf( string, fmt, va );
  60. va_end( va );
  61. FILE *fp = NULL;
  62. if ( uselogfile )
  63. {
  64. fp = fopen( "log.txt", "ab" );
  65. }
  66. while ( depth-- > 0 )
  67. {
  68. printf( " " );
  69. OutputDebugString( " " );
  70. if ( fp )
  71. {
  72. fprintf( fp, " " );
  73. }
  74. }
  75. ::printf( "%s", string );
  76. OutputDebugString( string );
  77. if ( fp )
  78. {
  79. char *p = string;
  80. while ( *p )
  81. {
  82. if ( *p == '\n' )
  83. {
  84. fputc( '\r', fp );
  85. }
  86. fputc( *p, fp );
  87. p++;
  88. }
  89. fclose( fp );
  90. }
  91. }
  92. void logprint( char const *logfile, const char *fmt, ... )
  93. {
  94. char string[ 8192 ];
  95. va_list va;
  96. va_start( va, fmt );
  97. vsprintf( string, fmt, va );
  98. va_end( va );
  99. FILE *fp = NULL;
  100. static bool first = true;
  101. if ( first )
  102. {
  103. first = false;
  104. fp = fopen( logfile, "wb" );
  105. }
  106. else
  107. {
  108. fp = fopen( logfile, "ab" );
  109. }
  110. if ( fp )
  111. {
  112. char *p = string;
  113. while ( *p )
  114. {
  115. if ( *p == '\n' )
  116. {
  117. fputc( '\r', fp );
  118. }
  119. fputc( *p, fp );
  120. p++;
  121. }
  122. fclose( fp );
  123. }
  124. }
  125. void Con_Printf( const char *fmt, ... )
  126. {
  127. va_list args;
  128. static char output[1024];
  129. va_start( args, fmt );
  130. vprintf( fmt, args );
  131. vsprintf( output, fmt, args );
  132. vprint( 0, output );
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. //-----------------------------------------------------------------------------
  137. void printusage( void )
  138. {
  139. vprint( 0, "usage: kvc <wildcard path> [<wildcard path>] <outputfile>\n\
  140. \n\
  141. -v = verbose output\n\
  142. -l = log to file log.txt\n\
  143. -t = perform load timing tests\n\
  144. -p = perform paint kit macro expansion\n\
  145. in this mode if no output file is specified,\n\
  146. the input file is copied to <input>_bak and <input> is overwritten\n\
  147. with -p, each file specified is processed separately without wildcards\n\
  148. -f = With -p, output is to <input>_fix and <input> is unchanged\n\
  149. \n\
  150. e.g.: kvc -l u:/xbox/game/hl2x/materials/*.vmt u:/xbox/game/hl2x/kvc/vmt.kv\n\
  151. \n\
  152. kvc -v -p americanpastoral_rocketlauncher.paintkit\n\
  153. \n" );
  154. // Exit app
  155. exit( 1 );
  156. }
  157. void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension )
  158. {
  159. WIN32_FIND_DATA wfd;
  160. char directory[ 256 ];
  161. char filename[ 256 ];
  162. HANDLE ff;
  163. sprintf( directory, "%s\\*.*", dir );
  164. #if defined( TESTING )
  165. if ( files.Count() > 100 )
  166. return;
  167. #endif
  168. if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
  169. return;
  170. int extlen = strlen( extension );
  171. do
  172. {
  173. #if defined( TESTING )
  174. if ( files.Count() > 100 )
  175. return;
  176. #endif
  177. if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  178. {
  179. if ( wfd.cFileName[ 0 ] == '.' )
  180. continue;
  181. // Recurse down directory
  182. sprintf( filename, "%s\\%s", dir, wfd.cFileName );
  183. BuildFileList_R( files, filename, extension );
  184. }
  185. else
  186. {
  187. int len = strlen( wfd.cFileName );
  188. if ( len > extlen )
  189. {
  190. if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) )
  191. {
  192. char filename[ MAX_PATH ];
  193. Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName );
  194. _strlwr( filename );
  195. Q_FixSlashes( filename );
  196. CUtlSymbol sym = g_Analysis.symbols.AddString( filename );
  197. files.AddToTail( sym );
  198. if ( !( files.Count() % 3000 ) )
  199. {
  200. vprint( 0, "...found %i .%s files\n", files.Count(), extension );
  201. }
  202. }
  203. }
  204. }
  205. } while ( FindNextFile( ff, &wfd ) );
  206. }
  207. void BuildFileList( CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension )
  208. {
  209. files.RemoveAll();
  210. BuildFileList_R( files, rootdir, extension );
  211. }
  212. void BuildFileListWildcard_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *wildcard )
  213. {
  214. // Match files in current directory againsxt the wildcard
  215. char filesearch[ 256 ];
  216. WIN32_FIND_DATA filedata;
  217. HANDLE h;
  218. Q_snprintf( filesearch, sizeof( filesearch ), "%s\\%s", dir, wildcard );
  219. if ( ( h = FindFirstFile( filesearch, &filedata ) ) != INVALID_HANDLE_VALUE )
  220. {
  221. do
  222. {
  223. #if defined( TESTING )
  224. if ( files.Count() > 100 )
  225. return;
  226. #endif
  227. if ( filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  228. {
  229. continue;
  230. }
  231. char filename[ MAX_PATH ];
  232. Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, filedata.cFileName );
  233. _strlwr( filename );
  234. Q_FixSlashes( filename );
  235. CUtlSymbol sym = g_Analysis.symbols.AddString( filename );
  236. files.AddToTail( sym );
  237. if ( !( files.Count() % 3000 ) )
  238. {
  239. vprint( 0, "...found %i files\n", files.Count() );
  240. }
  241. } while ( FindNextFile( h, &filedata ) );
  242. }
  243. // Now iterate the subdirectories and try them, too
  244. WIN32_FIND_DATA wfd;
  245. char directory[ 256 ];
  246. char filename[ 256 ];
  247. HANDLE ff;
  248. sprintf( directory, "%s\\*.*", dir );
  249. #if defined( TESTING )
  250. if ( files.Count() > 100 )
  251. return;
  252. #endif
  253. if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
  254. return;
  255. do
  256. {
  257. #if defined( TESTING )
  258. if ( files.Count() > 100 )
  259. return;
  260. #endif
  261. if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  262. {
  263. if ( wfd.cFileName[ 0 ] == '.' )
  264. continue;
  265. // Recurse down directory
  266. sprintf( filename, "%s\\%s", dir, wfd.cFileName );
  267. BuildFileListWildcard_R( files, filename, wildcard );
  268. }
  269. } while ( FindNextFile( ff, &wfd ) );
  270. }
  271. void BuildFileListFromWildcard( CUtlVector< CUtlSymbol >& files, char const *search )
  272. {
  273. char basepath[ 512 ];
  274. char wildcard[ 512 ];
  275. Q_ExtractFilePath( search, basepath, sizeof( basepath ) );
  276. Q_StripTrailingSlash( basepath );
  277. Q_strncpy( wildcard, &search[ Q_strlen( basepath ) + 1 ], sizeof( wildcard ) );
  278. BuildFileListWildcard_R( files, basepath, wildcard );
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose:
  282. //-----------------------------------------------------------------------------
  283. void CheckLogFile( void )
  284. {
  285. if ( uselogfile )
  286. {
  287. _unlink( "log.txt" );
  288. vprint( 0, " Outputting to log.txt\n" );
  289. }
  290. }
  291. void PrintHeader()
  292. {
  293. vprint( 0, "Valve Software - kvc.exe (%s)\n", __DATE__ );
  294. vprint( 0, "--- KeyValues File compiler ---\n" );
  295. }
  296. void CompileKeyValuesFiles( CUtlVector< CUtlSymbol >& scriptFiles, CCompiledKeyValuesWriter& writer )
  297. {
  298. CUtlVector< CUtlSymbol > disposition;
  299. StartPacifier( "CompileKeyValuesFiles" );
  300. int i;
  301. int c = scriptFiles.Count();
  302. for ( i = 0 ; i < c; ++i )
  303. {
  304. UpdatePacifier( (float)i / (float)c );
  305. char filename[ 512 ];
  306. Q_strncpy( filename, g_Analysis.symbols.String( scriptFiles[ i ] ), sizeof( filename ) );
  307. writer.AppendKeyValuesFile( &filename[ Q_strlen( gamedir ) ] );
  308. }
  309. EndPacifier();
  310. }
  311. void DescribeKV( int depth, KeyValues *parent, KeyValues *kv )
  312. {
  313. switch ( kv->GetDataType() )
  314. {
  315. default:
  316. case KeyValues::TYPE_NONE:
  317. vprint( depth, "%s\n", kv->GetName() );
  318. break;
  319. case KeyValues::TYPE_STRING:
  320. case KeyValues::TYPE_INT:
  321. case KeyValues::TYPE_FLOAT:
  322. case KeyValues::TYPE_PTR:
  323. case KeyValues::TYPE_WSTRING:
  324. case KeyValues::TYPE_COLOR:
  325. {
  326. vprint( depth, "%s = %s\n", kv->GetName(), kv->GetString() );
  327. }
  328. break;
  329. }
  330. // Describe children
  331. for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
  332. {
  333. DescribeKV( depth + 1, kv, sub );
  334. }
  335. // Then add peers
  336. if ( !parent && kv->GetNextKey() )
  337. {
  338. DescribeKV( depth, NULL, kv->GetNextKey() );
  339. }
  340. }
  341. void ExamineKVFile( char const *filename )
  342. {
  343. int i;
  344. CCompiledKeyValuesReader reader;
  345. CFastTimer timer;
  346. CFastTimer timer2;
  347. CFastTimer timer3;
  348. CUtlDict< KeyValues *, unsigned short > results;
  349. timer.Start();
  350. reader.LoadFile( filename );
  351. timer.End();
  352. timer2.Start();
  353. // Now get the actual files
  354. for ( i = reader.First(); i != reader.InvalidIndex(); i = reader.Next( i ) )
  355. {
  356. char fn[ 256 ];
  357. reader.GetFileName( i, fn, sizeof( fn ) );
  358. // Instance keyvalues
  359. KeyValues *kv = reader.Instance( fn );
  360. results.Insert( fn, kv );
  361. }
  362. timer2.End();
  363. timer3.Start();
  364. KeyValues *foo = new KeyValues( "bar" );
  365. // Now get the actual files
  366. for ( i = reader.First(); i != reader.InvalidIndex(); i = reader.Next( i ) )
  367. {
  368. foo->Clear();
  369. char fn[ 256 ];
  370. reader.GetFileName( i, fn, sizeof( fn ) );
  371. // Instance keyvalues
  372. reader.InstanceInPlace( *foo, fn );
  373. }
  374. foo->deleteThis();
  375. timer3.End();
  376. /*
  377. for ( i = results.First(); i != results.InvalidIndex(); i = results.Next( i ) )
  378. {
  379. vprint( 1, "%s\n", results.GetElementName( i ) );
  380. KeyValues *kv = results[ i ];
  381. DescribeKV( 1, NULL, kv );
  382. }
  383. */
  384. vprint( 0, "loading of %d elements took %.3f msec, create %.3f in-place %.3f\n",
  385. results.Count(),
  386. (float)timer.GetDuration().GetMillisecondsF(),
  387. (float)timer2.GetDuration().GetMillisecondsF(),
  388. (float)timer3.GetDuration().GetMillisecondsF());
  389. CUtlVector< KeyValues * > test;
  390. // Now load them the hard way
  391. CFastTimer kvt;
  392. kvt.Start();
  393. for ( i = results.First(); i != results.InvalidIndex(); i = results.Next( i ) )
  394. {
  395. KeyValues *kv = new KeyValues( results.GetElementName( i ) );
  396. kv->LoadFromFile( filesystem, results.GetElementName( i ) );
  397. test.AddToTail( kv );
  398. }
  399. kvt.End();
  400. // Clean up
  401. int c = test.Count();
  402. for ( i = 0; i < c; ++i )
  403. {
  404. test[ i ]->deleteThis();
  405. }
  406. for ( i = results.First(); i != results.InvalidIndex(); i = results.Next( i ) )
  407. {
  408. results[ i ]->deleteThis();
  409. }
  410. vprint( 0, "parsing of %d elements took %.3f msec\n", results.Count(), (float)kvt.GetDuration().GetMillisecondsF() );
  411. }
  412. //-----------------------------------------------------------------------------
  413. // The application object
  414. //-----------------------------------------------------------------------------
  415. class CCompileKeyValuesApp : public CSteamAppSystemGroup
  416. {
  417. typedef CSteamAppSystemGroup BaseClass;
  418. public:
  419. // Methods of IApplication
  420. virtual bool Create();
  421. virtual bool PreInit();
  422. virtual int Main();
  423. virtual void PostShutdown();
  424. virtual void Destroy();
  425. private:
  426. // Sets up the search paths
  427. bool SetupSearchPaths();
  428. };
  429. bool CCompileKeyValuesApp::Create()
  430. {
  431. SpewOutputFunc( SpewFunc );
  432. SpewActivate( "kvc", 2 );
  433. AppSystemInfo_t appSystems[] =
  434. {
  435. { "", "" } // Required to terminate the list
  436. };
  437. if ( !AddSystems( appSystems ) )
  438. return false;
  439. g_pFullFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION );
  440. g_pFileSystem = filesystem = g_pFullFileSystem;
  441. if ( !filesystem )
  442. {
  443. Error("Unable to load required library interface!\n");
  444. }
  445. return true;
  446. }
  447. void CCompileKeyValuesApp::Destroy()
  448. {
  449. g_pFullFileSystem = NULL;
  450. g_pFileSystem = filesystem = NULL;
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Sets up the game path
  454. //-----------------------------------------------------------------------------
  455. bool CCompileKeyValuesApp::SetupSearchPaths()
  456. {
  457. if ( !BaseClass::SetupSearchPaths( NULL, false, true ) )
  458. return false;
  459. // Set gamedir.
  460. Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), GetGameInfoPath() );
  461. Q_AppendSlash( gamedir, sizeof( gamedir ) );
  462. return true;
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Init, shutdown
  466. //-----------------------------------------------------------------------------
  467. bool CCompileKeyValuesApp::PreInit( )
  468. {
  469. // MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  470. g_pFullFileSystem->SetWarningFunc( Warning );
  471. // Add paths...
  472. if ( !SetupSearchPaths() )
  473. return false;
  474. return true;
  475. }
  476. void CCompileKeyValuesApp::PostShutdown()
  477. {
  478. }
  479. //-----------------------------------------------------------------------------
  480. // main application
  481. //-----------------------------------------------------------------------------
  482. int CCompileKeyValuesApp::Main()
  483. {
  484. bool bOptPaintKit = false;
  485. CUtlVector< CUtlSymbol > worklist;
  486. int i;
  487. for ( i=1 ; i<CommandLine()->ParmCount() ; i++ )
  488. {
  489. if ( CommandLine()->GetParm( i )[ 0 ] == '-' )
  490. {
  491. switch( CommandLine()->GetParm( i )[ 1 ] )
  492. {
  493. case 'l':
  494. uselogfile = true;
  495. break;
  496. case 'v':
  497. verbose = true;
  498. break;
  499. case 'g': // -game
  500. ++i;
  501. break;
  502. case 't':
  503. timing = true;
  504. break;
  505. case 'p':
  506. bOptPaintKit = true;
  507. break;
  508. case 'f': // -f is valid when -p is specified
  509. break;
  510. default:
  511. printusage();
  512. break;
  513. }
  514. }
  515. else if ( i != 0 )
  516. {
  517. CUtlSymbol sym;
  518. sym = CommandLine()->GetParm( i );
  519. worklist.AddToTail( sym );
  520. }
  521. }
  522. if ( bOptPaintKit )
  523. {
  524. if ( CommandLine()->ParmCount() < 2 || ( i != CommandLine()->ParmCount() ) || ( worklist.Count() < 1 ) )
  525. {
  526. PrintHeader();
  527. printusage(); // This exits app
  528. }
  529. ProcessPaintKitKeyValuesFiles( worklist );
  530. return 0;
  531. }
  532. if ( CommandLine()->ParmCount() < 2 || ( i != CommandLine()->ParmCount() ) || worklist.Count() < 2 )
  533. {
  534. PrintHeader();
  535. printusage();
  536. }
  537. CheckLogFile();
  538. PrintHeader();
  539. char binaries[MAX_PATH];
  540. Q_strncpy( binaries, gamedir, MAX_PATH );
  541. Q_StripTrailingSlash( binaries );
  542. Q_strncat( binaries, "/../bin", MAX_PATH, MAX_PATH );
  543. char outfile[ 512 ];
  544. Q_strncpy( outfile, worklist[ worklist.Count() - 1 ].String() , sizeof( outfile ) );
  545. g_pFullFileSystem->AddSearchPath( binaries, "EXECUTABLE_PATH");
  546. vprint( 0, " Compiling keyvalues files...\n" );
  547. CUtlVector< CUtlSymbol > diskfiles;
  548. for ( i = 0; i < worklist.Count() - 1; ++i )
  549. {
  550. char workdir[ 256 ];
  551. Q_snprintf( workdir, sizeof( workdir ), "%s", worklist[ i ].String() );
  552. Q_StripTrailingSlash( workdir );
  553. vprint( 0, "Processing '%s'\n", workdir );
  554. int oldc = diskfiles.Count();
  555. BuildFileListFromWildcard( diskfiles, workdir );
  556. int added = diskfiles.Count() - oldc;
  557. vprint( 0, "found %i files\n\n", added );
  558. }
  559. {
  560. CCompiledKeyValuesWriter writer;
  561. CompileKeyValuesFiles( diskfiles, writer );
  562. vprint( 0, "Writing compiled file '%s'\n", outfile );
  563. writer.WriteFile( outfile );
  564. }
  565. if ( timing )
  566. {
  567. ExamineKVFile( outfile );
  568. }
  569. return 0;
  570. }
  571. //-----------------------------------------------------------------------------
  572. // Purpose:
  573. // Input : argc -
  574. // argv[] -
  575. // Output : int
  576. //-----------------------------------------------------------------------------
  577. int main( int argc, char* argv[] )
  578. {
  579. CommandLine()->CreateCmdLine( argc, argv );
  580. CCompileKeyValuesApp kvCompiler;
  581. CSteamApplication steamApplication( &kvCompiler );
  582. int nRetVal = steamApplication.Run();
  583. return nRetVal;
  584. }