sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // This file holds the class methods for the Rom Address Lookup Cache feature sl@0: // of FBServ: CFbsRalCacheEl, CFbsRalCache. sl@0: // sl@0: // sl@0: sl@0: #include "FbsRalc.h" sl@0: #include sl@0: sl@0: sl@0: // ============================================================================ sl@0: sl@0: /** sl@0: Destructor of CFbsRalCacheEl objects releasing memory used by attributes. sl@0: @internalComponent sl@0: @post Object state undefined. sl@0: */ sl@0: CFbsRalCacheEl::~CFbsRalCacheEl() sl@0: { sl@0: User::Free(iFilename); sl@0: iFilename = 0; sl@0: } sl@0: sl@0: /** sl@0: Default constructor for CFbsRalCacheEl objects. sl@0: @internalComponent sl@0: @post CFbsRalCacheEl initialised with a null mapping information. sl@0: */ sl@0: CFbsRalCacheEl::CFbsRalCacheEl() sl@0: : CBase(), iFilename(0), iAddress(0) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Constructor for constructing TFbsRalCacheEl objects with valid sl@0: mapping information. sl@0: @internalComponent sl@0: @param aFilename full name of the file to store sl@0: @param aMemAddr ROM memory address file starts at sl@0: @post TFbsRalCacheEl initialised with the filename and memory address sl@0: supplied. sl@0: @panic EEmptyFilename panic generated when no chars in name sl@0: @panic EInvalidRomAddress panic generated when address out of range sl@0: */ sl@0: CFbsRalCacheEl* sl@0: CFbsRalCacheEl::New( sl@0: const TDesC& aFilename, sl@0: TAny* aMemAddr sl@0: ) sl@0: { sl@0: // Allocate memory for new cache element object and construct. sl@0: CFbsRalCacheEl* ptr = new CFbsRalCacheEl; sl@0: if (!ptr) sl@0: return 0; sl@0: sl@0: // Initialise attributes of cache element. sl@0: ptr->iFilename = HBufC::New(aFilename.Length()); sl@0: if (!ptr->iFilename) sl@0: { sl@0: User::Free(ptr); sl@0: return 0; sl@0: } sl@0: *(ptr->iFilename) = aFilename; sl@0: ptr->iAddress = aMemAddr; sl@0: #ifdef _RALC_DEBUG sl@0: ptr->iHitCount = 1; sl@0: #endif //_RALC_DEBUG sl@0: sl@0: // Done, return address to caller. sl@0: return ptr; sl@0: } sl@0: sl@0: /** sl@0: This routine is used by callers to release the memory directly used for the sl@0: CFbsRalCacheEl object specified WITHOUT destroying the object first. Users sl@0: wishing to destroy the object can do so by calling the destructory directly. sl@0: This is necessary since new/delete are not used for objects of this class as sl@0: out of memory panics must be avoided. sl@0: Therefore this routine must be used with caution to avoid memory leaks! sl@0: @internalComponent sl@0: @param aThisRef Ptr to object to free. Ptr set to 0 on exit sl@0: */ sl@0: void sl@0: CFbsRalCacheEl::FreeOnly( sl@0: CFbsRalCacheEl*& aThisRef sl@0: ) sl@0: { sl@0: User::Free (aThisRef); sl@0: aThisRef = 0; sl@0: } sl@0: sl@0: /** sl@0: An optimised routine for checking the filename in the entry matches that sl@0: supplied to the routine. It compares filenames in a right to left fashion sl@0: since most differences in filenames are in the last 16 characters or so. sl@0: ASCII characters are compared in a case insensitive fashion. sl@0: @internalComponent sl@0: @param aSearchKey filename to compare entry with sl@0: @return ETrue if entry matches search key, EFalse otherwise. sl@0: */ sl@0: TBool sl@0: CFbsRalCacheEl::MatchKey( sl@0: const TDesC& aSearchKey sl@0: ) sl@0: { sl@0: if (!iFilename) sl@0: return EFalse; sl@0: sl@0: // Check both filename descriptors are the same length sl@0: TInt charIndex = iFilename->Length(); sl@0: if (charIndex != aSearchKey.Length()) sl@0: return EFalse; sl@0: sl@0: // Then check every character is the same by comparing right to left. sl@0: while (charIndex) sl@0: { sl@0: charIndex--; sl@0: if (ToLower((*iFilename)[charIndex]) != ToLower(aSearchKey[charIndex])) sl@0: return EFalse; sl@0: } sl@0: sl@0: // If we reach here we know the entry matches what we are looking for. sl@0: return ETrue; sl@0: } sl@0: sl@0: TInt CFbsRalCacheEl::ToLower(TInt aInt) sl@0: { sl@0: return (0x40 < aInt && 0x5B > aInt) ? (aInt + 0x20) : aInt; sl@0: } sl@0: sl@0: // ============================================================================ sl@0: sl@0: /** sl@0: Destructor of CFbsRalCache objects by resetting the circular buffer. sl@0: @internalComponent sl@0: @post Object state undefined. sl@0: */ sl@0: CFbsRalCache::~CFbsRalCache() sl@0: { sl@0: #ifdef _RALC_DEBUG sl@0: RDebug::Print(_L("FBS RALCache destructed for process:%x\n"),(TUint)iProcId); sl@0: PrintCache(); sl@0: #endif //_RALC_DEBUG sl@0: sl@0: while (Count()) sl@0: DropItem(); sl@0: sl@0: Reset(); sl@0: } sl@0: sl@0: /** sl@0: CFbsRalCache private constructor. sl@0: @internalComponent sl@0: @param aFs valid file serve session handle used in lookups. sl@0: @post TFbsRalCache initialised with empty cache buffer. sl@0: @see Public construction achieved using static New() class method. sl@0: */ sl@0: CFbsRalCache::CFbsRalCache( sl@0: RFs& aFs sl@0: ) sl@0: : CCirBuf(), iFs(aFs) sl@0: { sl@0: #ifdef _RALC_DEBUG sl@0: RProcess current; sl@0: iProcId = current.Id(); sl@0: RDebug::Print(_L("FBS RALCache constructed for process:%x\n"), sl@0: (TUint)iProcId); sl@0: #endif sl@0: } sl@0: sl@0: /** sl@0: CFbsRalCache public constructor. This method allocates memory for a new sl@0: object on the default heap and initialises it with the supplied data. sl@0: @internalComponent sl@0: @param aCacheSize number (fixed) of entries in the cache. sl@0: @param aFs valid file serve session handle used in lookups. sl@0: @return Pointer to new object, otherwise 0 when error detected. sl@0: @post TFbsRalCache initialised with empty cache buffer. sl@0: */ sl@0: CFbsRalCache* sl@0: CFbsRalCache::New( sl@0: TInt aCacheSize, sl@0: RFs& aFs sl@0: ) sl@0: { sl@0: if (aCacheSize == 0) sl@0: return 0; sl@0: sl@0: // Allocate memory for new cache object sl@0: // and call its constructor to initialise it. sl@0: CFbsRalCache* ptr = new CFbsRalCache(aFs); sl@0: if (!ptr) sl@0: return 0; sl@0: sl@0: // Reserve capacity in circular buffer for cache entries. sl@0: TRAPD(lc, ptr->SetLengthL(aCacheSize)); sl@0: if (lc != KErrNone) sl@0: { sl@0: User::Free(ptr); sl@0: return 0; sl@0: } sl@0: sl@0: // Successful, new cache created. sl@0: return ptr; sl@0: } sl@0: sl@0: /** sl@0: This is the main cache lookup method for getting a file's start address sl@0: should it be found in ROM. It first scans the cache for a match and on a hit sl@0: it returns the stored address. On a miss it uses the file server to get sl@0: the file's ROM address. This result if +ve is stored and the Most-recently-used sl@0: cache, otherwise 0 is returned. sl@0: @internalComponent sl@0: @param aFileKey Full file name of file to get address for. sl@0: @return Start address in ROM for the file, 0 if not in ROM. sl@0: @post Cache updated with new entry if ROM file and not in cache. sl@0: */ sl@0: TAny* sl@0: CFbsRalCache::Lookup( sl@0: const TDesC& aFileKey sl@0: ) sl@0: { sl@0: sl@0: // Search the cache from the head to the tail should it have any entries sl@0: // based on a MRU policy. sl@0: if (Count()) sl@0: { sl@0: TUint8* ptr = iHead; sl@0: for (TInt num = Count(); num; num--) sl@0: { sl@0: // Calculate the address of the entry. sl@0: if (ptr <= iPtr) sl@0: ptr = iPtrE; sl@0: ptr-=iSize; sl@0: CFbsRalCacheEl* entry = (CFbsRalCacheEl*)ptr; sl@0: sl@0: // Compare the entry key with that suppled for a match and return. sl@0: if (entry->MatchKey(aFileKey)) sl@0: { sl@0: #ifdef _RALC_DEBUG sl@0: RDebug::Print(_L("FBS RALCache lookup HIT: %S\n"), &aFileKey); sl@0: entry->iHitCount++; sl@0: #endif //_RALC_DEBUG sl@0: return entry->iAddress; sl@0: } sl@0: } sl@0: } sl@0: sl@0: #ifdef _RALC_DEBUG sl@0: RDebug::Print(_L("FBS RALCache lookup MISS: %S\n"), &aFileKey); sl@0: #endif //_RALC_DEBUG sl@0: sl@0: // Filename not in cache, ask file server for it's ROM address. sl@0: TAny *romAddr = iFs.IsFileInRom (aFileKey); sl@0: if (romAddr) sl@0: { sl@0: // Store new filename/address mapping in cache and return. sl@0: (void)AddItem (aFileKey, romAddr); sl@0: return romAddr; sl@0: } sl@0: sl@0: // It's not a file in ROM sl@0: return 0; sl@0: } sl@0: sl@0: /** sl@0: This method will create a cache entry from the supplied data and add it to the sl@0: head of the circular cache buffer. If the cache is full this will result in the sl@0: entry at the tail being overwritten with the new entry inserted at the head. sl@0: @internalComponent sl@0: @param aFilename full name of the file to store sl@0: @param aMemAddr ROM memory address file starts at sl@0: @return ETrue when successfully added, EFalse otherwise. sl@0: @post Cache updated as described above. sl@0: */ sl@0: TBool sl@0: CFbsRalCache::AddItem( sl@0: const TDesC& aFilename, sl@0: TAny* aMemAddr sl@0: ) sl@0: { sl@0: // Construct the new cache entry from the supplied data. sl@0: CFbsRalCacheEl* entry = CFbsRalCacheEl::New(aFilename, aMemAddr); sl@0: if (!entry) sl@0: return EFalse; sl@0: sl@0: // Make room in the cache if we need to based on MRU policy. sl@0: if (Count() == Length()) // Is it full? sl@0: DropItem(); sl@0: sl@0: // Add a copy of the cache entry to the circular buffer. sl@0: if (Add(entry) == 0) sl@0: { sl@0: // Failed, can't cache it! sl@0: entry->~CFbsRalCacheEl(); sl@0: CFbsRalCacheEl::FreeOnly(entry); sl@0: return EFalse; sl@0: } sl@0: sl@0: // Item now cached so clean up local entry memory only sl@0: CFbsRalCacheEl::FreeOnly(entry); sl@0: return ETrue; sl@0: } sl@0: sl@0: /** sl@0: This method will create a cache entry from the supplied data and add it to the sl@0: head of the circular cache buffer. If tha cache is full this will result in the sl@0: entry at the tail being overwritten with the new entry inserted at the head. sl@0: @internalComponent sl@0: @post Cache updated as described above. sl@0: */ sl@0: void sl@0: CFbsRalCache::DropItem() sl@0: { sl@0: // No items to drop from cache!? sl@0: if (Count() == 0) sl@0: return; sl@0: sl@0: // Remove cache entry at tail copying into temporary variable. sl@0: CFbsRalCacheEl entry; sl@0: Remove(&entry); sl@0: sl@0: #ifdef _RALC_DEBUG sl@0: RDebug::Print(_L("FBS RALCache droped element: %S, %x, %d\n"), sl@0: entry.iFilename, entry.iAddress, entry.iHitCount); sl@0: #endif //_RALC_DEBUG sl@0: sl@0: // 'entry' destroyed on exit and cleaned up. sl@0: } sl@0: sl@0: sl@0: #ifdef _RALC_DEBUG sl@0: void sl@0: CFbsRalCache::PrintCache() sl@0: { sl@0: if (Count()) sl@0: { sl@0: TUint8* ptr = iHead; sl@0: TInt num = Count(); sl@0: RDebug::Print(_L("FBS RALCache contents (%d):\n"), num); sl@0: for (; num; num--) sl@0: { sl@0: if (ptr <= iPtr) sl@0: ptr = iPtrE; sl@0: ptr-=iSize; sl@0: CFbsRalCacheEl* entry = (CFbsRalCacheEl*)ptr; sl@0: RDebug::Print(_L("FBS RALCache El %d: %S, %x, %d\n"), num, sl@0: entry->iFilename, entry->iAddress, entry->iHitCount); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: RDebug::Print(_L("FBS RALCache emtpy.\n")); sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: // ==========================================================================