tripwire-open-source/src/tw/fcodatabasefile.cpp

328 lines
9.3 KiB
C++

//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000-2017 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<DbList*>(&mDbList)->begin(); i != const_cast<DbList*>(&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<int32>( 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;
}