//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include #include "bsplib.h" #include "cmdlib.h" #include "tier0/icommandline.h" #include "utlbuffer.h" int CopyVariableLump( int lump, void **dest, int size ); void StripPath( const char* pPath, char* pBuf, int nBufLen ) { const char *pSrc; // want filename only pSrc = pPath + Q_strlen( pPath ) - 1; while ((pSrc != pPath) && (*(pSrc-1) != '\\') && (*(pSrc-1) != '/') && (*(pSrc-1) != ':')) pSrc--; Q_strncpy( pBuf, pSrc, nBufLen ); } bool RepackBSP( const char *pszMapFile, bool bCompress ) { Msg( "Repacking %s\n", pszMapFile ); if ( !g_pFullFileSystem->FileExists( pszMapFile ) ) { Warning( "Couldn't open input file %s - BSP recompress failed\n", pszMapFile ); return false; } CUtlBuffer inputBuffer; if ( !g_pFullFileSystem->ReadFile( pszMapFile, NULL, inputBuffer ) ) { Warning( "Couldn't read file %s - BSP compression failed\n", pszMapFile ); return false; } CUtlBuffer outputBuffer; if ( !RepackBSP( inputBuffer, outputBuffer, bCompress ? RepackBSPCallback_LZMA : NULL, bCompress ? IZip::eCompressionType_LZMA : IZip::eCompressionType_None ) ) { Warning( "Internal error compressing BSP\n" ); return false; } g_pFullFileSystem->WriteFile( pszMapFile, NULL, outputBuffer ); Msg( "Successfully repacked %s -- %u -> %u bytes\n", pszMapFile, inputBuffer.TellPut(), outputBuffer.TellPut() ); return true; } void Usage( void ) { fprintf( stderr, "usage: \n" ); fprintf( stderr, "bspzip -extract \n"); fprintf( stderr, "bspzip -extractfiles \n"); fprintf( stderr, "bspzip -dir \n"); fprintf( stderr, "bspzip -addfile \n"); fprintf( stderr, "bspzip -addlist \n"); fprintf( stderr, "bspzip -addorupdatelist \n"); fprintf( stderr, "bspzip -extractcubemaps \n"); fprintf( stderr, " Extracts the cubemaps to .\n"); fprintf( stderr, "bspzip -deletecubemaps \n"); fprintf( stderr, " Deletes the cubemaps from .\n"); fprintf( stderr, "bspzip -addfiles \n"); fprintf( stderr, " Adds files to .\n"); fprintf( stderr, "bspzip -repack [ -compress ] \n"); fprintf( stderr, " Optimally repacks a BSP file, optionally using compressed BSP format.\n"); fprintf( stderr, " Using on a compressed BSP without -compress will effectively decompress\n"); fprintf( stderr, " a compressed BSP.\n"); exit( -1 ); } char* xzpFilename = NULL; int main( int argc, char **argv ) { ::SetHDRMode( false ); Msg( "\nValve Software - bspzip.exe (%s)\n", __DATE__ ); int curArg = 1; // Options parsing assumes // [ -game foo ] - // Skip -game foo if ( argc >= curArg + 2 && stricmp( argv[curArg], "-game" ) == 0 ) { // Handled by filesystem code curArg += 2; } // Should have at least action if ( curArg >= argc ) { // End of args Usage(); return 0; } // Pointers to the action, the file, and any action args so I can remove all the messy argc pointer math this was // using. char *pAction = argv[curArg]; curArg++; char **pActionArgs = &argv[curArg]; int nActionArgs = argc - curArg; CommandLine()->CreateCmdLine( argc, argv ); MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); if( ( stricmp( pAction, "-extract" ) == 0 ) && nActionArgs == 2 ) { // bspzip -extract CmdLib_InitFileSystem( pActionArgs[0] ); char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) ); char zipName[MAX_PATH] = { 0 }; V_strncpy( zipName, pActionArgs[1], sizeof( zipName ) ); Q_DefaultExtension(zipName, ".zip", sizeof( zipName ) ); ExtractZipFileFromBSP( bspName, zipName ); } else if( ( stricmp( pAction, "-extractfiles" ) == 0 ) && nActionArgs == 2 ) { // bsipzip -extractfiles CmdLib_InitFileSystem( pActionArgs[0] ); // necessary for xbox process // only the .vtf are extracted as necessary for streaming and not the .vmt // the .vmt are non-streamed and therefore remain, referenced normally as part of the bsp search path char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) ); char targetPathName[MAX_PATH] = { 0 }; V_strncpy( targetPathName, pActionArgs[1], sizeof( targetPathName ) ); Q_AppendSlash( targetPathName, sizeof( targetPathName ) ); printf( "\n" ); printf( "Opening bsp file: %s\n", bspName ); LoadBSPFile( bspName ); CUtlBuffer buf; char relativeName[MAX_PATH] = { 0 }; char targetName[MAX_PATH] = { 0 }; int fileSize = 0; int id = -1; int numFilesExtracted = 0; while(true) { id = GetNextFilename( GetPakFile(), id, relativeName, sizeof(relativeName), fileSize ); if ( id == -1) break; { buf.EnsureCapacity( fileSize ); buf.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); ReadFileFromPak( GetPakFile(), relativeName, false, buf ); V_strncpy( targetName, targetPathName, sizeof(targetName) ); V_strncat( targetName, relativeName, sizeof(targetName) ); Q_FixSlashes( targetName, '\\' ); SafeCreatePath( targetName ); printf( "Writing file: %s\n", targetName ); FILE *fp = fopen( targetName, "wb" ); if ( !fp ) { printf( "Error: Could not write %s\n", targetName); exit( -1 ); } fwrite( buf.Base(), fileSize, 1, fp ); fclose( fp ); numFilesExtracted++; } } printf( "%d files extracted.\n", numFilesExtracted ); } else if( ( stricmp( pAction, "-extractcubemaps" ) == 0 ) && nActionArgs == 2 ) { // bspzip -extractcubemaps CmdLib_InitFileSystem( pActionArgs[0] ); // necessary for xbox process // only the .vtf are extracted as necessary for streaming and not the .vmt // the .vmt are non-streamed and therefore remain, referenced normally as part of the bsp search path char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) ); char targetPathName[MAX_PATH] = { 0 }; V_strncpy( targetPathName, pActionArgs[1], sizeof(targetPathName) ); Q_AppendSlash( targetPathName, sizeof( targetPathName ) ); printf( "\n" ); printf( "Opening bsp file: %s\n", bspName ); LoadBSPFile( bspName ); CUtlBuffer buf; char relativeName[MAX_PATH] = { 0 }; char targetName[MAX_PATH] = { 0 }; int fileSize = 0; int id = -1; int numFilesExtracted = 0; while (1) { id = GetNextFilename( GetPakFile(), id, relativeName, sizeof(relativeName), fileSize ); if ( id == -1) break; if ( Q_stristr( relativeName, ".vtf" ) ) { buf.EnsureCapacity( fileSize ); buf.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); ReadFileFromPak( GetPakFile(), relativeName, false, buf ); V_strncpy( targetName, targetPathName, sizeof( targetName ) ); V_strncat( targetName, relativeName, sizeof( targetName ) ); Q_FixSlashes( targetName, '\\' ); SafeCreatePath( targetName ); printf( "Writing vtf file: %s\n", targetName ); FILE *fp = fopen( targetName, "wb" ); if ( !fp ) { printf( "Error: Could not write %s\n", targetName); exit( -1 ); } fwrite( buf.Base(), fileSize, 1, fp ); fclose( fp ); numFilesExtracted++; } } printf( "%d cubemaps extracted.\n", numFilesExtracted ); } else if( ( stricmp( pAction, "-deletecubemaps" ) == 0 ) && nActionArgs == 1 ) { // bspzip -deletecubemaps CmdLib_InitFileSystem( pActionArgs[0] ); // necessary for xbox process // the cubemaps are deleted as they cannot yet be streamed out of the bsp char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) ); printf( "\n" ); printf( "Opening bsp file: %s\n", bspName ); LoadBSPFile( bspName ); CUtlBuffer buf; char relativeName[MAX_PATH] = { 0 }; int fileSize = 0; int id = -1; int numFilesDeleted = 0; while (1) { id = GetNextFilename( GetPakFile(), id, relativeName, sizeof(relativeName), fileSize ); if ( id == -1) break; if ( Q_stristr( relativeName, ".vtf" ) ) { RemoveFileFromPak( GetPakFile(), relativeName ); numFilesDeleted++; // start over id = -1; } } printf( "%d cubemaps deleted.\n", numFilesDeleted ); if ( numFilesDeleted ) { // save out bsp file printf( "Updating bsp file: %s\n", bspName ); WriteBSPFile( bspName ); } } else if( ( stricmp( pAction, "-addfiles" ) == 0 ) && nActionArgs == 4 ) { // bspzip -addfiles CmdLib_InitFileSystem( pActionArgs[0] ); char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension( bspName, ".bsp", sizeof( bspName ) ); char relativePrefixName[MAX_PATH] = { 0 }; V_strncpy( relativePrefixName, pActionArgs[1], sizeof( relativePrefixName ) ); char filelistName[MAX_PATH] = { 0 }; V_strncpy( filelistName, pActionArgs[2], sizeof( filelistName ) ); char newbspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[3] ); Q_DefaultExtension( newbspName, ".bsp", sizeof( newbspName) ); char fullpathName[MAX_PATH] = { 0 }; FILE *fp = fopen(filelistName, "r"); if ( fp ) { printf("Opening bsp file: %s\n", bspName); LoadBSPFile(bspName); while ( !feof(fp) ) { if ( ( fgets( fullpathName, sizeof( fullpathName ), fp ) != NULL ) ) { if ( *fullpathName && fullpathName[strlen(fullpathName) - 1] == '\n' ) { fullpathName[strlen(fullpathName) - 1] = '\0'; } // strip the path and add relative prefix char fileName[MAX_PATH] = { 0 }; char relativeName[MAX_PATH] = { 0 }; StripPath( fullpathName, fileName, sizeof( fileName ) ); V_strncpy( relativeName, relativePrefixName, sizeof( relativeName ) ); V_strncat( relativeName, fileName, sizeof( relativeName ) ); printf( "Adding file: %s as %s\n", fullpathName, relativeName ); AddFileToPak( GetPakFile(), relativeName, fullpathName ); } else if ( !feof( fp ) ) { printf( "Error: Missing full path names\n"); fclose( fp ); return( -1 ); } } printf("Writing new bsp file: %s\n", newbspName); WriteBSPFile(newbspName); fclose( fp ); } } else if( ( stricmp( pAction, "-dir" ) == 0 ) && nActionArgs == 1 ) { // bspzip -dir CmdLib_InitFileSystem( pActionArgs[0] ); char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) ); LoadBSPFile (bspName); PrintBSPPackDirectory(); } else if( ( stricmp( pAction, "-addfile" ) == 0 ) && nActionArgs == 4 ) { // bspzip -addfile CmdLib_InitFileSystem( pActionArgs[0] ); char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) ); char relativeName[MAX_PATH] = { 0 }; V_strncpy( relativeName, pActionArgs[1], sizeof( relativeName ) ); char fullpathName[MAX_PATH] = { 0 }; V_strncpy( fullpathName, pActionArgs[2], sizeof( fullpathName ) ); char newbspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[3] ); Q_DefaultExtension (newbspName, ".bsp", sizeof( newbspName ) ); // read it in, add pack file, write it back out LoadBSPFile (bspName); AddFileToPak( GetPakFile(), relativeName, fullpathName ); WriteBSPFile(newbspName); } else if( ( stricmp( pAction, "-addlist" ) == 0 ) && nActionArgs == 3 ) { // bspzip -addlist CmdLib_InitFileSystem( pActionArgs[0] ); char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) ); char filelistName[MAX_PATH] = { 0 }; V_strncpy( filelistName, pActionArgs[1], sizeof( filelistName ) ); char newbspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[2] ); Q_DefaultExtension (newbspName, ".bsp", sizeof( newbspName) ); // read it in, add pack file, write it back out char relativeName[MAX_PATH] = { 0 }; char fullpathName[MAX_PATH] = { 0 }; FILE *fp = fopen(filelistName, "r"); if ( fp ) { printf("Opening bsp file: %s\n", bspName); LoadBSPFile (bspName); while ( !feof(fp) ) { relativeName[ 0 ] = 0; fullpathName[ 0 ] = 0; if ( ( fgets( relativeName, sizeof( relativeName ), fp ) != NULL ) && ( fgets( fullpathName, sizeof( fullpathName ), fp ) != NULL ) ) { int l1 = strlen(relativeName); int l2 = strlen(fullpathName); if ( l1 > 0 ) { if ( relativeName[ l1 - 1 ] == '\n' ) { relativeName[ l1 - 1 ] = 0; } } if ( l2 > 0 ) { if ( fullpathName[ l2 - 1 ] == '\n' ) { fullpathName[ l2 - 1 ] = 0; } } printf("Adding file: %s\n", fullpathName); AddFileToPak( GetPakFile(), relativeName, fullpathName ); } else if ( !feof( fp ) || ( relativeName[0] && !fullpathName[0] ) ) { printf( "Error: Missing paired relative/full path names\n"); fclose( fp ); return( -1 ); } } printf("Writing new bsp file: %s\n", newbspName); WriteBSPFile(newbspName); fclose( fp ); } } else if( ( stricmp( pAction, "-addorupdatelist" ) == 0 ) && nActionArgs == 3 ) { // bspzip -addorupdatelist CmdLib_InitFileSystem( pActionArgs[0] ); char bspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( bspName, sizeof( bspName ), pActionArgs[0] ); Q_DefaultExtension (bspName, ".bsp", sizeof( bspName ) ); char filelistName[MAX_PATH] = { 0 }; V_strncpy( filelistName, pActionArgs[1], sizeof( filelistName ) ); char newbspName[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( newbspName, sizeof( newbspName ), pActionArgs[2] ); Q_DefaultExtension (newbspName, ".bsp", sizeof( newbspName) ); // read it in, add pack file, write it back out char relativeName[MAX_PATH] = { 0 }; char fullpathName[MAX_PATH] = { 0 }; FILE *fp = fopen(filelistName, "r"); if ( fp ) { printf("Opening bsp file: %s\n", bspName); LoadBSPFile (bspName); while ( !feof(fp) ) { relativeName[ 0 ] = 0; fullpathName[ 0 ] = 0; if ( ( fgets( relativeName, sizeof( relativeName ), fp ) != NULL ) && ( fgets( fullpathName, sizeof( fullpathName ), fp ) != NULL ) ) { int l1 = strlen(relativeName); int l2 = strlen(fullpathName); if ( l1 > 0 ) { if ( relativeName[ l1 - 1 ] == '\n' ) { relativeName[ l1 - 1 ] = 0; } } if ( l2 > 0 ) { if ( fullpathName[ l2 - 1 ] == '\n' ) { fullpathName[ l2 - 1 ] = 0; } } bool bUpdating = FileExistsInPak( GetPakFile(), relativeName ); printf("%s file: %s\n", bUpdating ? "Updating" : "Adding", fullpathName); if ( bUpdating ) { RemoveFileFromPak( GetPakFile(), relativeName ); } AddFileToPak( GetPakFile(), relativeName, fullpathName ); } else if ( !feof( fp ) || ( relativeName[0] && !fullpathName[0] ) ) { printf( "Error: Missing paired relative/full path names\n"); fclose( fp ); return( -1 ); } } printf("Writing new bsp file: %s\n", newbspName); WriteBSPFile(newbspName); fclose( fp ); } } else if( ( stricmp( pAction, "-repack" ) == 0 ) && ( nActionArgs == 1 || nActionArgs == 2 ) ) { // bspzip -repack [ -compress ] bool bCompress = false; const char *pFile = pActionArgs[0]; if ( nActionArgs == 2 && stricmp( pActionArgs[0], "-compress" ) == 0 ) { pFile = pActionArgs[1]; bCompress = true; } else if ( nActionArgs == 2 ) { Usage(); return 0; } CmdLib_InitFileSystem( pFile ); char szAbsBSPPath[MAX_PATH] = { 0 }; Q_MakeAbsolutePath( szAbsBSPPath, sizeof( szAbsBSPPath ), pFile ); Q_DefaultExtension( szAbsBSPPath, ".bsp", sizeof( szAbsBSPPath ) ); return RepackBSP( szAbsBSPPath, bCompress ) ? 0 : -1; } else { Usage(); } return 0; }