void Cache_Print_Sounds_And_Totals (void) { char buf[50]; cache_system_t *cd; cache_system_t *sortarray[MAX_SFX]; long i=0,j=0; long totalsndbytes=0; FileHandle_t file = g_pFileSystem->Open(mem_dbgfile.GetString(), "a"); int subtot=0; if (!file) return; memset(sortarray,sizeof(cache_system_t*)*MAX_SFX,0); //pack names into the array. for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) { if (Q_stristr(cd->name,".wav")) { sortarray[i++]=cd; } } qsort(sortarray,i,sizeof(cache_system_t*),CacheSystemCompare); if (!file) return; g_pFileSystem->FPrintf(file,"\nCACHED SOUNDS:\n"); //now process the sorted list. (totals by directory) for (j=0;j<i;j++) { g_pFileSystem->FPrintf(file, "\t%16.16s : %s\n", Q_pretifymem(sortarray[j]->size,buf),sortarray[j]->name); totalsndbytes+=sortarray[j]->size; #ifdef _WIN32 if (j+1==i || ComparePath1(sortarray[j]->name,sortarray[j+1]->name)==0) { char pathbuf[512]; _splitpath(sortarray[j]->name,NULL,pathbuf,NULL,NULL); g_pFileSystem->FPrintf(file, "\tTotal Bytes used in \"%s\": %s\n",pathbuf,Q_pretifymem(totalsndbytes-subtot,buf)); subtot=totalsndbytes; } #endif } g_pFileSystem->FPrintf(file,"Total bytes in cache used by sound: %s\n",Q_pretifymem(totalsndbytes,buf)); g_pFileSystem->Close(file); }
void Cache_Print_Models_And_Totals (void) { char buf[50]; cache_system_t *cd; cache_system_t *sortarray[512]; long i=0,j=0; long totalbytes=0; FileHandle_t file = g_pFileSystem->Open(mem_dbgfile.GetString(), "a"); int subtot=0; if (!file) return; memset(sortarray,sizeof(cache_system_t*)*512,0); //pack names into the array. for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) { if (strstr(cd->name,".mdl")) { sortarray[i++]=cd; } } qsort(sortarray,i,sizeof(cache_system_t*),CacheSystemCompare); g_pFileSystem->FPrintf(file,"\nCACHED MODELS:\n"); //now process the sorted list. for (j=0;j<i;j++) { int k; mstudiotexture_t *ptexture; studiohdr_t *phdr=(studiohdr_t*)sortarray[j]->user->data; ptexture = (mstudiotexture_t *)( ((char*)phdr) + phdr->textureindex); subtot=0; for (k = 0; k < phdr->numtextures; k++) subtot+=ptexture[k].width * ptexture[k].height+768; // (256*3 for the palette) g_pFileSystem->FPrintf(file, "\t%16.16s : %s\n", Q_pretifymem(sortarray[j]->size,buf),sortarray[j]->name); totalbytes+=sortarray[j]->size; } g_pFileSystem->FPrintf(file,"Total bytes in cache used by models: %s\n",Q_pretifymem(totalbytes,buf)); g_pFileSystem->Close(file); }
void Netchan_ReportFlow( netchan_t *chan ) { char incoming[CS_SIZE]; char outgoing[CS_SIZE]; ASSERT( chan != NULL ); Q_strcpy( incoming, Q_pretifymem((float)chan->flow[FLOW_INCOMING].totalbytes, 3 )); Q_strcpy( outgoing, Q_pretifymem((float)chan->flow[FLOW_OUTGOING].totalbytes, 3 )); MsgDev( D_INFO, "Signon network traffic: %s from server, %s to server\n", incoming, outgoing ); }
/* ============ Cache_Print ============ */ void Cache_Print (void) { cache_system_t *cd; cache_system_t *sortarray[512]; int i=0,j=0; FileHandle_t file = g_pFileSystem->Open(mem_dbgfile.GetString(), "a"); if (!file) return; memset(sortarray,sizeof(cache_system_t*)*512,0); g_pFileSystem->FPrintf(file,"\nCACHE:\n"); for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) { sortarray[i++]=cd; } //Sort the array alphabetically qsort(sortarray,i,sizeof(cache_system_t*),CacheSystemCompare); for(j=0;j<i;j++) g_pFileSystem->FPrintf(file, "%16.16s : %-16s\n", Q_pretifymem(sortarray[j]->size), sortarray[j]->name); g_pFileSystem->Close(file); }
int MEM_Summary_Console( void ) { Msg("MEMORY: Engine hunk, cache, and zone:\n------------------------------------\n"); Msg("\tTotal memory available: %s\n",Q_pretifymem(hunk_size)); Msg("\tTotal used in low hunk: %s\n",Q_pretifymem(hunk_low_used)); Msg("\tTotal used in high hunk: %s\n",Q_pretifymem(hunk_high_used)); Msg("\tTotal cache space: %s\n",Q_pretifymem(hunk_size - hunk_low_used - hunk_high_used)); Msg("\tTotal cache used: %s\n",Q_pretifymem(Cache_TotalUsed())); Msg("\tTotal memory available: %s\n",Q_pretifymem(hunk_size - hunk_low_used - hunk_high_used-Cache_TotalUsed())); Msg("------------------------------------\n"); return hunk_size; }
void MEM_Summary(void) { FileHandle_t file = g_pFileSystem->Open(mem_dbgfile.GetString(), "a"); int CacheUsed=Cache_TotalUsed(); char buf[50]; if (!file) return; g_pFileSystem->FPrintf(file, "MEMORY SUMMARY:\n------------------------------------\n"); g_pFileSystem->FPrintf(file, "\tTotal memory available: %s\n",Q_pretifymem(hunk_size,buf)); g_pFileSystem->FPrintf(file, "\tTotal used in low hunk: %s\n",Q_pretifymem(hunk_low_used,buf)); g_pFileSystem->FPrintf(file, "\tTotal used in high hunk: %s\n",Q_pretifymem(hunk_high_used,buf)); g_pFileSystem->FPrintf(file, "\tTotal cache space: %s\n",Q_pretifymem(hunk_size - hunk_low_used - hunk_high_used,buf)); g_pFileSystem->FPrintf(file, "\tTotal cache used: %s\n",Q_pretifymem(CacheUsed,buf)); g_pFileSystem->FPrintf(file, "\tTotal memory available: %s\n",Q_pretifymem(hunk_size - hunk_low_used - hunk_high_used-CacheUsed,buf)); g_pFileSystem->FPrintf(file, "------------------------------------\n\n"); g_pFileSystem->Close(file); }
int main( int argc, char *argv[] ) { if ( argc < 2 ) { Msg("Usage:\nmakephx [options] <FILESPEC>\ne.g. makephx [-r] *.phy\n"); return 0; } CommandLine()->CreateCmdLine( argc, argv ); g_bRecursive = CommandLine()->FindParm("-r") > 0 ? true : false; g_bQuiet = CommandLine()->FindParm("-quiet") > 0 ? true : false; InitFilesystem( "*.*" ); InitVPhysics(); // disable automatic packing, we want to do this ourselves. physcollision->SetPackOnLoad( false ); MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); InstallSpewFunction(); g_pModelConfig = new KeyValues("config"); g_pModelConfig->LoadFromFile( g_pFullFileSystem, "phx.cfg", "GAME" ); g_TotalOut = 0; g_TotalCompress = 0; FileFindHandle_t handle; char fullpath[1024], currentFile[1024], dirName[1024], nameext[256]; strcpy( fullpath, argv[argc-1] ); strcpy( fullpath, ExpandPath( fullpath ) ); strcpy( fullpath, ExpandArg( fullpath ) ); Q_strncpy(dirName, fullpath, sizeof(dirName)); Q_StripFilename(dirName); Q_strncpy(nameext, fullpath + strlen(dirName)+1, sizeof(nameext)); CUtlVector< const char * > directoryList; directoryList.AddToTail( strdup(dirName) ); int current = 0; int count = 0; do { if ( g_bRecursive ) { MakeFilename( currentFile, sizeof(currentFile), directoryList[current], "*.*" ); const char *pFilename = g_pFullFileSystem->FindFirst( currentFile, &handle ); while ( pFilename ) { if ( pFilename[0] != '.' && g_pFullFileSystem->FindIsDirectory( handle ) ) { MakeDirname( currentFile, sizeof(currentFile), directoryList[current], pFilename ); directoryList.AddToTail(strdup(currentFile)); } pFilename = g_pFullFileSystem->FindNext( handle ); } g_pFullFileSystem->FindClose( handle ); } MakeFilename(currentFile, sizeof(currentFile), directoryList[current], nameext); const char *pFilename = g_pFullFileSystem->FindFirst( currentFile, &handle ); while ( pFilename ) { phyfile_t phy; MakeFilename(currentFile, sizeof(currentFile), directoryList[current], pFilename); LoadPHYFile( &phy, currentFile ); if ( phy.collide.isPacked || phy.collide.solidCount < 1 ) { Msg("%s is not a valid PHY file\n", currentFile ); } else { WritePHXFile( currentFile, phy ); count++; } UnloadPHYFile( &phy ); pFilename = g_pFullFileSystem->FindNext( handle ); } g_pFullFileSystem->FindClose( handle ); current++; } while( current < directoryList.Count() ); if ( count ) { if (!g_bQuiet) { Msg("\n------\nTotal %s, %s\nSaved %s\n", Q_pretifymem( g_TotalOut ), Q_pretifymem( g_TotalCompress ), Q_pretifymem( g_TotalOut - g_TotalCompress ) ); Msg("%.2f%% savings\n", ((float)(g_TotalOut-g_TotalCompress) / (float)g_TotalOut) * 100.0f ); } } else { Msg("No files found in %s!\n", directoryList[current] ); } return 0; }
//----------------------------------------------------------------------------- // Purpose: Loads up all camera samples from a .dem file into the passed in context. // Input : *filename - // smoothing - //----------------------------------------------------------------------------- void LoadSmoothingInfo( const char *filename, CSmoothingContext& smoothing ) { char name[ MAX_OSPATH ]; Q_strncpy (name, filename, sizeof(name) ); Q_DefaultExtension( name, ".dem", sizeof( name ) ); CToolDemoFile demoFile; if ( !demoFile.Open( filename, true ) ) { Warning( "ERROR: couldn't open %s.\n", name ); return; } demoheader_t * header = demoFile.ReadDemoHeader(); if ( !header ) { demoFile.Close(); return; } Msg( "\n\n" ); Msg( "--------------------------------------------------------------\n" ); Msg( "demofilestamp: '%s'\n", header->demofilestamp ); Msg( "demoprotocol: %i\n", header->demoprotocol ); Msg( "networkprotocol: %i\n", header->networkprotocol ); Msg( "servername: '%s'\n", header->servername ); Msg( "clientname: '%s'\n", header->clientname ); Msg( "mapname: '%s'\n", header->mapname ); Msg( "gamedirectory: '%s'\n", header->gamedirectory ); Msg( "playback_time: %f seconds\n", header->playback_time ); Msg( "playback_ticks: %i ticks\n", header->playback_ticks ); Msg( "playback_frames: %i frames\n", header->playback_frames ); Msg( "signonlength: %s\n", Q_pretifymem( header->signonlength ) ); smoothing.active = true; Q_strncpy( smoothing.filename, name, sizeof(smoothing.filename) ); smoothing.smooth.RemoveAll(); ClearSmoothingInfo( smoothing ); ParseSmoothingInfo( demoFile, smoothing.smooth ); Msg( "--------------------------------------------------------------\n" ); Msg( "smoothing data: %i samples\n", smoothing.smooth.Count() ); if ( verbose ) { int c = smoothing.smooth.Count(); for ( int i = 0; i < c; ++i ) { demosmoothing_t& sample = smoothing.smooth[ i ]; Msg( "Sample %i:\n", i ); Msg( " file pos: %i\n", sample.file_offset ); Msg( " tick: %i\n", sample.frametick ); Msg( " flags: %s\n", DescribeFlags( sample.info.flags ) ); Msg( " Original Data:\n" ); Msg( " origin: %.4f %.4f %.4f\n", sample.info.viewOrigin.x, sample.info.viewOrigin.y, sample.info.viewOrigin.z ); Msg( " viewangles: %.4f %.4f %.4f\n", sample.info.viewAngles.x, sample.info.viewAngles.y, sample.info.viewAngles.z ); Msg( " localviewangles: %.4f %.4f %.4f\n", sample.info.localViewAngles.x, sample.info.localViewAngles.y, sample.info.localViewAngles.z ); Msg( " Resampled Data:\n" ); Msg( " origin: %.4f %.4f %.4f\n", sample.info.viewOrigin2.x, sample.info.viewOrigin2.y, sample.info.viewOrigin2.z ); Msg( " viewangles: %.4f %.4f %.4f\n", sample.info.viewAngles2.x, sample.info.viewAngles2.y, sample.info.viewAngles2.z ); Msg( " localviewangles: %.4f %.4f %.4f\n", sample.info.localViewAngles2.x, sample.info.localViewAngles2.y, sample.info.localViewAngles2.z ); Msg( "\n" ); } } demoFile.Close(); }
/* ============== Hunk_Print If "all" is specified, every single allocation is printed. Otherwise, allocations with the same name will be totaled up before printing. ============== */ void Hunk_Print (qboolean all) { hunk_t *h, *next, *endlow, *starthigh, *endhigh; int count, sum; int totalblocks; char name[HUNK_NAME_LEN+1]; name[HUNK_NAME_LEN] = 0; count = 0; sum = 0; totalblocks = 0; FileHandle_t file = g_pFileSystem->Open(mem_dbgfile.GetString(), "a"); if (!file) return; h = (hunk_t *)hunk_base; endlow = (hunk_t *)(hunk_base + hunk_low_used); starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); endhigh = (hunk_t *)(hunk_base + hunk_size); //Con_Printf (" :%8i total hunk size\n", hunk_size); //Con_Printf ("-------------------------\n"); g_pFileSystem->FPrintf(file, " :%16.16s total hunk size\n", Q_pretifymem(hunk_size)); g_pFileSystem->FPrintf(file, "-------------------------\n"); while (1) { // // skip to the high hunk if done with low hunk // if ( h == endlow ) { g_pFileSystem->FPrintf(file, "-------------------------\n"); g_pFileSystem->FPrintf(file, " :%16.16s REMAINING\n", Q_pretifymem(hunk_size - hunk_low_used - hunk_high_used)); g_pFileSystem->FPrintf(file, "-------------------------\n"); h = starthigh; } // // if totally done, break // if ( h == endhigh ) break; // // run consistancy checks // if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trahsed sentinal"); if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); next = (hunk_t *)((byte *)h+h->size); count++; totalblocks++; sum += h->size; // // print the single block // memcpy (name, h->name, HUNK_NAME_LEN); if (all) g_pFileSystem->FPrintf(file, "%8p :%16.16s %16s\n",h, Q_pretifymem(h->size), name); // // print the total // if (next == endlow || next == endhigh || strncmp (h->name, next->name, HUNK_NAME_LEN) ) { if (!all) g_pFileSystem->FPrintf(file, " :%16.16s %16s (TOTAL)\n",Q_pretifymem(sum), name); count = 0; sum = 0; } h = next; } g_pFileSystem->FPrintf(file, "-------------------------\n"); g_pFileSystem->FPrintf(file, "%8i total blocks\n", totalblocks); g_pFileSystem->Close(file); }
void MEM_PrintHunk( void ) { SMemoryBin *pHunkBins = NULL, *pCur = NULL; FileHandle_t file = g_pFileSystem->Open(mem_dbgfile.GetString(), "a"); hunk_t *h = (hunk_t *)hunk_base; hunk_t *endlow = (hunk_t *)(hunk_base + hunk_low_used); hunk_t *starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); hunk_t *endhigh = (hunk_t *)(hunk_base + hunk_size); if (!file) return; g_pFileSystem->FPrintf(file, "\n\nHunk:\n\n" ); while (1) { // // skip to the high hunk if done with low hunk // if ( h == endlow ) h = starthigh; // // if totally done, break // if ( h == endhigh ) break; // total up info pCur = pHunkBins; while( pCur ) { if( !strncmp( pCur->binName, h->name, sizeof( h->name ) ) ) { pCur->size += h->size; break; } pCur = pCur->pNext; } // If we ran out of bins, make a newmem one. if( !pCur ) { pCur = (SMemoryBin *) malloc( sizeof( SMemoryBin ) ); Q_strncpy( pCur->binName, h->name, sizeof(pCur->binName) ); pCur->size = h->size; pCur->pNext = pHunkBins; pHunkBins = pCur; } // next block h = (hunk_t *)((byte *)h + h->size); } pCur = pHunkBins; while( pCur ) { SMemoryBin *pLast = pCur; g_pFileSystem->FPrintf(file, "%16.16s : %16s \n", Q_pretifymem(pCur->size), pCur->binName); pCur = pCur->pNext; free( pLast ); } pHunkBins = NULL; g_pFileSystem->Close(file); // Hunk_Print( 1 ); }
void Correlate( CUtlRBTree< ReferencedFile, int >& referencedfiles, CUtlVector< FileEntry >& contentfiles, const char *modname ) { int i; int c = contentfiles.Count(); double totalDiskSize = 0; double totalReferencedDiskSize = 0; double totalWhiteListDiskSize = 0; for ( i = 0; i < c; ++i ) { totalDiskSize += contentfiles [ i ].size; } vprint( 0, "Content tree size on disk %s\n", Q_pretifymem( totalDiskSize, 3 ) ); // Analysis is to walk tree and see which files on disk are referenced in the .lst files // Need a fast lookup from file symbol to referenced list CUtlRBTree< ReferencedFile, int > tree( 0, 0, ReferencedFileLessFunc ); c = referencedfiles.Count(); for ( i = 0 ; i < c; ++i ) { tree.Insert( referencedfiles[ i ] ); } // Now walk the on disk file and see check off resources which are in referenced c = contentfiles.Count(); int invalidindex = tree.InvalidIndex(); unsigned int refcounted = 0; unsigned int whitelisted = 0; filesystem->RemoveFile( CFmtStr( "%swhitelist.lst", g_szReslistDir ), "GAME" ); for ( i = 0; i < c; ++i ) { FileEntry & entry = contentfiles[ i ]; ReferencedFile foo; foo.sym = entry.sym; bool gameref = tree.Find( foo ) != invalidindex; char const *fn = g_Analysis.symbols.String( entry.sym ); bool whitelist = g_WhiteList.Find( entry.sym ) != g_WhiteList.InvalidIndex(); if ( gameref || whitelist ) { entry.referenced = gameref ? REFERENCED_GAME : REFERENCED_WHITELIST; totalReferencedDiskSize += entry.size; if ( entry.referenced == REFERENCED_WHITELIST ) { logprint( CFmtStr( "%swhitelist.lst", g_szReslistDir ), "\"%s\\%s\"\n", modname, fn ); totalWhiteListDiskSize += entry.size; ++whitelisted; } ++refcounted; } } vprint( 0, "Found %i referenced (%i whitelist) files in tree, %s\n", refcounted, whitelisted, Q_pretifymem( totalReferencedDiskSize, 2 ) ); vprint( 0, "%s appear unused\n", Q_pretifymem( totalDiskSize - totalReferencedDiskSize, 2 ) ); // Now sort and dump the unreferenced ones.. vprint( 0, "Sorting unreferenced files list...\n" ); CUtlRBTree< FileEntry, int > unreftree( 0, 0, FileEntryLessFunc ); for ( i = 0; i < c; ++i ) { FileEntry & entry = contentfiles[ i ]; if ( entry.referenced != REFERENCED_NO ) continue; unreftree.Insert( entry ); } // Now walk the unref tree in order i = unreftree.FirstInorder(); invalidindex = unreftree.InvalidIndex(); int index = 0; while ( i != invalidindex ) { FileEntry & entry = unreftree[ i ]; if ( showreferencedfiles ) { vprint( 1, "%6i %12s: %s\n", ++index, Q_pretifymem( entry.size, 2 ), g_Analysis.symbols.String( entry.sym ) ); } i = unreftree.NextInorder( i ); } if ( showmapfileusage ) { vprint( 0, "Writing referenced.csv...\n" ); // Now walk the list of referenced files and print out how many and which maps reference them i = tree.FirstInorder(); invalidindex = tree.InvalidIndex(); index = 0; while ( i != invalidindex ) { ReferencedFile & entry = tree[ i ]; char ext[ 32 ]; Q_ExtractFileExtension( g_Analysis.symbols.String( entry.sym ), ext, sizeof( ext ) ); logprint( "referenced.csv", "\"%s\",\"%s\",%d", g_Analysis.symbols.String( entry.sym ), ext, entry.maplist.Count() ); int mapcount = entry.maplist.Count(); for ( int j = 0 ; j < mapcount; ++j ) { char basemap[ 128 ]; Q_FileBase( g_Analysis.symbols.String( entry.maplist[ j ] ), basemap, sizeof( basemap ) ); logprint( "referenced.csv", ",\"%s\"", basemap ); } logprint( "referenced.csv", "\n" ); i = tree.NextInorder( i ); } } vprint( 0, "\nBuilding directory summary list...\n" ); // Now build summaries by root branch off of gamedir (e.g., for sound, materials, models, etc.) CUtlDict< DirEntry, int > directories; invalidindex = directories.InvalidIndex(); for ( i = 0; i < c; ++i ) { FileEntry & entry = contentfiles[ i ]; // Get the dir name char const *dirname = g_Analysis.symbols.String( entry.sym ); const char *backslash = strstr( dirname, "\\" ); char dir[ 256 ]; if ( !backslash ) { dir[0] = 0; } else { Q_strncpy( dir, dirname, backslash - dirname + 1); } int idx = directories.Find( dir ); if ( idx == invalidindex ) { DirEntry foo; idx = directories.Insert( dir, foo ); } DirEntry & de = directories[ idx ]; de.total += entry.size; if ( entry.referenced == REFERENCED_NO ) { de.unreferenced += entry.size; } if ( entry.referenced == REFERENCED_WHITELIST ) { de.whitelist += entry.size; } } if ( spewdeletions ) { // Spew deletion commands to console if ( immediatedelete ) { vprint( 0, "\n\nDeleting files...\n" ); } else { vprint( 0, "\n\nGenerating deletions.bat\n" ); } i = unreftree.FirstInorder(); invalidindex = unreftree.InvalidIndex(); float deletionSize = 0.0f; int deletionCount = 0; while ( i != invalidindex ) { FileEntry & entry = unreftree[ i ]; i = unreftree.NextInorder( i ); // Don't delete stuff that's in the white list if ( g_WhiteList.Find( entry.sym ) != g_WhiteList.InvalidIndex() ) { if ( verbose ) { vprint( 0, "whitelist blocked deletion of %s\n", g_Analysis.symbols.String( entry.sym ) ); } continue; } ++deletionCount; deletionSize += entry.size; if ( immediatedelete ) { if ( _chmod( g_Analysis.symbols.String( entry.sym ), _S_IWRITE ) == -1 ) { vprint( 0, "Could not find file %s\n", g_Analysis.symbols.String( entry.sym ) ); } if ( _unlink( g_Analysis.symbols.String( entry.sym ) ) == -1 ) { vprint( 0, "Could not delete file %s\n", g_Analysis.symbols.String( entry.sym ) ); } if ( deletionCount % 1000 == 0 ) { vprint( 0, "...deleted %i files\n", deletionCount ); } } else { logprint( "deletions.bat", "del \"%s\" /f\n", g_Analysis.symbols.String( entry.sym ) ); } } vprint( 0, "\nFile deletion (%d files, %s)\n\n", deletionCount, Q_pretifymem(deletionSize, 2) ); } double grand_total = 0; double grand_total_unref = 0; double grand_total_white = 0; char totalstring[ 20 ]; char unrefstring[ 20 ]; char refstring[ 20 ]; char whiteliststring[ 20 ]; vprint( 0, "---------------------------------------- Summary ----------------------------------------\n" ); vprint( 0, "% 15s % 15s % 15s % 15s %12s\n", "Referenced", "WhiteListed", "Unreferenced", "Total", "Directory" ); // Now walk the dictionary in order i = directories.First(); while ( i != invalidindex ) { DirEntry & de = directories[ i ]; double remainder = de.total - de.unreferenced; float percent_unref = 0.0f; float percent_white = 0.0f; if ( de.total > 0 ) { percent_unref = 100.0f * (float)de.unreferenced / (float)de.total; percent_white = 100.0f * (float)de.whitelist / (float)de.total; } Q_strncpy( totalstring, Q_pretifymem( de.total, 2 ), sizeof( totalstring ) ); Q_strncpy( unrefstring, Q_pretifymem( de.unreferenced, 2 ), sizeof( unrefstring ) ); Q_strncpy( refstring, Q_pretifymem( remainder, 2 ), sizeof( refstring ) ); Q_strncpy( whiteliststring, Q_pretifymem( de.whitelist, 2 ), sizeof( whiteliststring ) ); vprint( 0, "%15s (%8.3f%%) %15s (%8.3f%%) %15s (%8.3f%%) %15s => dir: %s\n", refstring, 100.0f - percent_unref, whiteliststring, percent_white, unrefstring, percent_unref, totalstring, directories.GetElementName( i ) ); grand_total += de.total; grand_total_unref += de.unreferenced; grand_total_white += de.whitelist; i = directories.Next( i ); } Q_strncpy( totalstring, Q_pretifymem( grand_total, 2 ), sizeof( totalstring ) ); Q_strncpy( unrefstring, Q_pretifymem( grand_total_unref, 2 ), sizeof( unrefstring ) ); Q_strncpy( refstring, Q_pretifymem( grand_total - grand_total_unref, 2 ), sizeof( refstring ) ); Q_strncpy( whiteliststring, Q_pretifymem( grand_total_white, 2 ), sizeof( whiteliststring ) ); double percent_unref = 100.0 * grand_total_unref / grand_total; double percent_white = 100.0 * grand_total_white / grand_total; vprint( 0, "-----------------------------------------------------------------------------------------\n" ); vprint( 0, "%15s (%8.3f%%) %15s (%8.3f%%) %15s (%8.3f%%) %15s\n", refstring, 100.0f - percent_unref, whiteliststring, percent_white, unrefstring, percent_unref, totalstring ); }
static qboolean HPAK_Validate( const char *filename, qboolean quiet ) { file_t *f; hpak_dir_t *dataDir; hpak_header_t hdr; byte *dataPak; int i, num_lumps; MD5Context_t MD5_Hash; string pakname; resource_t *pRes; char md5[16]; if( quiet ) HPAK_FlushHostQueue(); // not an error - just flush queue if( !filename || !*filename ) return true; Q_strncpy( pakname, filename, sizeof( pakname )); FS_StripExtension( pakname ); FS_DefaultExtension( pakname, ".hpk" ); f = FS_Open( pakname, "rb", false ); if( !f ) { MsgDev( D_INFO, "Couldn't find %s.\n", pakname ); return true; } if( !quiet ) MsgDev( D_INFO, "Validating %s\n", pakname ); FS_Read( f, &hdr, sizeof( hdr )); if( hdr.ident != IDCUSTOMHEADER || hdr.version != IDCUSTOM_VERSION ) { MsgDev( D_ERROR, "HPAK_ValidatePak: %s does not have a valid HPAK header.\n", pakname ); FS_Close( f ); return false; } FS_Seek( f, hdr.seek, SEEK_SET ); FS_Read( f, &num_lumps, sizeof( num_lumps )); if( num_lumps < 1 || num_lumps > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_ValidatePak: %s has too many lumps %u.\n", pakname, num_lumps ); FS_Close( f ); return false; } if( !quiet ) MsgDev( D_INFO, "# of Entries: %i\n", num_lumps ); dataDir = Z_Malloc( sizeof( hpak_dir_t ) * num_lumps ); FS_Read( f, dataDir, sizeof( hpak_dir_t ) * num_lumps ); if( !quiet ) MsgDev( D_INFO, "# Type Size FileName : MD5 Hash\n" ); for( i = 0; i < num_lumps; i++ ) { if( dataDir[i].size < 1 || dataDir[i].size > 131071 ) { // odd max size MsgDev( D_ERROR, "HPAK_ValidatePak: lump %i has invalid size %s\n", i, Q_pretifymem( dataDir[i].size, 2 )); Mem_Free( dataDir ); FS_Close(f); return false; } dataPak = Z_Malloc( dataDir[i].size ); FS_Seek( f, dataDir[i].seek, SEEK_SET ); FS_Read( f, dataPak, dataDir[i].size ); Q_memset( &MD5_Hash, 0, sizeof( MD5Context_t )); MD5Init( &MD5_Hash ); MD5Update( &MD5_Hash, dataPak, dataDir[i].size ); MD5Final( md5, &MD5_Hash ); pRes = &dataDir[i].DirectoryResource; MsgDev( D_INFO, "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ), Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName ); if( Q_memcmp( md5, pRes->rgucMD5_hash, 0x10 )) { if( quiet ) { MsgDev( D_ERROR, "HPAK_ValidatePak: %s has invalid checksum.\n", pakname ); Mem_Free( dataPak ); Mem_Free( dataDir ); FS_Close( f ); return false; } else MsgDev( D_INFO, "failed\n" ); } else { if( !quiet ) MsgDev( D_INFO, "OK\n" ); } // at this point, it's passed our checks. Mem_Free( dataPak ); } Mem_Free( dataDir ); FS_Close( f ); return true; }
void HPAK_AddLump( qboolean add_to_queue, const char *name, resource_t *DirEnt, byte *data, file_t *f ) { int i, position, length; string pakname1, pakname2; char md5[16]; MD5Context_t MD5_Hash; hpak_container_t hpak1, hpak2; file_t *f1, *f2; hpak_dir_t *dirs; byte *temp; if( !name || !name[0] ) { MsgDev( D_ERROR, "HPAK_AddLump: NULL name\n" ); return; } if( !DirEnt ) { MsgDev( D_ERROR, "HPAK_AddLump: invalid lump\n" ); return; } if( data == NULL && f == NULL ) { MsgDev( D_ERROR, "HPAK_AddLump: missing lump data\n" ); return; } if( DirEnt->nDownloadSize < 1024 || DirEnt->nDownloadSize > 131072 ) { MsgDev( D_ERROR, "HPAK_AddLump: invalid size %s\n", Q_pretifymem( DirEnt->nDownloadSize, 2 )); return; } // hash it Q_memset( &MD5_Hash, 0, sizeof( MD5Context_t )); MD5Init( &MD5_Hash ); if( data == NULL ) { // there are better ways position = FS_Tell( f ); temp = Z_Malloc( DirEnt->nDownloadSize ); FS_Read( f, temp, DirEnt->nDownloadSize ); FS_Seek( f, position, SEEK_SET ); MD5Update( &MD5_Hash, temp, DirEnt->nDownloadSize ); Mem_Free( temp ); } else { MD5Update( &MD5_Hash, data, DirEnt->nDownloadSize ); } MD5Final( md5, &MD5_Hash ); if( Q_memcmp( md5, DirEnt->rgucMD5_hash, 0x10 )) { MsgDev( D_ERROR, "HPAK_AddLump: bad checksum for %s. Ignored\n", DirEnt->szFileName ); return; } if( add_to_queue ) { HPAK_AddToQueue( name, DirEnt, data, f ); return; } Q_strncpy( pakname1, name, sizeof( pakname1 )); FS_StripExtension( pakname1 ); FS_DefaultExtension( pakname1, ".hpk" ); f1 = FS_Open( pakname1, "rb", false ); if( !f1 ) { // create new pack HPAK_CreatePak( name, DirEnt, data, f ); return; } Q_strncpy( pakname2, pakname1, sizeof( pakname2 )); FS_StripExtension( pakname2 ); FS_DefaultExtension( pakname2, ".hp2" ); f2 = FS_Open( pakname2, "w+b", false ); if( !f2 ) { MsgDev( D_ERROR, "HPAK_AddLump: couldn't open %s.\n", pakname2 ); FS_Close( f1 ); return; } // load headers FS_Read( f1, &hash_pack_header, sizeof( hpak_header_t )); if( hash_pack_header.version != IDCUSTOM_VERSION ) { // we don't check the HPAK bit for some reason. MsgDev( D_ERROR, "HPAK_AddLump: %s does not have a valid header.\n", pakname2 ); FS_Close( f1 ); FS_Close( f2 ); } length = FS_FileLength( f1 ); HPAK_FileCopy( f2, f1, length ); FS_Seek( f1, hash_pack_header.seek, SEEK_SET ); FS_Read( f1, &hpak1.count, sizeof( hpak1.count )); if( hpak1.count < 1 || hpak1.count > MAX_FILES_IN_WAD ) { MsgDev( D_ERROR, "HPAK_AddLump: %s contain too many lumps.\n", pakname1 ); FS_Close( f1 ); FS_Close( f2 ); return; } // load the data hpak1.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpak1.count ); FS_Read( f1, hpak1.dirs, sizeof( hpak_dir_t ) * hpak1.count ); FS_Close( f1 ); if( HPAK_FindResource( &hpak1, DirEnt->rgucMD5_hash, NULL )) { Mem_Free( hpak1.dirs ); FS_Close( f2 ); } // make a new container hpak2.count = hpak1.count; hpak2.dirs = Z_Malloc( sizeof( hpak_dir_t ) * hpak2.count ); Q_memcpy( hpak2.dirs, hpak1.dirs, hpak1.count ); for( i = 0, dirs = NULL; i < hpak1.count; i++ ) { if( Q_memcmp( hpak1.dirs[i].DirectoryResource.rgucMD5_hash, DirEnt->rgucMD5_hash, 16 ) < 0 ) { dirs = &hpak1.dirs[i]; while( i < hpak1.count ) { hpak2.dirs[i+1] = hpak1.dirs[i]; i++; } break; } } if( dirs == NULL ) dirs = &hpak2.dirs[hpak2.count-1]; Q_memset( dirs, 0, sizeof( hpak_dir_t )); FS_Seek( f2, hash_pack_header.seek, SEEK_SET ); dirs->DirectoryResource = *DirEnt; dirs->seek = FS_Tell( f2 ); dirs->size = DirEnt->nDownloadSize; if( !data ) HPAK_FileCopy( f2, f, dirs->size ); else FS_Write( f2, data, dirs->size ); hash_pack_header.seek = FS_Tell( f2 ); FS_Write( f2, &hpak2.count, sizeof( hpak2.count )); for( i = 0; i < hpak2.count; i++ ) { FS_Write( f2, &hpak2.dirs[i], sizeof( hpak_dir_t )); } // finalize Mem_Free( hpak1.dirs ); Mem_Free( hpak2.dirs ); FS_Seek( f2, 0, SEEK_SET ); FS_Write( f2, &hash_pack_header, sizeof( hpak_header_t )); FS_Close( f2 ); FS_Delete( pakname1 ); FS_Rename( pakname2, pakname1 ); }