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

930 lines
26 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.
//
///////////////////////////////////////////////////////////////////////////////
// fcoreport.h
///////////////////////////////////////////////////////////////////////////////
#include "stdtw.h"
#include "fcoreport.h"
#include "fcoreportutil.h"
#include "fco/fcospeclist.h"
#include "fco/fcosetimpl.h"
#include "fco/fcosetws.h"
#include "fco/fcospecutil.h"
#include "fco/fcopropvector.h"
#include "core/serializer.h"
#include "core/debug.h"
#include "core/errorbucketimpl.h"
#include "fco/iterproxy.h"
#include "core/hashtable.h"
#include "core/fsservices.h"
#include "fco/fcospecattr.h"
#include "core/fileheader.h"
#include "headerinfo.h"
#include <time.h>
//=============================================================================
// class cFCOReport_i
//=============================================================================
class cFCOReport_i
{
public:
cFCOReport_i();
~cFCOReport_i();
// note that all iFCOs and all iFCOSpecs in this structure are AddRef()ed when added
// and will be Release()d when deleted.
struct cChangeNode
{
const iFCO* mpOldFCO;
const iFCO* mpNewFCO;
cFCOPropVector mChangeVector;
cChangeNode();
cChangeNode(const cChangeNode& rhs);
~cChangeNode();
void Clear();
};
struct cNode
{
iFCOSpec* mpSpec; // _must_ be valid (non-0)
const cFCOSpecAttr* mpSpecAttr; // _must_ be valid (non-0)
cFCOSetWS mAdded; // these two sets make sure their fcos are in mpSpec.
cFCOSetWS mRemoved;
std::list<cChangeNode> mChanged;
cErrorQueue mErrorQueue;
int32 mnObjectsScanned;
cNode();
cNode(const cNode& rhs);
~cNode();
void Clear();
};
typedef std::list<cNode> SpecList;
struct cGenreNode
{
cGenreNode() {};
cGenreNode( const cGenreNode& rhs );
cFCOReportGenreHeader mGenreHeader;
cGenre::Genre mGenre;
SpecList mSpecList;
};
typedef std::list<cGenreNode> GenreSpecList;
// data members
cErrorQueue mErrorQueue; // the general error queue
GenreSpecList mGenreList;
};
cFCOReport_i::cGenreNode::cGenreNode( const cFCOReport_i::cGenreNode& rhs )
: mGenreHeader( rhs.mGenreHeader ), mGenre( rhs.mGenre ), mSpecList( rhs.mSpecList )
{
}
cFCOReport_i::cFCOReport_i()
{
}
cFCOReport_i::~cFCOReport_i()
{
}
cFCOReport_i::cChangeNode::cChangeNode()
: mpOldFCO(0),
mpNewFCO(0)
{
}
cFCOReport_i::cChangeNode::cChangeNode(const cFCOReport_i::cChangeNode& rhs)
{
mpOldFCO = rhs.mpOldFCO;
if (mpOldFCO)
mpOldFCO->AddRef();
mpNewFCO = rhs.mpNewFCO;
if (mpNewFCO)
mpNewFCO->AddRef();
mChangeVector = rhs.mChangeVector;
}
cFCOReport_i::cChangeNode::~cChangeNode()
{
Clear();
}
void cFCOReport_i::cChangeNode::Clear()
{
if(mpOldFCO)
mpOldFCO->Release();
if(mpNewFCO)
mpNewFCO->Release();
mpOldFCO = mpNewFCO = 0;
}
cFCOReport_i::cNode::cNode() :
mpSpec(0),
mpSpecAttr(0),
mAdded(0),
mRemoved(0),
mnObjectsScanned(0)
{
}
cFCOReport_i::cNode::cNode(const cFCOReport_i::cNode& rhs)
: mAdded(rhs.mAdded),
mRemoved(rhs.mRemoved)
{
mpSpec = rhs.mpSpec;
if (mpSpec)
mpSpec->AddRef();
mpSpecAttr = rhs.mpSpecAttr;
if (mpSpecAttr)
mpSpecAttr->AddRef();
mChanged = rhs.mChanged;
mErrorQueue = rhs.mErrorQueue;
mnObjectsScanned = rhs.mnObjectsScanned;
}
cFCOReport_i::cNode::~cNode()
{
Clear();
}
void cFCOReport_i::cNode::Clear()
{
mAdded.Clear();
mAdded.SetSpec(0);
mRemoved.Clear();
mRemoved.SetSpec(0);
mChanged.clear();
mErrorQueue.Clear();
if(mpSpec)
mpSpec->Release();
if(mpSpecAttr)
mpSpecAttr->Release();
mpSpec = 0;
mpSpecAttr = 0;
mnObjectsScanned = 0;
}
//=============================================================================
// cFCOReportGenreIter
//=============================================================================
class cFCOReportGenreIter_i
{
public:
cFCOReport_i::GenreSpecList* mpList;
cFCOReport_i::GenreSpecList::iterator mIter;
};
cFCOReportGenreIter::cFCOReportGenreIter(const cFCOReport& report)
{
mpData = new cFCOReportGenreIter_i;
mpData->mpList = &report.mpData->mGenreList;
mpData->mIter = mpData->mpList->begin();
}
cFCOReportGenreIter::cFCOReportGenreIter(const cFCOReportGenreIter& rhs)
{
mpData = new cFCOReportGenreIter_i;
*this = rhs;
}
cFCOReportGenreIter::~cFCOReportGenreIter()
{
delete mpData;
}
void cFCOReportGenreIter::operator=(const cFCOReportGenreIter& rhs)
{
mpData->mpList = rhs.mpData->mpList;
mpData->mIter = rhs.mpData->mIter;
}
// iteration methods
void cFCOReportGenreIter::SeekBegin() const
{
mpData->mIter = mpData->mpList->begin();
}
void cFCOReportGenreIter::Next() const
{
++mpData->mIter;
}
bool cFCOReportGenreIter::Done() const
{
return mpData->mIter == mpData->mpList->end();
}
// seeks to specific genre. Returns false if genre does not exist in report
bool cFCOReportGenreIter::SeekToGenre(cGenre::Genre genre)
{
for (mpData->mIter = mpData->mpList->begin(); ; ++mpData->mIter)
{
if (mpData->mIter == mpData->mpList->end())
return false;
if (mpData->mIter->mGenre == genre)
break;
}
return true;
}
// removes the entire genre from report
void cFCOReportGenreIter::Remove()
{
ASSERT(!Done());
mpData->mIter = mpData->mpList->erase(mpData->mIter);
}
cFCOReportGenreHeader& cFCOReportGenreIter::GetGenreHeader() const
{
return mpData->mIter->mGenreHeader;
}
// Get current genre
cGenre::Genre cFCOReportGenreIter::GetGenre() const
{
if (mpData->mIter == mpData->mpList->end())
{
ASSERT(false);
return cGenre::GENRE_INVALID;
}
return mpData->mIter->mGenre;
}
//=============================================================================
// cFCOReportSpecIter
//=============================================================================
class cFCOReportSpecIter_i
{
public:
cFCOReport_i::SpecList* mpList;
cFCOReport_i::SpecList::iterator mIter;
};
/////////////////////////
// ctor and dtor
/////////////////////////
cFCOReportSpecIter::cFCOReportSpecIter(const cFCOReport& report, cGenre::Genre genre)
{
mpData = 0;
cFCOReport_i::GenreSpecList::iterator genreIter;
for (genreIter = report.mpData->mGenreList.begin(); ; ++genreIter)
{
if (genreIter == report.mpData->mGenreList.end())
{
ASSERT(false);
THROW_INTERNAL("fcoreport.cpp");
}
if (genreIter->mGenre == genre)
break;
}
mpData = new cFCOReportSpecIter_i();
mpData->mpList = &genreIter->mSpecList;
mpData->mIter = mpData->mpList->begin();
}
cFCOReportSpecIter::cFCOReportSpecIter(cFCOReport& report, cGenre::Genre genre)
{
mpData = 0;
cFCOReport_i::GenreSpecList::iterator genreIter;
for (genreIter = report.mpData->mGenreList.begin(); ; ++genreIter)
{
if (genreIter == report.mpData->mGenreList.end())
{
// add an empty spec to the report
report.AddSpec(genre, 0, 0, 0);
genreIter = report.mpData->mGenreList.end();
--genreIter;
ASSERT(genreIter->mGenre == genre);
}
if (genreIter->mGenre == genre)
break;
}
mpData = new cFCOReportSpecIter_i();
mpData->mpList = &genreIter->mSpecList;
mpData->mIter = mpData->mpList->begin();
}
cFCOReportSpecIter::cFCOReportSpecIter(const cFCOReportGenreIter& genreIter)
{
mpData = new cFCOReportSpecIter_i();
mpData->mpList = &genreIter.mpData->mIter->mSpecList;
mpData->mIter = mpData->mpList->begin();
}
cFCOReportSpecIter::~cFCOReportSpecIter()
{
delete mpData;
}
cFCOReportSpecIter::cFCOReportSpecIter(const cFCOReportSpecIter& rhs)
{
mpData = new cFCOReportSpecIter_i();
*this = rhs;
}
void cFCOReportSpecIter::operator=(const cFCOReportSpecIter& rhs)
{
if (mpData == 0)
mpData = new cFCOReportSpecIter_i();
mpData->mpList = rhs.mpData->mpList;
mpData->mIter = rhs.mpData->mIter;
}
int cFCOReportSpecIter::GetNumChanged() const
{
ASSERT(! Done());
return mpData ? mpData->mIter->mChanged.size() : 0;
}
void cFCOReportSpecIter::SetObjectsScanned( int nObjectsScanned )
{
ASSERT(mpData != 0);
if (mpData == 0)
THROW_INTERNAL("fcoreport.cpp");
mpData->mIter->mnObjectsScanned = nObjectsScanned;
}
int cFCOReportSpecIter::GetObjectsScanned() const
{
ASSERT(! Done());
return mpData ? mpData->mIter->mnObjectsScanned : 0;
}
void cFCOReportSpecIter::Remove()
{
ASSERT(! Done());
mpData->mIter->Clear();
mpData->mIter = mpData->mpList->erase(mpData->mIter);
}
/////////////////////////
// iteration methods
/////////////////////////
void cFCOReportSpecIter::SeekBegin() const
{
if (mpData)
mpData->mIter = mpData->mpList->begin();
}
void cFCOReportSpecIter::Next() const
{
ASSERT(mpData != 0);
mpData->mIter++;
}
bool cFCOReportSpecIter::Done() const
{
return mpData ? (mpData->mIter == mpData->mpList->end()) : true;
}
const iFCOSpec* cFCOReportSpecIter::GetSpec() const
{
ASSERT(! Done());
return mpData ? (mpData->mIter->mpSpec) : 0;
}
bool cFCOReportSpecIter::SeekToSpec(const iFCOSpec* pSpec)
{
if (mpData)
for(mpData->mIter = mpData->mpList->begin(); mpData->mIter != mpData->mpList->end(); mpData->mIter++)
{
if(iFCOSpecUtil::FCOSpecEqual(*mpData->mIter->mpSpec, *pSpec))
return true;
}
return false;
}
const cFCOSpecAttr* cFCOReportSpecIter::GetAttr() const
{
ASSERT(! Done());
return mpData ? (mpData->mIter->mpSpecAttr) : 0;
}
const cErrorQueue* cFCOReportSpecIter::GetErrorQueue() const
{
ASSERT(! Done());
return mpData ? (&mpData->mIter->mErrorQueue) : 0;
}
cErrorQueue* cFCOReportSpecIter::GetErrorQueue()
{
ASSERT(! Done());
return mpData ? (&mpData->mIter->mErrorQueue) : 0;
}
const iFCOSet* cFCOReportSpecIter::GetAddedSet() const
{
ASSERT(! Done());
return mpData ? (&mpData->mIter->mAdded) : 0;
}
iFCOSet* cFCOReportSpecIter::GetAddedSet()
{
ASSERT(! Done());
return mpData ? (&mpData->mIter->mAdded) : 0;
}
const iFCOSet* cFCOReportSpecIter::GetRemovedSet() const
{
ASSERT(! Done());
return mpData ? (&mpData->mIter->mRemoved) : 0;
}
iFCOSet* cFCOReportSpecIter::GetRemovedSet()
{
ASSERT(! Done());
return mpData ? (&mpData->mIter->mRemoved) : 0;
}
//=============================================================================
// class cFCOReportChangeIter
//=============================================================================
class cFCOReportChangeIter_i
{
public:
std::list<cFCOReport_i::cChangeNode>* mpList;
std::list<cFCOReport_i::cChangeNode>::iterator mIter;
};
cFCOReportChangeIter::cFCOReportChangeIter(const cFCOReportSpecIter& specIter)
{
ASSERT(!specIter.Done());
mpData = new cFCOReportChangeIter_i;
SetSpecIter(specIter);
}
cFCOReportChangeIter::cFCOReportChangeIter(const cFCOReportChangeIter& rhs)
{
mpData = new cFCOReportChangeIter_i;
*this = rhs;
}
cFCOReportChangeIter::~cFCOReportChangeIter()
{
delete mpData;
}
void cFCOReportChangeIter::operator=(const cFCOReportChangeIter& rhs)
{
mpData->mpList = rhs.mpData->mpList;
mpData->mIter = rhs.mpData->mIter;
}
void cFCOReportChangeIter::SetSpecIter(const cFCOReportSpecIter& specIter)
{
ASSERT(! specIter.Done());
mpData->mpList = &specIter.mpData->mIter->mChanged;
mpData->mIter = mpData->mpList->begin();
}
///////////////////////////////////////////////////////////////////////////////
// Remove
///////////////////////////////////////////////////////////////////////////////
void cFCOReportChangeIter::Remove()
{
ASSERT(! Done());
mpData->mIter->Clear();
mpData->mIter = mpData->mpList->erase(mpData->mIter);
}
void cFCOReportChangeIter::SeekBegin() const
{
ASSERT(mpData->mpList != 0);
mpData->mIter = mpData->mpList->begin();
}
void cFCOReportChangeIter::Next() const
{
ASSERT(mpData->mpList != 0);
mpData->mIter++;
}
bool cFCOReportChangeIter::Done() const
{
ASSERT(mpData->mpList != 0);
if(! mpData->mpList)
return true;
return (mpData->mIter == mpData->mpList->end());
}
const iFCO* cFCOReportChangeIter::GetOld() const
{
ASSERT(! Done());
return (mpData->mIter->mpOldFCO);
}
const iFCO* cFCOReportChangeIter::GetNew() const
{
ASSERT(! Done());
return (mpData->mIter->mpNewFCO);
}
const cFCOPropVector& cFCOReportChangeIter::GetChangeVector() const
{
ASSERT(! Done());
return (mpData->mIter->mChangeVector);
}
//=============================================================================
// class cFCOReport
//=============================================================================
IMPLEMENT_TYPEDSERIALIZABLE(cFCOReport, _T("cFCOReport"), 0, 1);
cFCOReport::cFCOReport()
{
mpData = new cFCOReport_i;
}
cFCOReport::~cFCOReport()
{
ClearReport();
delete mpData;
}
////////////////////////////////////////////////////////////
cErrorQueue* cFCOReport::GetErrorQueue()
{
return &mpData->mErrorQueue;
}
const cErrorQueue* cFCOReport::GetErrorQueue() const
{
return &mpData->mErrorQueue;
}
///////////////////////////////////////////////////////////////////////////////
// GetNumSpecs
///////////////////////////////////////////////////////////////////////////////
int cFCOReport::GetNumSpecs(cGenre::Genre genre) const
{
cFCOReport_i::GenreSpecList::iterator genreIter;
for (genreIter = mpData->mGenreList.begin(); ; ++genreIter)
{
if (genreIter == mpData->mGenreList.end())
{
return 0;
}
if (genreIter->mGenre == genre)
break;
}
return genreIter->mSpecList.size();
}
///////////////////////////////////////////////////////////////////////////////
// ClearReport
///////////////////////////////////////////////////////////////////////////////
void cFCOReport::ClearReport()
{
mpData->mGenreList.clear();
}
///////////////////////////////////////////////////////////////////////////////
// AddSpec
///////////////////////////////////////////////////////////////////////////////
void cFCOReport::AddSpec(cGenre::Genre genre, const iFCOSpec* pSpec, const cFCOSpecAttr* pAttr, cFCOReportSpecIter* pIter)
{
// look up the genre
cFCOReport_i::GenreSpecList::iterator genreIter;
for (genreIter = mpData->mGenreList.begin(); ; ++genreIter)
{
if (genreIter == mpData->mGenreList.end())
{
cFCOReport_i::cGenreNode newGenre;
newGenre.mGenre = genre;
mpData->mGenreList.push_back(newGenre);
genreIter = mpData->mGenreList.end();
--genreIter;
break;
}
if (genreIter->mGenre == genre)
break;
}
if (pSpec == 0)
{
ASSERT(pAttr == 0);
ASSERT(pIter == 0);
return;
}
// make sure this spec doesn't overlap any others
cFCOReport_i::SpecList::iterator specIter;
for(specIter = genreIter->mSpecList.begin(); specIter != genreIter->mSpecList.end(); ++specIter)
{
// TODO -- what is the right action to take?
if(iFCOSpecUtil::SpecsOverlap(pSpec, specIter->mpSpec))
{
ASSERT(false);
THROW_INTERNAL("fcoreport.cpp");
}
}
genreIter->mSpecList.push_back(cFCOReport_i::cNode());
cFCOReport_i::cNode& node = genreIter->mSpecList.back();
node.mpSpec = pSpec->Clone();
node.mpSpecAttr = pAttr;
pAttr->AddRef();
node.mAdded.SetSpec(node.mpSpec);
node.mRemoved.SetSpec(node.mpSpec);
// fill out the iterator
if (pIter && pIter->mpData && pIter->mpData->mpList == &genreIter->mSpecList)
{
pIter->mpData->mIter = genreIter->mSpecList.end();
pIter->mpData->mIter--;
ASSERT(pIter->GetSpec() == node.mpSpec);
}
}
///////////////////////////////////////////////////////////////////////////////
// AddChangedFCO
///////////////////////////////////////////////////////////////////////////////
void cFCOReport::AddChangedFCO(const cFCOReportSpecIter& iter, const iFCO* pOldFCO, const iFCO* pNewFCO, const cFCOPropVector& changedProps)
{
cDebug d("cFCOReport::AddChangedFCO");
// make some assertions about the iterator
#ifdef _DEBUG
// make sure iter points to one of our spec lists
cFCOReport_i::GenreSpecList::iterator genreIter;
for (genreIter = mpData->mGenreList.begin(); ; ++genreIter)
{
if (genreIter == mpData->mGenreList.end())
{
ASSERT(false);
THROW_INTERNAL("fcoreport.cpp");
}
if (&genreIter->mSpecList == iter.mpData->mpList)
break;
}
#endif
ASSERT(! iter.Done()); // make sure it points to something valid
// some sanity checking for the fco names...
ASSERT(pOldFCO->GetName().IsEqual(pNewFCO->GetName()));
ASSERT((iter.GetSpec()->SpecContainsFCO(pOldFCO->GetName())));
iter.mpData->mIter->mChanged.push_back(cFCOReport_i::cChangeNode());
cFCOReport_i::cChangeNode& changeNode = iter.mpData->mIter->mChanged.back();
changeNode.mpOldFCO = pOldFCO;
changeNode.mpNewFCO = pNewFCO;
changeNode.mChangeVector = changedProps;
pOldFCO->AddRef();
pNewFCO->AddRef();
}
///////////////////////////////////////////////////////////////////////////////
// iSerializable interface
///////////////////////////////////////////////////////////////////////////////
void cFCOReport::Read(iSerializer* pSerializer, int32 version)
{
if (version > Version())
ThrowAndAssert(eSerializerVersionMismatch(_T("Report Read")));
ClearReport();
// read in main error queue
pSerializer->ReadObject(&mpData->mErrorQueue);
// read in the genres
int32 genreIter, genreCount;
int32 specIter, specCount;
pSerializer->ReadInt32(genreCount);
for (genreIter = 0; genreIter < genreCount; genreIter++)
{
cFCOReport_i::cGenreNode newGenre;
int32 genre;
// TODO:BAM -- this used to be int16, so take care of backwards compatability
pSerializer->ReadInt32(genre);
newGenre.mGenre = (cGenre::Genre)genre;
pSerializer->ReadObject( &newGenre.mGenreHeader );
pSerializer->ReadInt32(specCount);
for (specIter = 0; specIter < specCount; specIter++)
{
newGenre.mSpecList.push_back(cFCOReport_i::cNode());
cFCOReport_i::cNode& node = newGenre.mSpecList.back();
node.mpSpec = static_cast<iFCOSpec*> (pSerializer->ReadObjectDynCreate());
node.mpSpecAttr = static_cast<cFCOSpecAttr*>(pSerializer->ReadObjectDynCreate());
pSerializer->ReadObject(&node.mErrorQueue);
pSerializer->ReadObject(&node.mAdded);
pSerializer->ReadObject(&node.mRemoved);
pSerializer->ReadInt32( node.mnObjectsScanned );
node.mAdded.SetSpec(node.mpSpec);
node.mRemoved.SetSpec(node.mpSpec);
int32 changeSize;
pSerializer->ReadInt32(changeSize);
for(int j=0; j<changeSize; j++)
{
node.mChanged.push_back(cFCOReport_i::cChangeNode());
cFCOReport_i::cChangeNode& cnode = node.mChanged.back();
cnode.mpOldFCO = static_cast<iFCO*>(pSerializer->ReadObjectDynCreate());
cnode.mpNewFCO = static_cast<iFCO*>(pSerializer->ReadObjectDynCreate());
cnode.mChangeVector.Read(pSerializer);
}
}
mpData->mGenreList.push_back(newGenre);
}
// TODO -- we should do some kind of test here to ensure that all the data we read
// is consistant (ie -- no overlapping specs)
}
void cFCOReport::Write(iSerializer* pSerializer) const
{
cFCOReport_i::GenreSpecList::iterator genreIter;
cFCOReport_i::SpecList::iterator specIter;
// write out the main error queue
pSerializer->WriteObject(&mpData->mErrorQueue);
// iteratate over genres
pSerializer->WriteInt32(mpData->mGenreList.size());
for (genreIter = mpData->mGenreList.begin(); genreIter != mpData->mGenreList.end(); ++genreIter)
{
// TODO:BAM -- this used to be int16, so take care of backwards compatability
pSerializer->WriteInt32(genreIter->mGenre);
pSerializer->WriteObject( &genreIter->mGenreHeader );
// write each node out...
pSerializer->WriteInt32(genreIter->mSpecList.size());
for (specIter = genreIter->mSpecList.begin(); specIter != genreIter->mSpecList.end(); ++specIter)
{
pSerializer->WriteObjectDynCreate(specIter->mpSpec);
pSerializer->WriteObjectDynCreate(specIter->mpSpecAttr);
pSerializer->WriteObject(&specIter->mErrorQueue);
pSerializer->WriteObject(&specIter->mAdded);
pSerializer->WriteObject(&specIter->mRemoved);
pSerializer->WriteInt32( specIter->mnObjectsScanned );
std::list<cFCOReport_i::cChangeNode>::iterator changedIter;
pSerializer->WriteInt32(specIter->mChanged.size());
for(changedIter = specIter->mChanged.begin(); changedIter != specIter->mChanged.end(); ++changedIter)
{
pSerializer->WriteObjectDynCreate(changedIter->mpOldFCO);
pSerializer->WriteObjectDynCreate(changedIter->mpNewFCO);
changedIter->mChangeVector.Write(pSerializer);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// GetFileHeaderID()
///////////////////////////////////////////////////////////////////////////////
struct cFCOReportFHID {
cFileHeaderID* ReportID;
cFCOReportFHID() { ReportID = 0; }
~cFCOReportFHID() { delete ReportID; }
} gFCOReportFHID;
const cFileHeaderID& cFCOReport::GetFileHeaderID()
{
if (gFCOReportFHID.ReportID == 0)
gFCOReportFHID.ReportID = new cFileHeaderID(CLASS_TYPE(cFCOReport).AsString());
// sanity check
ASSERT(*gFCOReportFHID.ReportID == cFileHeaderID(CLASS_TYPE(cFCOReport).AsString()));
return *gFCOReportFHID.ReportID;
}
void cFCOReport::TraceContents(int dl) const
{
if(dl < 0)
dl = cDebug::D_DEBUG;
cDebug d("cFCOReport:");
d.TraceDebug("Global Error Queue:\n");
mpData->mErrorQueue.TraceContents(dl);
cFCOReport_i::GenreSpecList::iterator genreIter;
cFCOReport_i::SpecList::iterator specIter;
for (genreIter = mpData->mGenreList.begin(); genreIter != mpData->mGenreList.end(); ++genreIter)
{
d.Trace(dl, "> Genre [%d]:\n", (int)genreIter->mGenre);
int specCount = 0;
for (specIter = genreIter->mSpecList.begin(); specIter != genreIter->mSpecList.end(); ++specIter, ++specCount)
{
d.Trace(dl, ">>> Spec [%d]:\n", specCount);
ASSERT(specIter->mpSpec != 0);
specIter->mpSpec->TraceContents(dl);
specIter->mpSpecAttr->TraceContents(dl);
specIter->mErrorQueue.TraceContents(dl);
// trace out added & removed files
d.TraceDebug(">>> Added Files:\n");
specIter->mAdded.TraceContents(dl);
d.TraceDebug(">>> Removed Files:\n");
specIter->mRemoved.TraceContents(dl);
// trace out changed files
d.TraceDebug(">>> Changed Files:\n");
std::list<cFCOReport_i::cChangeNode>::iterator changedIter;
int changeCounter = 0;
for (changedIter = specIter->mChanged.begin(); changedIter != specIter->mChanged.end(); ++changedIter, ++changeCounter)
{
d.Trace(dl, ">>>>> Changed fco [%d]\n", changeCounter);
d.Trace(dl, ">>>>> Old FCO:\n");
(*changedIter).mpOldFCO->TraceContents(dl);
d.Trace(dl, ">>>>> New FCO:\n");
(*changedIter).mpNewFCO->TraceContents(dl);
(*changedIter).mChangeVector.TraceContents(dl);
}
}
}
}