testexecmdw/tef/inifileparser/src/iniparser.cpp
branchRCL_3
changeset 3 9397a16b6eb8
parent 1 6edeef394eb7
equal deleted inserted replaced
1:6edeef394eb7 3:9397a16b6eb8
     1 /*
       
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 * CINIDATA.CPP
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 #include <e32std.h>
       
    22 #include "iniparser.h"
       
    23 
       
    24 // Default directory to look for INI file
       
    25 _LIT(KIniFileDir,"\\System\\Data\\");
       
    26 _LIT(KIniSysDrive, "${SYSDRIVE}");
       
    27 _LIT(KLegacySysDrive, "C:");
       
    28 
       
    29 // Constant Value changed for defect047130 fix
       
    30 const TInt KTokenSize=256;
       
    31 
       
    32 enum TIniPanic
       
    33 	{
       
    34 	ESectionNameTooBig,
       
    35 	EKeyNameTooBig,
       
    36 	};
       
    37 
       
    38 #ifndef EKA2
       
    39 ////////////////////////////////////////////////////////////////////////////////
       
    40 //
       
    41 // DLL entry point
       
    42 //
       
    43 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)	
       
    44 
       
    45 	{
       
    46 	return (KErrNone);
       
    47 	}
       
    48 #endif
       
    49 
       
    50 ////////////////////////////////////////////////////////////////////////////////
       
    51 void Panic(TIniPanic aPanic)
       
    52 	{
       
    53 	_LIT(CIniData,"CIniData");
       
    54 	User::Panic(CIniData,aPanic);
       
    55 	}
       
    56 
       
    57 /**
       
    58  * Updates ${SYSDRIVE} variables in the ini file buffer
       
    59  * To the system drive set during object constrcution
       
    60  */
       
    61 void CIniData::UpdateVariablesL()
       
    62 	{
       
    63 	if (iIniData != NULL)
       
    64 		{
       
    65 		//prevent re-allocating to copy the same data again
       
    66 		TPtr temp(iIniData->Des()) ; 
       
    67 		if(iPtr.Compare(temp) != 0)
       
    68 			{
       
    69 			delete iIniData;
       
    70 			iIniData = NULL ; 
       
    71 			}
       
    72 		}
       
    73 	// if iIniData was never allocated or just deleted...
       
    74 	if(iIniData == NULL)
       
    75 		{
       
    76 		iIniData = iPtr.AllocL();
       
    77 		}
       
    78 		
       
    79 	iPtrExpandedVars.Set(iIniData->Des());
       
    80 	
       
    81 	if(iPtrExpandedVars.FindF(KIniSysDrive) == KErrNotFound)
       
    82 		return;
       
    83 
       
    84 	while ( iPtrExpandedVars.Find(KIniSysDrive) != KErrNotFound )
       
    85 		{
       
    86 		TInt offset = iPtrExpandedVars.Find(KIniSysDrive);
       
    87 		iPtrExpandedVars.Replace(offset, 11, iSysDrive);
       
    88 		}
       
    89 	}
       
    90 
       
    91 /**
       
    92  * Constructor
       
    93  */
       
    94 EXPORT_C CIniData::CIniData() 
       
    95 	: iPtr(NULL,0), iPtrExpandedVars(NULL,0)
       
    96 	{
       
    97 	__DECLARE_NAME(_S("CIniData"));
       
    98 	iSysDrive.Copy(KLegacySysDrive);
       
    99 	}
       
   100 
       
   101 /**
       
   102  * Overloaded constructor
       
   103  * Takes in the system drive letter to overwrite
       
   104  */
       
   105 EXPORT_C CIniData::CIniData(const TDesC& aSysDrive) 
       
   106 	: iPtr(NULL,0), iPtrExpandedVars(NULL,0)
       
   107 	{
       
   108 	__DECLARE_NAME(_S("CIniData"));
       
   109 	if ( aSysDrive.Length() == 2 )
       
   110 		iSysDrive.Copy(aSysDrive);
       
   111 	}
       
   112 
       
   113 /**
       
   114  * Destructor
       
   115  * Frees the resources located in second-phase constructor
       
   116  */
       
   117 EXPORT_C CIniData::~CIniData()
       
   118 	{
       
   119 	if( iIniData != NULL )
       
   120 		delete iIniData;
       
   121 	delete (TText*)iPtr.Ptr();
       
   122 	delete iToken;
       
   123 	delete iName;
       
   124 	}
       
   125 
       
   126 /**
       
   127  * Creates, and returns a pointer to CIniData object, leave on failure
       
   128  * @param aName - Path and name of the ini file to be parsed
       
   129  * @return A pointer to the CiniData object
       
   130  */
       
   131 EXPORT_C CIniData* CIniData::NewL(const TDesC& aName)
       
   132 	{
       
   133 	CIniData* p=new(ELeave) CIniData();
       
   134 	CleanupStack::PushL(p);
       
   135 	p->ConstructL(aName);
       
   136 	CleanupStack::Pop();
       
   137 	return p;
       
   138 	}
       
   139 
       
   140 /**
       
   141  * Creates, and returns a pointer to CIniData object, leave on failure
       
   142  * @param aName - Path and name of the ini file to be parsed
       
   143  * @param aSysDrive - Drive letter to overwrite the default system drive
       
   144  * @return A pointer to the CiniData object
       
   145  */
       
   146 EXPORT_C CIniData* CIniData::NewL(const TDesC& aName, const TDesC& aSysDrive)
       
   147 	{
       
   148 	CIniData* p=new(ELeave) CIniData(aSysDrive);
       
   149 	CleanupStack::PushL(p);
       
   150 	p->ConstructL(aName);
       
   151 	CleanupStack::Pop();
       
   152 	return p;
       
   153 	}
       
   154 
       
   155 /**
       
   156  * Second-phase constructor.
       
   157  * The function attempts to allocate a buffer and Read file's contents into iPtr
       
   158  * @param aName the name of the file which contains the ini data
       
   159  * @leave One of the system-wide error codes
       
   160  */
       
   161 EXPORT_C void CIniData::ConstructL(const TDesC& aName)
       
   162 	{
       
   163  	// Allocate space for token
       
   164 	iToken=HBufC::NewL(KTokenSize+2);	// 2 extra chars for [tokenName]
       
   165 
       
   166 	// Connect to file server
       
   167 	TAutoClose<RFs> fs;
       
   168 	User::LeaveIfError(fs.iObj.Connect());
       
   169 	fs.PushL();
       
   170 
       
   171 	// Find file, given name
       
   172 	TFindFile ff(fs.iObj);
       
   173 	TFileName iniFileDir(KLegacySysDrive);
       
   174 	iniFileDir.Append(KIniFileDir);
       
   175 	User::LeaveIfError(ff.FindByDir(aName, iniFileDir));
       
   176 	iName=ff.File().AllocL();
       
   177 
       
   178 	// Open file
       
   179 	TAutoClose<RFile> file;
       
   180 	TInt size;
       
   181 	User::LeaveIfError(file.iObj.Open(fs.iObj,*iName,EFileStreamText|EFileShareReadersOrWriters));
       
   182 	file.PushL();
       
   183 
       
   184 	// Get file size and read in
       
   185 	User::LeaveIfError(file.iObj.Size(size));
       
   186 	TText* data=(TText*)User::AllocL(size);
       
   187 	iPtr.Set(data, size/sizeof(TText), size/sizeof(TText));
       
   188 	TPtr8 dest((TUint8*)data, 0, size);
       
   189 	User::LeaveIfError(file.iObj.Read(dest));
       
   190 	TUint8* ptr = (TUint8*)data;
       
   191 
       
   192 	//
       
   193 	// This is orderred as FEFF assuming the processor is Little Endian
       
   194 	// The data in the file is FFFE.		PRR 28/9/98
       
   195 	//
       
   196 	if(size>=(TInt)sizeof(TText) && iPtr[0]==0xFEFF)
       
   197 	{
       
   198 		// UNICODE Text file so lose the FFFE
       
   199 		Mem::Copy(ptr, ptr+sizeof(TText), size-sizeof(TText));
       
   200 		iPtr.Set(data, size/sizeof(TText)-1, size/sizeof(TText)-1);
       
   201 	}
       
   202 	else if(size)
       
   203 	{
       
   204 		// NON-UNICODE so convert to UNICODE
       
   205 		TText* newdata = (TText*)User::AllocL(size*sizeof(TText));
       
   206 		iPtr.Set(newdata, size, size);
       
   207 		TInt i;
       
   208 		for(i=0 ; i<size ; ++i)
       
   209 			iPtr[i]=ptr[i];
       
   210 		delete data;
       
   211 	}
       
   212 
       
   213 	// Create a duplicate of the iPtr
       
   214 	// Expand all ${SYSDRIVE} entries to system drive letter
       
   215 	UpdateVariablesL();
       
   216 
       
   217 	file.Pop();
       
   218 	fs.Pop();
       
   219 }
       
   220 
       
   221 ////////////////////////////////////////////////////////////////////////////////
       
   222 /**
       
   223  * Find a text value from given aKeyName regardless the section in the ini data file
       
   224  * @param aKeyName Key being searched for
       
   225  * @param aResult On return, contains the text result 
       
   226  * @return ETrue if found, otherwise EFalse
       
   227  */
       
   228 EXPORT_C TBool CIniData::FindVar(const TDesC &aKeyName, TPtrC &aResult)
       
   229 {
       
   230 	// Call with no section, so starts at beginning
       
   231 	if (FindVar((TDesC&)KNullDesC , aKeyName, aResult))
       
   232 		return(ETrue);
       
   233 	else
       
   234 		return(EFalse);
       
   235 }
       
   236 
       
   237 /**
       
   238  * Find a text value from given aKeyName and aSecName in the ini data file
       
   239  * @param aSectName Section containing key
       
   240  * @param aKeyName Key being searched for in aSectName
       
   241  * @param aResult On return, contains the text result 
       
   242  * @return ETrue if found, otherwise EFalse
       
   243  */
       
   244 EXPORT_C TBool CIniData::FindVar(const TDesC &aSectName,const TDesC &aKeyName,TPtrC &aResult)
       
   245 	{
       
   246 	__ASSERT_DEBUG(aSectName.Length()<=KTokenSize,Panic(ESectionNameTooBig));
       
   247 	__ASSERT_DEBUG(aKeyName.Length()<=KTokenSize,Panic(EKeyNameTooBig));
       
   248 
       
   249 	return FindVar(aSectName,aKeyName,aResult, iPtrExpandedVars);
       
   250 	}
       
   251 
       
   252 /**
       
   253  * Find a text value from given aKeyName and aSecName in the provided ini data pointer
       
   254  * @param aSectName Section containing key
       
   255  * @param aKeyName Key being searched for in aSectName
       
   256  * @param aResult On return, contains the text result 
       
   257  * @param aIniDataPtr ini data pointer to be used to find the value
       
   258  * @return ETrue if found, otherwise EFalse
       
   259  */
       
   260 TBool CIniData::FindVar(const TDesC &aSectName,const TDesC &aKeyName,TPtrC &aResult, TPtr& aIniDataPtr)
       
   261 	{
       
   262 	TInt posStartOfSection(0);
       
   263 	TInt posEndOfSection(aIniDataPtr.Length()); // Default to the entire length of the ini data
       
   264 	TPtrC SearchBuf;
       
   265 
       
   266 	// If we have a section, set pos to section start
       
   267 	TInt posI(0);	// Position in internal data Buffer
       
   268 	if( aSectName.Length() > 0 )
       
   269 		{
       
   270 		TBool FoundSection(false);
       
   271 		while ( ! FoundSection )
       
   272 			{
       
   273 			// Move search buffer to next area of interest
       
   274 			SearchBuf.Set(aIniDataPtr.Mid(posI));
       
   275 
       
   276 			// Make up token "[SECTIONNAME]", to search for
       
   277 			TPtr sectionToken=iToken->Des();
       
   278 			_LIT(sectionTokenFmtString,"[%S]");
       
   279 			sectionToken.Format(sectionTokenFmtString,&aSectName);
       
   280 
       
   281 			// Search for next occurrence of aSectName
       
   282 			TInt posSB = SearchBuf.Find(sectionToken);
       
   283 
       
   284 			if (posSB==KErrNotFound)
       
   285 				return(EFalse);
       
   286 
       
   287 			// Check this is at beginning of line (ie. non-commented)
       
   288 			// ie. Check preceding char was LF
       
   289 			if(posSB>0)
       
   290 				{
       
   291 				// Create a Buffer, starting one char before found subBuf
       
   292 				TPtrC CharBefore(SearchBuf.Right(SearchBuf.Length()-posSB+1));
       
   293 				// Check first char is end of prev
       
   294 				if(CharBefore[0] == '\n')
       
   295 					{
       
   296 					FoundSection = ETrue;		// found
       
   297 					posI = posI + posSB;
       
   298 					}
       
   299 				else
       
   300 					{
       
   301 					posI = posI + posSB + 1;	// try again
       
   302 					}
       
   303 				}
       
   304 			else
       
   305 				{
       
   306 				FoundSection = ETrue;
       
   307 				}
       
   308 
       
   309 			}	// while ( ! FoundSection ) 
       
   310 
       
   311 		// Set start of section, after section name, (incl '[' and ']')
       
   312 		posStartOfSection = posI + aSectName.Length() + 2;
       
   313 
       
   314 		// Set end of section, by finding begin of next section or end
       
   315 		SearchBuf.Set(aIniDataPtr.Mid(posI));
       
   316 		_LIT(nextSectionBuf,"\n[");
       
   317 		TInt posSB = SearchBuf.Find(nextSectionBuf);
       
   318 		if(posSB != KErrNotFound)
       
   319 			{
       
   320 			posEndOfSection = posI + posSB;
       
   321 			}
       
   322 		else
       
   323 			{
       
   324 			posEndOfSection = aIniDataPtr.Length();
       
   325 			}
       
   326 
       
   327 		}	// if( aSectName.Length() > 0 )
       
   328 
       
   329 	// Look for key in ini file data Buffer
       
   330 	posI = posStartOfSection;
       
   331 	TBool FoundKey(false);
       
   332 	while ( ! FoundKey )
       
   333 		{
       
   334 		// Search for next occurrence of aKeyName
       
   335 		SearchBuf.Set(aIniDataPtr.Mid(posI,posEndOfSection-posI));
       
   336 		TInt posSB = SearchBuf.Find(aKeyName);
       
   337 
       
   338 		// If not found, return
       
   339 		if (posSB==KErrNotFound)
       
   340 			return(EFalse);
       
   341 
       
   342 		// Check this is at beginning of line (ie. non-commented)
       
   343 		// ie. Check preceding char was CR or LF
       
   344 		if(posSB>0)
       
   345 			{
       
   346 			// Create a Buffer, starting one char before found subBuf
       
   347 			TPtrC CharBefore(SearchBuf.Right(SearchBuf.Length()-posSB+1));
       
   348 			// Check if the first char is end of prev and also check 
       
   349 			// if the token found is not a substring of another string  
       
   350 			TBool beginningOK = ((CharBefore[0] == '\n') || (CharBefore[0] == ' ') || (CharBefore[0] == '\t'));
       
   351 			TBool endingOK = ((CharBefore[aKeyName.Length()+1] == '=') || (CharBefore[aKeyName.Length()+1] == ' ') || (CharBefore[aKeyName.Length()+1] == '\t'));
       
   352 			if (beginningOK && endingOK)
       
   353 				{
       
   354 				FoundKey = ETrue;
       
   355 				posI = posI + posSB;
       
   356 				}
       
   357 			else
       
   358 				{
       
   359 				posI = posI + posSB + 1;
       
   360 				}
       
   361 			}
       
   362 		else
       
   363 			{
       
   364 			FoundKey = ETrue;
       
   365 			}
       
   366 		}	// while ( ! FoundKey )
       
   367 
       
   368 	// Set pos, to just after '=' sign
       
   369 	SearchBuf.Set(aIniDataPtr.Mid(posI));
       
   370 	TInt posSB = SearchBuf.Locate('=');
       
   371 	if(posSB==KErrNotFound)		// Illegal format, should flag this...
       
   372 		return(EFalse);
       
   373 
       
   374 	// Identify start and end of data (EOL or EOF)
       
   375 	posI = posI + posSB + 1;	// 1 char after '='
       
   376 	TInt posValStart = posI;
       
   377 	TInt posValEnd;
       
   378 	SearchBuf.Set(aIniDataPtr.Mid(posI));
       
   379 	posSB = SearchBuf.Locate('\n');
       
   380 	if(posSB!=KErrNotFound)
       
   381 		{
       
   382      		// ini file uses LF for EOL 
       
   383             posValEnd = posI + posSB; 
       
   384 		}
       
   385 	else
       
   386 		{
       
   387 		posValEnd = aIniDataPtr.Length();
       
   388 		}
       
   389 
       
   390 	// Check we are still in the section requested
       
   391 	if( aSectName.Length() > 0 )
       
   392 		{
       
   393 		if( posValEnd > posEndOfSection )
       
   394 			{
       
   395 			return(EFalse);
       
   396 			}
       
   397 		}
       
   398 	// Parse Buffer from posn of key
       
   399 	// Start one space after '='
       
   400 	TLex lex(aIniDataPtr.Mid(posValStart, posValEnd-posValStart));
       
   401 	lex.SkipSpaceAndMark();		// Should be at the start of the data
       
   402 	aResult.Set(lex.MarkedToken().Ptr(),posValEnd-posValStart - lex.Offset() );
       
   403 
       
   404 	TInt filterOffset;
       
   405 	
       
   406 	// Mark the offset value to the end of the value string
       
   407 	filterOffset = aResult.Length() - 1;
       
   408 
       
   409 	// Loop from end of the value string marked by the offset fetched by above process
       
   410     // And check to see if there is spaces, tabs or carriage returns
       
   411 	while(filterOffset >= 0 &&
       
   412 		(aResult[filterOffset] == '\t' ||
       
   413          aResult[filterOffset] == ' ' ||
       
   414          aResult[filterOffset] == '\r'))
       
   415 		{
       
   416 		// If found, reduce the offset by 1 for every space and tab during the while loop
       
   417 		filterOffset--;
       
   418 		}
       
   419 
       
   420 	// The final offset value indicating end of actual value
       
   421 	// within the ini data is set to the result string reference passed in
       
   422 	aResult.Set(aResult.Mid(0,filterOffset + 1));
       
   423 
       
   424 	return(ETrue);
       
   425 	}
       
   426 
       
   427 /**
       
   428  * Find an integer value from given aKeyName regardless the section in the ini data file
       
   429  * @param aKeyName Key being searched for
       
   430  * @param aResult On return, contains the TInt result 
       
   431  * @return ETrue if found, otherwise EFalse
       
   432  */
       
   433 EXPORT_C TBool CIniData::FindVar(const TDesC &aKeyName, TInt &aResult)
       
   434 	{
       
   435 	TPtrC ptr(NULL,0);
       
   436 	if (FindVar(aKeyName,ptr))
       
   437 		{
       
   438 		TLex lex(ptr);
       
   439 		if (lex.Val(aResult)==KErrNone)
       
   440 			return(ETrue);
       
   441 		}
       
   442 	return(EFalse);
       
   443 	}
       
   444 
       
   445 /**
       
   446  * Find an integer value from given aKeyName and aSecName in the ini data file
       
   447  * @param aSectName Section containing key
       
   448  * @param aKeyName Key being searched for  in aSectName
       
   449  * @param aResult On return, contains TInt result 
       
   450  * @return ETrue if found, otherwise EFalse
       
   451  */
       
   452 EXPORT_C TBool CIniData::FindVar(const TDesC &aSection,const TDesC &aKeyName,TInt &aResult)
       
   453 	{
       
   454 	TPtrC ptr(NULL,0);
       
   455 	if (FindVar(aSection,aKeyName,ptr))
       
   456 		{
       
   457 		TLex lex(ptr);
       
   458 		if (lex.Val(aResult)==KErrNone)
       
   459 			return(ETrue);
       
   460 		}
       
   461 	return(EFalse);
       
   462 	}
       
   463 /**
       
   464  * Find an 64-bit integer value from given aKeyName and aSecName in the ini data file
       
   465  * @param aSectName Section containing key
       
   466  * @param aKeyName Key being searched for  in aSectName
       
   467  * @param aResult On return, contains TInt64 result 
       
   468  * @return ETrue if found, otherwise EFalse
       
   469  */
       
   470 EXPORT_C TBool CIniData::FindVar(const TDesC &aSection,	// Section to look under
       
   471 					const TDesC &aKeyName,		// Key to look for
       
   472 					TInt64 &aResult)			// Int64 ref to store result
       
   473 	{
       
   474 	TPtrC ptr(NULL,0);
       
   475 	if (FindVar(aSection,aKeyName,ptr))
       
   476 		{
       
   477 		TLex lex(ptr);
       
   478 		if (lex.Val(aResult)==KErrNone)
       
   479 			return(ETrue);
       
   480 		}
       
   481 	return(EFalse);
       
   482 	}
       
   483 /**
       
   484  * Set a text value to given aKeyName and aSecName in the ini data file
       
   485  * @param aSectName Section containing key
       
   486  * @param aKeyName Key being set  in aSectName
       
   487  * @param aValue A text value set for the aKeyName in section ASecName
       
   488  * @return KErrNone if sucessful, otherwise system error
       
   489  */
       
   490 EXPORT_C TInt CIniData::SetValue(const TDesC& aSection,const TDesC& aKeyName,const TDesC& aValue)
       
   491 	{
       
   492 	// First find the variable - this gives us a descriptor into the
       
   493 	// ini data giving the bound of the item that has got to be replaced.
       
   494 	TPtrC ptr;
       
   495 	
       
   496 	if (!FindVar(aSection, aKeyName, ptr, iPtr))
       
   497 		return KErrNotFound;
       
   498 	
       
   499 	TInt pos = ptr.Ptr()-iPtr.Ptr();
       
   500 	TInt size = iPtr.Length()+aValue.Length()-ptr.Length();
       
   501 
       
   502 	if (size>iPtr.MaxLength())
       
   503 		{
       
   504 		size = size * sizeof(TText);
       
   505 		TText* newdata = (TText*)User::ReAlloc((TUint8*)iPtr.Ptr(), size); 
       
   506 		if (newdata == 0)
       
   507 			return KErrNoMemory;
       
   508 
       
   509 		iPtr.Set(newdata, iPtr.Length(), iPtr.Length()>size/(TInt)sizeof(TText)?iPtr.Length():size/(TInt)sizeof(TText));
       
   510 		}
       
   511 	iPtr.Replace(pos, ptr.Length(), aValue);
       
   512 	return(KErrNone);
       
   513 	}
       
   514 
       
   515 /**
       
   516  * Set a text value to given aKeyName regardless of the section in the ini data file
       
   517  * @param aKeyName Key being searched for
       
   518  * @param aValue A text value set for the aKeyName 
       
   519  * @return KErrNone if sucessful, otherwise system error
       
   520  */
       
   521 EXPORT_C TInt CIniData::SetValue(const TDesC& aKeyName,const TDesC& aValue)
       
   522 	{
       
   523 	// Call with no section, so starts at beginning
       
   524 	return SetValue((TDesC&)KNullDesC, aKeyName, aValue);
       
   525 	}
       
   526 
       
   527 /**
       
   528  * Add key aKeyName to end of ini data file
       
   529  * @param aKeyName aKeyName Key being added
       
   530  * @param aValue Text value assigned to the aKeyName
       
   531  * @return KErrNone if sucessful, otherwise system error
       
   532  */
       
   533 EXPORT_C TInt CIniData::AddValue(const TDesC& aKeyName,const TDesC& aValue)
       
   534 	{
       
   535 		// Call with no section, so starts at beginning
       
   536 		return AddValue((TDesC&)KNullDesC, aKeyName, aValue);
       
   537 	}
       
   538 
       
   539 /**
       
   540  * Add key aKeyName to section aSectName
       
   541  * @param aSectName Section
       
   542  * @param aKeyName Key being added to section aSectName
       
   543  * @param aValue A text value added to the aKeyName 
       
   544  * @return KErrNone if sucessful, otherwise system error
       
   545  */
       
   546 EXPORT_C TInt CIniData::AddValue(const TDesC& aSectName,const TDesC& aKeyName,const TDesC& aValue)
       
   547 	{
       
   548 	// The request will be denied if the variable exists. 
       
   549 	// 
       
   550 	// If the variable is not there then making an implementation.
       
   551 	// If the Section name existed in the ini file then just append it 
       
   552 	// to this section otherwise append the section, key name and 
       
   553 	// variable at the end of the ini file.
       
   554 	TPtrC ptr;
       
   555 	
       
   556 	if (FindVar(aSectName, aKeyName, ptr))  
       
   557 		return KErrAlreadyExists;  // an key name exists, 
       
   558 								// not allow to add value again to same key
       
   559 		/////////////////////////////
       
   560 	TPtr insertSection =iToken->Des();
       
   561 	TInt size;
       
   562 		
       
   563 	TInt posEndOfSection(iPtr.Length()); // Default to the entire length of the ini data
       
   564 	TPtrC SearchBuf;
       
   565 
       
   566 	// If there is a section, set pos to section start
       
   567 	TInt posI(0);	// Initiate to 0. Position in internal data Buffer
       
   568 	TInt posSB(0);  
       
   569 	if( aSectName.Length() > 0 )
       
   570 		{
       
   571 		TBool FoundSection(false);
       
   572 		while ( ! FoundSection )
       
   573 			{
       
   574 			// Move search buffer to next area of interest
       
   575 			SearchBuf.Set(iPtr.Mid(posI));
       
   576 
       
   577 			// Make up token "[SECTIONNAME]", to search for
       
   578 			TPtr sectionToken=iToken->Des();
       
   579 			_LIT(sectionTokenFmtString,"[%S]");
       
   580 			sectionToken.Format(sectionTokenFmtString,&aSectName);
       
   581 
       
   582 			// Search for next occurrence of aSectName
       
   583 			posSB = SearchBuf.Find(sectionToken);
       
   584 
       
   585 			// If not found, return
       
   586 			if (posSB==KErrNotFound)
       
   587 			{
       
   588 				FoundSection = ETrue; //Stop while searching
       
   589 				_LIT(insertSectionfmt,"\r\n[%S]\r\n%S = %S\r\n");  //if there is no section existed
       
   590 				insertSection.Format(insertSectionfmt,&aSectName,&aKeyName, &aValue);
       
   591 			}
       
   592 			
       
   593 
       
   594 			// Check this is at beginning of line (ie. non-commented)
       
   595 			// ie. Check preceding char was LF
       
   596 			if(posSB>=0)
       
   597 				{
       
   598 				// Create a Buffer, starting one char before found subBuf
       
   599 				TPtrC CharBefore(SearchBuf.Right(SearchBuf.Length()-posSB+1));
       
   600 				// Check first char is end of prev
       
   601 				if(CharBefore[0] == '\n' or posSB == 0)
       
   602 					{
       
   603 					FoundSection = ETrue;		// found
       
   604 					posI = posI + posSB;
       
   605 					_LIT(insertSectionfmt,"\r\n%S = %S\r\n");  //if there is no section existed
       
   606 					insertSection.Format(insertSectionfmt,&aKeyName, &aValue);
       
   607 					}
       
   608 				else
       
   609 					{
       
   610 					posI = posI + posSB + 1;	// try again
       
   611 					}
       
   612 				}
       
   613 			else
       
   614 				{
       
   615 				FoundSection = ETrue; //found at the beginning of the search buffer
       
   616 				}
       
   617 
       
   618 			}	// while ( ! FoundSection ) 
       
   619 			
       
   620 			// Set start of section, after section name, (incl '[' and ']')
       
   621 			if(posSB!=KErrNotFound)
       
   622 			{
       
   623 
       
   624 				// Set end of section, by finding begin of next section or end
       
   625 				SearchBuf.Set(iPtr.Mid(posI));
       
   626 				_LIT(nextSectionBuf,"\n[");
       
   627 				TInt posSB = SearchBuf.Find(nextSectionBuf);
       
   628 				if(posSB != KErrNotFound)
       
   629 					{
       
   630 					posEndOfSection = posI + posSB+1;  //insert it between \n and [
       
   631 					}
       
   632 				else
       
   633 					{
       
   634 					posEndOfSection = iPtr.Length();
       
   635 					}			
       
   636 			}
       
   637 
       
   638 		}	// if( aSectName.Length() > 0 )
       
   639 		
       
   640 	// append/insert here
       
   641 	size = (iPtr.Length()+ insertSection.Length())*sizeof(TText);
       
   642 	if (size>iPtr.MaxLength())
       
   643 		{
       
   644 		TText* newdata = (TText*)User::ReAlloc((TUint8*)iPtr.Ptr(), size); 
       
   645 		if (newdata == 0)
       
   646 			return KErrNoMemory;
       
   647 
       
   648 		iPtr.Set(newdata, iPtr.Length(), size/(TInt)sizeof(TText));
       
   649 		}
       
   650 
       
   651 	iPtr.Insert(posEndOfSection,insertSection);
       
   652 	return(KErrNone);
       
   653 	}
       
   654 	
       
   655 	
       
   656 /**
       
   657  * A method used to flush the data in the buffer to the file given in second-phase constructor
       
   658  */
       
   659 EXPORT_C void CIniData::WriteToFileL()
       
   660 	{
       
   661 
       
   662 #ifndef __WINC__
       
   663 
       
   664 	TAutoClose<RFs> fs;
       
   665 	User::LeaveIfError(fs.iObj.Connect());
       
   666 	fs.PushL();
       
   667 
       
   668 	TAutoClose<RFile> file;
       
   669 	User::LeaveIfError(file.iObj.Replace(fs.iObj,*iName,EFileStreamText|EFileShareExclusive));
       
   670 	file.PushL();
       
   671 	
       
   672 	// convert 16 bits to 8 bits stream
       
   673 
       
   674 	HBufC8* buf8 = HBufC8::NewL(iPtr.Length());
       
   675 	TPtr8 ptr8(buf8->Des());
       
   676 	ptr8.Copy(iPtr);
       
   677 	User::LeaveIfError(file.iObj.Write(ptr8));
       
   678 
       
   679 	delete buf8;
       
   680 
       
   681 	// Refresh the iPtrExpandedVars with the new written ini file content
       
   682 	// Repeat the process of expanding the ${SYSDRIVE}
       
   683 	UpdateVariablesL();
       
   684 
       
   685 	file.Pop();
       
   686 	fs.Pop();
       
   687 #endif
       
   688 	}