tripwire-open-source/src/fco/fcodatasourceiterimpl.cpp

464 lines
14 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.
//
///////////////////////////////////////////////////////////////////////////////
// fcodatasourceiterimpl.cpp
//
//=========================================================================
// DEFINES AND MACROS
//=========================================================================
//=========================================================================
// INCLUDES
//=========================================================================
#include "stdfco.h"
#include "fcodatasourceiterimpl.h"
#include "fco.h"
#include "core/upperbound.h"
#include "core/errorbucket.h"
//=========================================================================
// METHOD CODE
//=========================================================================
cFCODataSourceIterImpl::cFCODataSourceIterImpl()
: mFlags(0)
{
}
cFCODataSourceIterImpl::~cFCODataSourceIterImpl()
{
ClearList();
}
///////////////////////////////////////////////////////////////////////////////
// operator =
///////////////////////////////////////////////////////////////////////////////
cFCODataSourceIterImpl& cFCODataSourceIterImpl::operator=( const cFCODataSourceIterImpl& rhs )
{
ClearList();
mPeers = rhs.mPeers;
mParentName = rhs.mParentName;
mpErrorBucket = rhs.mpErrorBucket;
mFlags = rhs.mFlags;
//
// we need to addref all of the fcos we just got...
//
for( FCOList::const_iterator i = mPeers.begin(); i != mPeers.end(); i++ )
{
(*i)->AddRef();
}
//
// figuring out where to put the iterator is a little trickier...
// TODO -- if we ever change the mPeers data structure from a vector, this will
// have to change (luckily, the compiler should catch this!)
//
if( rhs.Done() )
{
mCurPos = mPeers.end();
}
else
{
int offset = rhs.mCurPos - rhs.mPeers.begin();
mCurPos = mPeers.begin() + offset;
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// GetShortName
///////////////////////////////////////////////////////////////////////////////
const TCHAR* cFCODataSourceIterImpl::GetShortName() const
{
ASSERT( ! Done() );
return ( (*mCurPos)->GetName().GetShortName() );
}
///////////////////////////////////////////////////////////////////////////////
// GetName
///////////////////////////////////////////////////////////////////////////////
cFCOName cFCODataSourceIterImpl::GetName() const
{
ASSERT( ! Done() );
return ( (*mCurPos)->GetName() );
}
///////////////////////////////////////////////////////////////////////////////
// GetParentName
///////////////////////////////////////////////////////////////////////////////
cFCOName cFCODataSourceIterImpl::GetParentName() const
{
return mParentName;
}
///////////////////////////////////////////////////////////////////////////////
// GetParentName
///////////////////////////////////////////////////////////////////////////////
bool cFCODataSourceIterImpl::AtRoot() const //throw (eError)
{
return ( mParentName.GetSize() == 0 );
}
///////////////////////////////////////////////////////////////////////////////
// CanDescend
///////////////////////////////////////////////////////////////////////////////
bool cFCODataSourceIterImpl::CanDescend() const //throw (eError)
{
ASSERT( ! Done() );
if( Done() )
{
return false;
}
return ( (*mCurPos)->GetCaps() & iFCO::CAP_CAN_HAVE_CHILDREN );
}
///////////////////////////////////////////////////////////////////////////////
// Descend
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::Descend() //throw (eError)
{
ASSERT( CanDescend() );
mParentName = GetName();
GeneratePeers( );
}
///////////////////////////////////////////////////////////////////////////////
// Ascend
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::Ascend() //throw (eError)
{
ASSERT( ! AtRoot() );
cFCOName name = mParentName;
SeekToFCO( name ); // I do this because SeekToFCO modifies mCwd and takes a reference parameter.
}
///////////////////////////////////////////////////////////////////////////////
// SeekBegin
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::SeekBegin()
{
mCurPos = mPeers.begin();
}
///////////////////////////////////////////////////////////////////////////////
// Done
///////////////////////////////////////////////////////////////////////////////
bool cFCODataSourceIterImpl::Done() const
{
return ( mCurPos == mPeers.end() );
}
///////////////////////////////////////////////////////////////////////////////
// Next
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::Next()
{
mCurPos++;
}
///////////////////////////////////////////////////////////////////////////////
// CreateFCO
///////////////////////////////////////////////////////////////////////////////
iFCO* cFCODataSourceIterImpl::CreateFCO() //throw (eError)
{
ASSERT( ! Done() );
InitializeTypeInfo( *mCurPos );
(*mCurPos)->AddRef();
return *mCurPos;
}
///////////////////////////////////////////////////////////////////////////////
// SeekToFCO
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::SeekToFCO(const cFCOName& name, bool bCreatePeers) // throw (eFCODataSourceIter)
{
ASSERT( name.GetSize() > 0 );
ASSERT( name.IsCaseSensitive() == IsCaseSensitive() );
//
// get the parent name and pop the short child name
//
cFCOName parentName = name;
parentName.Pop(); // RAD:05/10/1999 -- Used to assign result to "shortname"
if( parentName.GetSize() == 0 )
{
// we are going to the root directory...
// note that we are not responsible for iterating over the root nodes (for example,
// all of the drive letters in NT or all the hive names in the registry)
//
mParentName.Clear();
ClearList();
iFCO* pObj = CreateObject( name, bCreatePeers );
if( ! pObj )
{
// error creating object; just return.
return;
}
InsertIntoPeers( pObj );
mCurPos = mPeers.begin();
return;
}
else
{
// if we are not creating our peers, simply create the single object and return...
//
if( ! bCreatePeers )
{
ClearList();
mParentName = parentName;
iFCO* pNewObj = CreateObject( name, false );
if( pNewObj )
{
InsertIntoPeers( pNewObj );
mCurPos = mPeers.begin();
}
return;
}
//
// otherwise, load up everything. Note that we can't do the if(parentName == mParentName) optimization
// because if you do a SeekToFCO( c:/foo, false) and then a SeekToFCO( c:/bar, true), it won't work
// correctly -- 27 Jan 99 mdb
//
mParentName = parentName;
ClearList();
GeneratePeers();
}
SeekToPeerByName( (*mCurPos)->GetName().GetShortName() );
}
///////////////////////////////////////////////////////////////////////////////
// IsCaseSensitive
///////////////////////////////////////////////////////////////////////////////
bool cFCODataSourceIterImpl::IsCaseSensitive() const
{
return mParentName.IsCaseSensitive();
}
///////////////////////////////////////////////////////////////////////////////
// ClearList
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::ClearList()
{
for( mCurPos = mPeers.begin(); mCurPos != mPeers.end(); mCurPos++ )
{
(*mCurPos)->Release();
}
mPeers.clear();
mCurPos = mPeers.end();
}
///////////////////////////////////////////////////////////////////////////////
// GeneratePeers
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::GeneratePeers()
{
///TODO -- BIG BIG TODO -- I need to implement some lazy evaluation for these
// fcos so that when I seek to a start point, I don't stat everything in the
// same directory as myself.
// NOTE: This might be alleviated by differentiating between seeks that need
// peers and ones that do not (or maybe lazy evaluation of the peers)
ClearList();
//
// read all of the children of the parent...
//
std::vector<TSTRING> vChildrenNames;
GetChildrenNames( mParentName.AsString(), vChildrenNames );
//
// insert the children into the set...
//
std::vector<TSTRING>::iterator i;
cFCOName curName = mParentName;
for( i = vChildrenNames.begin(); i != vChildrenNames.end(); i++)
{
curName.Push( *i );
iFCO* pNewObj = CreateObject( curName, true );
if( pNewObj )
{
if( ! InsertIntoPeers( pNewObj ) )
{
// no need for an error msg; that is handled by InsertIntoPeers;
// just release the object.
//
pNewObj->Release();
}
}
curName.Pop();
}
mCurPos = mPeers.begin();
}
///////////////////////////////////////////////////////////////////////////////
// TraceContents
///////////////////////////////////////////////////////////////////////////////
bool cFCODataSourceIterImpl::SeekTo( const TCHAR* shortName )
{
FCOList::iterator i = UpperBound( shortName );
if( i != mPeers.end() )
{
if( REL_EQ == Compare( shortName, (*i)->GetName().GetShortName() ) )
{
mCurPos = i;
return true;
}
}
mCurPos = mPeers.end();
return false;
}
///////////////////////////////////////////////////////////////////////////////
// TraceContents
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::TraceContents(int dl) const
{
if( dl == -1 )
dl = cDebug::D_DEBUG;
cDebug d("cFCODataSourceIterImpl::TraceContents");
d.Trace( dl, "FCO Iterator; parent = %s\n", mParentName.AsString().c_str() );
d.Trace( dl, "---- Peers ---- (current has a * by it)\n" );
int cnt = 0;
for( FCOList::const_iterator iter = mPeers.begin(); iter != mPeers.end(); iter++, cnt++ )
{
d.Trace( dl, "[%d]%c\t:%s\n", cnt, iter == mCurPos ? _T('*') : _T(' '), (*iter)->GetName().AsString().c_str() );
}
d.Trace( dl, "--------------- \n" );
}
///////////////////////////////////////////////////////////////////////////////
// InsertIntoPeers
///////////////////////////////////////////////////////////////////////////////
// inserts the fco into peers.
// Sorted in increasing order by short name of the FCO.
bool cFCODataSourceIterImpl::InsertIntoPeers( iFCO* pFCO )
{
FCOList::iterator i = UpperBound( pFCO->GetName().GetShortName() );
if( i != mPeers.end() )
{
// never insert two objects that have the same name...
//
if( REL_EQ == Compare( pFCO->GetName().GetShortName(), (*i)->GetName().GetShortName() ) )
{
mpErrorBucket->AddError( eFCODataSourceIterDupeFCO( pFCO->GetName().AsString(), eError::NON_FATAL ) );
return false;
}
else
mPeers.insert( i, pFCO );
}
else
mPeers.push_back( pFCO );
return true;
}
///////////////////////////////////////////////////////////////////////////////
// SeekToPeerByName
///////////////////////////////////////////////////////////////////////////////
void cFCODataSourceIterImpl::SeekToPeerByName( const TCHAR* pchName )
{
FCOList::iterator i = UpperBound( pchName );
if( i != mPeers.end() )
{
if( REL_EQ == Compare( pchName, (*i)->GetName().GetShortName() ) )
{
mCurPos = i;
return;
}
}
mCurPos = mPeers.end();
}
///////////////////////////////////////////////////////////////////////////////
// CompareShortName
///////////////////////////////////////////////////////////////////////////////
bool cFCODataSourceIterImpl::CompareForUpperBound( const iFCO* pFCO, const TCHAR* pchName ) const
{
return( Compare( pFCO->GetName().GetShortName(), pchName ) == REL_LT );
}
///////////////////////////////////////////////////////////////////////////////
// cFCODataSourceIterImplCallCompare
// -- used to sneak a pointer-to-member-function where a
// pointer-to-non-member-function is expected
///////////////////////////////////////////////////////////////////////////////
class cFCODataSourceIterImplCallCompare
{
public:
cFCODataSourceIterImplCallCompare( const cFCODataSourceIterImpl* pcls )
: pc( pcls ) {};
bool operator()( const iFCO* a1, const TCHAR* a2 )
{
return pc->CompareForUpperBound( a1, a2 );
}
private:
const cFCODataSourceIterImpl* pc;
};
///////////////////////////////////////////////////////////////////////////////
// UpperBound
///////////////////////////////////////////////////////////////////////////////
cFCODataSourceIterImpl::FCOList::iterator cFCODataSourceIterImpl::UpperBound( const TCHAR* pchShortName )
{
cFCODataSourceIterImplCallCompare comp( this );
return ::UpperBound( mPeers.begin(), mPeers.end(), pchShortName, comp );
}