diff -r 000000000000 -r 3e07fef1e154 testexecmdw/inifileparser/src/iniparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testexecmdw/inifileparser/src/iniparser.cpp Mon Mar 08 15:03:44 2010 +0800 @@ -0,0 +1,688 @@ +/* +* Copyright (c) 2005-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: +* CINIDATA.CPP +* +*/ + + + +#include +#include "iniparser.h" + +// Default directory to look for INI file +_LIT(KIniFileDir,"\\System\\Data\\"); +_LIT(KIniSysDrive, "${SYSDRIVE}"); +_LIT(KLegacySysDrive, "C:"); + +// Constant Value changed for defect047130 fix +const TInt KTokenSize=256; + +enum TIniPanic + { + ESectionNameTooBig, + EKeyNameTooBig, + }; + +#ifndef EKA2 +//////////////////////////////////////////////////////////////////////////////// +// +// DLL entry point +// +GLDEF_C TInt E32Dll(TDllReason /*aReason*/) + + { + return (KErrNone); + } +#endif + +//////////////////////////////////////////////////////////////////////////////// +void Panic(TIniPanic aPanic) + { + _LIT(CIniData,"CIniData"); + User::Panic(CIniData,aPanic); + } + +/** + * Updates ${SYSDRIVE} variables in the ini file buffer + * To the system drive set during object constrcution + */ +void CIniData::UpdateVariablesL() + { + if (iIniData != NULL) + { + //prevent re-allocating to copy the same data again + TPtr temp(iIniData->Des()) ; + if(iPtr.Compare(temp) != 0) + { + delete iIniData; + iIniData = NULL ; + } + } + // if iIniData was never allocated or just deleted... + if(iIniData == NULL) + { + iIniData = iPtr.AllocL(); + } + + iPtrExpandedVars.Set(iIniData->Des()); + + if(iPtrExpandedVars.FindF(KIniSysDrive) == KErrNotFound) + return; + + while ( iPtrExpandedVars.Find(KIniSysDrive) != KErrNotFound ) + { + TInt offset = iPtrExpandedVars.Find(KIniSysDrive); + iPtrExpandedVars.Replace(offset, 11, iSysDrive); + } + } + +/** + * Constructor + */ +EXPORT_C CIniData::CIniData() + : iPtr(NULL,0), iPtrExpandedVars(NULL,0) + { + __DECLARE_NAME(_S("CIniData")); + iSysDrive.Copy(KLegacySysDrive); + } + +/** + * Overloaded constructor + * Takes in the system drive letter to overwrite + */ +EXPORT_C CIniData::CIniData(const TDesC& aSysDrive) + : iPtr(NULL,0), iPtrExpandedVars(NULL,0) + { + __DECLARE_NAME(_S("CIniData")); + if ( aSysDrive.Length() == 2 ) + iSysDrive.Copy(aSysDrive); + } + +/** + * Destructor + * Frees the resources located in second-phase constructor + */ +EXPORT_C CIniData::~CIniData() + { + if( iIniData != NULL ) + delete iIniData; + delete (TText*)iPtr.Ptr(); + delete iToken; + delete iName; + } + +/** + * Creates, and returns a pointer to CIniData object, leave on failure + * @param aName - Path and name of the ini file to be parsed + * @return A pointer to the CiniData object + */ +EXPORT_C CIniData* CIniData::NewL(const TDesC& aName) + { + CIniData* p=new(ELeave) CIniData(); + CleanupStack::PushL(p); + p->ConstructL(aName); + CleanupStack::Pop(); + return p; + } + +/** + * Creates, and returns a pointer to CIniData object, leave on failure + * @param aName - Path and name of the ini file to be parsed + * @param aSysDrive - Drive letter to overwrite the default system drive + * @return A pointer to the CiniData object + */ +EXPORT_C CIniData* CIniData::NewL(const TDesC& aName, const TDesC& aSysDrive) + { + CIniData* p=new(ELeave) CIniData(aSysDrive); + 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 + */ +EXPORT_C void CIniData::ConstructL(const TDesC& aName) + { + // Allocate space for token + iToken=HBufC::NewL(KTokenSize+2); // 2 extra chars for [tokenName] + + // Connect to file server + TAutoClose fs; + User::LeaveIfError(fs.iObj.Connect()); + fs.PushL(); + + // Find file, given name + TFindFile ff(fs.iObj); + TFileName iniFileDir(KLegacySysDrive); + iniFileDir.Append(KIniFileDir); + User::LeaveIfError(ff.FindByDir(aName, iniFileDir)); + iName=ff.File().AllocL(); + + // Open file + TAutoClose 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. PRR 28/9/98 + // + 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 0 ) + { + TBool FoundSection(false); + while ( ! FoundSection ) + { + // Move search buffer to next area of interest + SearchBuf.Set(aIniDataPtr.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(aIniDataPtr.Mid(posI)); + _LIT(nextSectionBuf,"\n["); + TInt posSB = SearchBuf.Find(nextSectionBuf); + if(posSB != KErrNotFound) + { + posEndOfSection = posI + posSB; + } + else + { + posEndOfSection = aIniDataPtr.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(aIniDataPtr.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(aIniDataPtr.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(aIniDataPtr.Mid(posI)); + posSB = SearchBuf.Locate('\n'); + if(posSB!=KErrNotFound) + { + // ini file uses LF for EOL + posValEnd = posI + posSB; + } + else + { + posValEnd = aIniDataPtr.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(aIniDataPtr.Mid(posValStart, posValEnd-posValStart)); + lex.SkipSpaceAndMark(); // Should be at the start of the data + aResult.Set(lex.MarkedToken().Ptr(),posValEnd-posValStart - lex.Offset() ); + + TInt filterOffset; + + // Mark the offset value to the end of the value string + filterOffset = aResult.Length() - 1; + + // Loop from end of the value string marked by the offset fetched by above process + // And check to see if there is spaces, tabs or carriage returns + while(filterOffset >= 0 && + (aResult[filterOffset] == '\t' || + aResult[filterOffset] == ' ' || + aResult[filterOffset] == '\r')) + { + // If found, reduce the offset by 1 for every space and tab during the while loop + filterOffset--; + } + + // The final offset value indicating end of actual value + // within the ini data is set to the result string reference passed in + aResult.Set(aResult.Mid(0,filterOffset + 1)); + + 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 + */ +EXPORT_C TBool CIniData::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 + */ +EXPORT_C TBool CIniData::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); + } +/** + * Find an 64-bit 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 TInt64 result + * @return ETrue if found, otherwise EFalse + */ +EXPORT_C TBool CIniData::FindVar(const TDesC &aSection, // Section to look under + const TDesC &aKeyName, // Key to look for + TInt64 &aResult) // Int64 ref to store result + { + TPtrC ptr(NULL,0); + if (FindVar(aSection,aKeyName,ptr)) + { + TLex lex(ptr); + if (lex.Val(aResult)==KErrNone) + return(ETrue); + } + return(EFalse); + } +/** + * Set a text value to given aKeyName and aSecName in the ini data file + * @param aSectName Section containing key + * @param aKeyName Key being set in aSectName + * @param aValue A text value set for the aKeyName in section ASecName + * @return KErrNone if sucessful, otherwise system error + */ +EXPORT_C TInt CIniData::SetValue(const TDesC& aSection,const TDesC& aKeyName,const TDesC& aValue) + { + // First find the variable - this gives us a descriptor into the + // ini data giving the bound of the item that has got to be replaced. + TPtrC ptr; + + if (!FindVar(aSection, aKeyName, ptr, iPtr)) + return KErrNotFound; + + TInt pos = ptr.Ptr()-iPtr.Ptr(); + TInt size = iPtr.Length()+aValue.Length()-ptr.Length(); + + if (size>iPtr.MaxLength()) + { + size = size * sizeof(TText); + TText* newdata = (TText*)User::ReAlloc((TUint8*)iPtr.Ptr(), size); + if (newdata == 0) + return KErrNoMemory; + + iPtr.Set(newdata, iPtr.Length(), iPtr.Length()>size/(TInt)sizeof(TText)?iPtr.Length():size/(TInt)sizeof(TText)); + } + iPtr.Replace(pos, ptr.Length(), aValue); + return(KErrNone); + } + +/** + * Set a text value to given aKeyName regardless of the section in the ini data file + * @param aKeyName Key being searched for + * @param aValue A text value set for the aKeyName + * @return KErrNone if sucessful, otherwise system error + */ +EXPORT_C TInt CIniData::SetValue(const TDesC& aKeyName,const TDesC& aValue) + { + // Call with no section, so starts at beginning + return SetValue((TDesC&)KNullDesC, aKeyName, aValue); + } + +/** + * Add key aKeyName to end of ini data file + * @param aKeyName aKeyName Key being added + * @param aValue Text value assigned to the aKeyName + * @return KErrNone if sucessful, otherwise system error + */ +EXPORT_C TInt CIniData::AddValue(const TDesC& aKeyName,const TDesC& aValue) + { + // Call with no section, so starts at beginning + return AddValue((TDesC&)KNullDesC, aKeyName, aValue); + } + +/** + * Add key aKeyName to section aSectName + * @param aSectName Section + * @param aKeyName Key being added to section aSectName + * @param aValue A text value added to the aKeyName + * @return KErrNone if sucessful, otherwise system error + */ +EXPORT_C TInt CIniData::AddValue(const TDesC& aSectName,const TDesC& aKeyName,const TDesC& aValue) + { + // The request will be denied if the variable exists. + // + // If the variable is not there then making an implementation. + // If the Section name existed in the ini file then just append it + // to this section otherwise append the section, key name and + // variable at the end of the ini file. + TPtrC ptr; + + if (FindVar(aSectName, aKeyName, ptr)) + return KErrAlreadyExists; // an key name exists, + // not allow to add value again to same key + ///////////////////////////// + TPtr insertSection =iToken->Des(); + TInt size; + + TInt posEndOfSection(iPtr.Length()); // Default to the entire length of the ini data + TPtrC SearchBuf; + + // If there is a section, set pos to section start + TInt posI(0); // Initiate to 0. Position in internal data Buffer + TInt posSB(0); + 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 + posSB = SearchBuf.Find(sectionToken); + + // If not found, return + if (posSB==KErrNotFound) + { + FoundSection = ETrue; //Stop while searching + _LIT(insertSectionfmt,"\r\n[%S]\r\n%S = %S\r\n"); //if there is no section existed + insertSection.Format(insertSectionfmt,&aSectName,&aKeyName, &aValue); + } + + + // 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' or posSB == 0) + { + FoundSection = ETrue; // found + posI = posI + posSB; + _LIT(insertSectionfmt,"\r\n%S = %S\r\n"); //if there is no section existed + insertSection.Format(insertSectionfmt,&aKeyName, &aValue); + } + else + { + posI = posI + posSB + 1; // try again + } + } + else + { + FoundSection = ETrue; //found at the beginning of the search buffer + } + + } // while ( ! FoundSection ) + + // Set start of section, after section name, (incl '[' and ']') + if(posSB!=KErrNotFound) + { + + // 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+1; //insert it between \n and [ + } + else + { + posEndOfSection = iPtr.Length(); + } + } + + } // if( aSectName.Length() > 0 ) + + // append/insert here + size = (iPtr.Length()+ insertSection.Length())*sizeof(TText); + if (size>iPtr.MaxLength()) + { + TText* newdata = (TText*)User::ReAlloc((TUint8*)iPtr.Ptr(), size); + if (newdata == 0) + return KErrNoMemory; + + iPtr.Set(newdata, iPtr.Length(), size/(TInt)sizeof(TText)); + } + + iPtr.Insert(posEndOfSection,insertSection); + return(KErrNone); + } + + +/** + * A method used to flush the data in the buffer to the file given in second-phase constructor + */ +EXPORT_C void CIniData::WriteToFileL() + { + +#ifndef __WINC__ + + TAutoClose fs; + User::LeaveIfError(fs.iObj.Connect()); + fs.PushL(); + + TAutoClose file; + User::LeaveIfError(file.iObj.Replace(fs.iObj,*iName,EFileStreamText|EFileShareExclusive)); + file.PushL(); + + // convert 16 bits to 8 bits stream + + HBufC8* buf8 = HBufC8::NewL(iPtr.Length()); + TPtr8 ptr8(buf8->Des()); + ptr8.Copy(iPtr); + User::LeaveIfError(file.iObj.Write(ptr8)); + + delete buf8; + + // Refresh the iPtrExpandedVars with the new written ini file content + // Repeat the process of expanding the ${SYSDRIVE} + UpdateVariablesL(); + + file.Pop(); + fs.Pop(); +#endif + }