/*==LICENSE==*
CyanWorlds . com Engine - MMOG client , server and tools
Copyright ( C ) 2011 Cyan Worlds , Inc .
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . 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 , see < http : //www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program , or any covered work , by linking or
combining it with any of RAD Game Tools Bink SDK , Autodesk 3 ds Max SDK ,
NVIDIA PhysX SDK , Microsoft DirectX SDK , OpenSSL library , Independent
JPEG Group JPEG library , Microsoft Windows Media SDK , or Apple QuickTime SDK
( or a modified version of those libraries ) ,
containing parts covered by the terms of the Bink SDK EULA , 3 ds Max EULA ,
PhysX SDK EULA , DirectX SDK EULA , OpenSSL and SSLeay licenses , IJG
JPEG Library README , Windows Media SDK EULA , or QuickTime SDK EULA , the
licensors of this Program grant you additional
permission to convey the resulting work . Corresponding Source for a
non - source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work .
You can contact Cyan Worlds , Inc . by email legal @ cyan . com
or by snail mail at :
Cyan Worlds , Inc .
14617 N Newport Hwy
Mead , WA 99021
* = = LICENSE = = */
//////////////////////////////////////////////////////////////////////////////
//
// plResManagerHelper - The wonderful helper class that can receive messages
// for the resManager.
//
//// History /////////////////////////////////////////////////////////////////
//
// 6.7.2002 mcn - Created
//
//////////////////////////////////////////////////////////////////////////////
# include "HeadSpin.h"
# include "plResManagerHelper.h"
# include "plResManager.h"
# include "plRegistryNode.h"
# include "plRegistryHelpers.h"
//#include "plRegistry.h"
# include "plResMgrSettings.h"
# include "pnKeyedObject/plFixedKey.h"
# include "plMessage/plResMgrHelperMsg.h"
# include "plStatusLog/plStatusLog.h"
# include "hsTimer.h"
# ifdef MCN_RESMGR_DEBUGGING
static const int kLogSize = 40 ;
static const float kUpdateDelay = 0.5f ;
# include "plInputCore/plInputInterface.h"
# include "plInputCore/plInputDevice.h"
# include "plInputCore/plInputInterfaceMgr.h"
# include "pnInputCore/plInputMap.h"
# include "plMessage/plInputEventMsg.h"
# include "plMessage/plInputIfaceMgrMsg.h"
# include "pnKeyedObject/plKeyImp.h"
# endif
/// Logging #define for easier use
# define kResMgrLog( level ) if( plResMgrSettings::Get().GetLoggingLevel() >= level ) plStatusLog::AddLineS( "resources.log",
//// Constructor/Destructor //////////////////////////////////////////////////
plResManagerHelper * plResManagerHelper : : fInstance = nil ;
plResManagerHelper : : plResManagerHelper ( plResManager * resMgr )
{
fResManager = resMgr ;
fInstance = this ;
fInShutdown = false ;
# ifdef MCN_RESMGR_DEBUGGING
fDebugScreen = nil ;
fCurrAge = - 1 ;
fCurrAgeExpanded = false ;
fRefreshing = false ;
fDebugDisplayType = 0 ;
# endif
}
plResManagerHelper : : ~ plResManagerHelper ( )
{
fInstance = nil ;
}
//// Shutdown ////////////////////////////////////////////////////////////////
void plResManagerHelper : : Shutdown ( void )
{
EnableDebugScreen ( false ) ;
UnRegisterAs ( kResManagerHelper_KEY ) ;
}
//// Init ////////////////////////////////////////////////////////////////////
void plResManagerHelper : : Init ( void )
{
RegisterAs ( kResManagerHelper_KEY ) ;
}
//// MsgReceive //////////////////////////////////////////////////////////////
bool plResManagerHelper : : MsgReceive ( plMessage * msg )
{
plResMgrHelperMsg * refferMsg = plResMgrHelperMsg : : ConvertNoRef ( msg ) ;
if ( refferMsg ! = nil )
{
if ( refferMsg - > GetCommand ( ) = = plResMgrHelperMsg : : kKeyRefList )
{
// Message to let go of these keys. So unref the key list, destroy it and we're done!
kResMgrLog ( 2 ) 0xff80ff80 , " Dropping page keys after timed delay " ) ;
hsStatusMessage ( " *** Dropping page keys after timed delay *** " ) ;
delete refferMsg - > fKeyList ;
refferMsg - > fKeyList = nil ;
}
else if ( refferMsg - > GetCommand ( ) = = plResMgrHelperMsg : : kUpdateDebugScreen )
{
IUpdateDebugScreen ( ) ;
}
else if ( refferMsg - > GetCommand ( ) = = plResMgrHelperMsg : : kEnableDebugScreen )
EnableDebugScreen ( true ) ;
else if ( refferMsg - > GetCommand ( ) = = plResMgrHelperMsg : : kDisableDebugScreen )
EnableDebugScreen ( false ) ;
return true ;
}
return hsKeyedObject : : MsgReceive ( msg ) ;
}
//// Read/Write //////////////////////////////////////////////////////////////
void plResManagerHelper : : Read ( hsStream * s , hsResMgr * mgr )
{
hsAssert ( false , " You should never read me in! " ) ;
}
void plResManagerHelper : : Write ( hsStream * s , hsResMgr * mgr )
{
hsAssert ( false , " You should never write me out! " ) ;
}
//// LoadAndHoldPageKeys /////////////////////////////////////////////////////
// Loads and refs the keys for the given page, then sends the ref list as
// a list to ourself, time delayed 1 second, so that we can unref them one
// second later.
void plResManagerHelper : : LoadAndHoldPageKeys ( plRegistryPageNode * page )
{
hsAssert ( GetKey ( ) ! = nil , " Can't load and hold keys when we don't have a key for the helper " ) ;
// Create our msg
plResMgrHelperMsg * refferMsg = new plResMgrHelperMsg ( plResMgrHelperMsg : : kKeyRefList ) ;
refferMsg - > fKeyList = new plResPageKeyRefList ;
fResManager - > LoadPageKeys ( page ) ;
page - > IterateKeys ( refferMsg - > fKeyList ) ;
// Load and ref the keys
# ifdef HS_DEBUGGING
char msg [ 256 ] ;
sprintf ( msg , " *** Temporarily loading keys for room %s>%s based on FindKey() query, will drop in 1 sec *** " , page - > GetPageInfo ( ) . GetAge ( ) , page - > GetPageInfo ( ) . GetPage ( ) ) ;
hsStatusMessage ( msg ) ;
# endif
kResMgrLog ( 2 ) 0xff80ff80 , " Temporarily loading keys for room %s>%s, will drop in 1 sec " , page - > GetPageInfo ( ) . GetAge ( ) , page - > GetPageInfo ( ) . GetPage ( ) ) ;
// Deliver the message to ourselves!
refferMsg - > SetTimeStamp ( hsTimer : : GetSysSeconds ( ) + 1.f ) ;
refferMsg - > Send ( GetKey ( ) ) ;
}
# ifdef MCN_RESMGR_DEBUGGING
//////////////////////////////////////////////////////////////////////////////
//// plResMgrDebugInterface Definition ///////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class plResMgrDebugInterface : public plInputInterface
{
protected :
plResManagerHelper * const fParent ;
virtual ControlEventCode * IGetOwnedCodeList ( void ) const
{
static ControlEventCode codes [ ] = { END_CONTROLS } ;
return codes ;
}
public :
plResMgrDebugInterface ( plResManagerHelper * const mgr ) : fParent ( mgr ) { SetEnabled ( true ) ; }
virtual uint32_t GetPriorityLevel ( void ) const { return kGUISystemPriority + 10 ; }
virtual bool InterpretInputEvent ( plInputEventMsg * pMsg )
{
plKeyEventMsg * pKeyMsg = plKeyEventMsg : : ConvertNoRef ( pMsg ) ;
if ( pKeyMsg ! = nil & & pKeyMsg - > GetKeyDown ( ) )
{
if ( pKeyMsg - > GetKeyCode ( ) = = KEY_UP & & fParent - > fCurrAge > = 0 )
{
fParent - > fCurrAge - - ;
fParent - > IUpdateDebugScreen ( true ) ;
return true ;
}
else if ( pKeyMsg - > GetKeyCode ( ) = = KEY_DOWN )
{
fParent - > fCurrAge + + ;
fParent - > IUpdateDebugScreen ( true ) ;
return true ;
}
else if ( pKeyMsg - > GetKeyCode ( ) = = KEY_ENTER )
{
fParent - > fCurrAgeExpanded = ! fParent - > fCurrAgeExpanded ;
fParent - > IUpdateDebugScreen ( true ) ;
return true ;
}
else if ( pKeyMsg - > GetKeyCode ( ) = = KEY_ESCAPE )
{
plResMgrHelperMsg * msg = new plResMgrHelperMsg ( plResMgrHelperMsg : : kDisableDebugScreen ) ;
msg - > Send ( fParent - > GetKey ( ) ) ;
return true ;
}
else if ( pKeyMsg - > GetKeyCode ( ) = = KEY_RIGHT )
{
if ( ! fParent - > fCurrAgeExpanded )
fParent - > fCurrAgeExpanded = true ;
else
{
fParent - > fDebugDisplayType + + ;
if ( fParent - > fDebugDisplayType = = plResManagerHelper : : kMaxDisplayType )
fParent - > fDebugDisplayType = 0 ;
}
fParent - > IUpdateDebugScreen ( true ) ;
return true ;
}
else if ( pKeyMsg - > GetKeyCode ( ) = = KEY_LEFT )
{
fParent - > fCurrAgeExpanded = false ;
fParent - > IUpdateDebugScreen ( true ) ;
return true ;
}
}
return false ;
}
virtual uint32_t GetCurrentCursorID ( void ) const { return 0 ; }
virtual bool HasInterestingCursorID ( void ) const { return false ; }
} ;
# endif
//// EnableDebugScreen ///////////////////////////////////////////////////////
void plResManagerHelper : : EnableDebugScreen ( bool enable )
{
# ifdef MCN_RESMGR_DEBUGGING
if ( enable )
{
if ( fDebugScreen = = nil )
{
fDebugScreen = plStatusLogMgr : : GetInstance ( ) . CreateStatusLog ( kLogSize , " ResManager Status " , plStatusLog : : kFilledBackground | plStatusLog : : kDontWriteFile ) ;
fRefreshing = true ;
plResMgrHelperMsg * msg = new plResMgrHelperMsg ( plResMgrHelperMsg : : kUpdateDebugScreen ) ;
// msg->SetTimeStamp( hsTimer::GetSysSeconds() + kUpdateDelay );
msg - > Send ( GetKey ( ) ) ;
fDebugInput = new plResMgrDebugInterface ( this ) ;
plInputIfaceMgrMsg * imsg = new plInputIfaceMgrMsg ( plInputIfaceMgrMsg : : kAddInterface ) ;
imsg - > SetIFace ( fDebugInput ) ;
imsg - > Send ( ) ;
}
}
else
{
fRefreshing = false ;
if ( fDebugScreen ! = nil )
{
delete fDebugScreen ;
fDebugScreen = nil ;
plInputIfaceMgrMsg * imsg = new plInputIfaceMgrMsg ( plInputIfaceMgrMsg : : kRemoveInterface ) ;
imsg - > SetIFace ( fDebugInput ) ;
imsg - > Send ( ) ;
hsRefCnt_SafeUnRef ( fDebugInput ) ;
fDebugInput = nil ;
}
}
# endif
}
//// IUpdateDebugScreen /////////////////////////////////////////////////////
# ifdef MCN_RESMGR_DEBUGGING
class plDebugPrintIterator : public plRegistryPageIterator , plRegistryKeyIterator
{
public :
plStatusLog * fLog ;
uint8_t fStep , fLines ;
uint32_t & fLoadedCount , & fHoldingCount , fPageCount , fAgeIndex ;
char fCurrAge [ 128 ] ;
uint32_t fLoadedKeys , fTotalKeys , fTotalSize , fLoadedSize ;
plResManagerHelper * fParent ;
plDebugPrintIterator ( plResManagerHelper * parent , plStatusLog * log , uint32_t & loadedCount , uint32_t & holdingCount )
: fParent ( parent ) , fLog ( log ) , fStep ( 0 ) , fLines ( 0 ) , fLoadedCount ( loadedCount ) , fHoldingCount ( holdingCount )
{
fLoadedCount = fHoldingCount = 0 ;
fCurrAge [ 0 ] = 0 ;
fPageCount = 0 ;
fAgeIndex = 0 ;
}
virtual bool EatPage ( plRegistryPageNode * page )
{
if ( fStep = = 0 )
{
fLog - > AddLineF ( 0xff80ff80 , " Loaded Pages " ) ;
fStep = 1 ;
fLines + + ;
}
else if ( fStep = = 1 & & page ! = nil & & ! page - > IsLoaded ( ) )
{
fStep = 2 ;
fLog - > AddLineF ( 0xff80ff80 , " Holding Pages " ) ;
fLines + + ;
}
if ( page ! = nil & & page - > IsLoaded ( ) )
fLoadedCount + + ;
else if ( page ! = nil )
fHoldingCount + + ;
// Changed ages?
if ( page = = nil | | strcmp ( fCurrAge , page - > GetPageInfo ( ) . GetAge ( ) ) ! = 0 )
{
// Print some info for the last age we were on
if ( fCurrAge [ 0 ] ! = 0 )
{
if ( fParent - > fCurrAge ! = fAgeIndex | | ! fParent - > fCurrAgeExpanded )
{
if ( fLines < kLogSize - 4 )
{
uint32_t color = plStatusLog : : kWhite ;
if ( fParent - > fCurrAge = = fAgeIndex )
color = plStatusLog : : kYellow ;
fLog - > AddLineF ( color , " %s (%d pages) " , fCurrAge , fPageCount ) ;
fLines + + ;
}
else if ( fLines = = kLogSize - 4 )
{
fLog - > AddLineF ( plStatusLog : : kWhite , " ... " ) ;
fLines + + ;
}
}
fAgeIndex + + ;
}
fPageCount = 0 ;
if ( page ! = nil )
strncpy ( fCurrAge , page - > GetPageInfo ( ) . GetAge ( ) , sizeof ( fCurrAge ) - 1 ) ;
else
fCurrAge [ 0 ] = 0 ;
if ( fParent - > fCurrAge = = fAgeIndex & & fParent - > fCurrAgeExpanded )
{
// Print header now, since we won't be printing a footer
if ( fLines < kLogSize - 4 )
{
fLog - > AddLineF ( plStatusLog : : kYellow , " %s> " , fCurrAge ) ;
fLines + + ;
}
else if ( fLines = = kLogSize - 4 )
{
fLog - > AddLineF ( plStatusLog : : kWhite , " ... " ) ;
fLines + + ;
}
}
}
fPageCount + + ;
if ( fParent - > fCurrAge = = fAgeIndex & & fParent - > fCurrAgeExpanded & & page ! = nil )
{
// Count keys for this page
fTotalKeys = fLoadedKeys = fTotalSize = fLoadedSize = 0 ;
page - > IterateKeys ( this ) ;
// Print page for this expanded age view
if ( fLines < kLogSize - 4 )
{
if ( fParent - > fDebugDisplayType = = plResManagerHelper : : kSizes )
fLog - > AddLineF ( plStatusLog : : kWhite , " %s (%d keys @ %4.1fk, %d loaded @ %4.1fk) " , page - > GetPageInfo ( ) . GetPage ( ) , fTotalKeys , fTotalSize / 1024.f , fLoadedKeys , fLoadedSize / 1024.f ) ;
else if ( fParent - > fDebugDisplayType = = plResManagerHelper : : kPercents )
fLog - > AddLineF ( plStatusLog : : kWhite , " %s (%d%% loaded of %d keys @ %4.1fk) " , page - > GetPageInfo ( ) . GetPage ( ) , fLoadedSize * 100 / ( fTotalSize > 0 ? fTotalSize : - 1 ) , fTotalKeys , fTotalSize / 1024.f ) ;
else //if( fParent->fDebugDisplayType == plResManagerHelper::kBars )
{
const int startPos = 20 , length = 32 ;
char line [ 128 ] ;
memset ( line , ' ' , sizeof ( line ) - 1 ) ;
line [ 127 ] = 0 ;
if ( strlen ( page - > GetPageInfo ( ) . GetPage ( ) ) < startPos - 2 )
memcpy ( line + 2 , page - > GetPageInfo ( ) . GetPage ( ) , strlen ( page - > GetPageInfo ( ) . GetPage ( ) ) ) ;
else
memcpy ( line + 2 , page - > GetPageInfo ( ) . GetPage ( ) , startPos - 2 ) ;
line [ startPos ] = ' | ' ;
if ( fTotalSize = = 0 )
{
line [ startPos + 1 ] = ' | ' ;
line [ startPos + 2 ] = 0 ;
}
else
{
char temp [ 12 ] ;
sprintf ( temp , " %d%% " , fLoadedSize * 100 / fTotalSize ) ;
line [ startPos + length + 1 ] = ' | ' ;
int i , sum = 0 ;
for ( i = startPos + 1 ; i < startPos + length + 1 & & sum < fLoadedSize ; i + + )
{
line [ i ] = ' = ' ;
sum + = fTotalSize / length ;
}
line [ startPos + length + 2 ] = 0 ;
memcpy ( line + startPos + 1 , temp , strlen ( temp ) ) ;
}
fLog - > AddLine ( line , plStatusLog : : kWhite ) ;
}
fLines + + ;
}
else if ( fLines = = kLogSize - 4 )
{
fLog - > AddLineF ( plStatusLog : : kWhite , " ... " ) ;
fLines + + ;
}
}
return true ;
}
virtual bool EatKey ( const plKey & key )
{
if ( key - > ObjectIsLoaded ( ) )
{
fLoadedKeys + + ;
fLoadedSize + = ( ( plKeyImp * ) key ) - > GetDataLen ( ) ;
}
fTotalKeys + + ;
fTotalSize + = ( ( plKeyImp * ) key ) - > GetDataLen ( ) ;
return true ;
}
} ;
# endif
void plResManagerHelper : : IUpdateDebugScreen ( bool force )
{
# ifdef MCN_RESMGR_DEBUGGING
if ( ! fRefreshing )
return ;
plRegistry * reg = fResManager - > IGetRegistry ( ) ;
uint32_t loadedCnt , holdingCnt ;
fDebugScreen - > Clear ( ) ;
plDebugPrintIterator iter ( this , fDebugScreen , loadedCnt , holdingCnt ) ;
reg - > IterateAllPages ( & iter ) ;
iter . EatPage ( nil ) ; // Force a final update
fDebugScreen - > AddLineF ( plStatusLog : : kGreen , " %d pages loaded, %d holding " , loadedCnt , holdingCnt ) ;
if ( fCurrAge > = iter . fAgeIndex )
fCurrAge = - 1 ;
// Repump our update
if ( ! force )
{
plResMgrHelperMsg * msg = new plResMgrHelperMsg ( plResMgrHelperMsg : : kUpdateDebugScreen ) ;
msg - > SetTimeStamp ( hsTimer : : GetSysSeconds ( ) + kUpdateDelay ) ;
msg - > Send ( GetKey ( ) ) ;
}
# endif
}
#if 0
// FIXME
bool VerifyKeyUnloaded ( const char * logFile , const plKey & key ) ;
// Verifies that a key which shouldn't be loaded isn't, and if it is tries to figure out why.
void VerifyAgeUnloaded ( const char * logFile , const char * age ) ;
// Helper for VerifyKeyUnloaded
bool IVerifyKeyUnloadedRecur ( const char * logFile , const plKey & baseKey , const plKey & upKey , const char * baseAge ) ;
bool ILookForCyclesRecur ( const char * logFile , const plKey & key , hsTArray < plKey > & tree , int & cycleStart ) ;
bool plResManager : : ILookForCyclesRecur ( const char * logFile , const plKey & key , hsTArray < plKey > & tree , int & cycleStart )
{
int idx = tree . Find ( key ) ;
tree . Append ( key ) ;
if ( tree . kMissingIndex ! = idx )
{
cycleStart = idx ;
// Found a cycle.
return true ;
}
// Now recurse up the active reference tree.
for ( int i = 0 ; i < key - > GetNumNotifyCreated ( ) ; i + + )
{
if ( key - > GetActiveBits ( ) . IsBitSet ( i ) )
{
for ( int j = 0 ; j < key - > GetNotifyCreated ( i ) - > GetNumReceivers ( ) ; j + + )
{
plKey reffer = key - > GetNotifyCreated ( i ) - > GetReceiver ( j ) ;
if ( ILookForCyclesRecur ( logFile , reffer , tree , cycleStart ) )
return true ;
}
}
}
tree . Pop ( ) ;
return false ;
}
bool plResManager : : IVerifyKeyUnloadedRecur ( const char * logFile , const plKey & baseKey , const plKey & upKey , const char * baseAge )
{
const plPageInfo & pageInfo = FindPage ( upKey - > GetUoid ( ) . GetLocation ( ) ) - > GetPageInfo ( ) ;
const char * upAge = pageInfo . GetAge ( ) ;
const char * upPage = pageInfo . GetPage ( ) ;
if ( ! upKey - > GetActiveRefs ( ) )
{
// We've hit a key active reffing us that should be inactive.
// If it's object is loaded, then it somehow missed getting unloaded.
// Else it must have missed letting go of us when it got unloaded.
if ( upKey - > ObjectIsLoaded ( ) )
{
plStatusLog : : AddLineS ( logFile , " \t Held by %s [%s] page %s which is loaded but nothing is reffing " ,
upKey - > GetName ( ) ,
plFactory : : GetNameOfClass ( upKey - > GetUoid ( ) . GetClassType ( ) ) ,
upPage ) ;
return true ;
}
else
{
plStatusLog : : AddLineS ( logFile , " \t Held by %s [%s] page %s which isn't even loaded " ,
upKey - > GetName ( ) ,
plFactory : : GetNameOfClass ( upKey - > GetUoid ( ) . GetClassType ( ) ) ,
upPage ) ;
return true ;
}
}
// if the age of this key is different from the age on the baseKey,
// we've got a cross age active ref, which is illegal.
if ( stricmp ( upAge , baseAge ) )
{
plStatusLog : : AddLineS ( logFile , " \t Held by %s [%s] which is in a different age %s-%s " ,
upKey - > GetName ( ) ,
plFactory : : GetNameOfClass ( upKey - > GetUoid ( ) . GetClassType ( ) ) ,
upAge ,
upPage ) ;
return true ;
}
int numActive = 0 ;
int i ;
for ( i = 0 ; i < upKey - > GetNumNotifyCreated ( ) ; i + + )
{
if ( upKey - > GetActiveBits ( ) . IsBitSet ( i ) )
{
numActive + + ;
}
}
if ( numActive < upKey - > GetActiveRefs ( ) )
{
// Someone has AddRef'd us
plStatusLog : : AddLineS ( logFile , " \t Held by %s [%s] page %s which is loaded due to %d AddRef(s) " ,
upKey - > GetName ( ) ,
plFactory : : GetNameOfClass ( upKey - > GetUoid ( ) . GetClassType ( ) ) ,
upPage ,
upKey - > GetActiveRefs ( ) - numActive ) ;
return true ;
}
// Now recurse up the active reference tree.
for ( i = 0 ; i < upKey - > GetNumNotifyCreated ( ) ; i + + )
{
if ( upKey - > GetActiveBits ( ) . IsBitSet ( i ) )
{
int j ;
for ( j = 0 ; j < upKey - > GetNotifyCreated ( i ) - > GetNumReceivers ( ) ; j + + )
{
plKey reffer = upKey - > GetNotifyCreated ( i ) - > GetReceiver ( j ) ;
if ( IVerifyKeyUnloadedRecur ( logFile , baseKey , reffer , baseAge ) )
{
return true ;
}
}
}
}
return false ;
}
bool plResManager : : VerifyKeyUnloaded ( const char * logFile , const plKey & key )
{
if ( key - > ObjectIsLoaded ( ) )
{
const plPageInfo & pageInfo = FindPage ( key - > GetUoid ( ) . GetLocation ( ) ) - > GetPageInfo ( ) ;
const char * age = pageInfo . GetAge ( ) ;
const char * page = pageInfo . GetPage ( ) ;
plStatusLog : : AddLineS ( logFile , " ================================== " ) ;
plStatusLog : : AddLineS ( logFile , " Object %s [%s] page %s is loaded " , key - > GetName ( ) , plFactory : : GetNameOfClass ( key - > GetUoid ( ) . GetClassType ( ) ) , page ) ;
hsTArray < plKey > tree ;
int cycleStart ;
bool hasCycle = ILookForCyclesRecur ( logFile , key , tree , cycleStart ) ;
if ( hasCycle )
{
plStatusLog : : AddLineS ( logFile , " \t %s [%s] held by dependency cycle " , key - > GetName ( ) , plFactory : : GetNameOfClass ( key - > GetUoid ( ) . GetClassType ( ) ) ) ;
int i ;
for ( i = cycleStart ; i < tree . GetCount ( ) ; i + + )
{
plStatusLog : : AddLineS ( logFile , " \t %s [%s] " , tree [ i ] - > GetName ( ) , plFactory : : GetNameOfClass ( tree [ i ] - > GetUoid ( ) . GetClassType ( ) ) ) ;
}
plStatusLog : : AddLineS ( logFile , " \t End Cycle " ) ;
return true ;
}
else
{
return IVerifyKeyUnloadedRecur ( logFile , key , key , age ) ;
}
}
return false ;
}
class plValidateKeyIterator : public plRegistryKeyIterator
{
protected :
plRegistry * fRegistry ;
const char * fLogFile ;
public :
plValidateKeyIterator ( const char * logFile , plRegistry * reg )
{
fRegistry = reg ;
fLogFile = logFile ;
}
virtual bool EatKey ( const plKey & key )
{
fRegistry - > VerifyKeyUnloaded ( fLogFile , key ) ;
return true ;
}
} ;
class plValidatePageIterator : public plRegistryPageIterator
{
protected :
const char * fAge ;
plRegistryKeyIterator * fIter ;
public :
plValidatePageIterator ( const char * age , plRegistryKeyIterator * iter ) : fAge ( age ) , fIter ( iter ) { }
virtual bool EatPage ( plRegistryPageNode * keyNode )
{
if ( ! stricmp ( fAge , keyNode - > GetPageInfo ( ) . GetAge ( ) ) )
return keyNode - > IterateKeys ( fIter ) ;
return true ;
}
} ;
void plResManager : : VerifyAgeUnloaded ( const char * logFile , const char * age )
{
bool autoLog = false ;
char buff [ 256 ] ;
if ( ! logFile | | ! * logFile )
{
sprintf ( buff , " %s.log " , age ) ;
logFile = buff ;
autoLog = true ;
}
if ( ! autoLog )
{
plStatusLog : : AddLineS ( logFile , " /////////////////////////////////// " ) ;
plStatusLog : : AddLineS ( logFile , " Begin Verification of age %s " , age ) ;
}
plValidateKeyIterator keyIter ( logFile , this ) ;
plValidatePageIterator pageIter ( age , & keyIter ) ;
IterateAllPages ( & pageIter ) ;
if ( ! autoLog )
{
plStatusLog : : AddLineS ( logFile , " End Verification of age %s " , age ) ;
plStatusLog : : AddLineS ( logFile , " /////////////////////////////////// " ) ;
}
}
# endif