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.

552 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include "bsplib.h"
  9. #include "cmdlib.h"
  10. #include "tier0/icommandline.h"
  11. #include "utlbuffer.h"
  12. int CopyVariableLump( int lump, void **dest, int size );
  13. void StripPath( const char* pPath, char* pBuf, int nBufLen )
  14. {
  15. const char *pSrc;
  16. // want filename only
  17. pSrc = pPath + Q_strlen( pPath ) - 1;
  18. while ((pSrc != pPath) && (*(pSrc-1) != '\\') && (*(pSrc-1) != '/') && (*(pSrc-1) != ':'))
  19. pSrc--;
  20. Q_strncpy( pBuf, pSrc, nBufLen );
  21. }
  22. bool RepackBSP( const char *pszMapFile, bool bCompress )
  23. {
  24. Msg( "Repacking %s\n", pszMapFile );
  25. if ( !g_pFullFileSystem->FileExists( pszMapFile ) )
  26. {
  27. Warning( "Couldn't open input file %s - BSP recompress failed\n", pszMapFile );
  28. return false;
  29. }
  30. CUtlBuffer inputBuffer;
  31. if ( !g_pFullFileSystem->ReadFile( pszMapFile, NULL, inputBuffer ) )
  32. {
  33. Warning( "Couldn't read file %s - BSP compression failed\n", pszMapFile );
  34. return false;
  35. }
  36. CUtlBuffer outputBuffer;
  37. if ( !RepackBSP( inputBuffer, outputBuffer,
  38. bCompress ? RepackBSPCallback_LZMA : NULL,
  39. bCompress ? IZip::eCompressionType_LZMA : IZip::eCompressionType_None ) )
  40. {
  41. Warning( "Internal error compressing BSP\n" );
  42. return false;
  43. }
  44. g_pFullFileSystem->WriteFile( pszMapFile, NULL, outputBuffer );
  45. Msg( "Successfully repacked %s -- %u -> %u bytes\n",
  46. pszMapFile, inputBuffer.TellPut(), outputBuffer.TellPut() );
  47. return true;
  48. }
  49. void Usage( void )
  50. {
  51. fprintf( stderr, "usage: \n" );
  52. fprintf( stderr, "bspzip -extract <bspfile> <blah.zip>\n");
  53. fprintf( stderr, "bspzip -extractfiles <bspfile> <targetpath>\n");
  54. fprintf( stderr, "bspzip -dir <bspfile>\n");
  55. fprintf( stderr, "bspzip -addfile <bspfile> <relativepathname> <fullpathname> <newbspfile>\n");
  56. fprintf( stderr, "bspzip -addlist <bspfile> <listfile> <newbspfile>\n");
  57. fprintf( stderr, "bspzip -addorupdatelist <bspfile> <listfile> <newbspfile>\n");
  58. fprintf( stderr, "bspzip -extractcubemaps <bspfile> <targetPath>\n");
  59. fprintf( stderr, " Extracts the cubemaps to <targetPath>.\n");
  60. fprintf( stderr, "bspzip -deletecubemaps <bspfile>\n");
  61. fprintf( stderr, " Deletes the cubemaps from <bspFile>.\n");
  62. fprintf( stderr, "bspzip -addfiles <bspfile> <relativePathPrefix> <listfile> <newbspfile>\n");
  63. fprintf( stderr, " Adds files to <newbspfile>.\n");
  64. fprintf( stderr, "bspzip -repack [ -compress ] <bspfile>\n");
  65. fprintf( stderr, " Optimally repacks a BSP file, optionally using compressed BSP format.\n");
  66. fprintf( stderr, " Using on a compressed BSP without -compress will effectively decompress\n");
  67. fprintf( stderr, " a compressed BSP.\n");
  68. exit( -1 );
  69. }
  70. char* xzpFilename = NULL;
  71. int main( int argc, char **argv )
  72. {
  73. ::SetHDRMode( false );
  74. Msg( "\nValve Software - bspzip.exe (%s)\n", __DATE__ );
  75. int curArg = 1;
  76. // Options parsing assumes
  77. // [ -game foo ] -<action> <action specific args>
  78. // Skip -game foo
  79. if ( argc >= curArg + 2 && stricmp( argv[curArg], "-game" ) == 0 )
  80. {
  81. // Handled by filesystem code
  82. curArg += 2;
  83. }
  84. // Should have at least action
  85. if ( curArg >= argc )
  86. {
  87. // End of args
  88. Usage();
  89. return 0;
  90. }
  91. // Pointers to the action, the file, and any action args so I can remove all the messy argc pointer math this was
  92. // using.
  93. char *pAction = argv[curArg];
  94. curArg++;
  95. char **pActionArgs = &argv[curArg];
  96. int nActionArgs = argc - curArg;
  97. CommandLine()->CreateCmdLine( argc, argv );
  98. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
  99. if( ( stricmp( pAction, "-extract" ) == 0 ) && nActionArgs == 2 )
  100. {
  101. // bspzip -extract <bspfile> <blah.zip>
  102. CmdLib_InitFileSystem( pActionArgs[0] );
  103. char bspName[MAX_PATH] = { 0 };
  104. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  105. Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) );
  106. char zipName[MAX_PATH] = { 0 };
  107. V_strncpy( zipName, pActionArgs[1], sizeof( zipName ) );
  108. Q_DefaultExtension(zipName, ".zip", sizeof( zipName ) );
  109. ExtractZipFileFromBSP( bspName, zipName );
  110. }
  111. else if( ( stricmp( pAction, "-extractfiles" ) == 0 ) && nActionArgs == 2 )
  112. {
  113. // bsipzip -extractfiles <bspfile> <targetpath>
  114. CmdLib_InitFileSystem( pActionArgs[0] );
  115. // necessary for xbox process
  116. // only the .vtf are extracted as necessary for streaming and not the .vmt
  117. // the .vmt are non-streamed and therefore remain, referenced normally as part of the bsp search path
  118. char bspName[MAX_PATH] = { 0 };
  119. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  120. Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) );
  121. char targetPathName[MAX_PATH] = { 0 };
  122. V_strncpy( targetPathName, pActionArgs[1], sizeof( targetPathName ) );
  123. Q_AppendSlash( targetPathName, sizeof( targetPathName ) );
  124. printf( "\n" );
  125. printf( "Opening bsp file: %s\n", bspName );
  126. LoadBSPFile( bspName );
  127. CUtlBuffer buf;
  128. char relativeName[MAX_PATH] = { 0 };
  129. char targetName[MAX_PATH] = { 0 };
  130. int fileSize = 0;
  131. int id = -1;
  132. int numFilesExtracted = 0;
  133. while(true)
  134. {
  135. id = GetNextFilename( GetPakFile(), id, relativeName, sizeof(relativeName), fileSize );
  136. if ( id == -1)
  137. break;
  138. {
  139. buf.EnsureCapacity( fileSize );
  140. buf.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  141. ReadFileFromPak( GetPakFile(), relativeName, false, buf );
  142. V_strncpy( targetName, targetPathName, sizeof(targetName) );
  143. V_strncat( targetName, relativeName, sizeof(targetName) );
  144. Q_FixSlashes( targetName, '\\' );
  145. SafeCreatePath( targetName );
  146. printf( "Writing file: %s\n", targetName );
  147. FILE *fp = fopen( targetName, "wb" );
  148. if ( !fp )
  149. {
  150. printf( "Error: Could not write %s\n", targetName);
  151. exit( -1 );
  152. }
  153. fwrite( buf.Base(), fileSize, 1, fp );
  154. fclose( fp );
  155. numFilesExtracted++;
  156. }
  157. }
  158. printf( "%d files extracted.\n", numFilesExtracted );
  159. }
  160. else if( ( stricmp( pAction, "-extractcubemaps" ) == 0 ) && nActionArgs == 2 )
  161. {
  162. // bspzip -extractcubemaps <bspfile> <targetPath>
  163. CmdLib_InitFileSystem( pActionArgs[0] );
  164. // necessary for xbox process
  165. // only the .vtf are extracted as necessary for streaming and not the .vmt
  166. // the .vmt are non-streamed and therefore remain, referenced normally as part of the bsp search path
  167. char bspName[MAX_PATH] = { 0 };
  168. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  169. Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) );
  170. char targetPathName[MAX_PATH] = { 0 };
  171. V_strncpy( targetPathName, pActionArgs[1], sizeof(targetPathName) );
  172. Q_AppendSlash( targetPathName, sizeof( targetPathName ) );
  173. printf( "\n" );
  174. printf( "Opening bsp file: %s\n", bspName );
  175. LoadBSPFile( bspName );
  176. CUtlBuffer buf;
  177. char relativeName[MAX_PATH] = { 0 };
  178. char targetName[MAX_PATH] = { 0 };
  179. int fileSize = 0;
  180. int id = -1;
  181. int numFilesExtracted = 0;
  182. while (1)
  183. {
  184. id = GetNextFilename( GetPakFile(), id, relativeName, sizeof(relativeName), fileSize );
  185. if ( id == -1)
  186. break;
  187. if ( Q_stristr( relativeName, ".vtf" ) )
  188. {
  189. buf.EnsureCapacity( fileSize );
  190. buf.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  191. ReadFileFromPak( GetPakFile(), relativeName, false, buf );
  192. V_strncpy( targetName, targetPathName, sizeof( targetName ) );
  193. V_strncat( targetName, relativeName, sizeof( targetName ) );
  194. Q_FixSlashes( targetName, '\\' );
  195. SafeCreatePath( targetName );
  196. printf( "Writing vtf file: %s\n", targetName );
  197. FILE *fp = fopen( targetName, "wb" );
  198. if ( !fp )
  199. {
  200. printf( "Error: Could not write %s\n", targetName);
  201. exit( -1 );
  202. }
  203. fwrite( buf.Base(), fileSize, 1, fp );
  204. fclose( fp );
  205. numFilesExtracted++;
  206. }
  207. }
  208. printf( "%d cubemaps extracted.\n", numFilesExtracted );
  209. }
  210. else if( ( stricmp( pAction, "-deletecubemaps" ) == 0 ) && nActionArgs == 1 )
  211. {
  212. // bspzip -deletecubemaps <bspfile>
  213. CmdLib_InitFileSystem( pActionArgs[0] );
  214. // necessary for xbox process
  215. // the cubemaps are deleted as they cannot yet be streamed out of the bsp
  216. char bspName[MAX_PATH] = { 0 };
  217. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  218. Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) );
  219. printf( "\n" );
  220. printf( "Opening bsp file: %s\n", bspName );
  221. LoadBSPFile( bspName );
  222. CUtlBuffer buf;
  223. char relativeName[MAX_PATH] = { 0 };
  224. int fileSize = 0;
  225. int id = -1;
  226. int numFilesDeleted = 0;
  227. while (1)
  228. {
  229. id = GetNextFilename( GetPakFile(), id, relativeName, sizeof(relativeName), fileSize );
  230. if ( id == -1)
  231. break;
  232. if ( Q_stristr( relativeName, ".vtf" ) )
  233. {
  234. RemoveFileFromPak( GetPakFile(), relativeName );
  235. numFilesDeleted++;
  236. // start over
  237. id = -1;
  238. }
  239. }
  240. printf( "%d cubemaps deleted.\n", numFilesDeleted );
  241. if ( numFilesDeleted )
  242. {
  243. // save out bsp file
  244. printf( "Updating bsp file: %s\n", bspName );
  245. WriteBSPFile( bspName );
  246. }
  247. }
  248. else if( ( stricmp( pAction, "-addfiles" ) == 0 ) && nActionArgs == 4 )
  249. {
  250. // bspzip -addfiles <bspfile> <relativePathPrefix> <listfile> <newbspfile>
  251. CmdLib_InitFileSystem( pActionArgs[0] );
  252. char bspName[MAX_PATH] = { 0 };
  253. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  254. Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) );
  255. char relativePrefixName[MAX_PATH] = { 0 };
  256. V_strncpy( relativePrefixName, pActionArgs[1], sizeof( relativePrefixName ) );
  257. char filelistName[MAX_PATH] = { 0 };
  258. V_strncpy( filelistName, pActionArgs[2], sizeof( filelistName ) );
  259. char newbspName[MAX_PATH] = { 0 };
  260. Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[3] );
  261. Q_DefaultExtension( newbspName, ".bsp", sizeof( newbspName) );
  262. char fullpathName[MAX_PATH] = { 0 };
  263. FILE *fp = fopen(filelistName, "r");
  264. if ( fp )
  265. {
  266. printf("Opening bsp file: %s\n", bspName);
  267. LoadBSPFile(bspName);
  268. while ( !feof(fp) )
  269. {
  270. if ( ( fgets( fullpathName, sizeof( fullpathName ), fp ) != NULL ) )
  271. {
  272. if ( *fullpathName && fullpathName[strlen(fullpathName) - 1] == '\n' )
  273. {
  274. fullpathName[strlen(fullpathName) - 1] = '\0';
  275. }
  276. // strip the path and add relative prefix
  277. char fileName[MAX_PATH] = { 0 };
  278. char relativeName[MAX_PATH] = { 0 };
  279. StripPath( fullpathName, fileName, sizeof( fileName ) );
  280. V_strncpy( relativeName, relativePrefixName, sizeof( relativeName ) );
  281. V_strncat( relativeName, fileName, sizeof( relativeName ) );
  282. printf( "Adding file: %s as %s\n", fullpathName, relativeName );
  283. AddFileToPak( GetPakFile(), relativeName, fullpathName );
  284. }
  285. else if ( !feof( fp ) )
  286. {
  287. printf( "Error: Missing full path names\n");
  288. fclose( fp );
  289. return( -1 );
  290. }
  291. }
  292. printf("Writing new bsp file: %s\n", newbspName);
  293. WriteBSPFile(newbspName);
  294. fclose( fp );
  295. }
  296. }
  297. else if( ( stricmp( pAction, "-dir" ) == 0 ) && nActionArgs == 1 )
  298. {
  299. // bspzip -dir <bspfile>
  300. CmdLib_InitFileSystem( pActionArgs[0] );
  301. char bspName[MAX_PATH] = { 0 };
  302. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  303. Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) );
  304. LoadBSPFile (bspName);
  305. PrintBSPPackDirectory();
  306. }
  307. else if( ( stricmp( pAction, "-addfile" ) == 0 ) && nActionArgs == 4 )
  308. {
  309. // bspzip -addfile <bspfile> <relativepathname> <fullpathname> <newbspfile>
  310. CmdLib_InitFileSystem( pActionArgs[0] );
  311. char bspName[MAX_PATH] = { 0 };
  312. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  313. Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) );
  314. char relativeName[MAX_PATH] = { 0 };
  315. V_strncpy( relativeName, pActionArgs[1], sizeof( relativeName ) );
  316. char fullpathName[MAX_PATH] = { 0 };
  317. V_strncpy( fullpathName, pActionArgs[2], sizeof( fullpathName ) );
  318. char newbspName[MAX_PATH] = { 0 };
  319. Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[3] );
  320. Q_DefaultExtension (newbspName, ".bsp", sizeof( newbspName ) );
  321. // read it in, add pack file, write it back out
  322. LoadBSPFile (bspName);
  323. AddFileToPak( GetPakFile(), relativeName, fullpathName );
  324. WriteBSPFile(newbspName);
  325. }
  326. else if( ( stricmp( pAction, "-addlist" ) == 0 ) && nActionArgs == 3 )
  327. {
  328. // bspzip -addlist <bspfile> <listfile> <newbspfile>
  329. CmdLib_InitFileSystem( pActionArgs[0] );
  330. char bspName[MAX_PATH] = { 0 };
  331. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  332. Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) );
  333. char filelistName[MAX_PATH] = { 0 };
  334. V_strncpy( filelistName, pActionArgs[1], sizeof( filelistName ) );
  335. char newbspName[MAX_PATH] = { 0 };
  336. Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[2] );
  337. Q_DefaultExtension (newbspName, ".bsp", sizeof( newbspName) );
  338. // read it in, add pack file, write it back out
  339. char relativeName[MAX_PATH] = { 0 };
  340. char fullpathName[MAX_PATH] = { 0 };
  341. FILE *fp = fopen(filelistName, "r");
  342. if ( fp )
  343. {
  344. printf("Opening bsp file: %s\n", bspName);
  345. LoadBSPFile (bspName);
  346. while ( !feof(fp) )
  347. {
  348. relativeName[ 0 ] = 0;
  349. fullpathName[ 0 ] = 0;
  350. if ( ( fgets( relativeName, sizeof( relativeName ), fp ) != NULL ) &&
  351. ( fgets( fullpathName, sizeof( fullpathName ), fp ) != NULL ) )
  352. {
  353. int l1 = strlen(relativeName);
  354. int l2 = strlen(fullpathName);
  355. if ( l1 > 0 )
  356. {
  357. if ( relativeName[ l1 - 1 ] == '\n' )
  358. {
  359. relativeName[ l1 - 1 ] = 0;
  360. }
  361. }
  362. if ( l2 > 0 )
  363. {
  364. if ( fullpathName[ l2 - 1 ] == '\n' )
  365. {
  366. fullpathName[ l2 - 1 ] = 0;
  367. }
  368. }
  369. printf("Adding file: %s\n", fullpathName);
  370. AddFileToPak( GetPakFile(), relativeName, fullpathName );
  371. }
  372. else if ( !feof( fp ) || ( relativeName[0] && !fullpathName[0] ) )
  373. {
  374. printf( "Error: Missing paired relative/full path names\n");
  375. fclose( fp );
  376. return( -1 );
  377. }
  378. }
  379. printf("Writing new bsp file: %s\n", newbspName);
  380. WriteBSPFile(newbspName);
  381. fclose( fp );
  382. }
  383. }
  384. else if( ( stricmp( pAction, "-addorupdatelist" ) == 0 ) && nActionArgs == 3 )
  385. {
  386. // bspzip -addorupdatelist <bspfile> <listfile> <newbspfile>
  387. CmdLib_InitFileSystem( pActionArgs[0] );
  388. char bspName[MAX_PATH] = { 0 };
  389. Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] );
  390. Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) );
  391. char filelistName[MAX_PATH] = { 0 };
  392. V_strncpy( filelistName, pActionArgs[1], sizeof( filelistName ) );
  393. char newbspName[MAX_PATH] = { 0 };
  394. Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[2] );
  395. Q_DefaultExtension (newbspName, ".bsp", sizeof( newbspName) );
  396. // read it in, add pack file, write it back out
  397. char relativeName[MAX_PATH] = { 0 };
  398. char fullpathName[MAX_PATH] = { 0 };
  399. FILE *fp = fopen(filelistName, "r");
  400. if ( fp )
  401. {
  402. printf("Opening bsp file: %s\n", bspName);
  403. LoadBSPFile (bspName);
  404. while ( !feof(fp) )
  405. {
  406. relativeName[ 0 ] = 0;
  407. fullpathName[ 0 ] = 0;
  408. if ( ( fgets( relativeName, sizeof( relativeName ), fp ) != NULL ) &&
  409. ( fgets( fullpathName, sizeof( fullpathName ), fp ) != NULL ) )
  410. {
  411. int l1 = strlen(relativeName);
  412. int l2 = strlen(fullpathName);
  413. if ( l1 > 0 )
  414. {
  415. if ( relativeName[ l1 - 1 ] == '\n' )
  416. {
  417. relativeName[ l1 - 1 ] = 0;
  418. }
  419. }
  420. if ( l2 > 0 )
  421. {
  422. if ( fullpathName[ l2 - 1 ] == '\n' )
  423. {
  424. fullpathName[ l2 - 1 ] = 0;
  425. }
  426. }
  427. bool bUpdating = FileExistsInPak( GetPakFile(), relativeName );
  428. printf("%s file: %s\n", bUpdating ? "Updating" : "Adding", fullpathName);
  429. if ( bUpdating )
  430. {
  431. RemoveFileFromPak( GetPakFile(), relativeName );
  432. }
  433. AddFileToPak( GetPakFile(), relativeName, fullpathName );
  434. }
  435. else if ( !feof( fp ) || ( relativeName[0] && !fullpathName[0] ) )
  436. {
  437. printf( "Error: Missing paired relative/full path names\n");
  438. fclose( fp );
  439. return( -1 );
  440. }
  441. }
  442. printf("Writing new bsp file: %s\n", newbspName);
  443. WriteBSPFile(newbspName);
  444. fclose( fp );
  445. }
  446. }
  447. else if( ( stricmp( pAction, "-repack" ) == 0 ) && ( nActionArgs == 1 || nActionArgs == 2 ) )
  448. {
  449. // bspzip -repack [ -compress ] <bspfile>
  450. bool bCompress = false;
  451. const char *pFile = pActionArgs[0];
  452. if ( nActionArgs == 2 && stricmp( pActionArgs[0], "-compress" ) == 0 )
  453. {
  454. pFile = pActionArgs[1];
  455. bCompress = true;
  456. }
  457. else if ( nActionArgs == 2 )
  458. {
  459. Usage();
  460. return 0;
  461. }
  462. CmdLib_InitFileSystem( pFile );
  463. char szAbsBSPPath[MAX_PATH] = { 0 };
  464. Q_MakeAbsolutePath( szAbsBSPPath, sizeof( szAbsBSPPath ), pFile );
  465. Q_DefaultExtension( szAbsBSPPath, ".bsp", sizeof( szAbsBSPPath ) );
  466. return RepackBSP( szAbsBSPPath, bCompress ) ? 0 : -1;
  467. }
  468. else
  469. {
  470. Usage();
  471. }
  472. return 0;
  473. }