123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- /*
- ================================================================================================
- idResourceContainer
- ================================================================================================
- */
- /*
- ========================
- idResourceContainer::ReOpen
- ========================
- */
- void idResourceContainer::ReOpen() {
- delete resourceFile;
- resourceFile = fileSystem->OpenFileRead( fileName );
- }
- /*
- ========================
- idResourceContainer::Init
- ========================
- */
- bool idResourceContainer::Init( const char *_fileName, uint8 containerIndex ) {
- if ( idStr::Icmp( _fileName, "_ordered.resources" ) == 0 ) {
- resourceFile = fileSystem->OpenFileReadMemory( _fileName );
- } else {
- resourceFile = fileSystem->OpenFileRead( _fileName );
- }
- if ( resourceFile == NULL ) {
- idLib::Warning( "Unable to open resource file %s", _fileName );
- return false;
- }
- resourceFile->ReadBig( resourceMagic );
- if ( resourceMagic != RESOURCE_FILE_MAGIC ) {
- idLib::FatalError( "resourceFileMagic != RESOURCE_FILE_MAGIC" );
- }
- fileName = _fileName;
- resourceFile->ReadBig( tableOffset );
- resourceFile->ReadBig( tableLength );
- // read this into a memory buffer with a single read
- char * const buf = (char *)Mem_Alloc( tableLength, TAG_RESOURCE );
- resourceFile->Seek( tableOffset, FS_SEEK_SET );
- resourceFile->Read( buf, tableLength );
- idFile_Memory memFile( "resourceHeader", (const char *)buf, tableLength );
- // Parse the resourceFile header, which includes every resource used
- // by the game.
- memFile.ReadBig( numFileResources );
- cacheTable.SetNum( numFileResources );
- for ( int i = 0; i < numFileResources; i++ ) {
- idResourceCacheEntry &rt = cacheTable[ i ];
- rt.Read( &memFile );
- rt.filename.BackSlashesToSlashes();
- rt.filename.ToLower();
- rt.containerIndex = containerIndex;
- const int key = cacheHash.GenerateKey( rt.filename, false );
- bool found = false;
- //for ( int index = cacheHash.GetFirst( key ); index != idHashIndex::NULL_INDEX; index = cacheHash.GetNext( index ) ) {
- // idResourceCacheEntry & rtc = cacheTable[ index ];
- // if ( idStr::Icmp( rtc.filename, rt.filename ) == 0 ) {
- // found = true;
- // break;
- // }
- //}
- if ( !found ) {
- //idLib::Printf( "rez file name: %s\n", rt.filename.c_str() );
- cacheHash.Add( key, i );
- }
- }
- Mem_Free( buf );
- return true;
- }
- /*
- ========================
- idResourceContainer::WriteManifestFile
- ========================
- */
- void idResourceContainer::WriteManifestFile( const char *name, const idStrList &list ) {
- idStr filename( name );
- filename.SetFileExtension( "manifest" );
- filename.Insert( "maps/", 0 );
- idFile *outFile = fileSystem->OpenFileWrite( filename );
- if ( outFile != NULL ) {
- int num = list.Num();
- outFile->WriteBig( num );
- for ( int i = 0; i < num; i++ ) {
- outFile->WriteString( list[ i ] );
- }
- delete outFile;
- }
- }
- /*
- ========================
- idResourceContainer::ReadManifestFile
- ========================
- */
- int idResourceContainer::ReadManifestFile( const char *name, idStrList &list ) {
- idFile *inFile = fileSystem->OpenFileRead( name );
- if ( inFile != NULL ) {
- list.SetGranularity( 16384 );
- idStr str;
- int num;
- list.Clear();
- inFile->ReadBig( num );
- for ( int i = 0; i < num; i++ ) {
- inFile->ReadString( str );
- list.Append( str );
- }
- delete inFile;
- }
- return list.Num();
- }
- /*
- ========================
- idResourceContainer::UpdateResourceFile
- ========================
- */
- void idResourceContainer::UpdateResourceFile( const char *_filename, const idStrList &_filesToUpdate ) {
- idFile *outFile = fileSystem->OpenFileWrite( va( "%s.new", _filename ) );
- if ( outFile == NULL ) {
- idLib::Warning( "Unable to open resource file %s or new output file", _filename );
- return;
- }
- uint32 magic = 0;
- int _tableOffset = 0;
- int _tableLength = 0;
- idList< idResourceCacheEntry > entries;
- idStrList filesToUpdate = _filesToUpdate;
- idFile *inFile = fileSystem->OpenFileRead( _filename );
- if ( inFile == NULL ) {
- magic = RESOURCE_FILE_MAGIC;
- outFile->WriteBig( magic );
- outFile->WriteBig( _tableOffset );
- outFile->WriteBig( _tableLength );
- } else {
- inFile->ReadBig( magic );
- if ( magic != RESOURCE_FILE_MAGIC ) {
- delete inFile;
- return;
- }
- inFile->ReadBig( _tableOffset );
- inFile->ReadBig( _tableLength );
- // read this into a memory buffer with a single read
- char * const buf = (char *)Mem_Alloc( _tableLength, TAG_RESOURCE );
- inFile->Seek( _tableOffset, FS_SEEK_SET );
- inFile->Read( buf, _tableLength );
- idFile_Memory memFile( "resourceHeader", (const char *)buf, _tableLength );
- int _numFileResources = 0;
- memFile.ReadBig( _numFileResources );
- outFile->WriteBig( magic );
- outFile->WriteBig( _tableOffset );
- outFile->WriteBig( _tableLength );
- entries.SetNum( _numFileResources );
- for ( int i = 0; i < _numFileResources; i++ ) {
- entries[ i ].Read( &memFile );
- idLib::Printf( "examining %s\n", entries[ i ].filename.c_str() );
- byte * fileData = NULL;
- for ( int j = filesToUpdate.Num() - 1; j >= 0; j-- ) {
- if ( filesToUpdate[ j ].Icmp( entries[ i ].filename ) == 0 ) {
- idFile *newFile = fileSystem->OpenFileReadMemory( filesToUpdate[ j ] );
- if ( newFile != NULL ) {
- idLib::Printf( "Updating %s\n", filesToUpdate[ j ].c_str() );
- entries[ i ].length = newFile->Length();
- fileData = (byte *)Mem_Alloc( entries[ i ].length, TAG_TEMP );
- newFile->Read( fileData, newFile->Length() );
- delete newFile;
- }
- filesToUpdate.RemoveIndex( j );
- }
- }
- if ( fileData == NULL ) {
- inFile->Seek( entries[ i ].offset, FS_SEEK_SET );
- fileData = (byte *)Mem_Alloc( entries[ i ].length, TAG_TEMP );
- inFile->Read( fileData, entries[ i ].length );
- }
- entries[ i ].offset = outFile->Tell();
- outFile->Write( ( void* )fileData, entries[ i ].length );
- Mem_Free( fileData );
- }
- Mem_Free( buf );
- }
- while ( filesToUpdate.Num() > 0 ) {
- idFile *newFile = fileSystem->OpenFileReadMemory( filesToUpdate[ 0 ] );
- if ( newFile != NULL ) {
- idLib::Printf( "Appending %s\n", filesToUpdate[ 0 ].c_str() );
- idResourceCacheEntry rt;
- rt.filename = filesToUpdate[ 0 ];
- rt.length = newFile->Length();
- byte * fileData = (byte *)Mem_Alloc( rt.length, TAG_TEMP );
- newFile->Read( fileData, rt.length );
- int idx = entries.Append( rt );
- if ( idx >= 0 ) {
- entries[ idx ].offset = outFile->Tell();
- outFile->Write( ( void* )fileData, entries[ idx ].length );
- }
- delete newFile;
- Mem_Free( fileData );
- }
- filesToUpdate.RemoveIndex( 0 );
- }
- _tableOffset = outFile->Tell();
- outFile->WriteBig( entries.Num() );
- // write the individual resource entries
- for ( int i = 0; i < entries.Num(); i++ ) {
- entries[ i ].Write( outFile );
- }
- // go back and write the header offsets again, now that we have file offsets and lengths
- _tableLength = outFile->Tell() - _tableOffset;
- outFile->Seek( 0, FS_SEEK_SET );
- outFile->WriteBig( magic );
- outFile->WriteBig( _tableOffset );
- outFile->WriteBig( _tableLength );
- delete outFile;
- delete inFile;
- }
- /*
- ========================
- idResourceContainer::ExtractResourceFile
- ========================
- */
- void idResourceContainer::SetContainerIndex( const int & _idx ) {
- for ( int i = 0; i < cacheTable.Num(); i++ ) {
- cacheTable[ i ].containerIndex = _idx;
- }
- }
- /*
- ========================
- idResourceContainer::ExtractResourceFile
- ========================
- */
- void idResourceContainer::ExtractResourceFile ( const char * _fileName, const char * _outPath, bool _copyWavs ) {
- idFile *inFile = fileSystem->OpenFileRead( _fileName );
- if ( inFile == NULL ) {
- idLib::Warning( "Unable to open resource file %s", _fileName );
- return;
- }
- uint32 magic;
- inFile->ReadBig( magic );
- if ( magic != RESOURCE_FILE_MAGIC ) {
- delete inFile;
- return;
- }
- int _tableOffset;
- int _tableLength;
- inFile->ReadBig( _tableOffset );
- inFile->ReadBig( _tableLength );
- // read this into a memory buffer with a single read
- char * const buf = (char *)Mem_Alloc( _tableLength, TAG_RESOURCE );
- inFile->Seek( _tableOffset, FS_SEEK_SET );
- inFile->Read( buf, _tableLength );
- idFile_Memory memFile( "resourceHeader", (const char *)buf, _tableLength );
- int _numFileResources;
- memFile.ReadBig( _numFileResources );
- for ( int i = 0; i < _numFileResources; i++ ) {
- idResourceCacheEntry rt;
- rt.Read( &memFile );
- rt.filename.BackSlashesToSlashes();
- rt.filename.ToLower();
- byte *fbuf = NULL;
- if ( _copyWavs && ( rt.filename.Find( ".idwav" ) >= 0 || rt.filename.Find( ".idxma" ) >= 0 || rt.filename.Find( ".idmsf" ) >= 0 ) ) {
- rt.filename.SetFileExtension( "wav" );
- rt.filename.Replace( "generated/", "" );
- int len = fileSystem->GetFileLength( rt.filename );
- fbuf = (byte *)Mem_Alloc( len, TAG_RESOURCE );
- fileSystem->ReadFile( rt.filename, (void**)&fbuf, NULL );
- } else {
- inFile->Seek( rt.offset, FS_SEEK_SET );
- fbuf = (byte *)Mem_Alloc( rt.length, TAG_RESOURCE );
- inFile->Read( fbuf, rt.length );
- }
- idStr outName = _outPath;
- outName.AppendPath( rt.filename );
- idFile *outFile = fileSystem->OpenExplicitFileWrite( outName );
- if ( outFile != NULL ) {
- outFile->Write( ( byte* )fbuf, rt.length );
- delete outFile;
- }
- Mem_Free( fbuf );
- }
- delete inFile;
- Mem_Free( buf );
- }
- /*
- ========================
- idResourceContainer::Open
- ========================
- */
- void idResourceContainer::WriteResourceFile( const char *manifestName, const idStrList &manifest, const bool &_writeManifest ) {
- if ( manifest.Num() == 0 ) {
- return;
- }
- idLib::Printf( "Writing resource file %s\n", manifestName );
- // build multiple output files at 1GB each
- idList < idStrList > outPutFiles;
- idFileManifest outManifest;
- int64 size = 0;
- idStrList flist;
- flist.SetGranularity( 16384 );
- for ( int i = 0; i < manifest.Num(); i++ ) {
- flist.Append( manifest[ i ] );
- size += fileSystem->GetFileLength( manifest[ i ] );
- if ( size > 1024 * 1024 * 1024 ) {
- outPutFiles.Append( flist );
- size = 0;
- flist.Clear();
- }
- outManifest.AddFile( manifest[ i ] );
- }
- outPutFiles.Append( flist );
- if ( _writeManifest ) {
- idStr temp = manifestName;
- temp.Replace( "maps/", "manifests/" );
- temp.StripFileExtension();
- temp.SetFileExtension( "manifest" );
- outManifest.WriteManifestFile( temp );
- }
- for ( int idx = 0; idx < outPutFiles.Num(); idx++ ) {
- idStrList &fileList = outPutFiles[ idx ];
- if ( fileList.Num() == 0 ) {
- continue;
- }
- idStr fileName = manifestName;
- if ( idx > 0 ) {
- fileName = va( "%s_%02d", manifestName, idx );
- }
- fileName.SetFileExtension( "resources" );
- idFile *resFile = fileSystem->OpenFileWrite( fileName );
- if ( resFile == NULL ) {
- idLib::Warning( "Cannot open %s for writing.\n", fileName.c_str() );
- return;
- }
- idLib::Printf( "Writing resource file %s\n", fileName.c_str() );
- int tableOffset = 0;
- int tableLength = 0;
- int tableNewLength = 0;
- uint32 resourceFileMagic = RESOURCE_FILE_MAGIC;
- resFile->WriteBig( resourceFileMagic );
- resFile->WriteBig( tableOffset );
- resFile->WriteBig( tableLength );
- idList< idResourceCacheEntry > entries;
- entries.Resize( fileList.Num() );
- for ( int i = 0; i < fileList.Num(); i++ ) {
- idResourceCacheEntry ent;
- ent.filename = fileList[ i ];
- ent.length = 0;
- ent.offset = 0;
- idFile *file = fileSystem->OpenFileReadMemory( ent.filename, false );
- idFile_Memory *fm = dynamic_cast< idFile_Memory* >( file );
- if ( fm == NULL ) {
- continue;
- }
- // if the entry is uncompressed, align the file pointer to a 16 byte boundary
- // so it will be usable if memory mapped
- ent.length = fm->Length();
- // always get the offset, even if the file will have zero length
- ent.offset = resFile->Tell();
- entries.Append( ent );
- if ( ent.length == 0 ) {
- ent.filename = "";
- delete fm;
- continue;
- }
- resFile->Write( fm->GetDataPtr(), ent.length );
- delete fm;
- // pacifier every ten megs
- if ( ( ent.offset + ent.length ) / 10000000 != ent.offset / 10000000 ) {
- idLib::Printf( "." );
- }
- }
- idLib::Printf( "\n" );
- // write the table out now that we have all the files
- tableOffset = resFile->Tell();
- // count how many we are going to write for this platform
- int numFileResources = entries.Num();
- resFile->WriteBig( numFileResources );
- // write the individual resource entries
- for ( int i = 0; i < entries.Num(); i++ ) {
- entries[ i ].Write( resFile );
- if ( i + 1 == numFileResources ) {
- // we just wrote out the last new entry
- tableNewLength = resFile->Tell() - tableOffset;
- }
- }
- // go back and write the header offsets again, now that we have file offsets and lengths
- tableLength = resFile->Tell() - tableOffset;
- resFile->Seek( 0, FS_SEEK_SET );
- resFile->WriteBig( resourceFileMagic );
- resFile->WriteBig( tableOffset );
- resFile->WriteBig( tableLength );
- delete resFile;
- }
- }
|