diff -r 7fdc9a71d314 -r 8ad140f3dd41 stif/Parser/src/StifFileParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stif/Parser/src/StifFileParser.cpp Wed Oct 13 16:17:58 2010 +0300 @@ -0,0 +1,929 @@ +/* +* Copyright (c) 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: This module contains implementation of CStifParser +* class member functions. +* +*/ + +// INCLUDE FILES +#include +#include "StifFileParser.h" +#include "StifTestInterface.h" +#include "ParserTracing.h" + +// EXTERNAL DATA STRUCTURES +// None + +// EXTERNAL FUNCTION PROTOTYPES +// None + +// CONSTANTS +// None + +// MACROS +// None + +// LOCAL CONSTANTS AND MACROS +// None + +// MODULE DATA STRUCTURES +// None + +// LOCAL FUNCTION PROTOTYPES +// None + +// FORWARD DECLARATIONS +// None + +// ==================== LOCAL FUNCTIONS ======================================= +// None + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: CStifFileParser + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: TCommentType aCommentType: in: Comment type's indication + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CStifFileParser::CStifFileParser(CStifParser::TCommentType aCommentType) + { + iCommentType = aCommentType; + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Sets variables. + + Parameters: RFs& aFs: in: Handle to valid file server + RFile& aFile: in: Handle to the source file + TBool aIsUnicode in: Is file in unicode format + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::ConstructL(RFs& aFs, + RFile& aFile, + TBool aIsUnicode) + { + //Initialization + iFileServer = aFs; + iBaseFile = aFile; + iCurrentFile = &aFile; + iIsUnicode = aIsUnicode; + iBytesPerChar = iIsUnicode ? 2 : 1; + + //Create file stack (INCLUDE feature) + iFileStack = new (ELeave) CStackDeprecated; + + //Add base file to file names array + TFileName fn; + iCurrentFile->FullName(fn); + HBufC* newFile = fn.AllocLC(); + User::LeaveIfError(iFileNames.Append(newFile)); + CleanupStack::Pop(newFile); + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: NewL + + Description: Two-phased constructor. + + Starting creating parser with path and file information. + + Parameters: RFs& aFs: in: Handle to file server + RFile& aFile: in: Source path definition + TBool aIsUnicode in: Is file in unicode format + TCommentType aCommentType: in: Comment type's indication + + Return Values: CStifFileParser* : pointer to CStifFileParser object + + Errors/Exceptions: Leaves if ConstructL leaves + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CStifFileParser* CStifFileParser::NewL(RFs& aFs, + RFile& aFile, + TBool aIsUnicode, + CStifParser::TCommentType aCommentType) + { + // Create CStifParser object + CStifFileParser* parser = new (ELeave) CStifFileParser(aCommentType); + + CleanupStack::PushL(parser); + parser->ConstructL(aFs, aFile, aIsUnicode); + CleanupStack::Pop(parser); + + return parser; + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ~CStifFileParser + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CStifFileParser::~CStifFileParser() + { + //Close file stack + ClearFileStack(); + delete iFileStack; + + //Close section lines array + ClearSectionLinesArray(); + iSectionLines.Close(); + + //Close fila names array + while(iFileNames.Count() > 0) + { + delete iFileNames[0]; + iFileNames.Remove(0); + } + iFileNames.Close(); + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ReadLineL + + Description: Reads line from source file + + Parameters: TPtr& aLineBuffer: in: Descriptor in which line loads + TPtr& aEndOfLineBuffer: in: Descriptor in which end of line sequence is loaded (0x0A or 0x0D 0x0A) + + Return Values: TBool: determines whether line was readed or not + + Errors/Exceptions: Leaves if seek command leaves + Leaves if buffer is too small + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TBool CStifFileParser::ReadLineL(TPtr& aLineBuffer, + TPtr& aEndOfLineBuffer) + { + //Variables + TBuf8<128> buf8; + TBuf16<128> buf16; + TPtrC16 buf; + TInt pos; + TInt offset; + TChar char0x0A = 0x000A; + TChar char0x0D = 0x000D; + + TBuf<1> b0x0A; + b0x0A.Append(char0x0A); + + //Reset buffers + aLineBuffer.Zero(); + aEndOfLineBuffer.Zero(); + + //Read from source + User::LeaveIfError(iCurrentFile->Read(buf8)); + buf16.Copy(buf8); + if(iIsUnicode) + buf.Set((TUint16 *)(buf8.Ptr()), buf8.Length() / 2); + else + buf.Set(buf16.Ptr(), buf16.Length()); + + while(buf.Length()) + { + //Search for end of line char + pos = buf.Find(b0x0A); + + //If found, append readed data to output descriptor and move back file offset to correct position + if(pos >= 0) + { + offset = -((buf.Length() - pos - 1) * iBytesPerChar); + User::LeaveIfError(iCurrentFile->Seek(ESeekCurrent, offset)); + buf.Set(buf.Ptr(), pos + 1); + aLineBuffer.Append(buf); + break; + } + //Otherwise, append whole buffer to output descriptor + else + { + aLineBuffer.Append(buf); + } + //Read next part of data + User::LeaveIfError(iCurrentFile->Read(buf8)); + buf16.Copy(buf8); + if(iIsUnicode) + { + buf.Set((TUint16 *)(buf8.Ptr()), buf8.Length() / 2); + } + else + { + buf.Set(buf16.Ptr(), buf16.Length()); + } + } + + //Set correct end of line buffer + if(buf.Length() > 1) + { + if(buf[buf.Length() - 2] == char0x0D) + { + aEndOfLineBuffer.Append(char0x0D); + } + } + if(buf.Length() > 0) + { + if(buf[buf.Length() - 1] == char0x0A) + { + aEndOfLineBuffer.Append(char0x0A); + } + else + { + aEndOfLineBuffer.Zero(); + } + } + if(aEndOfLineBuffer.Length()) + { + aLineBuffer.SetLength(aLineBuffer.Length() - aEndOfLineBuffer.Length()); + } + + //If no data was found, try to get previous file from stack + if(aLineBuffer.Length() + aEndOfLineBuffer.Length() == 0) + { + //Pop file from stack. If stack is empty, then we achieved end of base file + if(!iFileStack->IsEmpty()) + { + PopFromFileStack(); + aEndOfLineBuffer.Copy(iEolBuf); + return aEndOfLineBuffer.Length(); + } + } + //Check if this is include line + else + { + if(aLineBuffer.Find(KIncludeKeyword) == 0) + { + TFileName fn; + TLex lex(aLineBuffer); + + fn.Copy(lex.NextToken()); //get INCLUDE keyword + fn.Copy(lex.NextToken()); //get cfg file name + if(fn.Length() > 0) + { + TStifUtil::CorrectFilePathL( fn ); + PushFileToStackL(fn); + iEolBuf.Copy(aEndOfLineBuffer); + } + else + { + __TRACE(KError, (_L("No filename was given after INCLUDE. Ignoring"))); + } + + //Read next line + return ReadLineL(aLineBuffer, aEndOfLineBuffer); + } + } + + return aLineBuffer.Length() + aEndOfLineBuffer.Length(); + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ReplaceCommentsLineL + + Description: Replaces comments with spaces from line and copy it to destination buffer + + Parameters: TPtr& aSrcBufPtr: in: Source line with comments + TPtr& aDstBufPtr: out: Destination line without comments + TWhatToFind& aFind: in out: Determines what method currently is looking for + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::ReplaceCommentsLineL(TPtr& aSrcBufPtr, + TPtr& aDstBufPtr, + TWhatToFind& aFind) + { + //Variables + TLex lex(aSrcBufPtr); + TChar ch; + TChar chSpace(' '); + TChar chSlash('/'); + TChar chQuota('\"'); + TChar chMulti('*'); + TChar chHash('#'); + + //Clean buffer + aDstBufPtr.Zero(); + + while(!lex.Eos()) + { + ch = lex.Get(); + + //If the end of line, exit + if(!ch) + { + break; + } + + //We're looking for start od quoted text or comment + if(aFind == EStart) + { + //Special character readed + if(ch == chQuota) + { + aFind = EQuota; + aDstBufPtr.Append(chSpace); + } + //Possible start of comment + else if(ch == chSlash) + { + //Comment to the end of line found + if(lex.Peek() == chSlash) + { + break; + } + //Beginning of a comment found + else if(lex.Peek() == chMulti) + { + aFind = EEndOfComment; + ch = lex.Get(); + aDstBufPtr.Append(chSpace); + aDstBufPtr.Append(chSpace); + } + //No start of comment - add read slash + else + { + aDstBufPtr.Append(ch); + } + } + //Start of hash comment (to the end of line) + else if(ch == chHash) + { + break; + } + //Append readed character to the destination buffer + else + { + aDstBufPtr.Append(ch); + } + } + //We're looking for the end of quoted text + else if(aFind == EQuota) + { + if(ch == chQuota) + { + aFind = EStart; + aDstBufPtr.Append(chSpace); + } + else + { + aDstBufPtr.Append(chSpace); + } + } + //We're looking for the end of comment + else if(aFind == EEndOfComment) + { + //It may be the end of a comment + if(ch == chMulti) + { + ch = lex.Peek(); + //It is the end of a comment + if(ch == chSlash) + { + aFind = EStart; + ch = lex.Get(); + aDstBufPtr.Append(chSpace); + aDstBufPtr.Append(chSpace); + } + //It is not the end of a comment, add this character to the destinaton buffer + else + { + aDstBufPtr.Append(chSpace); + } + } + //It is not the end of a comment, add this character to the destinaton buffer + else + { + aDstBufPtr.Append(chSpace); + } + } + } + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ReplaceHashCommentsLineL + + Description: Copy line to destination buffer and deletes #-style comments + + Parameters: TPtr& aSrcBufPtr: in: Source line with comments + TPtr& aDstBufPtr: out: Destination line without comments + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::ReplaceHashCommentsLineL(TPtr& aSrcBufPtr, + TPtr& aDstBufPtr) + { + //Variables + TLex lex(aSrcBufPtr); + TChar ch; + TChar chHash('#'); + + //Prepare destination buffer + aDstBufPtr.Zero(); + + //Copy source line to destination until # char is found + while(!lex.Eos()) + { + ch = lex.Get(); + + //If the end of line, exit + if(!ch) + { + break; + } + + if(ch == chHash) + { + break; + } + else + { + aDstBufPtr.Append(ch); + } + } + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: NextSectionL + + Description: Finds n-th (aSeeked) section in file starting from m-th (aOffset) position + + Parameters: const TDesc& aStartTag: in: Starting tag of a section + const TDesc& aEndTag: in: Ending tag of a section + TInt& aOffset: in out: Current offset in file (*) + TInt aSeeked: in: Which section is to be found + + Notification: aOffset has different meaning than before adding INCLUDE functionality. + If it has 0 value, that means that we need to remove files stack and go + back to base file to the beginning. Otherwise we don't change current + file read-handler position. + + Return Values: HBufC *: address of a descriptor containing section. Section is returned without tags. + Caller must take care about the freeing descriptor. + + Errors/Exceptions: Leaves if aSeeked is less than 1 or aOffset is negative + Leaves if seek command leaves + Leaves if cannot allocate buffers + Leaves if cannot allocate section + Leaves if length of readed line exceeds KMaxLineLength constant + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +HBufC* CStifFileParser::NextSectionL(const TDesC& aStartTag, + const TDesC& aEndTag, + TInt& aOffset, + TInt aSeeked) + { + // Check arguments + if(aSeeked < 1) + { + User::Leave(KErrArgument); + } + if(aOffset < 0) + { + User::Leave(KErrArgument); + } + + TInt foundSection = 0; + TInt ret; + + // Alloc buffers to read line + const TInt KMaxLineLength = 4096; //If length of readed line exceeds this constant, method will leave + + HBufC* buf = HBufC::NewL(KMaxLineLength); + CleanupStack::PushL(buf); + TPtr bufPtr(buf->Des()); + + HBufC* withoutCommentsBuf = HBufC::NewL(KMaxLineLength); + CleanupStack::PushL(withoutCommentsBuf); + TPtr withoutCommentsBufPtr(withoutCommentsBuf->Des()); + + HBufC* endOfLine = HBufC::NewL(2); //After reading a line it contains 0D0A or 0A or null (how readed line is ended) + CleanupStack::PushL(endOfLine); + TPtr endOfLinePtr(endOfLine->Des()); + + //Set valid position in file + //but only if offset shows to 0. Otherwise keep previus position + if(aOffset == 0) + { + User::LeaveIfError(iBaseFile.Seek(ESeekStart, aOffset)); + ClearFileStack(); + aOffset = 1; + } + + //Prepare to read lines + TBool validSectionBeginFound = EFalse; + TBool validSectionEndFound = EFalse; + TSectionFind whatToFindSection = ESectionStart; + //If no start tag is given start to find end tag immediatly + if(aStartTag.Length() == 0) + { + foundSection++; + whatToFindSection = ESectionEnd; + validSectionBeginFound = ETrue; + } + if(aEndTag.Length() == 0) + { + validSectionEndFound = ETrue; + } + TWhatToFind whatToFind = EStart; + + //Perform reading file + while(ReadLineL(bufPtr, endOfLinePtr)) + { + if(iCommentType == CStifParser::ECStyleComments) + { + ReplaceCommentsLineL(bufPtr, withoutCommentsBufPtr, whatToFind); + } + else + { + ReplaceHashCommentsLineL(bufPtr, withoutCommentsBufPtr); + } + if(whatToFindSection == ESectionStart) + { + //Find in line star tag (if start tag is not given, behave like we've found it) + if(aStartTag.Length() == 0) + { + ret = 0; + } + else + { + ret = withoutCommentsBuf->Find(aStartTag); + } + //If found remember position, move offset of file to actual position + if(ret >= 0) + { + whatToFindSection = ESectionEnd; + TInt offset = -(bufPtr.Length() + endOfLinePtr.Length() - ret - aStartTag.Length()) * iBytesPerChar; + User::LeaveIfError(iCurrentFile->Seek(ESeekCurrent, offset)); + + whatToFind = EStart; //reset marker, because if we've found tag, we couldn't be in the middle of comment or quota + foundSection++; + //Add this line to section lines array + if(foundSection == aSeeked) + { + validSectionBeginFound = ETrue; + } + continue; + } + } + else if(whatToFindSection == ESectionEnd) + { + //Find in line end tag (if end tag is not given, behave like we've found it) + if(aEndTag.Length() == 0) + { + ret = KErrNotFound; + } + else + { + ret = withoutCommentsBuf->Find(aEndTag); + } + //If found check if this is the one we're looking for + if(ret >= 0) + { + whatToFindSection = ESectionStart; + TInt offset = -(bufPtr.Length() + endOfLinePtr.Length() - ret - aEndTag.Length()) * iBytesPerChar; + User::LeaveIfError(iCurrentFile->Seek(ESeekCurrent, offset)); + + whatToFind = EStart; //reset marker, because if we've found tag, we couldn't be in the middle of comment or quota + if(foundSection == aSeeked) + { + //Add this line to section lines array + HBufC* line = HBufC::NewLC(bufPtr.Length()); + TPtr linePtr(line->Des()); + linePtr.Copy(bufPtr.MidTPtr(0, ret)); + User::LeaveIfError(iSectionLines.Append(line)); + CleanupStack::Pop(line); + validSectionEndFound = ETrue; + break; + } + else + { + continue; + } + } + else + { + //If we're in section we are looking for, add line to array + if(foundSection == aSeeked) + { + HBufC* line = HBufC::NewLC(bufPtr.Length() + endOfLinePtr.Length()); + TPtr linePtr(line->Des()); + linePtr.Copy(bufPtr); + linePtr.Append(endOfLinePtr); + User::LeaveIfError(iSectionLines.Append(line)); + CleanupStack::Pop(line); + } + } + } + } + + //Clean data + CleanupStack::PopAndDestroy(endOfLine); + CleanupStack::PopAndDestroy(withoutCommentsBuf); + CleanupStack::PopAndDestroy(buf); + + //Load into section if found + HBufC* section = NULL; + + if(validSectionBeginFound && validSectionEndFound) + { + //Count amount of memory needed for section + TInt i; + TInt size = 0; + for(i = 0; i < iSectionLines.Count(); i++) + size += iSectionLines[i]->Length(); + + //Copy section from array to buffer + section = HBufC::NewL(size); + CleanupStack::PushL(section); + TPtr sectionPtr(section->Des()); + + for(i = 0; i < iSectionLines.Count(); i++) + sectionPtr.Append(*iSectionLines[i]); + + ClearSectionLinesArray(); + + //Clean local data + CleanupStack::Pop(section); + + return section; + } + + ClearSectionLinesArray(); + + //If section was not found, then for compability with CSectionParser leave when not first section was seeking, return NULL when first section was seeking + if(foundSection != aSeeked) + { + if( aSeeked - foundSection > 1) + { + User::Leave(KErrNotFound); + } + } + + return section; + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ClearFileStack + + Description: Closes all files on file stack and clears the stack + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::ClearFileStack(void) + { + while(!iFileStack->IsEmpty()) + { + PopFromFileStack(); + } + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: PopFromFileStack + + Description: Pops RFile handle from file stack and sets correct current file handle + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::PopFromFileStack(void) + { + if(!iFileStack->IsEmpty()) + { + //Pop from stack + iCurrentFile = iFileStack->Pop(); + + TFileName fn; + iCurrentFile->FullName(fn); + + //And remove from file names array + for(TInt i = iFileNames.Count() - 1; i >= 0; i--) + { + if(fn.CompareF(iFileNames[i]->Des()) == KErrNone) + { + delete iFileNames[i]; + iFileNames.Remove(i); + break; + } + } + __TRACE(KInfo, (_L("Closing file [%S]"), &fn)); + + //Close file + iCurrentFile->Close(); + delete iCurrentFile; + + //Set correct current file + if(iFileStack->IsEmpty()) + { + iCurrentFile = &iBaseFile; //base file, because stack is empty + } + else + { + iCurrentFile = iFileStack->Last(); + } + } + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: PushFileToStack + + Description: Opens file and pushes it to stack + + Parameters: TDesc& aFileName in: name of file to open and add to stack + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::PushFileToStackL(const TDesC& aFileName) + { + + //First check if file is not already included + for(TInt i = 0; i < iFileNames.Count(); i++) + { + if(aFileName.CompareF(iFileNames[i]->Des()) == KErrNone) + { + __TRACE(KError, (_L("File [%S] was already included. Ignoring"), &aFileName)); + return; + } + } + + //Open and add file to stack + RFile *nf = new RFile(); + + __TRACE(KInfo, (_L("Including file [%S]"), &aFileName)); + TInt r = nf->Open(iFileServer, aFileName, EFileRead | EFileShareAny); + if(r == KErrNone) + { + //Add to stack + iFileStack->PushL(nf); + + //And add to file names array + HBufC* newFile = aFileName.AllocLC(); + User::LeaveIfError(iFileNames.Append(newFile)); + CleanupStack::Pop(newFile); + + //Set valid pointer of current file + iCurrentFile = nf; + } + else + { + __TRACE(KError, (_L("Could not open file [%S]. Error %d. Ignoring"), &aFileName, r)); + } + } + +/* +------------------------------------------------------------------------------- + + Class: CStifFileParser + + Method: ClearSectionLinesArray + + Description: Deletes all descriptors assigned to array and empties array + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CStifFileParser::ClearSectionLinesArray(void) + { + while(iSectionLines.Count() > 0) + { + delete iSectionLines[0]; + iSectionLines.Remove(0); + } + } + +// End of File