sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // @internalComponent sl@0: // sl@0: // sl@0: sl@0: #ifndef __INITEMPLATE_H__ sl@0: #define __INITEMPLATE_H__ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: namespace BSUL sl@0: { sl@0: //Line Type enumeration // sl@0: enum TLineType sl@0: { sl@0: EComment, sl@0: ESection, sl@0: EKeyValue sl@0: }; sl@0: sl@0: //utils template class// sl@0: static void GetBufferL(RFs& aFs,const TDesC& aFileName,HBufC8*& aBufferPtr) sl@0: { sl@0: //open the file for reading sl@0: RFile file; sl@0: User::LeaveIfError(file.Open(aFs,aFileName,EFileShareReadersOnly)); sl@0: sl@0: //only process the file if it exists sl@0: TInt filesize; sl@0: CleanupClosePushL(file); sl@0: User::LeaveIfError(file.Size(filesize)); sl@0: aBufferPtr=HBufC8::NewLC(filesize + 2); //In case '\r\n' needs to be appended sl@0: TPtr8 asWritableBuffer(aBufferPtr->Des()); sl@0: User::LeaveIfError(file.Read(0,asWritableBuffer,filesize)); sl@0: sl@0: //check if '\n' is present sl@0: if( filesize > 0 && asWritableBuffer[filesize - 1] != '\n' ) sl@0: { sl@0: asWritableBuffer.Append(_L8("\r\n")); sl@0: } sl@0: //pop the buffer sl@0: CleanupStack::Pop(); sl@0: //close the file sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: sl@0: template sl@0: TBool IsEosAfterSpace(TLexX& aLex) sl@0: { sl@0: aLex.SkipSpace(); sl@0: return (aLex.Eos()); sl@0: } sl@0: sl@0: template sl@0: void RemoveComment(TPtrCX& aLine) sl@0: { sl@0: //Trim anything on the rhs of any inline comment ';' or '#' sl@0: //in this case we need to locate which is the first occuring from left sl@0: TInt semiColon=aLine.Locate(';'); sl@0: TInt hash=aLine.Locate('#'); sl@0: if (semiColon!=KErrNotFound || hash!=KErrNotFound) sl@0: { sl@0: if (semiColon!=KErrNotFound && hash!=KErrNotFound) sl@0: { sl@0: aLine.Set(aLine.Left(semiColon sl@0: void RemoveWSBeforeAndAfter(const TPtrCX& aString,TPtrCX& aOutput) sl@0: { sl@0: TLexX parser(aString); sl@0: parser.SkipSpaceAndMark(); sl@0: TInt offset=parser.Offset(); sl@0: while(!parser.Eos()) sl@0: { sl@0: //now skip for whitespace and check end of string sl@0: //if this is eos we are done unget to mark and break sl@0: parser.SkipCharacters(); sl@0: parser.Mark(); sl@0: if (IsEosAfterSpace(parser)) sl@0: { sl@0: parser.UnGetToMark(); sl@0: break; sl@0: } sl@0: } sl@0: TInt endOffset=parser.MarkedOffset(); sl@0: aOutput.Set(aString.Mid(offset,endOffset-offset)); sl@0: } sl@0: sl@0: template sl@0: TInt CountTokens(TPtrCX aLine) sl@0: { sl@0: TLexX myLexer(aLine); sl@0: TInt tokenCount=0; sl@0: while (!myLexer.Eos()) sl@0: { sl@0: TPtrCX next = myLexer.NextToken(); sl@0: if (next.Size()) sl@0: { sl@0: tokenCount++; sl@0: } sl@0: } sl@0: return tokenCount; sl@0: } sl@0: sl@0: static void CorruptIfL(TBool aIsCorrupt) sl@0: { sl@0: if (aIsCorrupt) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: } sl@0: sl@0: template sl@0: TPtrCX ExtractLineFromBuffer(const TPtrCX& aFileBuffer, TInt aStartOffset) sl@0: { sl@0: TChar delim('\n'); sl@0: TPtrCX partialLine = aFileBuffer.Mid(aStartOffset, aFileBuffer.Length()- aStartOffset); sl@0: TInt delimOffset= partialLine.Locate(delim); sl@0: if (delimOffset==KErrNotFound) sl@0: { sl@0: return partialLine; sl@0: } sl@0: return partialLine.Left(delimOffset+1); sl@0: } sl@0: sl@0: //ini line template class // sl@0: template sl@0: NONSHARABLE_CLASS(CIniLine) : public CBase sl@0: { sl@0: public: sl@0: static CIniLine* NewL(const TDesCX& aLine); sl@0: static CIniLine* NewLC(const TDesCX& aLine); sl@0: static CIniLine* NewLC(HBufCX* aLine, TLineType aTypeOfLine); sl@0: static CIniLine* NewFromSectionNameLC(const TDesCX& aSectionName); sl@0: static CIniLine* NewFromKeyValueLineLC(const TDesCX& aKeyName, const TDesCX& aKeyValue); sl@0: sl@0: ~CIniLine(); sl@0: TLineType LineType() const; sl@0: void InsertBefore(CIniLine* aLine); sl@0: const HBufCX& LineBuffer() const; sl@0: TBool operator==(const CIniLine&) const; sl@0: public: sl@0: TDblQueLink iLink; sl@0: private: sl@0: TLineType DetermineTypeOfLine(const TDesCX& aLine); sl@0: void ConstructL(const TDesCX& aLine); sl@0: CIniLine(HBufCX* aLine, TLineType aLineType); sl@0: CIniLine(); sl@0: private: sl@0: HBufCX* iLine; sl@0: TLineType iLineType; sl@0: }; sl@0: sl@0: template sl@0: CIniLine* CIniLine::NewL(const TDesCX& aLine) sl@0: { sl@0: CIniLine* self=CIniLine::NewLC(aLine); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniLine* CIniLine::NewLC(const TDesCX& aLine) sl@0: { sl@0: CIniLine* self=new (ELeave) CIniLine(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aLine); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniLine* CIniLine::NewLC(HBufCX* aLine, TLineType aTypeOfLine) sl@0: { sl@0: CIniLine* self=new (ELeave) CIniLine(aLine, aTypeOfLine); sl@0: CleanupStack::PushL(self); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniLine::CIniLine(HBufCX* aLine, TLineType aTypeOfLine):iLine(aLine), iLineType(aTypeOfLine) sl@0: {} sl@0: sl@0: template sl@0: CIniLine::CIniLine() sl@0: {} sl@0: sl@0: template sl@0: CIniLine::~CIniLine() sl@0: { sl@0: iLink.Deque(); sl@0: delete iLine; sl@0: } sl@0: sl@0: template sl@0: void CIniLine::ConstructL(const TDesCX& aLine) sl@0: { sl@0: HBufCX* myHBuf = aLine.AllocL(); sl@0: this->iLine = myHBuf; sl@0: this->iLineType = this->DetermineTypeOfLine(aLine); sl@0: } sl@0: sl@0: template sl@0: TLineType CIniLine::DetermineTypeOfLine(const TDesCX& aLine) sl@0: { sl@0: // First recognized character wins. Otherwise return a comment. sl@0: for (TInt i=0; i< aLine.Length();i++) sl@0: { sl@0: TText myChar = aLine[i]; sl@0: switch (myChar) sl@0: { sl@0: case TText('#'): sl@0: case ';': sl@0: return EComment; sl@0: sl@0: case TText('['): sl@0: return ESection; sl@0: sl@0: case TText('='): sl@0: return EKeyValue; sl@0: sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: return EComment; sl@0: } sl@0: sl@0: template sl@0: CIniLine* CIniLine::NewFromSectionNameLC(const TDesCX& aSectionName) sl@0: { sl@0: //Fabricate a section name. sl@0: HBufCX* myBuffer=HBufCX::NewLC(aSectionName.Size()+ 6); //6= "2 cr's and \r" + "[]". sl@0: TPtrX myBuf (myBuffer->Des()); sl@0: myBuf.Append(_L("\r\n[")); sl@0: myBuf.Append(aSectionName); sl@0: myBuf.Append(_L("]\r\n")); sl@0: CIniLine* myLine = CIniLine::NewLC(myBuffer, ESection); sl@0: CleanupStack::Pop(2); sl@0: CleanupStack::PushL(myLine); sl@0: return myLine; sl@0: } sl@0: sl@0: template sl@0: CIniLine* CIniLine::NewFromKeyValueLineLC(const TDesCX& aKeyName, const TDesCX& aKeyValue) sl@0: { sl@0: //Fabricate a key = value line. sl@0: HBufCX* myBuffer=HBufCX::NewLC(aKeyName.Size()+ aKeyValue.Size() + 3); //3= "1 cr + \r" + "=". sl@0: TPtrX myBuf (myBuffer->Des()); sl@0: myBuf.Set(myBuffer->Des()); sl@0: myBuf.Append(aKeyName); sl@0: myBuf.Append('='); sl@0: myBuf.Append(aKeyValue); sl@0: myBuf.Append(_L("\r\n")); sl@0: CIniLine* myLine = CIniLine::NewLC(myBuffer, EKeyValue); sl@0: CleanupStack::Pop(2); sl@0: CleanupStack::PushL(myLine); sl@0: return myLine; sl@0: } sl@0: sl@0: template sl@0: TLineType CIniLine::LineType() const sl@0: { sl@0: return iLineType; sl@0: } sl@0: sl@0: template sl@0: void CIniLine::InsertBefore(CIniLine* aLine) sl@0: { sl@0: aLine->iLink.AddBefore(&(this->iLink)); sl@0: } sl@0: sl@0: template sl@0: const HBufCX& CIniLine::LineBuffer() const sl@0: { sl@0: return *iLine; sl@0: } sl@0: sl@0: template sl@0: TBool CIniLine::operator==(const CIniLine& aLine)const sl@0: { sl@0: if (LineType() != aLine.LineType()) sl@0: return EFalse; sl@0: sl@0: if ((LineBuffer()).Compare(aLine.LineBuffer()) != 0) sl@0: return EFalse; sl@0: return ETrue; sl@0: } sl@0: sl@0: //ini key template class// sl@0: template sl@0: NONSHARABLE_CLASS(CIniKey): public CBase sl@0: { sl@0: public: sl@0: static CIniKey* NewL(const TDesCX& aKeyName,const TDesCX& aKeyValue); sl@0: static CIniKey* NewLC(const TDesCX& aKeyName,const TDesCX& aKeyValue); sl@0: static CIniKey* NewLC(CIniLineX* aLine); sl@0: static TInt CompareKey(const CIniKey& aFirstKey,const CIniKey& aSecondKey); sl@0: sl@0: void SetKeyValue(const TDesCX& aKeyValue); sl@0: TPtrCX KeyName() const; sl@0: TPtrCX KeyValue() const; sl@0: CIniLineX* LineSrc() const; sl@0: ~CIniKey(); sl@0: private: sl@0: CIniKey(const TDesCX& aKeyName, const TDesCX& aKeyValue, CIniLineX* aLine); sl@0: CIniKey(const TDesCX& aKeyName, const TDesCX& aKeyValue); sl@0: static CIniKey* ParseKeyLineL(CIniLineX* aLine); sl@0: private: sl@0: TPtrCX iKeyName; sl@0: TPtrCX iKeyValue; sl@0: CIniLineX* iLineSrc; sl@0: }; sl@0: sl@0: template sl@0: CIniKey* CIniKey::NewL(const TDesCX& aKeyName,const TDesCX& aKeyValue) sl@0: { sl@0: CIniKey* self=new (ELeave) CIniKey(aKeyName, aKeyValue); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniKey* CIniKey::NewLC(const TDesCX& aKeyName,const TDesCX& aKeyValue) sl@0: { sl@0: CIniKey* self=CIniKey::NewL(aKeyName,aKeyValue); sl@0: CleanupStack::PushL(self); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniKey* CIniKey::NewLC(CIniLineX* aLine) sl@0: { sl@0: CIniKey* self=ParseKeyLineL(aLine); sl@0: CleanupStack::PushL(self); sl@0: self->iLineSrc=aLine; sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniKey::CIniKey(const TDesCX& aKeyName, const TDesCX& aKeyValue, CIniLineX* aLine):iKeyName(aKeyName),iKeyValue(aKeyValue),iLineSrc(aLine) sl@0: { } sl@0: sl@0: template sl@0: CIniKey::CIniKey(const TDesCX& aKeyName, const TDesCX& aKeyValue):iKeyName(aKeyName),iKeyValue(aKeyValue),iLineSrc(NULL) sl@0: { } sl@0: sl@0: template sl@0: CIniKey::~CIniKey() sl@0: {} sl@0: sl@0: template sl@0: TPtrCX CIniKey::KeyName() const sl@0: { sl@0: return iKeyName; sl@0: } sl@0: sl@0: template sl@0: TPtrCX CIniKey::KeyValue() const sl@0: { sl@0: return iKeyValue; sl@0: } sl@0: sl@0: template sl@0: CIniLineX* CIniKey::LineSrc() const sl@0: { sl@0: return iLineSrc; sl@0: } sl@0: sl@0: template sl@0: void CIniKey::SetKeyValue(const TDesCX& aKeyValue) sl@0: { sl@0: iKeyValue.Set(aKeyValue); sl@0: } sl@0: sl@0: template sl@0: TInt CIniKey::CompareKey(const CIniKey& aFirstKey,const CIniKey& aSecondKey) sl@0: { sl@0: return (aFirstKey.KeyName()).Compare(aSecondKey.KeyName()); sl@0: } sl@0: sl@0: template sl@0: CIniKey* CIniKey::ParseKeyLineL(CIniLineX* aIniLine) sl@0: { sl@0: const HBufCX& myLine = aIniLine->LineBuffer(); sl@0: //Get the first occurence of '=' sign sl@0: TInt equalOffset=myLine.Locate('='); sl@0: CorruptIfL(equalOffset==KErrNotFound); sl@0: sl@0: TInt tokenCount = CountTokens(myLine.Left(equalOffset)); sl@0: CorruptIfL(tokenCount != 1); sl@0: sl@0: //construct a TLex for checking the lhs of equal sign sl@0: TLexX parser; sl@0: parser.Assign(myLine.Left(equalOffset)); sl@0: parser.SkipSpaceAndMark(); sl@0: parser.SkipCharacters(); sl@0: TPtrCX keyname=parser.MarkedToken(); sl@0: TBool check = (keyname.Length()==0); sl@0: CorruptIfL(check); sl@0: sl@0: //strip off any white space before and after the value sl@0: TInt edgeOfValue=equalOffset; sl@0: while(++edgeOfValue < myLine.Length()) sl@0: { sl@0: TChar t = (myLine)[edgeOfValue]; sl@0: if (!t.IsSpace()) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: TPtrCX keyvalue; sl@0: if (edgeOfValue < myLine.Length()) sl@0: { sl@0: keyvalue.Set(myLine.Mid(edgeOfValue, (myLine.Length()-edgeOfValue-1))); sl@0: } sl@0: sl@0: TInt hashOffset=keyvalue.Locate('#'); sl@0: if (hashOffset>0) sl@0: { sl@0: keyvalue.Set(keyvalue.Left(hashOffset)); sl@0: } sl@0: TInt commentOffset=keyvalue.Locate(';'); sl@0: if (commentOffset > 0) sl@0: { sl@0: keyvalue.Set(keyvalue.Left(commentOffset)); sl@0: } sl@0: sl@0: TInt index = keyvalue.Length()-1; sl@0: if (index > 0) sl@0: { sl@0: while (index > 0) sl@0: { sl@0: TChar t = keyvalue[index]; sl@0: if (t.IsSpace()) sl@0: { sl@0: index--; sl@0: } sl@0: else sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: if (index < (keyvalue.Length()-1)) sl@0: { sl@0: keyvalue.Set(keyvalue.Left(index+1)); sl@0: } sl@0: } sl@0: sl@0: CIniKey* myKey = new (ELeave) CIniKey(keyname,keyvalue, aIniLine); sl@0: return myKey; sl@0: } sl@0: sl@0: //section template class// sl@0: template sl@0: NONSHARABLE_CLASS(CIniSection): public CBase sl@0: { sl@0: public: sl@0: static CIniSection* NewL(const TDesCX& aSectionName); sl@0: static CIniSection* NewLC(const TDesCX& aSectionName); sl@0: static CIniSection* NewL(const TDesCX& aSectionName, CIniLineX* aLineSrc); sl@0: static CIniSection* NewLC(CIniLineX* aLineSrc); sl@0: static TInt CompareSection(const CIniSection& aFirstSection,const CIniSection& aSecondSection); sl@0: ~CIniSection(); sl@0: sl@0: void InsertKeyL(const TDesCX& aKeyName,const TDesCX& aKeyValue); sl@0: void InsertKeyL(const CIniKeyX* aKey); sl@0: void RemoveKeyL(const TDesCX& aKeyName); sl@0: sl@0: TPtrCX KeyValueL(const TDesCX& aKeyName) const; sl@0: TInt KeyCount() const; sl@0: CIniKeyX* FindKeyL(const TDesCX& aKeyName) const; sl@0: TPtrCX SectionName() const; sl@0: sl@0: CIniLineX* SrcLine(); sl@0: void SetSrcLine(CIniLineX* aLineSrc); sl@0: sl@0: //to be used to access individual item sl@0: const CIniKeyX* Key(TInt aIndex) const {return iKeyArray[aIndex];} sl@0: void ReserveSpaceInKeyArrayL(){iKeyArray.ReserveL(1);} sl@0: private: sl@0: CIniSection(TPtrCX aSectionName); sl@0: CIniSection(TPtrCX aSectionName, CIniLineX* aLine); sl@0: static TPtrCX ParseSectionLineL(const HBufCX& aLine); sl@0: sl@0: private: sl@0: TPtrCX iSectionName; sl@0: RPointerArray iKeyArray; sl@0: CIniLineX* iLineSrc; //If no document object exists, then this object is not used. sl@0: }; sl@0: sl@0: template sl@0: CIniSection* CIniSection::NewL(const TDesCX& aSectionName) sl@0: { sl@0: CIniSection* self=new (ELeave) CIniSection(aSectionName); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniSection* CIniSection::NewL(const TDesCX& aSectionName,CIniLineX* aLineSrc) sl@0: { sl@0: CIniSection* self=new (ELeave) CIniSection(aSectionName, aLineSrc); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniSection* CIniSection::NewLC(const TDesCX& aSectionName) sl@0: { sl@0: CIniSection* self=new (ELeave) CIniSection(aSectionName); sl@0: CleanupStack::PushL(self); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniSection* CIniSection::NewLC(CIniLineX* aLineSrc) sl@0: { sl@0: const HBufCX& buffer = aLineSrc->LineBuffer(); sl@0: TPtrCX sectionName = ParseSectionLineL(buffer); sl@0: CIniSection* self=new (ELeave) CIniSection(sectionName, aLineSrc); sl@0: CleanupStack::PushL(self); sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: CIniSection::CIniSection(TPtrCX aSectionName, CIniLineX* aLine):iSectionName(aSectionName), iLineSrc(aLine) sl@0: { sl@0: iKeyArray.Reset(); sl@0: } sl@0: sl@0: template sl@0: CIniSection::CIniSection(TPtrCX aSectionName):iSectionName(aSectionName) sl@0: { sl@0: iKeyArray.Reset(); sl@0: } sl@0: sl@0: template sl@0: CIniSection::~CIniSection() sl@0: { sl@0: iKeyArray.ResetAndDestroy(); sl@0: } sl@0: sl@0: template sl@0: void CIniSection::SetSrcLine(CIniLineX* aLineSrc) sl@0: { sl@0: if (iLineSrc) sl@0: { sl@0: delete iLineSrc; sl@0: } sl@0: iLineSrc = aLineSrc; sl@0: } sl@0: sl@0: template sl@0: TInt CIniSection::KeyCount() const sl@0: { sl@0: return iKeyArray.Count(); sl@0: } sl@0: sl@0: template sl@0: TPtrCX CIniSection::SectionName() const sl@0: { sl@0: return iSectionName; sl@0: } sl@0: sl@0: template sl@0: CIniLineX* CIniSection::SrcLine() sl@0: { sl@0: return iLineSrc; sl@0: } sl@0: sl@0: template sl@0: TInt CIniSection::CompareSection(const CIniSection& aFirstSection,const CIniSection& aSecondSection) sl@0: { sl@0: return aFirstSection.SectionName().Compare(aSecondSection.SectionName()); sl@0: } sl@0: sl@0: template sl@0: void CIniSection::InsertKeyL(const TDesCX& aKeyName,const TDesCX& aKeyValue) sl@0: { sl@0: CIniKeyX* newKey=CIniKeyX::NewLC(aKeyName,aKeyValue); sl@0: InsertKeyL(newKey); sl@0: CleanupStack::Pop(newKey); sl@0: } sl@0: sl@0: template sl@0: void CIniSection::InsertKeyL(const CIniKeyX* aKey) sl@0: { sl@0: iKeyArray.InsertInOrderL(aKey,TLinearOrder(CIniKeyX::CompareKey)); sl@0: } sl@0: sl@0: template sl@0: void CIniSection::RemoveKeyL(const TDesCX& aKeyName) sl@0: { sl@0: CIniKeyX* key=FindKeyL(aKeyName); sl@0: CIniLineX* myLine = key->LineSrc(); sl@0: TInt index=iKeyArray.FindInOrderL(key,TLinearOrder(CIniKeyX::CompareKey)); sl@0: iKeyArray.Remove(index); sl@0: delete key; sl@0: delete myLine; sl@0: } sl@0: sl@0: template sl@0: CIniKeyX* CIniSection::FindKeyL(const TDesCX& aKeyName) const sl@0: { sl@0: CIniKeyX* key=CIniKeyX::NewLC(aKeyName, aKeyName); sl@0: TInt index=iKeyArray.FindInOrderL(key,TLinearOrder(CIniKeyX::CompareKey)); sl@0: CleanupStack::PopAndDestroy(key); sl@0: return iKeyArray[index]; sl@0: } sl@0: sl@0: template sl@0: TPtrCX CIniSection::KeyValueL(const TDesCX& aKeyName) const sl@0: { sl@0: CIniKeyX* key=FindKeyL(aKeyName); sl@0: return key->KeyValue(); sl@0: } sl@0: sl@0: template sl@0: TPtrCX CIniSection::ParseSectionLineL(const HBufCX& aLine) sl@0: { sl@0: //find the last terminating bracket ']' sl@0: //anything in between is considered the section name sl@0: TInt endBracket=aLine.Locate(']'); sl@0: //Check if the terminating bracket exits. Leave with an error code if not found. sl@0: CorruptIfL(endBracket == KErrNotFound); sl@0: sl@0: TInt startBracket=aLine.Locate('['); sl@0: CorruptIfL(startBracket == KErrNotFound); sl@0: sl@0: TPtrCX sectionName=aLine.Mid(startBracket+1, (endBracket-startBracket)-1); sl@0: sl@0: //corrupt if empty section e.g [] sl@0: TBool check = (sectionName.Length()==0); sl@0: CorruptIfL(check); sl@0: sl@0: TLexX lex(sectionName); sl@0: sl@0: //Check for any white space within section name sl@0: //check any white spaces directly after the '[' sl@0: lex.SkipSpace(); sl@0: check = (lex.Offset()>lex.MarkedOffset()); sl@0: CorruptIfL(check); sl@0: lex.SkipCharacters(); sl@0: sl@0: //At this stage we can extract the section name sl@0: sectionName.Set(lex.MarkedToken()); sl@0: return (sectionName); sl@0: } sl@0: sl@0: //iterator template class// sl@0: template sl@0: NONSHARABLE_CLASS(CIniSecIterImplX): public CBase sl@0: { sl@0: public: sl@0: CIniSecIterImplX():iCurrentIndex(0),iSection(NULL){} sl@0: TBool Next(TPtrCX& aKeyName,TPtrCX& aKeyValue); sl@0: void Reset(){iCurrentIndex=0;} sl@0: TBool End(){return iCurrentIndex>=iSection->KeyCount();} sl@0: public: sl@0: TInt iCurrentIndex; sl@0: CIniSectionX* iSection; sl@0: }; sl@0: sl@0: template sl@0: TBool CIniSecIterImplX::Next(TPtrCX& aKeyName,TPtrCX& aKeyValue) sl@0: { sl@0: if (iSection) sl@0: { sl@0: if (iCurrentIndexKeyCount()) sl@0: { sl@0: const CIniKeyX* key=iSection->Key(iCurrentIndex); sl@0: aKeyName.Set(key->KeyName()); sl@0: aKeyValue.Set(key->KeyValue()); sl@0: iCurrentIndex++; sl@0: return ETrue; sl@0: } sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: //inidocument template class// sl@0: template sl@0: NONSHARABLE_CLASS(CIniDocumentTmplX) : public CBase sl@0: { sl@0: public: sl@0: CIniDocumentTmplX(RFs& aFs,TBool aNarrow); sl@0: ~CIniDocumentTmplX(); sl@0: void FlushL(const TDesC& aFileName); sl@0: sl@0: TInt GetSectionList(RArray& aSectionList) const; sl@0: void GetKeyValueL(const TDesCX& aSectionName,const TDesCX& aKeyName,TPtrCX& aKeyValue) const; sl@0: CIniSectionX* SectionL(const TDesCX& aSectionName) const; sl@0: sl@0: CIniSectionX* AddSectionL(const TDesCX& aSectionName, CIniLineX* aLine); sl@0: CIniSectionX* AddSectionL(const TDesCX& aSectionName); sl@0: void AddSectionL(const CIniSectionX* aSection); sl@0: sl@0: void RemoveSectionL(const TDesCX& aSectionName); sl@0: void SetKeyL(const TDesCX& aSectionName,const TDesCX& aKeyName,const TDesCX& aKeyValue); sl@0: void RemoveKeyL(const TDesCX& aSectionName,const TDesCX& aKeyName); sl@0: void RemoveLineL(CIniLineX* aLine); sl@0: void InsertKeyValueIntoQueueL(CIniLineX* aKeyValue, CIniSectionX& aSection); sl@0: void AppendIntoQueue(CIniLineX* aSection); sl@0: TBool CompareDocs(CIniDocumentTmplX& aDoc); sl@0: sl@0: private: sl@0: CIniSectionX* FindSectionL(const TDesCX& aSectionName) const; sl@0: void ConstructL(const TDesC& aFileName); sl@0: sl@0: private: sl@0: TBool iNarrow; sl@0: RFs& iFs; sl@0: TDblQue iDocument; sl@0: RPointerArray iSectionArray; sl@0: }; sl@0: sl@0: template sl@0: CIniDocumentTmplX::CIniDocumentTmplX(RFs& aFs,TBool aNarrow):iNarrow(aNarrow),iFs(aFs) sl@0: { sl@0: iSectionArray.Reset(); sl@0: iDocument.SetOffset(_FOFF(CIniLineX, iLink)); sl@0: iDocument.Reset(); sl@0: } sl@0: sl@0: template sl@0: TBool CIniDocumentTmplX::CompareDocs(CIniDocumentTmplX& aDoc) sl@0: { sl@0: CIniLineX* lineFromA; // This object is a. The passed in one is b. sl@0: CIniLineX* lineFromB; sl@0: TDblQueIter itera(this->iDocument); sl@0: TDblQueIter iterb(aDoc.iDocument); sl@0: sl@0: TBool NotDoneYet= ETrue; sl@0: while (NotDoneYet) sl@0: { sl@0: lineFromA = itera++; sl@0: lineFromB = iterb++; sl@0: if ((lineFromA == NULL) || (lineFromB == NULL)) sl@0: break; sl@0: sl@0: if (!(*lineFromA == *lineFromB)) sl@0: { sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: if ( (lineFromA) || (lineFromB)) sl@0: return EFalse; sl@0: sl@0: if ((this->iSectionArray.Count()) != (aDoc.iSectionArray.Count())) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: for (TInt i=0; iiSectionArray.Count(); i++) sl@0: { sl@0: TPtrCX secNameA = this->iSectionArray[i]->SectionName(); sl@0: TPtrCX secNameB = aDoc.iSectionArray[i]->SectionName(); sl@0: if ((secNameA.Compare(secNameB))!= 0) sl@0: return EFalse; sl@0: sl@0: if ((this->iSectionArray[i]->KeyCount()) != (aDoc.iSectionArray[i]->KeyCount())) sl@0: return EFalse; sl@0: sl@0: lineFromA = this->iSectionArray[i]->SrcLine(); sl@0: lineFromB = aDoc.iSectionArray[i]->SrcLine(); sl@0: sl@0: if (!(*lineFromA == *lineFromB)) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: for (TInt k=0; kiSectionArray[i]->KeyCount(); k++) sl@0: { sl@0: const CIniKeyX* keyA = this->iSectionArray[i]->Key(k); sl@0: const CIniKeyX* keyB = aDoc.iSectionArray[i]->Key(k); sl@0: if (keyA->KeyName().Compare(keyB->KeyName()) != 0) sl@0: return EFalse; sl@0: if (keyA->KeyValue().Compare(keyB->KeyValue()) != 0) sl@0: return EFalse; sl@0: sl@0: lineFromA = keyA->LineSrc(); sl@0: lineFromB = keyB->LineSrc(); sl@0: sl@0: if (!(*lineFromA == *lineFromB)) sl@0: { sl@0: return EFalse; sl@0: } sl@0: } sl@0: } sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::AppendIntoQueue(CIniLineX* aLine) sl@0: { sl@0: if (iDocument.IsEmpty()) sl@0: { sl@0: iDocument.AddFirst(*aLine); sl@0: } sl@0: else sl@0: { sl@0: iDocument.AddLast(*aLine); //always at the end of the list. sl@0: } sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::InsertKeyValueIntoQueueL(CIniLineX* aKeyValue,CIniSectionX& aSection) sl@0: { sl@0: // Find the end of the section (if exists). sl@0: CIniLineX* lastEntry; sl@0: CIniLineX* line; sl@0: TDblQueIter iter(iDocument); sl@0: sl@0: lastEntry = aSection.SrcLine(); //by default insert into queue after this line entry. sl@0: iter.Set(*lastEntry); // search after this point for a keyvalue line. sl@0: iter++; //point to next line sl@0: while ((line = iter++) != NULL) sl@0: { sl@0: lastEntry=line; sl@0: TLineType typeOfLine = line->LineType(); sl@0: if (typeOfLine == ESection) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: sl@0: if ( line == NULL ) sl@0: { sl@0: AppendIntoQueue(aKeyValue); sl@0: } sl@0: else sl@0: { sl@0: if (iDocument.IsLast(lastEntry)) sl@0: { sl@0: AppendIntoQueue(aKeyValue); sl@0: } sl@0: else sl@0: { sl@0: lastEntry->InsertBefore(aKeyValue); sl@0: } sl@0: } sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::FlushL(const TDesC& aFileName) sl@0: { sl@0: //we need to get the path for the target file sl@0: TParse originFile; sl@0: User::LeaveIfError(originFile.Set(aFileName,NULL,NULL)); sl@0: sl@0: //Need to ensure path exists sl@0: TInt error=iFs.MkDirAll(originFile.DriveAndPath()); sl@0: if (error!=KErrAlreadyExists) sl@0: { sl@0: User::LeaveIfError(error); sl@0: } sl@0: sl@0: //Constructing the temp file name with the same directory and path sl@0: TFileName tempFile; sl@0: RFile file; sl@0: User::LeaveIfError(file.Temp(iFs,originFile.DriveAndPath(),tempFile,EFileWrite)); sl@0: CleanupClosePushL(file); sl@0: sl@0: TPtrC8 bufPtr; sl@0: if (!iNarrow) sl@0: { sl@0: TChar myChar(0xFEFF); sl@0: const unsigned char* myChar8=reinterpret_cast(&myChar); sl@0: bufPtr.Set(myChar8, 2); sl@0: User::LeaveIfError(file.Write(bufPtr)); sl@0: } sl@0: sl@0: TDblQueIter iter(iDocument); sl@0: CIniLineX* line; sl@0: while ((line = iter++) != NULL) sl@0: { sl@0: const HBufCX& tempBuffer=line->LineBuffer(); sl@0: const TUint8* rawptr8=reinterpret_cast(tempBuffer.Ptr()); sl@0: if (iNarrow) sl@0: { sl@0: bufPtr.Set(rawptr8,tempBuffer.Length()); sl@0: } sl@0: else sl@0: { sl@0: bufPtr.Set(rawptr8,tempBuffer.Length()*2); sl@0: } sl@0: User::LeaveIfError(file.Write(bufPtr)); sl@0: } sl@0: User::LeaveIfError(file.Flush()); sl@0: CleanupStack::PopAndDestroy(); sl@0: sl@0: //Finally try replacing or creating a new file sl@0: //depending on whether file exist or not sl@0: TEntry entry; sl@0: if (iFs.Entry(aFileName,entry)==KErrNone) sl@0: { sl@0: User::LeaveIfError(iFs.Replace(tempFile,aFileName)); sl@0: } sl@0: else sl@0: { sl@0: User::LeaveIfError(iFs.Rename(tempFile,aFileName)); sl@0: } sl@0: } sl@0: sl@0: template sl@0: TInt CIniDocumentTmplX::GetSectionList(RArray& aSectionList) const sl@0: { sl@0: //Reset the list first sl@0: aSectionList.Reset(); sl@0: for (TInt i=0;iSectionName(); sl@0: TInt ret=aSectionList.Append(nameptr); sl@0: //If error half way fo the copying, reset the list first sl@0: if (ret!=KErrNone) sl@0: { sl@0: aSectionList.Reset(); sl@0: return ret; sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::GetKeyValueL(const TDesCX& aSectionName,const TDesCX& aKeyName,TPtrCX& aKeyValue) const sl@0: { sl@0: //Find if section exists sl@0: CIniSectionX* section = SectionL(aSectionName); sl@0: aKeyValue.Set(section->KeyValueL(aKeyName)); sl@0: } sl@0: sl@0: template sl@0: CIniSectionX* CIniDocumentTmplX::SectionL(const TDesCX& aSectionName) const sl@0: { sl@0: CIniSectionX* section = FindSectionL(aSectionName); sl@0: return section; sl@0: } sl@0: sl@0: template sl@0: CIniSectionX* CIniDocumentTmplX::AddSectionL(const TDesCX& aSectionName) sl@0: { sl@0: //Find if section exists sl@0: CIniSectionX* section = NULL; sl@0: TRAPD(ret, section = FindSectionL(aSectionName)); sl@0: if ((ret == KErrNone) && (section != NULL)) sl@0: User::Leave(KErrAlreadyExists); sl@0: sl@0: //Fabricate objects upfront and on the cleanup stack to ensure their deletion if OOM conditions occur. sl@0: CIniLineX* myLine = CIniLineX::NewFromSectionNameLC(aSectionName); sl@0: AppendIntoQueue(myLine); sl@0: sl@0: // reserve 1 slot for the new section name to provoke the out of memory condition sl@0: // before actually inserting the object to avoid having to go back and remove it if it fails. sl@0: this->iSectionArray.ReserveL(1); sl@0: sl@0: // If we have not left, we are sure adding a section should not leave due to OOM. sl@0: CIniSectionX* newSection=AddSectionL(aSectionName, myLine); sl@0: CleanupStack::Pop(myLine); sl@0: return newSection; sl@0: } sl@0: sl@0: template sl@0: CIniSectionX* CIniDocumentTmplX::AddSectionL(const TDesCX& aSectionName, CIniLineX* aLine) sl@0: { sl@0: CIniSectionX* newSection=CIniSectionX::NewLC(aSectionName); sl@0: AddSectionL(newSection); sl@0: newSection->SetSrcLine(aLine); sl@0: CleanupStack::Pop(newSection); sl@0: return newSection; sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::AddSectionL(const CIniSectionX* aSection) sl@0: { sl@0: iSectionArray.InsertInOrderL(aSection,TLinearOrder(CIniSectionX::CompareSection)); sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::RemoveSectionL(const TDesCX& aSectionName) sl@0: { sl@0: CIniSectionX* section = FindSectionL(aSectionName); sl@0: CIniLineX* line = section->SrcLine(); sl@0: ASSERT(line); //This should never happen ie. the Key object must have a line associated with it. sl@0: sl@0: // remove the lines after to the start of the next section sl@0: TDblQueIter iter(iDocument); sl@0: iter.Set(*line); // search after this point for a keyvalue line. sl@0: TBool atStartofSection = ETrue; sl@0: while ((line = iter++) != NULL) sl@0: { sl@0: TLineType typeOfLine = line->LineType(); sl@0: if ((typeOfLine == ESection)) sl@0: { sl@0: if (!atStartofSection) sl@0: { sl@0: break; sl@0: } sl@0: else sl@0: { sl@0: delete line; sl@0: atStartofSection = EFalse; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: delete line; //includes comment lines which are only in the document object. Otherwise you could just ~section. sl@0: } sl@0: } sl@0: sl@0: TInt index=this->iSectionArray.FindInOrderL(section,TLinearOrder(CIniSectionX::CompareSection)); sl@0: iSectionArray.Remove(index); sl@0: delete section; sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::SetKeyL(const TDesCX& aSectionName,const TDesCX& aKeyName,const TDesCX& aKeyValue) sl@0: { sl@0: //Find if section exists sl@0: CIniSectionX* section = NULL; sl@0: TRAPD(ret, section = FindSectionL(aSectionName)); sl@0: if (ret == KErrNone) sl@0: { sl@0: TRAPD(ret2, RemoveKeyL(aSectionName, aKeyName)); sl@0: if ((ret2 != KErrNone) && (ret2 != KErrNotFound)) sl@0: { sl@0: User::Leave(ret2); sl@0: } sl@0: sl@0: CIniLineX* myLine2 = CIniLineX::NewFromKeyValueLineLC(aKeyName, aKeyValue); sl@0: CIniKeyX* myKey = CIniKeyX::NewLC(myLine2); sl@0: InsertKeyValueIntoQueueL(myLine2, *section); sl@0: sl@0: // reserve 1 slot in the key array to provoke the out of memory condition sl@0: // before inserting the key to avoid having to go back and remove the key if OOM occurs. sl@0: section->ReserveSpaceInKeyArrayL(); sl@0: section->InsertKeyL(myKey); sl@0: sl@0: CleanupStack::Pop(2); sl@0: return; sl@0: } sl@0: if (ret!=KErrNotFound) sl@0: { sl@0: User::Leave(ret); sl@0: } sl@0: sl@0: //Fabricate objects upfront and on the cleanup stack to ensure their deletion if OOM conditions occur. sl@0: CIniLineX* myLine = CIniLineX::NewFromSectionNameLC(aSectionName); sl@0: AppendIntoQueue(myLine); sl@0: CIniLineX* myLine3 = CIniLineX::NewFromKeyValueLineLC(aKeyName, aKeyValue); sl@0: AppendIntoQueue(myLine3); sl@0: CIniKeyX* myKey = CIniKeyX::NewLC(myLine3); sl@0: sl@0: // reserve 1 slot for the new section name to provoke the out of memory condition sl@0: // before actually inserting the object to avoid having to go back and remove it if it fails. sl@0: this->iSectionArray.ReserveL(1); sl@0: sl@0: // If we have not left, we are sure adding a section should not leave due to OOM. sl@0: CIniSectionX* newSection=AddSectionL(aSectionName, myLine); sl@0: sl@0: // reserve 1 slot in the key array of the newly created empty section to provoke the out of memory condition sl@0: // before inserting the key to avoid having to go back and remove the key if OOM occurs. sl@0: TRAPD(err, newSection->ReserveSpaceInKeyArrayL()); sl@0: if (err == KErrNoMemory) sl@0: { sl@0: // In this case, we have an empty newSection object to be removed. sl@0: TInt index=this->iSectionArray.FindInOrder(newSection,TLinearOrder(CIniSectionX::CompareSection)); sl@0: iSectionArray.Remove(index); sl@0: delete newSection; sl@0: CleanupStack::PopAndDestroy(3); sl@0: User::Leave(KErrNoMemory); sl@0: } sl@0: else sl@0: { sl@0: if (err!= KErrNone) sl@0: User::Leave(err); sl@0: } sl@0: sl@0: // we are now sure the next inserts will not fail due to OOM. sl@0: newSection->InsertKeyL(myKey); sl@0: CleanupStack::Pop(3); sl@0: } sl@0: sl@0: template sl@0: void CIniDocumentTmplX::RemoveKeyL(const TDesCX& aSectionName,const TDesCX& aKeyName) sl@0: { sl@0: //Find if section exists sl@0: CIniSectionX* section = FindSectionL(aSectionName); sl@0: section->RemoveKeyL(aKeyName); sl@0: } sl@0: sl@0: template sl@0: CIniSectionX* CIniDocumentTmplX::FindSectionL(const TDesCX& aSectionName) const sl@0: { sl@0: CIniSectionX* newSection=CIniSectionX::NewLC(aSectionName); sl@0: TInt index=iSectionArray.FindInOrderL(newSection,TLinearOrder(CIniSectionX::CompareSection)); sl@0: CleanupStack::PopAndDestroy(newSection); sl@0: return iSectionArray[index]; sl@0: } sl@0: sl@0: template sl@0: CIniDocumentTmplX::~CIniDocumentTmplX() sl@0: { sl@0: CIniLineX* line; sl@0: TDblQueIter iter(iDocument); sl@0: sl@0: while ((line = iter++) != NULL) sl@0: { sl@0: delete line; sl@0: } sl@0: iSectionArray.ResetAndDestroy(); sl@0: } sl@0: sl@0: //light weight template class// sl@0: template sl@0: NONSHARABLE_CLASS(CIniFileImplX): public CBase sl@0: { sl@0: public: sl@0: CIniFileImplX():iBuffer(NULL) {} sl@0: TInt FindVar(const TDesCX& aSection,const TDesCX& aKey,TPtrCX& aValue); sl@0: void ProcessBufferL(const TDesCX& aPtr); sl@0: ~CIniFileImplX() sl@0: { sl@0: delete iBuffer; sl@0: } sl@0: private: sl@0: HBufCX* iBuffer; sl@0: }; sl@0: sl@0: template sl@0: void CIniFileImplX::ProcessBufferL(const TDesCX& aPtr) sl@0: { sl@0: iBuffer = HBufCX::NewL(aPtr.Length() + sizeof('\n')); //1 for cr. sl@0: TPtrX bufferPtr(iBuffer->Des()); sl@0: TLexX lineParser(aPtr); sl@0: while (!lineParser.Eos()) sl@0: { sl@0: //Get line by line which is terminated by \n sl@0: lineParser.SkipSpaceAndMark(); sl@0: while (!lineParser.Eos() && lineParser.Peek()!='\n') sl@0: { sl@0: lineParser.Inc(); sl@0: } sl@0: TPtrCX line=lineParser.MarkedToken(); sl@0: //Now append the LHS of the comment to the buffer sl@0: RemoveComment(line); sl@0: sl@0: //trim any white space before section,key- value and comments sl@0: TLexX removeWs(line); sl@0: removeWs.SkipSpace(); sl@0: if (!removeWs.Eos()) sl@0: { sl@0: bufferPtr.Append(line); sl@0: //this added own delimiter is useful for syntax checking sl@0: bufferPtr.Append('\n'); sl@0: } sl@0: } sl@0: } sl@0: sl@0: template sl@0: TInt CIniFileImplX::FindVar(const TDesCX& aSection,const TDesCX& aKey,TPtrCX& aValue) sl@0: { sl@0: //first find the start of the section [aSectionName] sl@0: //5 here is []\n and the wildcard *\n[sectionname]* sl@0: HBufCX* section=HBufCX::New(aSection.Length()+5); sl@0: if (!section) sl@0: return KErrNoMemory; sl@0: TPtrX sectionPtr(section->Des()); sl@0: sectionPtr.Append(_L("*\n[")); sl@0: sectionPtr.Append(aSection); sl@0: sectionPtr.Append(_L("]*")); sl@0: sl@0: // Find a match purely on the section and not on the value, i.e. checking for a match on sl@0: // [SECTION] does not find a match on key=[SECTION]. sl@0: sl@0: TBool firstSection=ETrue; sl@0: // Matching on first section is different as it should be the first sl@0: // entry, i.e. no *\n before [aSection]* . sl@0: TInt sectionStart=iBuffer->Match(sectionPtr.Mid(2)); sl@0: if (sectionStart==KErrNotFound) sl@0: { sl@0: firstSection=EFalse; sl@0: // Then try to match on any section after the first, i.e. *\n[aSection]* . sl@0: sectionStart=iBuffer->Match(sectionPtr); sl@0: } sl@0: delete section; sl@0: if (sectionStart!=KErrNotFound) sl@0: { sl@0: // There will be always \n added after section, key or value. sl@0: TPtrCX searchBoundary(iBuffer->Mid(sectionStart+aSection.Length()+(firstSection?2:3))); sl@0: searchBoundary.Set(searchBoundary.Mid(searchBoundary.Locate('\n'))); sl@0: //now need to locate the start of next section or end of file sl@0: TBufX matchPattern; sl@0: matchPattern.Append(_L("*\n[*]*")); sl@0: TInt endSearchPos=searchBoundary.Match(matchPattern); sl@0: if (endSearchPos!=KErrNotFound) sl@0: { sl@0: //if can find next section block reduce the search boundary sl@0: searchBoundary.Set(searchBoundary.Left(++endSearchPos)); sl@0: } sl@0: //now time to find the first exact match key i.e "key" does not match "subkey" sl@0: TInt equalOffset; sl@0: //search through the boundary for matching key sl@0: while ((equalOffset=searchBoundary.Locate('='))!=KErrNotFound) sl@0: { sl@0: //skip over the \n char sl@0: searchBoundary.Set(searchBoundary.Mid(1)); sl@0: TLexX keyCheck(searchBoundary.Left(--equalOffset)); sl@0: keyCheck.SkipSpaceAndMark(); sl@0: keyCheck.SkipCharacters(); sl@0: TPtrCX key(keyCheck.MarkedToken()); sl@0: keyCheck.SkipSpace(); sl@0: if (keyCheck.Eos() && key.Compare(aKey)==0) sl@0: { sl@0: TInt location = searchBoundary.Locate('\n'); sl@0: __ASSERT_DEBUG(location >= 0, User::Invariant()); sl@0: //trim any white space before and after the value sl@0: TPtrCX rhs(searchBoundary.Mid(equalOffset+1,location-equalOffset-1)); sl@0: RemoveWSBeforeAndAfter(rhs,aValue); sl@0: return KErrNone; sl@0: } sl@0: //update the next search boundary sl@0: searchBoundary.Set(searchBoundary.Mid(searchBoundary.Locate('\n'))); sl@0: } sl@0: } sl@0: //cannot find here sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: }//namespace BSUL sl@0: #endif//__BAINIPARSERIMPL_H__