// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//
#include "msvinifile.h"
#include <f32file.h>
#include <e32std.h>
// Maximum token size
const TInt KTokenSize=256;
// Default location for our config files
_LIT(KIniFileDir, "Z:\\private\\1000484b\\");
CMsvIniData::CMsvIniData()
: iPtr(NULL,0)
{
__DECLARE_NAME(_S("CMsvIniData"));
}
CMsvIniData::~CMsvIniData()
{
delete (TText*)iPtr.Ptr();
delete iToken;
delete iName;
}
/**
Creates and returns a pointer to CMsvIniData object, leave on failure
@return A pointer to the CiniData object
*/
CMsvIniData* CMsvIniData::NewL(const TDesC& aName)
{
CMsvIniData* p=new(ELeave) CMsvIniData;
CleanupStack::PushL(p);
p->ConstructL(aName);
CleanupStack::Pop();
return p;
}
/**
Second-phase constructor.
The function attempts to allocate a buffer and Read file's contents into iPtr
@param aName The name of the file which contains the ini data.
@leave One of the system-wide error codes.
*/
void CMsvIniData::ConstructL(const TDesC& aName)
{
// Allocate space for token
iToken=HBufC::NewL(KTokenSize+2); // 2 extra chars for [tokenName]
// Connect to file server
TAutoClose<RFs> fs;
User::LeaveIfError(fs.iObj.Connect());
fs.PushL();
#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
iName = aName.AllocL();
#else
TFindFile ff(fs.iObj);
User::LeaveIfError(ff.FindByDir(aName, KIniFileDir));
iName=ff.File().AllocL();
#endif
// Open file
TAutoClose<RFile> file;
TInt size;
User::LeaveIfError(file.iObj.Open(fs.iObj,*iName,EFileStreamText|EFileShareReadersOrWriters));
file.PushL();
// Get file size and read in
User::LeaveIfError(file.iObj.Size(size));
TText* data=(TText*)User::AllocL(size);
iPtr.Set(data, size/sizeof(TText), size/sizeof(TText));
TPtr8 dest((TUint8*)data, 0, size);
User::LeaveIfError(file.iObj.Read(dest));
TUint8* ptr = (TUint8*)data;
//
// This is orderred as FEFF assuming the processor is Little Endian
// The data in the file is FFFE.
//
if(size>=(TInt)sizeof(TText) && iPtr[0]==0xFEFF)
{
// UNICODE Text file so lose the FFFE
Mem::Copy(ptr, ptr+sizeof(TText), size-sizeof(TText));
iPtr.Set(data, size/sizeof(TText)-1, size/sizeof(TText)-1);
}
else if(size)
{
// NON-UNICODE so convert to UNICODE
TText* newdata = (TText*)User::AllocL(size*sizeof(TText));
iPtr.Set(newdata, size, size);
TInt i;
for(i=0 ; i<size ; ++i)
{
iPtr[i]=ptr[i];
}
delete data;
}
file.Pop();
fs.Pop();
}
/**
Find a text value from given aKeyName regardless the section in the ini data file
@param aKeyName Key being searched for
@param aResult On return, contains the text result
@return ETrue if found, otherwise EFalse
*/
TBool CMsvIniData::FindVar(const TDesC& aKeyName, TPtrC& aResult)
{
// Call with no section, so starts at beginning
if (FindVar((TDesC&)KNullDesC , aKeyName, aResult))
{
return(ETrue);
}
else
{
return(EFalse);
}
}
/**
Find a text value from given aKeyName and aSecName in the ini data file
@param aSectName Section containing key
@param aKeyName Key being searched for in aSectName
@param aResult On return, contains the text result
@return ETrue if found, otherwise EFalse
*/
TBool CMsvIniData::FindVar(const TDesC& aSectName, const TDesC& aKeyName,TPtrC& aResult)
{
//Should use messaging panic codes???
__ASSERT_DEBUG(aSectName.Length() <= KTokenSize, User::Invariant());
__ASSERT_DEBUG(aKeyName.Length() <= KTokenSize, User::Invariant());
TInt posStartOfSection(0);
TInt posEndOfSection(iPtr.Length()); // Default to the entire length of the ini data
TPtrC SearchBuf;
// If we have a section, set pos to section start
TInt posI(0); // Position in internal data Buffer
if( aSectName.Length() > 0 )
{
TBool FoundSection(false);
while ( !FoundSection )
{
// Move search buffer to next area of interest
SearchBuf.Set(iPtr.Mid(posI));
// Make up token "[SECTIONNAME]", to search for
TPtr sectionToken=iToken->Des();
_LIT(sectionTokenFmtString,"[%S]");
sectionToken.Format(sectionTokenFmtString,&aSectName);
// Search for next occurrence of aSectName
TInt posSB = SearchBuf.Find(sectionToken);
if (posSB==KErrNotFound)
return(EFalse);
// Check this is at beginning of line (ie. non-commented)
// ie. Check preceding char was LF
if(posSB>0)
{
// Create a Buffer, starting one char before found subBuf
TPtrC CharBefore(SearchBuf.Right(SearchBuf.Length()-posSB+1));
// Check first char is end of prev
if(CharBefore[0] == '\n')
{
FoundSection = ETrue; // found
posI = posI + posSB;
}
else
{
posI = posI + posSB + 1; // try again
}
}
else
{
FoundSection = ETrue;
}
} // while ( ! FoundSection )
// Set start of section, after section name, (incl '[' and ']')
posStartOfSection = posI + aSectName.Length() + 2;
// Set end of section, by finding begin of next section or end
SearchBuf.Set(iPtr.Mid(posI));
_LIT(nextSectionBuf,"\n[");
TInt posSB = SearchBuf.Find(nextSectionBuf);
if(posSB != KErrNotFound)
{
posEndOfSection = posI + posSB;
}
else
{
posEndOfSection = iPtr.Length();
}
} // if( aSectName.Length() > 0 )
// Look for key in ini file data Buffer
posI = posStartOfSection;
TBool FoundKey(false);
while ( ! FoundKey )
{
// Search for next occurrence of aKeyName
SearchBuf.Set(iPtr.Mid(posI,posEndOfSection-posI));
TInt posSB = SearchBuf.Find(aKeyName);
// If not found, return
if (posSB==KErrNotFound)
return(EFalse);
// Check this is at beginning of line (ie. non-commented)
// ie. Check preceding char was CR or LF
if(posSB>0)
{
// Create a Buffer, starting one char before found subBuf
TPtrC CharBefore(SearchBuf.Right(SearchBuf.Length()-posSB+1));
// Check if the first char is end of prev and also check
// if the token found is not a substring of another string
TBool beginningOK = ((CharBefore[0] == '\n') || (CharBefore[0] == ' ') || (CharBefore[0] == '\t'));
TBool endingOK = ((CharBefore[aKeyName.Length()+1] == '=') || (CharBefore[aKeyName.Length()+1] == ' ') || (CharBefore[aKeyName.Length()+1] == '\t'));
if (beginningOK && endingOK)
{
FoundKey = ETrue;
posI = posI + posSB;
}
else
{
posI = posI + posSB + 1;
}
}
else
{
FoundKey = ETrue;
}
} // while ( ! FoundKey )
// Set pos, to just after '=' sign
SearchBuf.Set(iPtr.Mid(posI));
TInt posSB = SearchBuf.Locate('=');
if(posSB==KErrNotFound) // Illegal format, should flag this...
{
return(EFalse);
}
// Identify start and end of data (EOL or EOF)
posI = posI + posSB + 1; // 1 char after '='
TInt posValStart = posI;
TInt posValEnd;
SearchBuf.Set(iPtr.Mid(posI));
posSB = SearchBuf.Locate('\r');
if(posSB!=KErrNotFound)
{
posValEnd = posI + posSB;
}
else
{
posValEnd = iPtr.Length();
}
// Check we are still in the section requested
if( aSectName.Length() > 0 )
{
if( posValEnd > posEndOfSection )
{
return(EFalse);
}
}
// Parse Buffer from posn of key
// Start one space after '='
TLex lex(iPtr.Mid(posValStart, posValEnd-posValStart));
lex.SkipSpaceAndMark(); // Should be at the start of the data
aResult.Set(lex.MarkedToken().Ptr(),posValEnd-posValStart - lex.Offset() );
return(ETrue);
}
/**
Find an integer value from given aKeyName regardless the section in the ini data file
@param aKeyName Key being searched for
@param aResult On return, contains the TInt result
@return ETrue if found, otherwise EFalse
*/
TBool CMsvIniData::FindVar(const TDesC& aKeyName, TInt& aResult)
{
TPtrC ptr(NULL,0);
if (FindVar(aKeyName,ptr))
{
TLex lex(ptr);
if (lex.Val(aResult)==KErrNone)
return(ETrue);
}
return(EFalse);
}
/**
Find an integer value from given aKeyName and aSecName in the ini data file
@param aSectName Section containing key
@param aKeyName Key being searched for in aSectName
@param aResult On return, contains TInt result
@return ETrue if found, otherwise EFalse
*/
TBool CMsvIniData::FindVar(const TDesC& aSection, const TDesC& aKeyName,TInt& aResult)
{
TPtrC ptr(NULL,0);
if (FindVar(aSection,aKeyName,ptr))
{
TLex lex(ptr);
if (lex.Val(aResult)==KErrNone)
{
return(ETrue);
}
}
return(EFalse);
}