/*
* 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
* CStifSectionParser class member functions.
*
*/
// INCLUDE FILES
#include <e32std.h>
#include "StifSectionParser.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: CStifSectionParser
Method: CStifSectionParser
Description: Default constructor.
C++ default constructor can NOT contain any code, that
might leave.
Parameters: const TInt aLength: in: Parsed section length
Return Values: None
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
CStifSectionParser::CStifSectionParser( const TInt aLength ) :
iSection( 0, 0 ),
iLength( aLength ),
iSkipAndMarkPos( 0 ),
iLineIndicator( EFalse )
{
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: ConstructL
Description: Symbian OS second phase constructor.
Symbian OS default constructor can leave.
Parameters: None
Return Values: None
Errors/Exceptions: Leaves if iLength is negative
Leaves if called NewL method fails
Status: Approved
-------------------------------------------------------------------------------
*/
void CStifSectionParser::ConstructL()
{
// Construct modifiable heap-based descriptor
iHBufferSection = HBufC::NewL( iLength );
iSection.Set(iHBufferSection->Des());
iSubOffset = 0;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: NewL
Description: Two-phased constructor.
Parameters: const TInt aLength: in: Parsed section length
Return Values: CStifSectionParser* : pointer to CStifSectionParser object
Errors/Exceptions: Leaves if section length is negative
Leaves if construction fails
Status: Approved
-------------------------------------------------------------------------------
*/
CStifSectionParser* CStifSectionParser::NewL( const TInt aLength )
{
__TRACE( KInfo, ( _L( "STIFPARSER: Create a section" ) ) );
__ASSERT_ALWAYS( aLength > 0, User::Leave( KErrArgument ) );
CStifSectionParser* item = new (ELeave) CStifSectionParser( aLength );
CleanupStack::PushL( item );
item->ConstructL();
CleanupStack::Pop( item );
return item;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: ~CStifSectionParser
Description: Destructor
Parameters: None
Return Values: None
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
CStifSectionParser::~CStifSectionParser()
{
__TRACE( KInfo, ( _L( "STIFPARSER: Call destructor '~CStifSectionParser'" ) ) );
delete iHBufferSection;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: ParseStartAndEndPos
Description: Start and end position parser.
Parameters: TPtrC aSection: in: Parsed section
const TDesC& aStartTag: in: Start tag of parsing
TTagToReturnValue aTagIndicator: in: Will aStartTag included to
the returned values
TInt& aStartPos: inout: Start point of parsing
TInt& aEndPos: inout: End point of parsing
TInt& aLength: inout: Length of parsed section
Return Values: TInt: Error code
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CStifSectionParser::ParseStartAndEndPos( TPtrC aSection,
const TDesC& aStartTag,
TTagToReturnValue aTagIndicator,
TInt& aStartPos,
TInt& aEndPos,
TInt& aLength )
{
TLex lex( aSection );
lex.SkipAndMark( iSkipAndMarkPos );
// Check is aStartTag given
if ( aStartTag.Length() == 0 )
{
// Skip line break, tabs, spaces etc.
lex.SkipSpace();
aStartPos = lex.Offset();
}
else
{
// While end of section and aStartTag is given
while ( !lex.Eos() )
{
lex.SkipSpace();
TPtrC line = SubstractLine( lex.Remainder() );
TInt tagStartPos = 0;
TInt tagEndPos = 0;
if ( FindTag( line, aStartTag, tagStartPos, tagEndPos ) == KErrNone )
{
if ( aTagIndicator == ETag )
{
aStartPos = lex.Offset();
}
else
{
aStartPos = lex.Offset() + tagEndPos;
if ( line.Length() - tagEndPos == 0 )
{
return KErrNotFound;
}
}
break;
}
GotoEndOfLine( lex );
}
}
// End tag parsing starts and if we are end of the section
if( lex.Eos() )
{
return KErrNotFound;
}
// "Delete" white spaces(includes line break)
aEndPos = GotoEndOfLine( lex );
// Position where start next parsing.(End position, includes white spaces)
iSkipAndMarkPos = lex.Offset();
// The length includes spaces and end of lines
aLength = ( aEndPos - aStartPos );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: SubstractLine
Description: Substracts line from selected text
Parameters: TPtrC& aText: in: text.
Return Values: TPtrC: Substracted line.
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TPtrC CStifSectionParser::SubstractLine( const TPtrC& aText )
{
TLex lex( aText );
while( !lex.Eos() )
{
if ( lex.Get() == 0x0A ) // "\n" character. Unix style
{
break;
}
}
return aText.Left( lex.Offset() );
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: FindTag
Description: Searches for selected tag in text
Parameters: const TPtrC& aText: in: text,
const TPtrC& aTag: in: tag,
TInt& aStartPos: out: tag start position,
TInt& aEndPos: out: tag end position.
Return Values: TInt: KErrNone, if tag was found. KErrNotFound if it was not found.
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CStifSectionParser::FindTag( const TDesC& aText, const TDesC& aTag, TInt& aStartPos, TInt& aEndPos ) {
TBool tagWithEqualChar = EFalse;
HBufC* tagBuf = NULL;
TRAPD( err, tagBuf = aTag.AllocL() );
if ( err != KErrNone )
{
return err;
}
RBuf tag( tagBuf );
tag.Trim();
if ( tag.Right( 1 ) == _L("=") )
{
tagWithEqualChar = ETrue;
tag.SetLength( tag.Length() - 1 );
}
TLex lex(aText);
lex.SkipSpaceAndMark();
TInt startPos = lex.Offset();
TPtrC token = lex.NextToken();
if ( !tagWithEqualChar )
{
if ( token == tag )
{
aStartPos = startPos;
lex.SkipSpace();
aEndPos = lex.Offset();
tag.Close();
return KErrNone;
}
}
else
{
lex.UnGetToMark();
TPtrC remText = lex.Remainder();
if ( remText.Find( tag ) == 0 )
{
lex.SkipAndMark( tag.Length() );
lex.SkipSpaceAndMark();
if ( !lex.Eos() )
{
if ( lex.Get() == '=' )
{
aStartPos = startPos;
lex.SkipSpace();
aEndPos = lex.Offset();
tag.Close();
return KErrNone;
}
}
}
}
tag.Close();
return KErrNotFound;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GotoEndOfLine
Description: Goes end of the line.
Parameters: TLex& lex: inout: Parsed line.
Return Values: TInt: Last item's end position.
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CStifSectionParser::GotoEndOfLine( TLex& lex )
{
// End position of the last token(Initialized with current position)
TInt lastItemPosition( lex.Offset() );
// LINE BREAK NOTE:
// Line break in SOS, WIN: '\r\n'
// Line break in UNIX: '\n'
do
{
// Peek next character(10 or '\n' in UNIX style )
if( lex.Peek() == 0x0A )
{
lex.Inc();
break;
}
// Peek next character(13 or '\r' in Symbian OS)
if ( lex.Peek() == 0x0D )
{
// Increment the lex position
lex.Inc();
// Peek next character(10 or '\n' in Symbian OS)
if ( lex.Peek() == 0x0A )
{
// End of the section is found and increment the lex position
lex.Inc();
break;
}
// 0x0A not found, decrement position
lex.UnGet();
}
// Peek for tabulator(0x09) and space(0x20)
else if ( lex.Peek() == 0x09 || lex.Peek() == 0x20 )
{
// Increment the lex position
lex.Inc();
continue;
}
// If white spaces not found take next token
lex.NextToken();
lastItemPosition = lex.Offset();
} while ( !lex.Eos() );
return lastItemPosition;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetItemLineL
Description: Parses a line for items parsing.
If start tag is empty the parsing starts beging of the section.
Parameters: const TDesC& aTag: in: Indicates parsing start point.
TTagToReturnValue aTagIndicator: in: Will aTag included to the
returned object(For default the tag will be added)
Return Values: CStifItemParser* : pointer to CStifItemParser object
NULL will return if ParseStartAndEndPos() method returns -1
NULL will return if length is 0 or negative
NULL will return if iStartPos is 0
Errors/Exceptions: Leaves if called CStifItemParser::NewL method fails
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C CStifItemParser* CStifSectionParser::GetItemLineL( const TDesC& aTag,
TTagToReturnValue aTagIndicator )
{
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
// Indicator that GetItemLineL has been used
iLineIndicator = ETrue;
iSkipAndMarkPos = 0;
TInt ret = ParseStartAndEndPos( iSection, aTag, aTagIndicator,
startPos, endPos, length );
// No parsing found
if ( KErrNone != ret || length <= 0 || startPos < 0 )
{
__TRACE(
KInfo, ( _L( "STIFPARSER: GetItemLineL method returns a NULL" ) ) );
return NULL;
}
CStifItemParser* line = CStifItemParser::NewL(
iSection, startPos, length );
return line;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetNextItemLineL
Description: Parses a next line for items parsing.
Parameters: None
Return Values: CStifItemParser* : pointer to CStifItemParser object
NULL will return if iLineIndicator is false
NULL will return if ParseStartAndEndPos() method returns -1
NULL will return if length is 0 or negative
NULL will return if iStartPos is 0
Errors/Exceptions: Leaves if called CStifItemParser::NewL method fails
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C CStifItemParser* CStifSectionParser::GetNextItemLineL()
{
// GetLine() or GetItemLineL() method is not called
if ( !iLineIndicator )
{
__TRACE( KInfo,
( _L( "STIFPARSER: GetNextItemLineL method returns a NULL" ) ) );
return NULL;
}
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
// tagIndicator has no meaning in this method
TTagToReturnValue tagIndicator( ETag );
TInt ret = ParseStartAndEndPos( iSection, KNullDesC, tagIndicator,
startPos, endPos, length );
// No parsing found
if ( KErrNone != ret || length <= 0 || startPos < 0 )
{
__TRACE( KInfo,
( _L( "STIFPARSER: GetNextItemLineL method returns a NULL" ) ) );
return NULL;
}
CStifItemParser* line = CStifItemParser::NewL(
iSection, startPos, length );
return line;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetNextItemLineL
Description: Parses a next line for items parsing with a tag.
If start tag is empty the parsing starts beging of the section.
Parameters: const TDesC& aTag: in: Indicates parsing start point
TTagToReturnValue aTagIndicator: in: Will aTag included to the
returned object(For default the tag will be added)
Return Values: CStifItemParser* : pointer to CStifItemParser object
NULL will return if iLineIndicator is false
NULL will return if ParseStartAndEndPos() method returns -1
NULL will return if length is 0 or negative
NULL will return if iStartPos is 0
Errors/Exceptions: Leaves if called CStifItemParser::NewL method fails
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C CStifItemParser* CStifSectionParser::GetNextItemLineL(
const TDesC& aTag,
TTagToReturnValue aTagIndicator )
{
// GetLine() or GetItemLineL() method is not called
if ( !iLineIndicator )
{
__TRACE( KInfo,
( _L( "STIFPARSER: GetNextItemLineL method returns a NULL" ) ) );
return NULL;
}
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
TInt ret = ParseStartAndEndPos( iSection, aTag, aTagIndicator,
startPos, endPos, length );
// No parsing found
if ( KErrNone != ret || length <= 0 || startPos < 0 )
{
__TRACE( KInfo,
( _L( "STIFPARSER: GetNextItemLineL method returns a NULL" ) ) );
return NULL;
}
CStifItemParser* line = CStifItemParser::NewL(
iSection, startPos, length );
return line;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: SubSectionL
Description: Parses sub sections from the main section.
If start tag is empty the parsing starts begin of the section.
If end tag is empty the parsing goes end of section.
This method starts always from beginning of parsed section and parses
first subsection if aSeeked parameters is not given.
If parsed section includes several subsections with both start and end
tags so aSeeked parameter seeks the required subsection. The aSeeked
parameters indicates subsection that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates parsing start point
const TDesC& aEndTag: in: Indicates parsing end point
TInt aSeeked: in: a seeked subsection which will be parsed
Return Values: CStifItemParser* : pointer to CStifItemParser object
NULL will return if end tag is not found
NULL will return if length is 0 or negative
NULL will return if lengthStart is 0
Errors/Exceptions: Leaves if called CStifSectionParser::NewL method fails
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifSectionParser* CStifSectionParser::SubSectionL(
const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked )
{
iSubOffset = 0;
return NextSubSectionL( aStartTag, aEndTag, aSeeked );
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: SubSectionL
Description: Parses subsections from the main section.
If start tag is empty the parsing starts begin of the section.
If end tag is empty the parsing goes end of section.
This method will parse next subsection after the earlier subsection if
aSeeked parameter is not given.
If parser section includes several subsections with both start and end
tags so aSeeked parameter seeks the required subsection. The aSeeked
parameter indicates subsection that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates parsing start point
const TDesC& aEndTag: in: Indicates parsing end point
TInt aSeeked: in: a seeked subsection which will be parsed
Return Values: CStifItemParser* : pointer to CStifItemParser object
NULL will return if end tag is not found
NULL will return if length is 0 or negative
NULL will return if lengthStart is 0
Errors/Exceptions: Leaves if called CStifSectionParser::NewL method fails
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifSectionParser* CStifSectionParser::NextSubSectionL(
const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked )
{
TLex lex( iSection );
lex.SkipAndMark( iSubOffset );
// Get the required sub section length
TInt length( 0 );
TInt lengthStartPos( 0 );
TInt lengthEndPos( 0 );
TBool eos( EFalse );
TInt tagCount( 1 );
// Check is aStartTag given
if ( aStartTag.Length() == 0 )
{
// Skip line break, tabs, spaces etc.
lex.SkipSpace();
lengthStartPos = lex.Offset();
}
else
{
// While end of section and aStartTag is given
while ( !lex.Eos() )
{
TPtrC ptr = lex.NextToken();
// Start of the section is found and correct section
if ( ptr == aStartTag && tagCount == aSeeked )
{
// Start position
lengthStartPos = lex.Offset();
break;
}
// Start tag is found but not correct section
else if ( ptr == aStartTag )
{
tagCount++;
}
}
}
// If we are end of section lex.Eos() and eos will be ETrue
eos = lex.Eos();
// Seeked section is not found
if ( tagCount != aSeeked )
{
__TRACE( KInfo, ( _L( "STIFPARSER: NextSubSectionL method: Seeked subsection is not found" ) ) );
User::Leave( KErrNotFound );
}
// Check is aEndTag given
if ( aEndTag.Length() == 0 )
{
lengthEndPos = iSection.MaxLength();
}
else
{
// While end of section and aEndTag is given
while ( !lex.Eos() )
{
TPtrC ptr = lex.NextToken();
// End tag of the section is found
if ( ptr == aEndTag )
{
// End position
lengthEndPos = lex.Offset();
// Because Offset() position is after the aEndTag
lengthEndPos -= aEndTag.Length();
break;
}
}
}
// If we are end of section and lengthEndPos is 0
if ( lengthEndPos == 0 )
{
// lex.Eos() and eos will be ETrue
eos = lex.Eos();
}
// The length includes spaces and end of lines
length = ( lengthEndPos - lengthStartPos );
CStifSectionParser* section = NULL;
// If eos is true or length is negative
if ( eos || length <= 0 )
{
__TRACE( KInfo,
( _L( "STIFPARSER: SubSectionL method returns a NULL" ) ) );
}
else
{
// Position where start next parsing.(End position,
// includes white spaces)
iSubOffset = lex.Offset();
// Make CStifSectionParser object and alloc required length
section = CStifSectionParser::NewL( length );
CleanupStack::PushL( section );
// Copy required data to the section object
section->SetData( iSection, lengthStartPos, length );
CleanupStack::Pop( section );
}
return section;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetLine
Description: Get a line.
Search an item from the section and return rest of the line. If start tag
is empty the parsing starts beging of the section.
Parameters: const TDesC& aTag: in: Indicates parsing start point
TPtr& aLine: inout: Parsed line
TTagToReturnValue aTagIndicator: in: Will aTag included to the
returned value(For default the tag will be added)
Return Values: TInt: Error code
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C TInt CStifSectionParser::GetLine( const TDesC& aTag,
TPtrC& aLine,
TTagToReturnValue aTagIndicator )
{
TInt ret( KErrNone );
if ( 0 == iSection.Length() )
{
return KErrNotFound;
}
// Indicator that GetLine has been used
iLineIndicator = ETrue;
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
iSkipAndMarkPos = 0;
ret = ParseStartAndEndPos( iSection, aTag, aTagIndicator,
startPos, endPos, length );
if ( KErrNone != ret )
{
// Nothing to parse
return ret;
}
aLine.Set( &iSection[startPos], length );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetNextLine
Description: Get a line
Search an item from the section and return rest of the line.
Parameters: TPtr& aLine: inout: Parsed line
Return Values: TInt: Error code
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C TInt CStifSectionParser::GetNextLine( TPtrC& aLine )
{
TInt ret( KErrNone );
// GetLine() or GetItemLineL() method is not called
if ( !iLineIndicator )
{
return KErrNotReady;
}
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
// tagIndicator has no meaning in this method
TTagToReturnValue tagIndicator( ETag );
ret = ParseStartAndEndPos( iSection, KNullDesC, tagIndicator,
startPos, endPos, length );
if ( KErrNone != ret )
{
// Nothing to parse
return ret;
}
aLine.Set( &iSection[startPos], length );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetNextLine
Description: Get a line with tag
Search a next line with the required tag from the section. If start tag
is empty the parsing starts beging of the section.
Parameters: const TDesC& aTag: in: Indicates parsing start point
TPtr& aLine: inout: Parsed line
TTagToReturnValue aTagIndicator: in: Will aTag included to the
returned value(For default the tag will be added)
Return Values: TInt: Error code
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C TInt CStifSectionParser::GetNextLine( const TDesC& aTag, TPtrC& aLine,
TTagToReturnValue aTagIndicator )
{
TInt ret( KErrNone );
// GetLine() or GetItemLineL() method is not called
if ( !iLineIndicator )
{
return KErrNotReady;
}
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
ret = ParseStartAndEndPos( iSection, aTag, aTagIndicator,
startPos, endPos, length );
if ( KErrNone != ret )
{
// Nothing to parse
return ret;
}
aLine.Set( &iSection[startPos], length );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: GetPosition
Description: Get current position.
Returns current parsing position, which
can be used as parameter for SetPosition afterwards to go back
to old parsing position.
Parameters: None
Return Values: TInt: Current parsing position.
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C TInt CStifSectionParser::GetPosition()
{
return iSkipAndMarkPos;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: SetPosition
Description: Set current position.
SetPosition can be used to set parsing position, e.g. to rewind
back to some old position retrieved with GetPosition.
Parameters: TInt aPos: in: new parsing position.
Return Values: TInt: Error code
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C TInt CStifSectionParser::SetPosition( TInt aPos )
{
if( aPos < 0 || aPos >= iSection.Length() )
{
return KErrArgument;
}
iSkipAndMarkPos = aPos;
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: SetData
Description: Create a section.
Parameters: const TPtr aData: in: Data to be parsed
TInt aStartPos: in: Indicates parsing start position
TInt aLength: in: Indicates length of parsed section
Return Values: None
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
void CStifSectionParser::SetData( TPtr aData,
TInt aStartPos,
TInt aLength )
{
iSection.Copy( aData.Mid( aStartPos, aLength ) );
}
/*
-------------------------------------------------------------------------------
Class: CStifSectionParser
Method: Des
Description: Returns a section.
Parameters: None
Return Values: const TPtrC: Returns a current section
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
const TPtrC CStifSectionParser::Des()
{
return (TPtrC)iSection;
}
// ================= OTHER EXPORTED FUNCTIONS =================================
// End of File