// // 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( (*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; }