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

405 lines
13 KiB
C++

//
// 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.
//
///////////////////////////////////////////////////////////////////////////////
// dbdatasource.cpp
//
#include "stdtw.h"
#include "dbdatasource.h"
#include "fco/twfactory.h"
#include "fco/fconameinfo.h"
#include "core/archive.h"
#include "core/serializerimpl.h"
#include "fco/fcopropset.h"
#include "fco/fco.h"
#include "fco/fcodatasourceiter.h"
// TODO -- get rid of this include somehow!
#include "fco/genreswitcher.h"
///////////////////////////////////////////////////////////////////////////////
// ctor
///////////////////////////////////////////////////////////////////////////////
cDbDataSourceIter::cDbDataSourceIter(cHierDatabase* pDb, int genreNum )
: iFCODataSourceIter (),
mDbIter (pDb),
mFlags (0),
mpErrorBucket (0)
{
//
// remember the fco creation function...
// TODO -- Note that this couples this file with cGenreSwitcher; perhaps this should take the fco creation
// function instead...
//
if( genreNum == -1 )
genreNum = cGenreSwitcher::GetInstance()->CurrentGenre();
mFCOCreateFunc = cGenreSwitcher::GetInstance()->GetFactoryForGenre( (cGenre::Genre)genreNum )->GetCreateFunc();
#ifdef _DEBUG
//
// make some assertions about the current genre's name info
//
iFCONameInfo* pNameInfo = cGenreSwitcher::GetInstance()->GetFactoryForGenre( (cGenre::Genre)genreNum )->GetNameInfo();
ASSERT( pDb->IsCaseSensitive() == pNameInfo->IsCaseSensitive() );
ASSERT( pDb->GetDelimitingChar() == pNameInfo->GetDelimitingChar() );
#endif //#ifdef _DEBUG
}
///////////////////////////////////////////////////////////////////////////////
// cDbDataSourceIter
///////////////////////////////////////////////////////////////////////////////
cDbDataSourceIter::cDbDataSourceIter( const cDbDataSourceIter& rhs )
: iFCODataSourceIter(),
mDbIter ( rhs.mDbIter ),
mFCOCreateFunc ( rhs.mFCOCreateFunc ),
mFlags ( rhs.mFlags ),
mpErrorBucket ( rhs.mpErrorBucket )
{
}
///////////////////////////////////////////////////////////////////////////////
// operator=
///////////////////////////////////////////////////////////////////////////////
cDbDataSourceIter& cDbDataSourceIter::operator=( const cDbDataSourceIter& rhs )
{
mDbIter = rhs.mDbIter ;
mFCOCreateFunc = rhs.mFCOCreateFunc ;
mFlags = rhs.mFlags;
mpErrorBucket = rhs.mpErrorBucket;
return (*this);
}
///////////////////////////////////////////////////////////////////////////////
// dtor
///////////////////////////////////////////////////////////////////////////////
cDbDataSourceIter::~cDbDataSourceIter()
{
}
///////////////////////////////////////////////////////////////////////////////
// CreateCopy
///////////////////////////////////////////////////////////////////////////////
iFCODataSourceIter* cDbDataSourceIter::CreateCopy() const
{
//TODO -- implement this with a memory pool?
return new cDbDataSourceIter(*this);
}
///////////////////////////////////////////////////////////////////////////////
// GetName
///////////////////////////////////////////////////////////////////////////////
cFCOName cDbDataSourceIter::GetName() const
{
ASSERT( ! Done() );
cFCOName rtn( mDbIter.GetCwd() );
rtn.Push( mDbIter.GetName() );
return rtn;
}
///////////////////////////////////////////////////////////////////////////////
// CreateFCO
//
// note that cHierDatabase::GetData() will throw if we are Done() or the node
// doesn't have data
///////////////////////////////////////////////////////////////////////////////
iFCO* cDbDataSourceIter::CreateFCO() //throw (eError)
{
ASSERT( ! Done() );
//
// ok, first, we will create the new fco...
//
iFCO* pFCO = static_cast<iFCO*>( (*mFCOCreateFunc)() );
pFCO->SetName( GetName() );
try
{
ASSERT( mDbIter.HasData() );
int32 length;
int8* pData = mDbIter.GetData(length);
//
// associate a serializer with this memory and read in the property set...
//
cFixedMemArchive arch( pData, length );
cSerializerImpl ser ( arch, cSerializerImpl::S_READ );
ser.Init();
ser.ReadObject( pFCO->GetPropSet() );
ser.Finit();
}
catch(...)
{
pFCO->Release();
throw;
}
return pFCO;
}
///////////////////////////////////////////////////////////////////////////////
// HasFCOData
///////////////////////////////////////////////////////////////////////////////
bool cDbDataSourceIter::HasFCOData() const
{
ASSERT( ! Done() );
if( Done() )
return false;
return ( mDbIter.HasData() );
}
///////////////////////////////////////////////////////////////////////////////
// SeekToFCO
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::SeekToFCO(const cFCOName& name, bool bCreatePeers) //throw(eFCODataSourceIter)
{
ASSERT( name.GetSize() > 0 );
cFCOName parentName = name;
parentName.Pop();
if(! SeekToDirectory( parentName, false ) )
{
// make myself Done() and return...
//
while( ! Done() ) Next();
return;
}
//
// note that this is Done() if it fails, so we are good...
//
mDbIter.SeekTo( name.GetShortName() ) ;
}
///////////////////////////////////////////////////////////////////////////////
// AddFCO
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::AddFCO( const TSTRING& shortName, const iFCO* pFCO ) //throw (eFCODataSourceIter, eError)
{
mDbIter.CreateEntry( shortName );
//
// we are now pointing at the entry we just created, so now let's add the data...
//
SetFCOData( pFCO );
}
///////////////////////////////////////////////////////////////////////////////
// RemoveFCO
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::RemoveFCO() //throw (eError)
{
if( (! Done()) && (! HasFCOData()) )
{
mDbIter.DeleteEntry();
}
else
{
// this was called in inappropriate circumastances
ASSERT( false );
}
}
///////////////////////////////////////////////////////////////////////////////
// RemoveFCOData
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::RemoveFCOData() //throw (eError)
{
ASSERT( ! Done() );
ASSERT( HasFCOData() );
if( HasFCOData() )
{
mDbIter.RemoveData();
}
}
///////////////////////////////////////////////////////////////////////////////
// SetFCOData
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::SetFCOData( const iFCO* pFCO ) //throw (eError)
{
ASSERT( ! Done() );
if( Done() )
{
throw eHierDatabase( _T("Attempt to set FCO data when the iterator is done.") );
}
// TODO -- assert and throw if the fco's type is not the same as our creation function
// There is no way to do this through the serializable interface, but when there is,
// we should do the above assertion.
//
// if data already exists here, we first remove it;
//
if( mDbIter.HasData() )
{
mDbIter.RemoveData();
}
//
// write the fco's property set to a memory archive...
//
// TODO -- does this need to be static?
static cMemoryArchive arch;
arch.Seek ( 0, cBidirArchive::BEGINNING );
cSerializerImpl ser (arch, cSerializerImpl::S_WRITE);
ser.Init();
ser.WriteObject ( pFCO->GetPropSet() );
ser.Finit();
//
// write this to the archive...
//
mDbIter.SetData( arch.GetMemory(), arch.CurrentPos() );
}
///////////////////////////////////////////////////////////////////////////////
// AddChildArray
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::AddChildArray() //throw (eError)
{
ASSERT( ! Done() );
ASSERT( ! CanDescend() );
mDbIter.CreateChildArray();
}
///////////////////////////////////////////////////////////////////////////////
// RemoveChildArray
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::RemoveChildArray() //throw (eError)
{
//NOTE -- the hier db iter does all of the proper asserting...
//
mDbIter.DeleteChildArray();
}
///////////////////////////////////////////////////////////////////////////////
// CreatePath
///////////////////////////////////////////////////////////////////////////////
void cDbDataSourceIter::CreatePath( const cFCOName& name ) //throw (eError)
{
ASSERT( name.GetSize() > 0 );
cFCOName parentName = name;
parentName.Pop();
SeekToDirectory( parentName, true );
if( ! mDbIter.SeekTo( name.GetShortName() ) )
{
mDbIter.CreateEntry( name.GetShortName() );
}
}
///////////////////////////////////////////////////////////////////////////////
// SeekToDirectory
///////////////////////////////////////////////////////////////////////////////
bool cDbDataSourceIter::SeekToDirectory( const cFCOName& parentName, bool bCreate )
{
cDebug d( "cDbDataSourceIter::SeekToDirectory" );
//
// the first task is to ascend until we are in a directory that we can descend into to
// reach parentName...
//
cFCOName curParent = GetParentName();
d.TraceDebug( _T("Entering... Seeking to %s (cwd = %s)\n"), parentName.AsString().c_str(), curParent.AsString().c_str() );
int ascendCount ;
switch( curParent.GetRelationship( parentName ) )
{
case cFCOName::REL_BELOW:
//
// we must ascend...
//
ascendCount = curParent.GetSize() - parentName.GetSize();
d.TraceDetail( _T("\tAscending %d times...\n"), ascendCount );
ASSERT( ascendCount > 0 );
for( ; ascendCount > 0; ascendCount-- )
Ascend();
break;
case cFCOName::REL_ABOVE:
//
// we are above the needed directory; nothing else to do here...
//
d.TraceDetail( _T("\tAbove; not ascending...\n") );
break;
case cFCOName::REL_EQUAL:
//
// we need to do nothing else here...
//
d.TraceDetail( _T("\tEqual; doing nothing...\n") );
SeekBegin();
return true;
case cFCOName::REL_UNRELATED:
//
// we have to go all the way to the root...
//
d.TraceDetail( _T("\tUnrelated; seeking to root...\n") );
SeekToRoot();
break;
default:
// unreachable
ASSERT( false );
return false;
}
curParent = GetParentName();
if( parentName.GetSize() == curParent.GetSize() )
return true;
//
// now we will descend to the parent directory we are interested in...
//
cFCOName::iterator i(parentName);
i.SeekTo( curParent.GetSize() );
for(; (! i.Done()); i.Next() )
{
if( ! mDbIter.SeekTo( i.GetName() ) )
{
// this needs to be created!
if( bCreate )
mDbIter.CreateEntry( i.GetName() );
else
return false;
}
//
// create the child array and descend
//
if( ! mDbIter.CanDescend() )
{
if( bCreate )
mDbIter.CreateChildArray();
else
return false;
}
mDbIter.Descend();
}
return true;
}