lowlevellibsandfws/apputils/src/StringPoolImplementation.cpp
changeset 0 e4d67989cc36
child 44 97b0fb8a2cc2
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32base.h>
       
    17 #include "StringPoolImplementation.h"
       
    18 
       
    19 const TInt KMapGranularity=20;
       
    20 
       
    21 CStringPoolNode::~CStringPoolNode()
       
    22 	{
       
    23 	delete iDes;
       
    24 	}
       
    25 
       
    26 CStringPoolImplementation::CStringPoolImplementation() : iStringMapList(KMapGranularity, _FOFF(TStringIdMap, iSourceTableVal)), iStringMapListReverse(KMapGranularity, _FOFF(TStringIdMap, iTargetTableVal))
       
    27 	{
       
    28 	}
       
    29 
       
    30 CStringPoolImplementation::~CStringPoolImplementation()
       
    31 	{
       
    32 	// Look for non-expirable strings
       
    33 	TInt i;
       
    34 	for (i = 0; i < KHashModulo; i++ )
       
    35 		{
       
    36 		DeleteUndeletableStrings(iCIHashTable, i);
       
    37 		DeleteUndeletableStrings(iCSHashTable, i);		
       
    38 		}
       
    39 #ifdef _DEBUG
       
    40 
       
    41 	__LOG(_L8(":Closing String Pool.\n"))
       
    42 		TBool leaksFound = EFalse;
       
    43 	// Check that the string pool is empty, or more accurately that
       
    44 	// everything in it is a pre-loaded string
       
    45 	for (i = 0; i < KHashModulo; i++ )
       
    46 		{
       
    47 		if (iCIHashTable[i])
       
    48 			{
       
    49 			for (TInt j = 0; j < iCIHashTable[i]->Count(); j++)
       
    50 				{
       
    51 				if (!StringUtils::IsTableEntry(iCIHashTable[i]->At(j).iVal))
       
    52 					{
       
    53 					if (!leaksFound)
       
    54 						{
       
    55 						__LOG(_L8("The following strings were leaked through not being Closed:\n"))
       
    56 						leaksFound = ETrue;
       
    57 						}
       
    58 
       
    59 					// Get the problem string
       
    60 					CStringPoolNode* theProblem = 
       
    61 						reinterpret_cast<CStringPoolNode*>(
       
    62 							iCIHashTable[i]->At(j).iVal & KTokenToNode);
       
    63 					__LOG(theProblem->iDes->Des());
       
    64 					}
       
    65 				}
       
    66 			}
       
    67 		if (iCSHashTable[i])
       
    68 			{
       
    69 			for (TInt j = 0; j < iCSHashTable[i]->Count(); j++)
       
    70 				{
       
    71 				if (!StringUtils::IsTableEntry(iCSHashTable[i]->At(j).iVal))
       
    72 					{
       
    73 					if (!leaksFound)
       
    74 						{
       
    75 						__LOG(_L8("The following strings were leaked through not being Closed:\n"))
       
    76 						leaksFound = ETrue;
       
    77 						}
       
    78 
       
    79 					// Get the problem string
       
    80 					CStringPoolNode* theProblem = 
       
    81 						reinterpret_cast<CStringPoolNode*>(
       
    82 							iCSHashTable[i]->At(j).iVal & KTokenToNode);
       
    83 					__LOG(theProblem->iDes->Des());
       
    84 					}
       
    85 				}
       
    86 			}
       
    87 		if (leaksFound)
       
    88 			__DEBUGGER();
       
    89 		}
       
    90 
       
    91 	if (!leaksFound)
       
    92 		__LOG(_L8("No leakages were detected\n"));
       
    93 
       
    94 #endif //_DEBUG
       
    95 	for (TInt ii = 0; ii < KHashModulo; ii++)
       
    96 		{
       
    97 		delete iCIHashTable[ii];
       
    98 		delete iCSHashTable[ii];
       
    99 		}
       
   100 		
       
   101 	iTablePtrs.Close();
       
   102 	iStringMapList.Close();
       
   103 	iStringMapListReverse.Close();
       
   104 	iRollbackMapList.Close();	
       
   105 	iRollbackHashListCS.Close();
       
   106 	iRollbackHashListCI.Close();
       
   107 	// Notify the external users of the StringPool that the object is getting closed
       
   108 	TInt cBCounter = iCallBacks.Count();
       
   109 	if(cBCounter>0)
       
   110 		{
       
   111 		while (--cBCounter>=0)
       
   112 			{
       
   113 			iCallBacks[cBCounter]->StringPoolClosing();
       
   114 			}
       
   115 		}
       
   116 	iCallBacks.Close();
       
   117 	}
       
   118 
       
   119 // Check for any undeletable string and delete them now
       
   120 void CStringPoolImplementation::DeleteUndeletableStrings(CArrayFixSeg<RStringTokenEither>* aArray[KHashModulo], TInt i)
       
   121 	{
       
   122 	if (aArray[i])
       
   123 		{
       
   124 		for (TInt j = 0; j < aArray[i]->Count(); ++j)
       
   125 			{
       
   126 			if (!StringUtils::IsTableEntry(aArray[i]->At(j).iVal))
       
   127 				{
       
   128 				CStringPoolNode* node= reinterpret_cast<CStringPoolNode*>(aArray[i]->At(j).iVal & KTokenToNode);
       
   129 				if (KMarkedForNoDeleted==node->iRefcount)
       
   130 					{
       
   131 					delete node;										
       
   132 					aArray[i]->Delete(j);
       
   133 					j--;
       
   134 					}
       
   135 				}
       
   136 			}
       
   137 		}	
       
   138 	}
       
   139 
       
   140 CStringPoolImplementation* CStringPoolImplementation::NewL()
       
   141 	{
       
   142 	CStringPoolImplementation* table = new (ELeave) CStringPoolImplementation();	
       
   143 	return table;
       
   144 	}
       
   145 
       
   146 void CStringPoolImplementation::CleanupHashCS(TAny* aImplementation)
       
   147 	{
       
   148 	CStringPoolImplementation* imp=reinterpret_cast<CStringPoolImplementation*>(aImplementation);
       
   149 	CleanUpHash(&imp->iRollbackHashListCS, imp->iCSHashTable);
       
   150 	}
       
   151 
       
   152 void CStringPoolImplementation::CleanupHashCI(TAny* aImplementation)
       
   153 	{
       
   154 	CStringPoolImplementation* imp=reinterpret_cast<CStringPoolImplementation*>(aImplementation);
       
   155 	CleanUpHash(&imp->iRollbackHashListCI, imp->iCIHashTable);
       
   156 	}
       
   157 
       
   158 void CStringPoolImplementation::CleanUpHash(RPointerArray <RStringTokenEither>* aHashCleanup, CArrayFixSeg<RStringTokenEither>* aHash[KHashModulo])
       
   159 	{
       
   160 	if (aHashCleanup->Count()>0)
       
   161 		{
       
   162 		RStringTokenEither* token=(*aHashCleanup)[0];	// Get first entry
       
   163 		for (TInt i = 0; i < KHashModulo; i++ )
       
   164 			{
       
   165 			if (aHash[i])
       
   166 				{
       
   167 				for (TInt j = 0; j < aHash[i]->Count(); j++)
       
   168 					{
       
   169 					if (!StringUtils::IsTableEntry(aHash[i]->At(j).iVal))
       
   170 						{						
       
   171 						if (aHash[i]->At(j).iVal==token->iVal)
       
   172 							{		
       
   173 							CStringPoolNode* node= reinterpret_cast<CStringPoolNode*>(aHash[i]->At(j).iVal & KTokenToNode);
       
   174 							delete node;
       
   175 							aHash[i]->Delete(j);
       
   176 							aHashCleanup->Remove(0);
       
   177 							break;
       
   178 							}
       
   179 						}
       
   180 					}
       
   181 				}
       
   182 			
       
   183 			}
       
   184 		}
       
   185 	}
       
   186 
       
   187 void CStringPoolImplementation::CleanupIdMap(TAny* aImplementation)
       
   188 	{
       
   189 	CStringPoolImplementation* imp=reinterpret_cast<CStringPoolImplementation*>(aImplementation);
       
   190 	if (imp->iRollbackMapList.Count()>0)
       
   191 		{
       
   192 		TStringIdMap* map=imp->iRollbackMapList[0];			
       
   193 		TInt index=imp->iStringMapList.FindInUnsignedKeyOrder(*map);
       
   194 		imp->iRollbackMapList.Remove(0);
       
   195 		if (index!=KErrNotFound)
       
   196 			{
       
   197 			imp->iStringMapList.Remove(index);			
       
   198 			}		
       
   199 		index=imp->iStringMapListReverse.FindInUnsignedKeyOrder(*map);
       
   200 		if (index!=KErrNotFound)
       
   201 			{
       
   202 			for (TInt count=index;count<imp->iStringMapListReverse.Count();++count)
       
   203 				{
       
   204 				if (imp->iStringMapListReverse[count].iTargetTableVal==map->iTargetTableVal && imp->iStringMapListReverse[count].iSourceTableVal==map->iSourceTableVal)
       
   205 					{				
       
   206 					imp->iStringMapListReverse.Remove(index);
       
   207 					}
       
   208 				}
       
   209 			}
       
   210 		}
       
   211 	}
       
   212 
       
   213 void CStringPoolImplementation::AddTableL(const TStringTable& aTable)
       
   214 	{
       
   215 	for (TInt count=0;count<iTablePtrs.Count();++count)	// check for adding the same table twice
       
   216 		{
       
   217 		if (iTablePtrs[count]==&aTable)
       
   218 			{
       
   219 			return;
       
   220 			}
       
   221 		}
       
   222 	User::LeaveIfError(iTablePtrs.Append(&aTable));	// Add the pointer to this table so we can keep track of the Table IDs. The table ID is the index in this array
       
   223 	//Is the table Case Sensitive or not?
       
   224 	TBool (*genericValFromIndex)(TInt, TUint16);
       
   225 	if (aTable.iCaseSensitive==1)
       
   226 		genericValFromIndex = StringUtils::ValFromIndex;
       
   227 	else
       
   228 		genericValFromIndex = StringUtils::ValFromIndexF;
       
   229 
       
   230 	CArrayFixSeg<RStringTokenEither>** hashTableToUse =
       
   231 	aTable.iCaseSensitive ? iCSHashTable :iCIHashTable ;	
       
   232 	TInt cleanupCounter=0;
       
   233 	for (TUint i = 0; i < aTable.iCount; ++i)
       
   234 		{
       
   235 		const TStLitC8<1>* string=reinterpret_cast<const TStLitC8<1>* >(aTable.iTable[i]);		
       
   236 		
       
   237 		// Try to find the string in memory, maybe as a dynamic string or as a member of an another table  
       
   238 		RStringTokenEither token=FindDes(*string, !aTable.iCaseSensitive);
       
   239 		if (!token.IsNull())
       
   240 			{
       
   241 			TStringIdMap map;			
       
   242 			map.iSourceTableVal=StringUtils::ValFromIndex(i, (TInt16)(iTablePtrs.Count()-1),aTable.iCaseSensitive);
       
   243 			map.iTargetTableVal=token.iVal;
       
   244 
       
   245 			// Put on cleanup stack
       
   246 			User::LeaveIfError(iRollbackMapList.Append(&map));
       
   247 			TCleanupItem cleanup(CleanupIdMap, this);
       
   248 			CleanupStack::PushL(cleanup);
       
   249 			++cleanupCounter;
       
   250 			
       
   251 			User::LeaveIfError(iStringMapList.InsertInUnsignedKeyOrder(map));
       
   252 
       
   253 			// Check if this is a link to a dynamic string
       
   254 			if (!StringUtils::IsTableEntry(token.iVal))
       
   255 				{
       
   256 				CStringPoolNode* node = StringUtils::NodePtr(token.iVal);
       
   257 				node->iRefcount=KMarkedForNoDeleted; // Make sure this string never gets deleted
       
   258 				}
       
   259 
       
   260 			// Now store the reverse array						
       
   261 			User::LeaveIfError(iStringMapListReverse.InsertInUnsignedKeyOrderAllowRepeats(map));
       
   262 			}
       
   263 		else
       
   264 			{
       
   265 			TUint8 hash = static_cast<TUint8>(Hash(*string));
       
   266 			CArrayFixSeg<RStringTokenEither>* collisionList = hashTableToUse[hash];
       
   267 			if ( !collisionList )
       
   268 				//HashTableToUse now is used as list of all entry with the same hash
       
   269 				collisionList = hashTableToUse[hash] = 
       
   270 				new (ELeave) CArrayFixSeg<RStringTokenEither>( 2 );
       
   271 			RStringTokenEither s;
       
   272 			s.iVal = genericValFromIndex(i, (TInt16)(iTablePtrs.Count()-1));
       
   273 			
       
   274 			__LOG2(_L8("Table entry being added with hash %d, val %d"), hash, s.iVal);
       
   275 			__LOG(*reinterpret_cast<const TStLitC8<1>* >(aTable.iTable[i]));
       
   276 			// Put on cleanup stack
       
   277 			if (aTable.iCaseSensitive==1)
       
   278 				{
       
   279 				User::LeaveIfError(iRollbackHashListCS.Append(&s));
       
   280 				TCleanupItem cleanup(CleanupHashCS, this);
       
   281 				CleanupStack::PushL(cleanup);
       
   282 				}
       
   283 			else
       
   284 				{
       
   285 				User::LeaveIfError(iRollbackHashListCI.Append(&s));
       
   286 				TCleanupItem cleanup(CleanupHashCI, this);
       
   287 				CleanupStack::PushL(cleanup);
       
   288 				}
       
   289 			
       
   290 			++cleanupCounter;
       
   291 			collisionList->AppendL(s);
       
   292 			}
       
   293 		}	
       
   294 	CleanupStack::Pop(cleanupCounter);
       
   295 	iRollbackMapList.Reset();
       
   296 	iRollbackHashListCS.Reset();
       
   297 	iRollbackHashListCI.Reset();
       
   298 	}
       
   299 
       
   300 // Find FirstVal given duplicate val
       
   301 TInt32 CStringPoolImplementation::FindFirstValFromDuplicate(TInt32 aDuplicateVal) const 
       
   302 	{
       
   303 	TStringIdMap map;
       
   304 	map.iSourceTableVal=aDuplicateVal;	
       
   305 	TInt index=iStringMapList.FindInUnsignedKeyOrder(map);
       
   306 	if (index!=KErrNotFound)		
       
   307 		return iStringMapList[index].iTargetTableVal;
       
   308 	else
       
   309 		return KErrNotFound;
       
   310 	}
       
   311 
       
   312 
       
   313 
       
   314 // Find table index Val given first val & table UID
       
   315 TInt CStringPoolImplementation::FindTableIndexFromFirstVal(TInt32 aFirstVal, TInt aTableUid) const
       
   316 	{
       
   317 	TStringIdMap map;
       
   318 	map.iTargetTableVal=aFirstVal;		
       
   319 	TInt index=iStringMapListReverse.FindInUnsignedKeyOrder(map);
       
   320 	if (KErrNotFound==index)
       
   321 		return KErrNotFound;
       
   322 
       
   323 	for (TInt count=index;count<iStringMapListReverse.Count();++count)
       
   324 		{
       
   325 		if (iStringMapListReverse[count].iTargetTableVal==aFirstVal && StringUtils::TableUid(iStringMapListReverse[count].iSourceTableVal)==aTableUid)
       
   326 			{
       
   327 			return StringUtils::TableIndex(iStringMapListReverse[count].iSourceTableVal);
       
   328 			}
       
   329 		}	
       
   330 		return KErrNotFound;
       
   331 	}
       
   332 
       
   333 
       
   334 // Find the UId for a given table
       
   335 TInt16 CStringPoolImplementation::TableUid(const TStringTable& aTable) const
       
   336 	{
       
   337 	for (TInt count=0; count<iTablePtrs.Count(); ++count)
       
   338 		{
       
   339 		if (iTablePtrs[count]==&aTable)
       
   340 			return (TInt16)count;
       
   341 		}
       
   342 	return KErrNotFound;
       
   343 	}
       
   344 
       
   345 // Find a reference to the table that first added the  string represented by aVal to the pool 
       
   346 const TStringTable& CStringPoolImplementation::TableRef(TInt32 aVal) const
       
   347 	{
       
   348 	__ASSERT_DEBUG(aVal!=0, StringPoolPanic::Panic(StringPoolPanic::EIllegalUseOfNullString));
       
   349 	TInt16 tableUid=(TInt16)(aVal>>20);
       
   350 	const TStringTable* theTableRef=(iTablePtrs[tableUid]);
       
   351 	return  *theTableRef;
       
   352 	}
       
   353 
       
   354 // Find the descriptor for a given table and index
       
   355 const TDesC8& CStringPoolImplementation::TableLookup(TInt aIndex, TInt aTableUid) const
       
   356 	{	
       
   357 	return *reinterpret_cast<const TStLitC8<1>*>(iTablePtrs[aTableUid]->iTable[aIndex]);
       
   358 	}
       
   359 
       
   360 
       
   361 // Lookup with allocating
       
   362 //
       
   363 RStringTokenEither 
       
   364 CStringPoolImplementation::OpenL( const TDesC8& aAttributeName,
       
   365 								  TBool aCaseInsensitive)
       
   366 	{
       
   367 	// lookup the attribute
       
   368 	RStringTokenEither s(FindDes( aAttributeName , aCaseInsensitive));
       
   369 	if (!s.IsNull())
       
   370 		{
       
   371 		if (!StringUtils::IsTableEntry(s.iVal))
       
   372 			{
       
   373 
       
   374 			CStringPoolNode* node = StringUtils::NodePtr(s.iVal);
       
   375 			if (KMarkedForNoDeleted!=node->iRefcount)
       
   376 				node->iRefcount++;
       
   377 			__LOG1(_L8("String copied (during open). Count is now %d"), node->iRefcount);
       
   378 			__LOG(*node->iDes);
       
   379 			}
       
   380 		return s;
       
   381 		}
       
   382 	
       
   383 	// create a new node at the end of the appropriate array
       
   384 	CStringPoolNode* newnode = new (ELeave) CStringPoolNode();
       
   385 	CleanupStack::PushL( newnode );
       
   386 	newnode->iDes = aAttributeName.AllocL();
       
   387 	newnode->iRefcount = 1;
       
   388 
       
   389 	TInt hash = Hash( aAttributeName );
       
   390 	CArrayFixSeg<RStringTokenEither>** hashTableToUse = 
       
   391 		aCaseInsensitive ? iCIHashTable : iCSHashTable;
       
   392 	__LOG2(_L8("Newly added with hash value %d, node val 0x%x\n"), hash, newnode)
       
   393 	__LOG(aAttributeName);
       
   394 
       
   395 	newnode->iHash = static_cast<TUint8>(hash);
       
   396 	CArrayFixSeg<RStringTokenEither>* collisionList = hashTableToUse[hash];
       
   397 	if ( !collisionList )
       
   398 		collisionList = hashTableToUse[hash] = new (ELeave) CArrayFixSeg<RStringTokenEither>( 2 );
       
   399 
       
   400 	s.iVal = reinterpret_cast<TUint32>(newnode);
       
   401 	if (aCaseInsensitive)
       
   402 		s.iVal += 2;
       
   403 	collisionList->AppendL(s);
       
   404 
       
   405 	CleanupStack::Pop(); // newnode
       
   406 
       
   407 	return s;
       
   408 	}
       
   409 
       
   410 void CStringPoolImplementation::Close(RStringTokenEither aString)
       
   411 	{
       
   412 	if (StringUtils::IsTableEntry(aString.iVal))
       
   413 		return;
       
   414 
       
   415 	CStringPoolNode* node = StringUtils::NodePtr(aString.iVal);
       
   416 	if (KMarkedForNoDeleted == node->iRefcount)	// -1 means a non-expirable string
       
   417 		return;
       
   418 	if (--node->iRefcount == 0)
       
   419 		{
       
   420 		//this is  the last reference of this string
       
   421 		CArrayFixSeg<RStringTokenEither>** hashTableToUse = 
       
   422 		aString.iVal & 2 ? iCIHashTable : iCSHashTable;
       
   423 
       
   424 		// Delete the node and delete the entry in the relevant collision list 
       
   425 		CArrayFixSeg<RStringTokenEither>* collisionList = hashTableToUse[node->iHash];
       
   426 		TInt count = collisionList->Count();		
       
   427 		for (TInt i = 0; i < count; i++)
       
   428 			{
       
   429 			if (collisionList->At(i) == aString)
       
   430 				{
       
   431 				// Log the fact that a string reference is about to die...
       
   432 				__LOG1(_L8("Removing string with hash value %d\n"), node->iHash)
       
   433 				__LOG(node->iDes->Des());
       
   434 				collisionList->Delete(i);
       
   435 				break;
       
   436 				}
       
   437 			}
       
   438 		delete node;
       
   439 		}
       
   440 	else
       
   441 		{
       
   442 		__LOG1(_L8("String closed. Count is now %d"), 
       
   443 			   node->iRefcount);
       
   444 		__LOG(node->iDes->Des());
       
   445 		}
       
   446 	}
       
   447 
       
   448 void CStringPoolImplementation::IncrementCount(RStringTokenEither aString)
       
   449 	{
       
   450 	if (StringUtils::IsTableEntry(aString.iVal))
       
   451 		return;
       
   452 	CStringPoolNode* node = StringUtils::NodePtr(aString.iVal);
       
   453 	if (KMarkedForNoDeleted!=node->iRefcount)
       
   454 		node->iRefcount++;
       
   455 	__LOG1(_L8("String copied. Count is now %d"), node->iRefcount);
       
   456 	__LOG(*node->iDes);
       
   457 	}
       
   458 
       
   459 // Very simple case-sensitive comparison. We can assume that the
       
   460 // strings are the same length, and we only care if the strings are
       
   461 // the same. (Unlike normal comparison functions that also tell you
       
   462 // which one is 'smaller')
       
   463 TBool CStringPoolImplementation::CompareCS(const TDesC8& s1, const TDesC8& s2)
       
   464 	{
       
   465 	const TUint8* ptr1 = s1.Ptr();
       
   466 	const TUint8* ptr2 = s2.Ptr();
       
   467 	const TUint8* stop = &ptr1[s1.Length()];
       
   468 	for (; ptr1 < stop; ptr1++,ptr2++)
       
   469 		{
       
   470 		if (*ptr1 != *ptr2)
       
   471 			return EFalse;
       
   472 		}
       
   473 	return ETrue;
       
   474 	}
       
   475 
       
   476 // Note that the hash function must generate the same hash values for
       
   477 // strings that differ by case. If changing the algorithm here make
       
   478 // sure this is still true.
       
   479 TBool CStringPoolImplementation::CompareCI(const TDesC8& s1, const TDesC8& s2)
       
   480 	{
       
   481 	const TUint8* ptr1 = s1.Ptr();
       
   482 	const TUint8* ptr2 = s2.Ptr();
       
   483 	const TUint8* stop = &ptr1[s1.Length()];
       
   484 	for (; ptr1 < stop; ptr1++,ptr2++)
       
   485 		{
       
   486 		if (*ptr1 != *ptr2)
       
   487 			{
       
   488 			// They're not exactly the same; see if they differ only
       
   489 			// by case. If one character is a letter, we can do a
       
   490 			// comparison ignoring bit 5 in both cases. If that
       
   491 			// matches, they are the same.
       
   492 			if (!((*ptr1 & KCaseInsensitive) == (*ptr2 & KCaseInsensitive) &&
       
   493 				  (*ptr1 >= 'A' && *ptr1 <= 'Z' || 
       
   494 				   *ptr1 >= 'a' && *ptr1 <= 'z')))
       
   495 				return EFalse;
       
   496 			}
       
   497 		}
       
   498 	return ETrue;
       
   499 	}
       
   500 
       
   501 // Find the given descriptor in the hash table
       
   502 //
       
   503 RStringTokenEither 
       
   504 CStringPoolImplementation::FindDes( const TDesC8& aAttributeName, TBool aCaseInsensitive) 
       
   505 	{
       
   506 	CArrayFixSeg<RStringTokenEither>** hashTableToUse = 
       
   507 		aCaseInsensitive ? iCIHashTable : iCSHashTable;
       
   508 	CArrayFixSeg<RStringTokenEither>* collisionList =hashTableToUse[Hash(aAttributeName)];
       
   509 	RStringPool pool;
       
   510 	TBool (*compareFunction)(const TDesC8&, const TDesC8&);
       
   511 	if (aCaseInsensitive)
       
   512 		compareFunction = CompareCI;
       
   513 	else
       
   514 		compareFunction = CompareCS;
       
   515 	pool.iImplementation = this;
       
   516 	if ( collisionList )
       
   517 		{
       
   518 		TInt length=aAttributeName.Length();
       
   519 		TInt count = collisionList->Count();
       
   520 		for ( TInt i = 0; i < count; i++ )
       
   521 			{
       
   522 			RStringTokenEither token = collisionList->At(i);
       
   523 			RStringEither s(this, token);
       
   524 			const TDesC8& string = s.DesC();
       
   525 			if ( string.Length()==length && 
       
   526 				 (*compareFunction)(aAttributeName, string))
       
   527 				return token;
       
   528 			}
       
   529 		}
       
   530 	return RStringTokenEither();
       
   531 	}
       
   532 
       
   533 
       
   534 // Generate a hash value
       
   535 //
       
   536 TUint CStringPoolImplementation::Hash( const TDesC8& aDes ) const
       
   537 	{
       
   538 	// We ignore bit 5, which is a crude way of making the hash case
       
   539 	// insensitive. This means that things that might differ only by
       
   540 	// case end up in the same bucket, and we can then worry about
       
   541 	// whether they're really the same later.
       
   542 	TInt len=aDes.Length();
       
   543 	TUint hash = 0;
       
   544 	const TUint8* ptr=aDes.Ptr();
       
   545 	for ( TInt i = 0; i < len; i++ )
       
   546 		hash = 131*hash + (*ptr++ & KCaseInsensitive);
       
   547 	return hash % KHashModulo;
       
   548 	}
       
   549 
       
   550 TInt StringUtils::ValFromIndex(TInt aIndex, TUint16 aTableId)
       
   551 	{
       
   552 	return (aTableId << 20) + (aIndex << 2) + 1;
       
   553 	}
       
   554 
       
   555 TInt StringUtils::ValFromIndexF(TInt aIndex, TUint16 aTableId)
       
   556 	{
       
   557 	return (aTableId << 20) + (aIndex << 2) + 3;
       
   558 	}
       
   559 
       
   560 TInt StringUtils::ValFromIndex(TInt aIndex, TUint16 aTableId, TBool aCaseSensitive)
       
   561 	{
       
   562 	if (aCaseSensitive)
       
   563 		return ValFromIndex(aIndex, aTableId);
       
   564 	else
       
   565 		return ValFromIndexF(aIndex, aTableId);
       
   566 	}
       
   567 void  CStringPoolImplementation::AddCallBackL( MStringPoolCloseCallBack& aCallBack)
       
   568 	{
       
   569 	User::LeaveIfError(iCallBacks.Append(&aCallBack));
       
   570 	}