// // The developer of the original code and/or files is Tripwire, Inc. // Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire, // Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights // reserved. // // This program is free software. The contents of this file are subject // to the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. You may redistribute it and/or modify it // only in compliance with the GNU General Public License. // // This program is distributed in the hope that it will be useful. // However, this program is distributed AS-IS WITHOUT ANY // WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS // FOR A PARTICULAR PURPOSE. Please see the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // // Nothing in the GNU General Public License or any other license to use // the code or files shall permit you to use Tripwire's trademarks, // service marks, or other intellectual property without Tripwire's // prior written consent. // // If you have any questions, please contact Tripwire, Inc. at either // info@tripwire.org or www.tripwire.org. // /////////////////////////////////////////////////////////////////////////////// // fcodatabasefile.cpp // #include "stdtw.h" #include "fcodatabasefile.h" #include "core/archive.h" #include "core/serializer.h" #include "core/serializerutil.h" #include "fco/fcogenre.h" #include "fco/genreswitcher.h" #include "fco/twfactory.h" #include "fco/fconameinfo.h" #include "core/fileheader.h" #include "core/fsservices.h" #include "db/blockrecordfile.h" // TODO: May localizable strings need to be moved to string table IMPLEMENT_TYPEDSERIALIZABLE(cFCODatabaseFile, _T("cFCODatabaseFile"), 0, 1) cFCODatabaseFile::tEntry::tEntry( cGenre::Genre genre ) //TODO -- ugh, this sucks! I need to add another interface to the database! : mDb ( cGenreSwitcher::GetInstance()->GetFactoryForGenre((cGenre::Genre)genre)->GetNameInfo()->IsCaseSensitive(), cGenreSwitcher::GetInstance()->GetFactoryForGenre((cGenre::Genre)genre)->GetNameInfo()->GetDelimitingChar() ), mGenre( genre ) { } cFCODatabaseFile::cFCODatabaseFile() #ifdef _DEBUG : mFileName( _T("Unknown file name") ) #else : mFileName( _T("") ) // If we don't know the filename, lets just not have one in release mode. #endif { } cFCODatabaseFile::~cFCODatabaseFile() { for( DbList::iterator i = mDbList.begin(); i != mDbList.end(); i++ ) { delete *i; } mDbList.clear(); } /////////////////////////////////////////////////////////////////////////////// // Read /////////////////////////////////////////////////////////////////////////////// void cFCODatabaseFile::Read(iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("Database Read"))); // // read the db header.. // pSerializer->ReadObject( &mHeader ); int32 numGenre; pSerializer->ReadInt32( numGenre ); for( int i=0; i < numGenre; i++ ) { // read the genre number and throw if it is incorrect // int32 iGenre; pSerializer->ReadInt32( iGenre ); cGenre::Genre genre = (cGenre::Genre) iGenre; if( ! cGenreSwitcher::GetInstance()->IsGenreRegistered( genre ) ) { throw eSerializerInputStreamFmt(_T("Encountered unknown genre. Can not read database on this platform."), mFileName, eSerializer::TY_FILE); } mDbList.push_back( new tEntry( genre ) ); tEntry& entry = *(mDbList.back()); // // read the db genre header.. // pSerializer->ReadObject( &entry.mGenreHeader ); // // get the spec list // pSerializer->ReadObject( &entry.mSpecList ); // // get the database data // int32 fileSize; pSerializer->ReadInt32( fileSize ); // // write the hier database into a temp file... // cLockedTemporaryFileArchive* pArch = new cLockedTemporaryFileArchive(); pArch->OpenReadWrite(); cSerializerUtil::Copy( pArch, pSerializer, fileSize ); // // associate the database with this file... // entry.mDb.Open( pArch ); } } /////////////////////////////////////////////////////////////////////////////// // Write /////////////////////////////////////////////////////////////////////////////// void cFCODatabaseFile::Write(iSerializer* pSerializer) const //throw( eFCODbFileTooBig ) { // // write the db header.. // pSerializer->WriteObject( &mHeader ); // iterate through the genres, writing each one... // pSerializer->WriteInt32( mDbList.size() ); // // TODO -- the database is not really const-correct; therefore I have the sick casts below... // for( DbList::iterator i = const_cast(&mDbList)->begin(); i != const_cast(&mDbList)->end(); i++ ) { pSerializer->WriteInt32 ( (*i)->mGenre ); pSerializer->WriteObject ( &(*i)->mGenreHeader ); pSerializer->WriteObject ( &(*i)->mSpecList ); // // copy the database's data into the archive... // (*i)->mDb.Flush(); cBidirArchive* pDbArch = (*i)->mDb.GetArchive(); pDbArch->Seek( 0, cBidirArchive::BEGINNING ); // TODO:BAM -- eventually we should write it as a 64 bit, // but that would change the db format if( pDbArch->Length() > TSS_INT32_MAX ) throw eFCODbFileTooBig(); pSerializer->WriteInt32( static_cast( pDbArch->Length() ) ); cSerializerUtil::Copy( pSerializer, pDbArch, pDbArch->Length() ); } } /////////////////////////////////////////////////////////////////////////////// // GetFileHeaderID() /////////////////////////////////////////////////////////////////////////////// static cFileHeaderID gFCODatabaseFileHeaderID(_T("cFCODatabaseFile")); const cFileHeaderID& cFCODatabaseFile::GetFileHeaderID() { return gFCODatabaseFileHeaderID; } /////////////////////////////////////////////////////////////////////////////// // AddGenre /////////////////////////////////////////////////////////////////////////////// void cFCODatabaseFile::AddGenre( cGenre::Genre genreId, cFCODatabaseFileIter* pIter ) { // // first, lets make sure this genre doesn't exist... // for( DbList::iterator i = mDbList.begin(); i != mDbList.end(); i++ ) { if( (*i)->mGenre == genreId ) { ASSERT( false ); return; } } // // just add it to the front; I don't care about order // mDbList.push_back( new tEntry( genreId ) ); if( pIter ) { pIter->mIter = mDbList.end()-1; } // // create a new prop displayer for the header. // mDbList.back()->mGenreHeader.SetPropDisplayer ( cGenreSwitcher::GetInstance()->GetFactoryForGenre((cGenre::Genre)mDbList.back()->mGenre)->CreatePropDisplayer() ); // // open the database // // // the hier database will own destroying this... // cLockedTemporaryFileArchive* pArch = new cLockedTemporaryFileArchive(); pArch->OpenReadWrite(); mDbList.back()->mDb.Open( pArch ); } void cFCODatabaseFile::SetFileName( const TSTRING& name ) { mFileName = name; } TSTRING cFCODatabaseFile::GetFileName() const { return mFileName; } //----------------------------------------------------------------------------- // cFCODatabaseFileIter //----------------------------------------------------------------------------- cFCODatabaseFileIter::cFCODatabaseFileIter( cFCODatabaseFile& dbFile ) : mDbFile( dbFile ) { SeekBegin(); } void cFCODatabaseFileIter::SeekBegin() { mIter = mDbFile.mDbList.begin(); } void cFCODatabaseFileIter::Next() { mIter++; } bool cFCODatabaseFileIter::Done() const { return ( mIter == mDbFile.mDbList.end() ); } void cFCODatabaseFileIter::SeekToGenre(cGenre::Genre genreId) { for( SeekBegin(); ! Done(); Next() ) { if( GetGenre() == genreId ) return; } } void cFCODatabaseFileIter::Remove() { ASSERT( ! Done() ); if( ! Done() ) { delete *mIter; mIter = mDbFile.mDbList.erase( mIter ); } } cGenre::Genre cFCODatabaseFileIter::GetGenre() const { ASSERT( ! Done() ); return (*mIter)->mGenre; } cHierDatabase& cFCODatabaseFileIter::GetDb() { ASSERT( ! Done() ); return (*mIter)->mDb; } const cHierDatabase& cFCODatabaseFileIter::GetDb() const { ASSERT( ! Done() ); return (*mIter)->mDb; } cFCOSpecList& cFCODatabaseFileIter::GetSpecList() { ASSERT( ! Done() ); return (*mIter)->mSpecList; } const cFCOSpecList& cFCODatabaseFileIter::GetSpecList() const { ASSERT( ! Done() ); return (*mIter)->mSpecList; } const cFCODbGenreHeader& cFCODatabaseFileIter::GetGenreHeader() const { ASSERT( ! Done() ); return (*mIter)->mGenreHeader; } cFCODbGenreHeader& cFCODatabaseFileIter::GetGenreHeader() { ASSERT( ! Done() ); return (*mIter)->mGenreHeader; }