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