--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Engine/Source/Helpers/MemSpyEngineHelperFbServ.cpp Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,1337 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include <memspy/engine/memspyenginehelperfbserv.h>
+
+// System includes
+#include <s32mem.h>
+#include <f32file.h>
+#include <e32rom.h>
+
+// Driver includes
+#include <memspy/driver/memspydriverclient.h>
+
+// User includes
+#include <memspy/engine/memspyengine.h>
+#include <memspy/engine/memspyengineutils.h>
+#include <memspy/engine/memspyengineoutputsink.h>
+#include <memspy/engine/memspyengineobjectprocess.h>
+#include <memspy/engine/memspyengineobjectthread.h>
+#include <memspy/engine/memspyengineobjectcontainer.h>
+
+// Literal constants
+_LIT( KMemSpyEngineFBServComma, ", " );
+_LIT( KMemSpyEngineFBServExportFileName, "Image_%08x_%02d_bpp_(%d x %d).bmp");
+_LIT( KMemSpyEngineFBSLargeChunkName, "FbsLargeChunk" );
+_LIT( KMemSpyEngineFBSSharedChunkName, "FbsSharedChunk" );
+
+
+CMemSpyEngineHelperFbServ::CMemSpyEngineHelperFbServ( CMemSpyEngine& aEngine )
+: iEngine( aEngine )
+ {
+ }
+
+
+CMemSpyEngineHelperFbServ::~CMemSpyEngineHelperFbServ()
+ {
+ iEngine.Driver().WalkHeapClose();
+ }
+
+
+void CMemSpyEngineHelperFbServ::ConstructL()
+ {
+ }
+
+
+CMemSpyEngineHelperFbServ* CMemSpyEngineHelperFbServ::NewL( CMemSpyEngine& aEngine )
+ {
+ CMemSpyEngineHelperFbServ* self = new(ELeave) CMemSpyEngineHelperFbServ( aEngine );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+TBool CMemSpyEngineHelperFbServ::IsLargeBitmapChunk( const TMemSpyDriverChunkInfo& aChunkInfo )
+ {
+ TBool ret = EFalse;
+ //
+ if ( aChunkInfo.iType == EMemSpyDriverChunkTypeGlobal )
+ {
+ ret = ( aChunkInfo.iName.FindF( KMemSpyEngineFBSLargeChunkName ) >= 0 );
+ }
+ //
+ return ret;
+ }
+
+
+TBool CMemSpyEngineHelperFbServ::IsSharedBitmapChunk( const TMemSpyDriverChunkInfo& aChunkInfo )
+ {
+ TBool ret = EFalse;
+ //
+ if ( aChunkInfo.iType == EMemSpyDriverChunkTypeGlobal )
+ {
+ ret = ( aChunkInfo.iName.FindF( KMemSpyEngineFBSSharedChunkName ) >= 0 );
+ }
+ //
+ return ret;
+ }
+
+
+EXPORT_C void CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL( RArray<TInt>& aHandles )
+ {
+ TInt fontConCount = 0;
+ TInt bitmapConCount =0;
+ //RArray<TInt> dirtyHandles;
+ //CleanupClosePushL( dirtyHandles );
+ GetArrayOfBitmapHandlesL( aHandles, bitmapConCount, fontConCount );
+ //CleanupStack::PopAndDestroy( &dirtyHandles );
+ }
+
+
+void CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL( RArray<TInt>& aHandles, TInt& aBitmapConCount, TInt& aFontConCount )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - START") );
+ CMemSpyThread& fbServThread = IdentifyFbServThreadL();
+
+ // Suspend the process
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - got FBServ thread, suspending it..."));
+ iEngine.ProcessSuspendLC( fbServThread.Process().Id() );
+
+ // Get the heap cell data for the correct object (CFbTop)
+ TAny* cellAddress = NULL;
+ HBufC8* cellData = LocateCFbTopHeapCellDataLC( fbServThread, cellAddress );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - got CFbTop cell data: %d bytes", cellData->Length()));
+
+ // Work out the offset to the bitmap address handles array
+ const TUint offsetBitmapCon = OffsetToCObjectConBitmapCon();
+ const TUint offsetFontCon = OffsetToCObjectConFontCon();
+ const TUint offsetHandleArray = OffsetToBitmapHandleArray();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - offsetBitmapCon: %d", offsetBitmapCon ));
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - offsetFontCon: %d", offsetFontCon ));
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - offsetHandleArray: %d", offsetHandleArray ));
+
+ // Create stream for reading heap data (makes life a bit easier).
+ RDesReadStream stream( *cellData );
+ CleanupClosePushL( stream );
+
+ // We need to skip over the preamble to the start of the actual data.
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - skipping %d bytes [to start of bitmap con]...", offsetBitmapCon ));
+ (void) stream.ReadL( offsetBitmapCon ); // skip this much
+
+ // Read CFbTop::iBitmapCon cell address
+ TAny* cellAddresBitmapCon = reinterpret_cast<TAny*>( stream.ReadUint32L() );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - cellAddresBitmapCon: 0x%08x", cellAddresBitmapCon ));
+ TInt bitmapConAllocated = 0;
+ RArray<TAny*> bitmapConAddresses;
+ CleanupClosePushL( bitmapConAddresses );
+ ReadCObjectConInfoL( cellAddresBitmapCon, bitmapConAddresses, aBitmapConCount, bitmapConAllocated );
+ CleanupStack::PopAndDestroy( &bitmapConAddresses );
+
+ // Read CFbTop::iFontCon cell address
+ TAny* cellAddresFontCon = reinterpret_cast<TAny*>( stream.ReadUint32L() );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - cellAddresFontCon: 0x%08x", cellAddresFontCon ));
+ TInt fontConAllocated = 0;
+ RArray<TAny*> fontConAddresses;
+ CleanupClosePushL( fontConAddresses );
+ ReadCObjectConInfoL( cellAddresFontCon, fontConAddresses, aFontConCount, fontConAllocated );
+ CleanupStack::PopAndDestroy( &fontConAddresses );
+
+ // Skip forwards to the bitmap handle array info
+ const TUint skipRemaining = ( offsetHandleArray - offsetFontCon );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - skipRemaining: %d", skipRemaining ));
+ (void) stream.ReadL( skipRemaining ); // skip this much
+
+ // The layout of RPointerArrayBase is as follows:
+ //
+ // TInt iCount;
+ // TAny** iEntries;
+ // TInt iAllocated;
+ // TInt iGranularity;
+ // TInt iSpare1;
+ // TInt iSpare2;
+
+ // Now read the next 4 bytes. This is the number of allocated array entries.
+ const TInt arrayEntryCount = stream.ReadInt32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - arrayEntryCount: %d", arrayEntryCount ));
+
+ // The next four bytes are the address of the cell we are interested in.
+ cellAddress = reinterpret_cast<TAny*>( stream.ReadUint32L() );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - cellAddress: 0x%08x", cellAddress ));
+
+ // The next four bytes are the allocated count
+ const TInt arrayAlloctedCount = stream.ReadInt32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - arrayAlloctedCount: %d", arrayAlloctedCount ));
+
+ // Validate
+ if ( arrayEntryCount > arrayAlloctedCount || arrayEntryCount < 0 || arrayAlloctedCount < 0 )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - invalid array details => Leave with KErrCorrupt"));
+ User::Leave( KErrCorrupt );
+ }
+
+ // Clean up - don't need this data anymore. Real data is in another cell
+ CleanupStack::PopAndDestroy( 2, cellData ); // stream & cellData
+
+ // Now obtain the heap cell data for the actual array itself.
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - trying to find bitmap array data..."));
+ cellData = LocateBitmapArrayHeapCellDataLC( cellAddress, arrayAlloctedCount );
+
+ // Parse the cell data in order to obtain the bitmap handles.
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - trying to extract bitmap handles..."));
+ ParseCellDataAndExtractHandlesL( *cellData, aHandles, arrayEntryCount );
+
+ // Tidy up
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - resuming process..."));
+ CleanupStack::PopAndDestroy( cellData );
+
+ // Close heap walker & resume process
+ iEngine.Driver().WalkHeapClose();
+ CleanupStack::PopAndDestroy();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetArrayOfBitmapHandlesL() - END"));
+ }
+
+
+void CMemSpyEngineHelperFbServ::GetBitmapInfoL( TInt aHandle, TMemSpyEngineFBServBitmapInfo& aInfo )
+ {
+ CFbsBitmap* bitmap = GetBitmapInfoLC( aHandle, aInfo );
+ CleanupStack::PopAndDestroy( bitmap );
+ }
+
+
+CFbsBitmap* CMemSpyEngineHelperFbServ::GetBitmapInfoLC( TInt aHandle, TMemSpyEngineFBServBitmapInfo& aInfo )
+ {
+ CFbsBitmap* bitmap = new(ELeave) CFbsBitmap();
+ CleanupStack::PushL( bitmap );
+ const TInt error = bitmap->Duplicate( aHandle );
+ User::LeaveIfError( error );
+
+ // Basic info from bitmap itself
+ aInfo.iHandle = aHandle;
+ aInfo.iDisplayMode = bitmap->DisplayMode();
+
+ // Extended info comes from header
+ const SEpocBitmapHeader header( bitmap->Header() );
+
+ aInfo.iSizeInPixels = header.iSizeInPixels;
+ aInfo.iCompressionType = header.iCompression;
+ aInfo.iColor = header.iColor;
+ aInfo.iBitsPerPixel = header.iBitsPerPixel;
+ aInfo.iSizeInBytes = header.iBitmapSize;
+
+ // Flags
+ aInfo.iFlags = TMemSpyEngineFBServBitmapInfo::EFlagsNone;
+ if ( bitmap->IsRomBitmap() )
+ {
+ aInfo.iFlags |= TMemSpyEngineFBServBitmapInfo::EFlagsIsRomBitmap;
+ }
+ if ( bitmap->IsLargeBitmap() )
+ {
+ aInfo.iFlags |= TMemSpyEngineFBServBitmapInfo::EFlagsIsLarge;
+ }
+ if ( bitmap->IsCompressedInRAM() )
+ {
+ aInfo.iFlags |= TMemSpyEngineFBServBitmapInfo::EFlagsIsCompressedInRam;
+ }
+ else
+ {
+ // Can only do this if not compressed
+ if ( bitmap->IsMonochrome() )
+ {
+ aInfo.iFlags |= TMemSpyEngineFBServBitmapInfo::EFlagsIsMonochrome;
+ }
+ }
+
+ return bitmap;
+ }
+
+
+CMemSpyThread& CMemSpyEngineHelperFbServ::IdentifyFbServThreadL()
+ {
+ _LIT(KFbServThreadName, "FbServ::!Fontbitmapserver");
+ //
+ CMemSpyThread* thread = NULL;
+ CMemSpyProcess* process = NULL;
+
+ // Get the fbserv thread object
+ CMemSpyEngineObjectContainer& container = iEngine.Container();
+ User::LeaveIfError( container.ProcessAndThreadByFullName( KFbServThreadName, process, thread ) );
+ //
+ return *thread;
+ }
+
+
+HBufC8* CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC( CMemSpyThread& aFbServThread, TAny*& aCellAddress )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - START"));
+
+ // We'll start looking for the CFbTop object at cell index 0, then we'll
+ // continue to a maximum of cell index 10. These are not actual allocation
+ // numbers, they are just cell indicies within FBServ's heap.
+ // Realistically, the cell should be the 7th.
+ const TInt KFbServWillingToStartAtCellIndex = 0;
+ const TInt KFbServWillingToSearchUntilCellIndex = 10;
+
+ // We know the size of the cell is pretty big, since it contains a large
+ // hash-map object (4096 elements by default, 4 bytes big => 16k). We'll
+ // not try to retrieve more than 18k of data.
+ const TInt KFbServExpectedMinimumCellSize = 14*1024;
+ const TInt KFbServExpectedMaximumCellSize = 18*1024;
+
+ // This is what we'll return, if we find it...
+ aCellAddress = NULL;
+ HBufC8* heapCellData = NULL;
+
+ // Get the heap info - we need this for verification purposes
+ TMemSpyHeapInfo info;
+ TInt err = iEngine.Driver().GetHeapInfoUser( info, aFbServThread.Id() );
+ if ( err == KErrNone && info.Type() != TMemSpyHeapInfo::ETypeRHeap )
+ {
+ err = KErrNotSupported;
+ }
+ User::LeaveIfError( err );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - allocated cell header length is: %d", info.AsRHeap().MetaData().HeaderSizeAllocated() ));
+
+ // Now walk the heap!
+ err = iEngine.Driver().WalkHeapInit( aFbServThread.Id() );
+ if ( err == KErrNone )
+ {
+ TMemSpyDriverCellType cellType;
+ TAny* cellAddress;
+ TInt cellLength;
+ TInt cellNestingLevel;
+ TInt cellAllocationNumber;
+ TInt cellHeaderSize;
+ TAny* cellPayloadAddress;
+ //
+ for( TInt cellIndex = KFbServWillingToStartAtCellIndex; err == KErrNone && cellIndex < KFbServWillingToSearchUntilCellIndex; cellIndex++ )
+ {
+ err = iEngine.Driver().WalkHeapNextCell( aFbServThread.Id(), cellType, cellAddress, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - cellIndex[%d] err: %d, cellLength: %d, cellAllocationNumber: %d, cellType: %d", cellIndex, err, cellLength, cellAllocationNumber, cellType));
+
+ if ( err == KErrNone && cellType == EMemSpyDriverGoodAllocatedCell )
+ {
+ // We know we are looking for a relatively large *allocated* cell.
+ if ( cellLength >= KFbServExpectedMinimumCellSize && cellLength <= KFbServExpectedMaximumCellSize && cellType == EMemSpyDriverGoodAllocatedCell )
+ {
+ const TInt payloadLength = cellLength - info.AsRHeap().MetaData().HeaderSizeAllocated();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - cell was long enough. Full cell len: %d, header: %d, therefore dataLen: %d", cellLength, info.AsRHeap().MetaData().HeaderSizeAllocated(), payloadLength));
+
+ // This is *probably* the right cell. Let's get the data and check.
+ HBufC8* data = HBufC8::NewLC( payloadLength );
+ TPtr8 pData( data->Des() );
+ //
+ err = iEngine.Driver().WalkHeapReadCellData( cellAddress, pData, payloadLength );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - data fetch returned error: %d", err));
+
+ if ( err == KErrNone )
+ {
+ //_LIT(KHeapDumpDataFormat, "%S");
+ //iEngine.Sink().OutputBinaryDataL( KHeapDumpDataFormat, pData.Ptr(), (const TUint8*) cellAddress, pData.Length() );
+
+ // Check the data
+ const TUint heapSize = info.AsRHeap().ObjectData().Size();
+ const TUint heapBaseAddress = (TUint) info.AsRHeap().ObjectData().Base();
+ const TBool correctHeapCellLocated = VerifyCorrectHeapCellL( *data, cellAddress, cellPayloadAddress, heapBaseAddress, heapSize );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - verified: %d", correctHeapCellLocated));
+
+ if ( correctHeapCellLocated )
+ {
+ aCellAddress = cellAddress;
+ heapCellData = data;
+ CleanupStack::Pop( data );
+ break;
+ }
+ else
+ {
+ // Not the right cell. Keep going...
+ CleanupStack::PopAndDestroy( data );
+ }
+ }
+ }
+ }
+ }
+
+ // NB: don't do this here -
+ // iEngine.Driver().WalkHeapClose();
+ // It gets done after all reading is complete
+ }
+
+ if ( heapCellData == NULL )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - END - didn't find the right cell => KErrNotFound"));
+ User::Leave( KErrNotFound );
+ }
+ //
+ CleanupStack::PushL( heapCellData );
+
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - END - everything okay, cell is: 0x%08x", aCellAddress));
+ return heapCellData;
+ }
+
+
+void CMemSpyEngineHelperFbServ::ReadCObjectConInfoL( TAny* aCellAddress, RArray<TAny*>& aContainerObjects, TInt& aCount, TInt& aAllocated )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - START - trying cell: 0x%08x", aCellAddress ));
+
+ // What we will return
+ HBufC8* cellData = NULL;
+
+ // Try to get info about real cell
+ TMemSpyDriverCellType cellType;
+ TInt cellLength;
+ TInt cellNestingLevel;
+ TInt cellAllocationNumber;
+ TInt cellHeaderSize;
+ TAny* cellPayloadAddress;
+
+ // NOTE: this call may change the value of 'cellAddress'
+ TInt err = iEngine.Driver().WalkHeapGetCellInfo( aCellAddress, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - err: %d, cellAddress: 0x%08x, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, aCellAddress, cellLength, cellAllocationNumber, cellType));
+
+ if ( err == KErrNone && cellType == EMemSpyDriverGoodAllocatedCell )
+ {
+ // Check that the cell size meets our expectations - it should be a CObjectCon cell.
+ const TInt expectedCellSize = sizeof(CObjectCon*) + cellHeaderSize;
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - expectedCellSize: %d, actual: %d, address: 0x%08x", expectedCellSize, cellLength, aCellAddress));
+
+ if ( expectedCellSize <= cellLength )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - cell lengths are good, trying to get cell data..."));
+
+ // Try to get real cell data
+ cellData = HBufC8::NewLC( cellLength );
+ TPtr8 pData( cellData->Des() );
+ //
+ err = iEngine.Driver().WalkHeapReadCellData( aCellAddress, pData, cellLength );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - reading cell data returned error: %d", err));
+ }
+ else
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - not enough data -> KErrCorrupt"));
+ err = KErrCorrupt;
+ }
+ }
+ else
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - END - didn't find cell data => KErrNotFound"));
+ User::Leave( KErrNotFound );
+ }
+
+ CObjectCon* con = CObjectCon::NewL();
+ const TUint32 KExpectedObjectConVTable = *((TUint32*) con);
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - KExpectedObjectConVTable: 0x%08x", KExpectedObjectConVTable ));
+ delete con;
+
+ // We should have the valid CObjectCon data now.
+ RDesReadStream stream( *cellData );
+ CleanupClosePushL( stream );
+
+ // Read vtable
+ const TUint32 vTable = stream.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - actual vTable: 0x%08x", vTable ));
+ if ( vTable != KExpectedObjectConVTable )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ const TInt uniqueId = stream.ReadInt32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - uniqueId: %d", uniqueId ));
+
+ aCount = stream.ReadInt32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - aCount: %d", aCount ));
+
+ aAllocated = stream.ReadInt32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - aAllocated: %d", aAllocated ));
+
+ // This is actually CObject's iObject, i.e. CObject** iObjects.
+ TAny* pObjects = reinterpret_cast< TAny*>( stream.ReadUint32L() );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - pObjects: 0x%08x", pObjects ));
+
+ CleanupStack::PopAndDestroy( 2, cellData ); // cellData & stream
+
+ // Now fetch the cell containing the CObject pointers...
+ err = iEngine.Driver().WalkHeapGetCellInfo( pObjects, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - array of CObject* cell fetch err: %d, cellAddress: 0x%08x, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, aCellAddress, cellLength, cellAllocationNumber, cellType));
+ User::LeaveIfError( err );
+
+ const TInt expectedSize = ( aAllocated * sizeof(CObject*) ) + cellHeaderSize;
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - expectedSize: %d, actual size: %d", expectedSize, cellLength ));
+ if ( cellLength < expectedSize )
+ {
+ User::Leave( KErrUnderflow );
+ }
+
+ // Get the data
+ cellData = HBufC8::NewLC( cellLength );
+ TPtr8 pData( cellData->Des() );
+ err = iEngine.Driver().WalkHeapReadCellData( pObjects, pData, cellLength );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - reading cell data returned error: %d", err));
+ User::LeaveIfError( err );
+
+ // Open stream
+ stream.Open( *cellData );
+ CleanupClosePushL( stream );
+
+ // Extract array of pointers
+ for( TInt i=0; i<aCount; i++ )
+ {
+ TAny* objectAddress = reinterpret_cast< TAny*>( stream.ReadUint32L() );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - object[%04d]: 0x%08x", i, objectAddress ));
+ aContainerObjects.AppendL( objectAddress );
+ }
+ CleanupStack::PopAndDestroy( 2, cellData ); // cellData & stream
+
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ReadCObjectConInfoL() - END" ));
+ }
+
+
+HBufC8* CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC( TAny*& aArrayCellAddress, TInt aArrayAllocCount )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - START - trying cell: 0x%08x, aArrayAllocCount: %d", aArrayCellAddress, aArrayAllocCount));
+
+ // What we will return
+ HBufC8* cellData = NULL;
+
+ // Try to get info about real cell
+ TMemSpyDriverCellType cellType;
+ TInt cellLength;
+ TInt cellNestingLevel;
+ TInt cellAllocationNumber;
+ TInt cellHeaderSize;
+ TAny* cellPayloadAddress;
+
+ // NOTE: this call may change the value of 'cellAddress'
+ TInt err = iEngine.Driver().WalkHeapGetCellInfo( aArrayCellAddress, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateCFbTopHeapCellDataLC() - err: %d, cellAddress: 0x%08x, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, aArrayCellAddress, cellLength, cellAllocationNumber, cellType));
+
+ if ( err == KErrNone && cellType == EMemSpyDriverGoodAllocatedCell )
+ {
+ // Check that the cell size meets our expectations.
+ // The cell should be a very specific length
+ const TInt expectedCellSize = (sizeof(CBase*) * aArrayAllocCount) + cellHeaderSize;
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - expectedCellSize: %d, actual: %d, address: 0x%08x", expectedCellSize, cellLength, aArrayCellAddress));
+
+ if ( expectedCellSize <= cellLength )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - cell lengths are good, trying to get cell data..."));
+
+ // Try to get real cell data
+ cellData = HBufC8::NewLC( cellLength );
+ TPtr8 pData( cellData->Des() );
+ //
+ err = iEngine.Driver().WalkHeapReadCellData( aArrayCellAddress, pData, cellLength );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - reading cell data returned error: %d", err));
+ }
+ else
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - not enough data -> KErrCorrupt"));
+ err = KErrCorrupt;
+ }
+ }
+ //
+ if ( cellData == NULL )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - END - didn't find cell data => KErrNotFound"));
+ err = KErrNotFound;
+ }
+ User::LeaveIfError( err );
+ //
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::LocateBitmapArrayHeapCellDataLC() - END - ok! - got %d bytes", cellData->Length() ) );
+ return cellData;
+ }
+
+
+void CMemSpyEngineHelperFbServ::ParseCellDataAndExtractHandlesL( const TDesC8& aData, RArray<TInt>& aHandles, TInt aArrayEntryCount )
+ {
+ aHandles.Reset();
+
+ // Create read stream
+ RDesReadStream stream( aData );
+ CleanupClosePushL( stream );
+
+ for( TInt i=0; i<aArrayEntryCount; i++ )
+ {
+ const TInt handle = stream.ReadInt32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::ParseCellDataAndExtractHandlesL() - handle[%4d] = 0x%08x", i, handle));
+ aHandles.AppendL( handle );
+ }
+
+ // Tidy up
+ CleanupStack::PopAndDestroy( &stream );
+ }
+
+
+TBool CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL( const TDesC8& aData, TAny* aCellAddress, TAny* aPayloadAddress, TUint aHeapStartingAddress, TUint aHeapSize )
+ {
+ (void) aPayloadAddress;
+ (void) aCellAddress;
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - START - aDataLen: %d, aCellAddress: 0x%08x, aPayloadAddress: 0x%08x, aHeapStartingAddress: 0x%08x, aHeapSize: %d", aData.Length(), aCellAddress, aPayloadAddress, aHeapStartingAddress, aHeapSize ));
+
+ const TUint KFbServHeapCeilingAddress = aHeapStartingAddress + aHeapSize;
+
+ // Whether we can use this cell's data...
+ TBool correctCell = EFalse;
+
+ // We can use certain knowledge of the layout of the cell to work out
+ // if we've found the right one.
+ //
+ // This is fragile because of the font and bitmap server heap layout changes
+ // significantly, then this can break.
+ RDesReadStream reader( aData );
+ CleanupClosePushL( reader );
+
+ // Get vtable address
+ TUint address = reader.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - suspected vtable: 0x%08x", address));
+
+#ifdef __EPOC32__
+ TBool isROMAddress = EFalse;
+ TInt err = User::IsRomAddress( isROMAddress, (TAny*) address );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - vtable (0x%08x) is in ROM: %d (error: %d)", address, isROMAddress, err));
+ User::LeaveIfError( err );
+
+ if ( !isROMAddress )
+ {
+ // Close stream
+ CleanupStack::PopAndDestroy( &reader );
+
+ // VTable value should be in the ROM range.
+ correctCell = EFalse;
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - END - suspected CFbTop vTable isn't in ROM address range! - correctCell: %d", correctCell));
+ return correctCell;
+ }
+#else
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - skipping vtable: 0x%08x", address));
+#endif
+
+ // First real item is an RFs object instance. We can't check this
+ // very easily because its an embedded object-> We must skip it
+ __ASSERT_ALWAYS( sizeof(RFs) == 4, User::Invariant() );
+ address = reader.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - skipping RFs: 0x%08x", address));
+
+ // Next object is an address (CFontStore* iFontStore). We can validate this against
+ // the method arguments.
+ address = reader.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - iFontStore: 0x%08x", address));
+
+ if ( address > aHeapStartingAddress && address < KFbServHeapCeilingAddress )
+ {
+ // Next comes another pointer (CObjectCon* iBitmapCon)
+ address = reader.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - iBitmapCon: 0x%08x", address));
+
+ if ( address > aHeapStartingAddress && address < KFbServHeapCeilingAddress )
+ {
+ // Next another pointer (CObjectCon* iFontCon)
+ address = reader.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - iFontCon: 0x%08x", address));
+
+ if ( address > aHeapStartingAddress && address < KFbServHeapCeilingAddress )
+ {
+ // And finally, yet another pointer (RHeap* iHeap)
+ address = reader.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - iHeap: 0x%08x", address));
+
+ if ( address > aHeapStartingAddress && address < KFbServHeapCeilingAddress )
+ {
+ // That'll do.
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - data seems okay!"));
+ correctCell = ETrue;
+ }
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &reader );
+ //
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::VerifyCorrectHeapCellL() - END - correctCell: %d", correctCell));
+ return correctCell;
+ }
+
+
+TUint CMemSpyEngineHelperFbServ::OffsetToCObjectConBitmapCon()
+ {
+ TUint ret = 0;
+
+ // VTable
+ ret += 4;
+
+ // RFs
+ ret += sizeof(RFs);
+
+ // CFontStore* iFontStore;
+ ret += sizeof(CBase*); // best effort
+
+ return ret;
+ }
+
+
+TUint CMemSpyEngineHelperFbServ::OffsetToCObjectConFontCon()
+ {
+ TUint ret = OffsetToCObjectConBitmapCon();
+
+ // CObjectCon* iBitmapCon;
+ ret += sizeof(CObjectCon*);
+
+ return ret;
+ }
+
+
+TUint CMemSpyEngineHelperFbServ::OffsetToBitmapHandleArray()
+ {
+ TUint ret = OffsetToCObjectConFontCon();
+
+ // CObjectConIx* iConIx;
+ ret += sizeof(CObjectConIx*);
+
+ // RHeap* iHeap;
+ ret += sizeof(RHeap*);
+
+ // RChunk iChunk
+ ret += sizeof(RChunk);
+
+ // RChunk iLargeBitmapChunk
+ ret += sizeof(RChunk);
+
+ // RMutex iLargeBitmapAccess
+ ret += sizeof(RMutex);
+
+ // CChunkPile* iPile;
+ ret += sizeof(CBase*); // best effort
+
+ // RPointerArray<HBufC> iFontNameAlias;
+ ret += sizeof(RPointerArray<HBufC>);
+
+ return ret;
+ }
+
+
+CMemSpyEngineHelperFbServ::CBitmapObject* CMemSpyEngineHelperFbServ::GetBitmapObjectLC( TAny* aCellAddress )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - START - aCellAddress: 0x%08x", aCellAddress ));
+
+ // What we will return
+ CBitmapObject* object = new(ELeave) CBitmapObject();
+ CleanupStack::PushL( object );
+
+ // The data we will read
+ HBufC8* cellData = NULL;
+
+ // Try to get info about real cell
+ TMemSpyDriverCellType cellType;
+ TInt cellLength;
+ TInt cellNestingLevel;
+ TInt cellAllocationNumber;
+ TInt cellHeaderSize;
+ TAny* cellPayloadAddress;
+
+ // NOTE: this call may change the value of 'cellAddress'
+ TInt err = iEngine.Driver().WalkHeapGetCellInfo( aCellAddress, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - err: %d, cellAddress: 0x%08x, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, aCellAddress, cellLength, cellAllocationNumber, cellType));
+
+ if ( err == KErrNone && cellType == EMemSpyDriverGoodAllocatedCell )
+ {
+ // Check that the cell size meets our expectations - it should be a CBitmapObject, but without the additional "this" pointer
+ // which we have tacked onto the object.
+ const TInt expectedCellSize = sizeof( CBitmapObject ) + cellHeaderSize - sizeof( CBitmapObject* );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - expectedCellSize: %d, actual: %d, address: 0x%08x", expectedCellSize, cellLength, aCellAddress));
+
+ if ( expectedCellSize <= cellLength )
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - cell lengths are good, trying to get cell data..."));
+
+ // Try to get real cell data
+ cellData = HBufC8::NewLC( cellLength );
+ TPtr8 pData( cellData->Des() );
+ //
+ err = iEngine.Driver().WalkHeapReadCellData( aCellAddress, pData, cellLength );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - reading cell data returned error: %d", err));
+ }
+ else
+ {
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - not enough data -> KErrCorrupt"));
+ err = KErrCorrupt;
+ }
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ RDesReadStream stream( *cellData );
+ CleanupClosePushL( stream );
+
+ // Read vtable
+ const TUint32 vTable = stream.ReadUint32L();
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - actual vTable: 0x%08x", vTable ));
+ TBool isROMAddress = EFalse;
+ err = User::IsRomAddress( isROMAddress, (TAny*) vTable );
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - vtable (0x%08x) is in ROM: %d (error: %d)", vTable, isROMAddress, err));
+ User::LeaveIfError( err );
+
+ // Skip CObject members
+ (void) stream.ReadL( sizeof( CObject ) ); // skip this much
+ object->iThisPointer = reinterpret_cast< CBitmapObject* >( cellPayloadAddress );;
+ object->iTop = reinterpret_cast< CBase* >( stream.ReadUint32L() );
+ object->iAddressPointer = reinterpret_cast< CBitwiseBitmap* >( stream.ReadUint32L() );
+ object->iHandle = stream.ReadInt32L();
+ object->iCleanBitmap = reinterpret_cast< CBitmapObject* >( stream.ReadUint32L() );
+
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - object->iThisPointer: 0x%08x", object->iThisPointer ));
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - object->iTop: 0x%08x", object->iTop ));
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - object->iAddressPointer: 0x%08x", object->iAddressPointer ));
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - object->iHandle: 0x%08x", object->iHandle ));
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - object->iCleanBitmap: 0x%08x", object->iCleanBitmap ));
+
+ // Clean up - don't need this data anymore. Real data is in another cell
+ CleanupStack::PopAndDestroy( 2, cellData ); // stream & cellData
+
+ TRACE( RDebug::Printf("CMemSpyEngineHelperFbServ::GetBitmapObjectLC() - END - aCellAddress: 0x%08x", aCellAddress ));
+ return object;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyEngineFbServBitmapArray::CMemSpyEngineFbServBitmapArray( const RArray<TInt>& aBitmapHandles )
+: CActive( CActive::EPriorityIdle ), iBitmapHandles( aBitmapHandles ), iGranularity( 0 )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+
+CMemSpyEngineFbServBitmapArray::CMemSpyEngineFbServBitmapArray( TInt aPriority, const RArray<TInt>& aBitmapHandles, MMemSpyEngineFbSerbBitmapArrayObserver& aObserver, TInt aGranularity )
+: CActive( aPriority ), iBitmapHandles( aBitmapHandles ), iObserver( &aObserver ), iGranularity( aGranularity )
+ {
+ CActiveScheduler::Add( this );
+ CompleteSelf();
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmapArray::~CMemSpyEngineFbServBitmapArray()
+ {
+ Cancel();
+ //
+ iBitmaps.ResetAndDestroy();
+ iBitmaps.Close();
+ }
+
+
+void CMemSpyEngineFbServBitmapArray::ConstructL()
+ {
+ if ( !IsActive() )
+ {
+ // Sync construction...
+ const TInt count = iBitmapHandles.Count();
+ for(TInt i=0; i<count; i++ )
+ {
+ const TInt handle = iBitmapHandles[ i ];
+ //
+ TRAP_IGNORE( CreateBitmapL( handle ) );
+ }
+
+ SortBySizeL();
+ }
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmapArray* CMemSpyEngineFbServBitmapArray::NewL( const RArray<TInt>& aBitmapHandles )
+ {
+ CMemSpyEngineFbServBitmapArray* self = new(ELeave) CMemSpyEngineFbServBitmapArray( aBitmapHandles );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmapArray* CMemSpyEngineFbServBitmapArray::NewL( TInt aPriority, const RArray<TInt>& aBitmapHandles, MMemSpyEngineFbSerbBitmapArrayObserver& aObserver, TInt aGranularity )
+ {
+ CMemSpyEngineFbServBitmapArray* self = new(ELeave) CMemSpyEngineFbServBitmapArray( aPriority, aBitmapHandles, aObserver, aGranularity );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineFbServBitmapArray::Count() const
+ {
+ return iBitmaps.Count();
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmap& CMemSpyEngineFbServBitmapArray::At( TInt aIndex )
+ {
+ return *iBitmaps[ aIndex ];
+ }
+
+
+EXPORT_C const CMemSpyEngineFbServBitmap& CMemSpyEngineFbServBitmapArray::At( TInt aIndex ) const
+ {
+ return *iBitmaps[ aIndex ];
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmap& CMemSpyEngineFbServBitmapArray::BitmapByHandleL( TInt aHandle )
+ {
+ const TInt index = BitmapIndexByHandle( aHandle );
+ User::LeaveIfError( index );
+ CMemSpyEngineFbServBitmap& ret = At( index );
+ return ret;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineFbServBitmapArray::BitmapIndexByHandle( TInt aHandle ) const
+ {
+ TInt ret = KErrNotFound;
+ //
+ const TInt count = Count();
+ for( TInt i=0; i<count; i++ )
+ {
+ const CMemSpyEngineFbServBitmap& bitmap = At( i );
+ //
+ if ( bitmap.Handle() == aHandle )
+ {
+ ret = i;
+ break;
+ }
+ }
+ //
+ return ret;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineFbServBitmapArray::MdcaCount() const
+ {
+ return Count();
+ }
+
+
+EXPORT_C TPtrC CMemSpyEngineFbServBitmapArray::MdcaPoint( TInt aIndex ) const
+ {
+ const CMemSpyEngineFbServBitmap& bitmap = At( aIndex );
+ return TPtrC( bitmap.Caption() );
+ }
+
+
+void CMemSpyEngineFbServBitmapArray::RunL()
+ {
+ const TInt bitmapHandleCount = iBitmapHandles.Count();
+ const TInt endIndex = Min( iIndex + iGranularity, bitmapHandleCount );
+ //
+ for( ; iIndex < endIndex; iIndex++ )
+ {
+ const TInt handle = iBitmapHandles[ iIndex ];
+ //
+ TRAP_IGNORE( CreateBitmapL( handle ) );
+ }
+
+ // Report progress & queue for next iteration
+ MMemSpyEngineFbSerbBitmapArrayObserver::TEvent event = MMemSpyEngineFbSerbBitmapArrayObserver::EBitmapArrayConstructionComplete;
+ if ( endIndex < bitmapHandleCount )
+ {
+ CompleteSelf();
+ event = MMemSpyEngineFbSerbBitmapArrayObserver::EBitmapItemsCreated;
+ }
+ else
+ {
+ SortBySizeL();
+ }
+
+ if ( iObserver )
+ {
+ iObserver->HandleFbServBitmapArrayEventL( event );
+ }
+ }
+
+
+void CMemSpyEngineFbServBitmapArray::DoCancel()
+ {
+ // Nothing to do
+ }
+
+
+TInt CMemSpyEngineFbServBitmapArray::RunError( TInt /*aError*/ )
+ {
+ return KErrNone;
+ }
+
+
+void CMemSpyEngineFbServBitmapArray::CompleteSelf()
+ {
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ SetActive();
+ }
+
+
+void CMemSpyEngineFbServBitmapArray::CreateBitmapL( TInt aHandle )
+ {
+ CMemSpyEngineFbServBitmap* bitmap = CMemSpyEngineFbServBitmap::NewLC( aHandle );
+ iBitmaps.AppendL( bitmap );
+ CleanupStack::Pop( bitmap );
+ }
+
+
+void CMemSpyEngineFbServBitmapArray::SortBySizeL()
+ {
+ TLinearOrder< CMemSpyEngineFbServBitmap > comparer( CompareBySize );
+ iBitmaps.Sort( comparer );
+ }
+
+
+TInt CMemSpyEngineFbServBitmapArray::CompareBySize( const CMemSpyEngineFbServBitmap& aLeft, const CMemSpyEngineFbServBitmap& aRight )
+ {
+ TInt ret = 1;
+ //
+ if ( aLeft.BitmapSizeInBytes() > aRight.BitmapSizeInBytes() )
+ {
+ ret = -1;
+ }
+ else if ( aLeft.BitmapSizeInBytes() == aRight.BitmapSizeInBytes() )
+ {
+ ret = 0;
+ }
+ //
+ return ret;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyEngineFbServBitmap::CMemSpyEngineFbServBitmap()
+: CDesCArrayFlat( 5 )
+ {
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmap::~CMemSpyEngineFbServBitmap()
+ {
+ delete iBitmap;
+ delete iCaption;
+ }
+
+
+void CMemSpyEngineFbServBitmap::ConstructL( TInt aHandle )
+ {
+ iBitmap = new(ELeave) CFbsBitmap();
+ const TInt error = iBitmap->Duplicate( aHandle );
+ User::LeaveIfError( error );
+ const SEpocBitmapHeader header( iBitmap->Header() );
+
+ // Prepare caption
+ _LIT( KCaptionFormat, "\t%2d bpp, %S\t\t%4d x %4d pixels" );
+ iCaption = HBufC::NewL( 128 );
+ TPtr pCaption( iCaption->Des() );
+
+ // Create size string
+ const TMemSpySizeText size( MemSpyEngineUtils::FormatSizeText( header.iBitmapSize ) );
+ pCaption.AppendFormat( KCaptionFormat, header.iBitsPerPixel, &size, header.iSizeInPixels.iWidth, header.iSizeInPixels.iHeight );
+
+ // Prepare items
+ PrepareItemsL();
+ }
+
+
+EXPORT_C CMemSpyEngineFbServBitmap* CMemSpyEngineFbServBitmap::NewLC( TInt aHandle )
+ {
+ CMemSpyEngineFbServBitmap* self = new(ELeave) CMemSpyEngineFbServBitmap();
+ CleanupStack::PushL( self );
+ self->ConstructL( aHandle );
+ return self;
+ }
+
+
+TInt CMemSpyEngineFbServBitmap::BitmapSizeInBytes() const
+ {
+ const SEpocBitmapHeader header( iBitmap->Header() );
+ return header.iBitmapSize;
+ }
+
+
+EXPORT_C const TDesC& CMemSpyEngineFbServBitmap::Caption() const
+ {
+ return *iCaption;
+ }
+
+
+EXPORT_C CFbsBitmap& CMemSpyEngineFbServBitmap::Bitmap()
+ {
+ return *iBitmap;
+ }
+
+
+EXPORT_C const CFbsBitmap& CMemSpyEngineFbServBitmap::Bitmap() const
+ {
+ return *iBitmap;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineFbServBitmap::Handle() const
+ {
+ return iBitmap->Handle();
+ }
+
+
+EXPORT_C void CMemSpyEngineFbServBitmap::OutputDataL( CMemSpyEngine& aEngine ) const
+ {
+ const SEpocBitmapHeader header( iBitmap->Header() );
+ //
+ _LIT(KMemSpyFBServHex, "0x%08x");
+ _LIT(KMemSpyFBServDecimal, "%d");
+ //
+ HBufC* columns = HBufC::NewLC( 1024 );
+ TPtr pColumns( columns->Des() );
+ //
+ pColumns.AppendFormat( KMemSpyFBServHex, Handle() );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ pColumns.AppendFormat( KMemSpyFBServDecimal, header.iBitmapSize );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ pColumns.AppendFormat( KMemSpyFBServDecimal, header.iSizeInPixels.iWidth );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ pColumns.AppendFormat( KMemSpyFBServDecimal, header.iSizeInPixels.iHeight );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ pColumns.AppendFormat( KMemSpyFBServDecimal, header.iBitsPerPixel );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ pColumns.AppendFormat( KMemSpyFBServDecimal, header.iColor );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ TBuf<24> fileCompressionType;
+ GetFileCompressionTypeAsString( header.iCompression, fileCompressionType );
+ pColumns.Append( fileCompressionType );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ GetExportableFileNameL( pColumns );
+ //
+ aEngine.Sink().OutputLineL( pColumns );
+ CleanupStack::PopAndDestroy( columns );
+ }
+
+
+EXPORT_C void CMemSpyEngineFbServBitmap::OutputDataColumnsL( CMemSpyEngine& aEngine )
+ {
+ HBufC* columns = HBufC::NewLC( 1024 );
+ TPtr pColumns( columns->Des() );
+ //
+ _LIT(KCol1, "Handle");
+ pColumns.Append( KCol1 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol2, "Uncompressed Size (Bytes)");
+ pColumns.Append( KCol2 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol3, "Width");
+ pColumns.Append( KCol3 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol4, "Height");
+ pColumns.Append( KCol4 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol5, "BPP");
+ pColumns.Append( KCol5 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol6, "Color");
+ pColumns.Append( KCol6 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol7, "Compression");
+ pColumns.Append( KCol7 );
+ pColumns.Append( KMemSpyEngineFBServComma );
+ //
+ _LIT(KCol8, "File Name");
+ pColumns.Append( KCol8 );
+ //
+ aEngine.Sink().OutputLineL( pColumns );
+ CleanupStack::PopAndDestroy( columns );
+ }
+
+
+EXPORT_C void CMemSpyEngineFbServBitmap::GetExportableFileNameL( TDes& aAppendName ) const
+ {
+ const SEpocBitmapHeader header( iBitmap->Header() );
+
+ // Create a filename
+ aAppendName.AppendFormat( KMemSpyEngineFBServExportFileName, Handle(), header.iBitsPerPixel, header.iSizeInPixels.iWidth, header.iSizeInPixels.iHeight );
+ }
+
+
+void CMemSpyEngineFbServBitmap::GetExportableFileNameL( const TMemSpyEngineFBServBitmapInfo& aInfo, TDes& aAppendName )
+ {
+ aAppendName.AppendFormat( KMemSpyEngineFBServExportFileName, aInfo.iHandle, aInfo.iBitsPerPixel, aInfo.iSizeInPixels.iWidth, aInfo.iSizeInPixels.iHeight );
+ }
+
+
+void CMemSpyEngineFbServBitmap::PrepareItemsL()
+ {
+ const SEpocBitmapHeader header( iBitmap->Header() );
+ TBuf<256> item;
+
+ // View bitmap (ugly, but needed by UI)
+ _LIT(KCaptionMinus2, "\tView Bitmap\t\t");
+ AppendL( KCaptionMinus2 );
+
+ // Dimensions
+ _LIT(KCaptionMinus1, "\tDimensions\t\t%5d x %5d");
+ item.Format( KCaptionMinus1, header.iSizeInPixels.iWidth, header.iSizeInPixels.iHeight );
+ AppendL( item );
+
+ // Handle
+ _LIT(KCaption0, "\tHandle\t\t0x%08x");
+ item.Format( KCaption0, iBitmap->Handle() );
+ AppendL( item );
+
+ // In Rom?
+ _LIT(KCaption1, "\tIn ROM?\t\t%S");
+ _LIT(KIsRomBitmap, "Yes");
+ _LIT(KNotRomBitmap, "No");
+ if ( iBitmap->IsRomBitmap() )
+ {
+ item.Format( KCaption1, &KIsRomBitmap );
+ }
+ else
+ {
+ item.Format( KCaption1, &KNotRomBitmap );
+ }
+ AppendL( item );
+
+ // Bits per pixel
+ _LIT(KCaption2, "\tBits Per Pixel\t\t%2d");
+ item.Format( KCaption2, header.iBitsPerPixel );
+ AppendL( item );
+
+ // Size of uncompressed bitmap data
+ _LIT(KCaption3, "\tUncompressed data size\t\t%S");
+ const TMemSpySizeText sizeStringUncompressed( MemSpyEngineUtils::FormatSizeText( header.iBitmapSize ) );
+ item.Format( KCaption3, &sizeStringUncompressed );
+ AppendL( item );
+
+ // Palette entry count
+ _LIT(KCaption4, "\tNumber of palette entries\t\t%d");
+ item.Format( KCaption4, header.iPaletteEntries );
+ AppendL( item );
+
+ // Colour
+ _LIT(KCaption5, "\tColour\t\t%d");
+ item.Format( KCaption5, header.iColor);
+ AppendL( item );
+
+ // Palette entry count
+ _LIT(KCaption6, "\tFile compression type\t\t%S");
+ TBuf<24> fileCompressionType;
+ GetFileCompressionTypeAsString( header.iCompression, fileCompressionType );
+ item.Format( KCaption6, &fileCompressionType );
+ AppendL( item );
+ }
+
+
+void CMemSpyEngineFbServBitmap::GetFileCompressionTypeAsString( TBitmapfileCompression aType, TDes& aString )
+ {
+ _LIT(KUnknown, "Unknown");
+ _LIT(KNoCompression, "None");
+ _LIT(KRLE, "RLE");
+ _LIT(KTwelveBitRLE, "12-bit RLE");
+ _LIT(KSixteenBitRLE, "16-bit RLE");
+ _LIT(KTwentyFourBitRLE, "24-bit RLE");
+ _LIT(KThirtyTwoBitRLE, "32-bit RLE");
+ //
+ switch( aType )
+ {
+ case ENoBitmapCompression:
+ aString = KNoCompression;
+ break;
+ case EByteRLECompression:
+ aString = KRLE;
+ break;
+ case ETwelveBitRLECompression:
+ aString = KTwelveBitRLE;
+ break;
+ case ESixteenBitRLECompression:
+ aString = KSixteenBitRLE;
+ break;
+ case ETwentyFourBitRLECompression:
+ aString = KTwentyFourBitRLE;
+ break;
+ case EThirtyTwoUBitRLECompression:
+ aString = KThirtyTwoBitRLE;
+ break;
+ default:
+ case ERLECompressionLast:
+ aString = KUnknown;
+ break;
+ }
+ }
+
+
+
+
+
+
+
+