/*
* 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 <e32std.h>
#include "StifParser.h"
#include "ParserTracing.h"
#include "StifFileParser.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: CStifParser
Method: CStifParser
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
-------------------------------------------------------------------------------
*/
CStifParser::CStifParser( TCommentType aCommentType ) :
iBuffer( 0, 0 )
{
iCommentType = aCommentType;
iParsingMode = EFileParsing;
iIsUnicode = EFalse;
iFileParser = NULL;
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: ConstructL
Description: Symbian OS second phase constructor
Symbian OS default constructor can leave.
Connecting and opening configuration file if path and file information is
given. If path and file information is not given and information is given
in buffer then create parser according to the buffer.
Parameters: const TDesC& aPath: in: Source path definition
const TDesC& aConfig: in: Configuration filename
const TDesC& aBuffer: in: Buffer of the parsed information
Return Values: None
Errors/Exceptions: Leaves if called Connect method fails
Leaves if called SetSessionPath method fails
Leaves if called Open method fails
Leaves if HBufC::NewL operation leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
void CStifParser::ConstructL( const TDesC& aPath,
const TDesC& aConfig,
const TDesC& aBuffer)
{
if( aPath == KNullDesC && aConfig == KNullDesC && aBuffer != KNullDesC )
{
// Set mode
iParsingMode = EBufferParsing;
// Construct modifiable heap-based descriptor.
iBufferTmp = HBufC::NewL( aBuffer.Length() );
//iBuffer = iBufferTmp->Des();
iBuffer.Set( iBufferTmp->Des() );
// Copy content
iBuffer.Copy( aBuffer );
}
else
{
User::LeaveIfError( iFileServer.Connect() );
__TRACE( KInfo, ( _L( "STIFPARSER: Open configfile '%S%S'" ),
&aPath, &aConfig ) );
User::LeaveIfError( iFileServer.SetSessionPath( aPath ) );
User::LeaveIfError( iFile.Open(
iFileServer, aConfig, EFileRead | EFileShareAny ) );
//Check whether the file is unicoded
__TRACE(KInfo, (_L("STIFPARSER: Check if the file is unicode")));
_LIT(KUnicode, "#UNICODE");
const TInt KUnicodeLength(8 * 2 + 2); //times two, because we want to read unicode string using 8bit descriptor
//two characters more because on some systems FEFF is always added on the beginning of unicode file
TInt size(0);
User::LeaveIfError(iFile.Size(size));
if(size >= KUnicodeLength)
{
TBuf8<KUnicodeLength> buf;
User::LeaveIfError(iFile.Read(0, buf));
TPtrC16 bufuni((TUint16 *)(buf.Ptr()), buf.Length() / 2);
if(bufuni.Find(KUnicode) != KErrNotFound)
{
iIsUnicode = ETrue;
__TRACE(KInfo, (_L("STIFPARSER: File is unicode")));
}
}
//Create file parser object
iFileParser = CStifFileParser::NewL(iFileServer, iFile, iIsUnicode, iCommentType);
}
iOffset = 0;
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: NewL
Description: Two-phased constructor.
Starting creating parser with path and file information.
Parameters: const TDesC& aPath: in: Source path definition
const TDesC& aConfig: in: Configuration filename
TCommentType aCommentType: in: Comment type's indication
Return Values: CStifParser* : pointer to CStifParser object
Errors/Exceptions: Leaves if ConstructL leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifParser* CStifParser::NewL( const TDesC& aPath,
const TDesC& aConfig,
TCommentType aCommentType )
{
__TRACE( KInfo, ( _L( "STIFPARSER: Debug information is used" ) ) );
// Create CStifParser object
CStifParser* parser = new (ELeave) CStifParser( aCommentType );
CleanupStack::PushL( parser );
parser->ConstructL( aPath, aConfig );
CleanupStack::Pop( parser );
return parser;
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: NewL
Description: Two-phased constructor.
Starting creating parser with buffer information.
Parameters: const TDesC& aBuffer: in: Buffer of the parsed informations
TCommentType aCommentType: in: Comment type's indication
Return Values: CStifParser* : pointer to CStifParser object
Errors/Exceptions: Leaves if ConstructL leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifParser* CStifParser::NewL( const TDesC& aBuffer,
TCommentType aCommentType )
{
__TRACE( KInfo, ( _L( "STIFPARSER: Debug information is used" ) ) );
// Create CStifParser object
CStifParser* parser = new (ELeave) CStifParser( aCommentType );
CleanupStack::PushL( parser );
// No path and file name informations. Buffer is given
parser->ConstructL( KNullDesC, KNullDesC, aBuffer );
CleanupStack::Pop( parser );
return parser;
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: ~CStifParser
Description: Destructor
Close file and the fileserver handles.
Parameters: None
Return Values: None
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifParser::~CStifParser()
{
if( iParsingMode == EBufferParsing )
{
delete iBufferTmp;
}
else
{
delete iFileParser;
iFile.Close();
iFileServer.Close();
}
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: SectionL
Description: Parses sections from configuration files.
Open and read configuration source and parses a required section.
If start tag is empty the parsing starts beginning of the configuration
file. If end tag is empty the parsing goes end of configuration file.
This method starts always from beginning of configuration file and parses
first section if aSeeked parameters is not given.
If configuration file includes several sections with both start and end
tags so aSeeked parameter seeks the required section. The aSeeked
parameters indicates section that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates a start tag for parsing
const TDesC& aEndTag: in: Indicates an end tag for parsing
TInt aSeeked: in: a seeked section which will be parsed
Return Values: See NextSectionL() method
Errors/Exceptions: See NextSectionL() method
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C CStifSectionParser* CStifParser::SectionL( const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked )
{
iOffset = 0;
return NextSectionL( aStartTag, aEndTag, aSeeked ,ETrue);
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: NextSectionL
Description: Parses sections from configuration files.
Open and read configuration source and parses a required section.
If start tag is empty the parsing starts beginning of the configuration
file. If end tag is empty the parsing goes end of configuration file.
This method will parse next section after the earlier section if aSeeked
parameter is not given.
If configuration file includes several sections with both start and end
tags so aSeeked parameter seeks the required section. The aSeeked
parameters indicates section that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates a start tag for parsing
const TDesC& aEndTag: in: Indicates an end tag for parsing
TInt aSeeked: in: a seeked section which will be parsed
Return Values: CStifSectionParser* : pointer to CStifSectionParser object
NULL will return if NextSectionFileL (or NextSectionMemoryL) returns NULL
Errors/Exceptions: Leaves if NextSectionFileL leaves
Leaves if NextSectionMemoryL leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifSectionParser* CStifParser::NextSectionL( const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked )
{
//If parsing mode is set to file, we parse directly in the file
if(iParsingMode == EFileParsing)
{
return NextSectionFileL(aStartTag, aEndTag, aSeeked,ETrue );
}
//If parsing mode is set to buffer, process in old way
return NextSectionMemoryL(aStartTag, aEndTag, aSeeked,ETrue );
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: SectionL
Description: Parses sections from configuration files.
Open and read configuration source and parses a required section.
If start tag is empty the parsing starts beginning of the configuration
file. If end tag is empty the parsing goes end of configuration file.
This method starts always from beginning of configuration file and parses
first section if aSeeked parameters is not given.
If configuration file includes several sections with both start and end
tags so aSeeked parameter seeks the required section. The aSeeked
parameters indicates section that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates a start tag for parsing
const TDesC& aEndTag: in: Indicates an end tag for parsing
TInt aSeeked: in: a seeked section which will be parsed
Return Values: See NextSectionL() method
Errors/Exceptions: See NextSectionL() method
Status: Approved
-------------------------------------------------------------------------------
*/
EXPORT_C CStifSectionParser* CStifParser::SectionL( const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked,TBool aIsHasEndTag )
{
iOffset = 0;
return NextSectionL( aStartTag, aEndTag, aSeeked ,aIsHasEndTag);
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: NextSectionL
Description: Parses sections from configuration files.
Open and read configuration source and parses a required section.
If start tag is empty the parsing starts beginning of the configuration
file. If end tag is empty the parsing goes end of configuration file.
This method will parse next section after the earlier section if aSeeked
parameter is not given.
If configuration file includes several sections with both start and end
tags so aSeeked parameter seeks the required section. The aSeeked
parameters indicates section that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates a start tag for parsing
const TDesC& aEndTag: in: Indicates an end tag for parsing
TInt aSeeked: in: a seeked section which will be parsed
Return Values: CStifSectionParser* : pointer to CStifSectionParser object
NULL will return if NextSectionFileL (or NextSectionMemoryL) returns NULL
Errors/Exceptions: Leaves if NextSectionFileL leaves
Leaves if NextSectionMemoryL leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
EXPORT_C CStifSectionParser* CStifParser::NextSectionL( const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked,TBool aIsHasEndTag )
{
//If parsing mode is set to file, we parse directly in the file
if(iParsingMode == EFileParsing)
{
return NextSectionFileL(aStartTag, aEndTag, aSeeked,aIsHasEndTag );
}
//If parsing mode is set to buffer, process in old way
return NextSectionMemoryL(aStartTag, aEndTag, aSeeked,aIsHasEndTag );
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: NextSectionMemoryL
Description: Parses sections from configuration files.
Open and read configuration source and parses a required section.
If start tag is empty the parsing starts beginning of the configuration
file. If end tag is empty the parsing goes end of configuration file.
This method will parse next section after the earlier section if aSeeked
parameter is not given.
If configuration file includes several sections with both start and end
tags so aSeeked parameter seeks the required section. The aSeeked
parameters indicates section that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates a start tag for parsing
const TDesC& aEndTag: in: Indicates an end tag for parsing
TInt aSeeked: in: a seeked section which will be parsed
Return Values: CStifSectionParser* : pointer to CStifSectionParser object
NULL will return if file size or aSeeked is not positive
NULL will return if start tag is not found
NULL will return if end tag is not found
NULL will return if parsed section length is not positive
Errors/Exceptions: Leaves if called Size method fails
Leaves if HBufC::NewLC method leaves
Leaves if called Read method fails
Leaves if CStifSectionParser::NewL methods leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
CStifSectionParser* CStifParser::NextSectionMemoryL( const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked, TBool /*aIsHasEndTag*/ )
{
TInt size( 0 );
// Parser is created straight with data
if( iParsingMode == EBufferParsing )
{
size = iBuffer.Length();
}
// Parser is created with path and file informations
else
{
User::LeaveIfError( iFile.Size( size ) );
}
// size or aSeeked cannot be 0 or negetive
if( size <= 0 || aSeeked <= 0)
{
__TRACE(
KInfo, ( _L( "STIFPARSER: NextSectionL method returns a NULL" ) ) );
return NULL;
}
const TInt tmpSize = 128;//--UNICODE-- KMaxName; // 128 - set to even value, because KMaxName may change in the future
TInt offset( 0 ); // Offset value to parts reading
// Construct modifiable heap-based descriptor. tmp to CleanupStack
HBufC* tmp = HBufC::NewLC( size );
TPtr wholeSection = tmp->Des();
// Construct modifiable heap-based descriptor. tmp2 to CleanupStack
HBufC8* tmp2 = HBufC8::NewLC( tmpSize ); // 128
TPtr8 buf = tmp2->Des();
// Construct modifiable heap-based descriptor. tmp3 to CleanupStack
HBufC* tmp3 = HBufC::NewLC( tmpSize ); // 128
TPtr currentSection = tmp3->Des();
// Parser is created straight with data
if( iParsingMode == EBufferParsing )
{
// If 8 bit copy changes to 16
wholeSection.Copy( iBuffer );
}
// Parser is created with path and file informations
else
{
TPtrC16 currentSectionUnicode;
do // Read data in parts(Maximum part size is KMaxName)
{
// Read data
User::LeaveIfError( iFile.Read( offset, buf, tmpSize ) );
// If file is unicode convert differently
if(iIsUnicode)
{
// 8 bit to 16 with unicode conversion - simply point to byte array as to double-byte array
currentSectionUnicode.Set((TUint16 *)(buf.Ptr()), buf.Length() / 2);
// Appends current section to whole section
wholeSection.Append( currentSectionUnicode );
}
else
{
// 8 bit to 16
currentSection.Copy( buf );
// Appends current section to whole section
wholeSection.Append( currentSection );
}
offset += tmpSize;
} while( offset < size );
}
CleanupStack::PopAndDestroy( tmp3 );
CleanupStack::PopAndDestroy( tmp2 );
// User wants section without c-style comments
if( iCommentType == ECStyleComments )
{
ParseCommentsOff( wholeSection );
}
TLex lex( wholeSection );
lex.SkipAndMark( iOffset );
// For the required section length and positions
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
while ( !lex.Eos() )
{
TPtrC ptr = lex.NextToken();
// Start of the section is found and correct section
if ( ptr == aStartTag && tagCount == aSeeked )
{
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: NextSectionL method: Seeked section is not found" ) ) );
CleanupStack::PopAndDestroy( tmp );
User::Leave( KErrNotFound );
}
// Check is aEndTag given
if ( aEndTag.Length() == 0 )
{
lengthEndPos = wholeSection.Length();
}
else
{
// While end of section
while ( !lex.Eos() )
{
TPtrC ptr = lex.NextToken();
// End tag of the section is found
if ( ptr == aEndTag )
{
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: NextSectionL method returns a NULL" ) ) );
}
else
{
// Make CStifSectionParser object and alloc required length
section = CStifSectionParser::NewL( length );
CleanupStack::PushL( section );
// Copy required data to the section object
section->SetData( wholeSection, lengthStartPos, length );
//iOffset += lengthEndPos + aEndTag.Length();
iOffset = lex.Offset();
CleanupStack::Pop( section );
}
CleanupStack::PopAndDestroy( tmp );
return section;
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: NextSectionFileL
Description: Parses sections from configuration files.
Open and read configuration source and parses a required section.
If start tag is empty the parsing starts beginning of the configuration
file. If end tag is empty the parsing goes end of configuration file.
This method will parse next section after the earlier section if aSeeked
parameter is not given.
If configuration file includes several sections with both start and end
tags so aSeeked parameter seeks the required section. The aSeeked
parameters indicates section that will be parsed.
Parameters: const TDesC& aStartTag: in: Indicates a start tag for parsing
const TDesC& aEndTag: in: Indicates an end tag for parsing
TInt aSeeked: in: a seeked section which will be parsed
Return Values: CStifSectionParser* : pointer to CStifSectionParser object
NULL will return if file size or aSeeked is not positive
NULL will return if start tag is not found
NULL will return if end tag is not found
NULL will return if parsed section length is not positive
Errors/Exceptions: Leaves if called Size method fails
Leaves if HBufC::NewLC method leaves
Leaves if called Read method fails
Leaves if CStifSectionParser::NewL methods leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
CStifSectionParser* CStifParser::NextSectionFileL( const TDesC& aStartTag,
const TDesC& aEndTag,
TInt aSeeked ,TBool aIsHasEndTag )
{
HBufC *bufSection = iFileParser->NextSectionL(aStartTag, aEndTag, iOffset, aSeeked,aIsHasEndTag);
if(bufSection)
{
CleanupStack::PushL(bufSection);
TPtr bufSectionPtr(bufSection->Des());
if(iCommentType == ECStyleComments)
{
ParseCommentsOff(bufSectionPtr);
}
// Make CStifSectionParser object and alloc required length
CStifSectionParser* section = CStifSectionParser::NewL(bufSection->Length());
CleanupStack::PushL(section);
// Copy required data to the section object
section->SetData(bufSectionPtr, 0, bufSection->Length());
// Clean
CleanupStack::Pop(section);
CleanupStack::PopAndDestroy(bufSection);
return section;
}
return NULL;
}
/*
-------------------------------------------------------------------------------
Class: CStifParser
Method: ParseCommentsOff
Description: Convert a section without comments.
Parameters: TPtr& aBuf: inout: section to parsed
Return Values: None
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
void CStifParser::ParseCommentsOff( TPtr& aBuf )
{
TInt startPos( 0 );
TInt endPos( 0 );
TInt length( 0 );
enum TSearchType
{
ENormalSearch, // Search a '//' or a '/*'
ECStyleSlashs, // Search is '//'
ECStyleSlashAndAsterisk,// Search is '/*'
EDoRemove, // Remove comment
};
TSearchType searchType( ENormalSearch );
TLex lex( aBuf );
// Remove comments
do
{
switch( searchType )
{
case ENormalSearch:
{
if( lex.Get() == '/' )
{
// Peek next character( '/' )
if( lex.Peek() == '/' )
{
startPos = lex.Offset();
startPos--;
lex.Inc();
searchType = ECStyleSlashs;
}
// Peek next character( '*' )
else if( lex.Peek() == '*' )
{
startPos = lex.Offset();
startPos--;
lex.Inc();
searchType = ECStyleSlashAndAsterisk;
}
}
break;
}
case ECStyleSlashs:
{
// Peek next character(10 or '\n' in UNIX style )
if( lex.Peek() == 0x0A )
{
// Don't remove line break!!( Else this fails:
// 1st line:"this is parsed text 1"
// 2nd line:"this is parsed text 2 // this is comments"
// 1st and 2nd lines will be together and following
// operations may fail)
endPos = lex.Offset();
searchType = EDoRemove;
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 )
{
// Don't remove line break!!( Else this fails:
// 1st line:"this is parsed text 1"
// 2nd line:"this is parsed text 2 // this is comments"
// 1st and 2nd lines will be together and following
// operations may fail)
endPos = lex.Offset();
endPos = endPos - 1; // Two line break characters
searchType = EDoRemove;
break;
}
// 0x0A not found, decrement position
lex.UnGet();
}
// Increment the lex position
lex.Inc();
// Take current end position
endPos = lex.Offset();
break;
}
case ECStyleSlashAndAsterisk:
{
// Peek next character( '*' )
if ( lex.Peek() == '*' )
{
// Increment the lex position
lex.Inc();
// Peek next character( '/')
if ( lex.Peek() == '/' )
{
// End of the section is found and increment the lex position
lex.Inc();
endPos = lex.Offset();
searchType = EDoRemove;
break;
}
// '/' not found, decrement position
lex.UnGet();
}
// Increment the lex position
lex.Inc();
// Take current end position
endPos = lex.Offset();
break;
}
default:
{
searchType = ENormalSearch;
break;
}
} // End of switch
// Remove comment
if( searchType == EDoRemove )
{
length = endPos - startPos;
aBuf.Delete( startPos, length );
lex = aBuf;
searchType = ENormalSearch;
}
} while ( !lex.Eos() );
// If comment is started and configure file ends to eof we remove
// comments althougt there are no end of line or '*/' characters
if( searchType == ECStyleSlashs || searchType == ECStyleSlashs )
{
length = lex.Offset() - startPos;
aBuf.Delete( startPos, length );
}
HandleSpecialMarks( aBuf );
}
//
//-----------------------------------------------------------------------------
//
// Class: CStifParser
//
// Method: HandleSpecialMarks
//
// Description: Handles special marks.( '\/\/', '\/\*' and '*/\/' ). This
// is used when ECStyleComments comment type is used.
//
// Parameters: TPtr& aBuf: inout: section to parsed
//
// Return Values: None
//
// Errors/Exceptions: None
//
// Status: Proposal
//
//-----------------------------------------------------------------------------
//
void CStifParser::HandleSpecialMarks( TPtr& aBuf )
{
TLex lex( aBuf );
TInt firstPos( 0 );
TInt secondPos( 0 );
// // => \/\/ => //
// /* => \/\* => /*
// */ => \*\/ => */
do
{
firstPos = lex.Offset();
TChar get = lex.Get();
// Check is '\'
if( get == '\\' )
{
// Peek next character( '/' )
if( lex.Peek() == '/' )
{
lex.Inc();
secondPos = lex.Offset();
// Peek next character( '\' )
if( lex.Peek() == '\\' )
{
lex.Inc();
// Peek next character( '/' )
if( lex.Peek() == '/' )
{
// Delete mark '\/\/' and replace this with '//'
aBuf.Delete( secondPos, 1 );
aBuf.Delete( firstPos, 1 );
lex = aBuf;
}
// Peek next character( '/' )
else if( lex.Peek() == '*' )
{
// Delete mark '\/\*' and replace this with '/*'
aBuf.Delete( secondPos, 1 );
aBuf.Delete( firstPos, 1 );
lex = aBuf;
}
}
}
// Peek next character( '/' )
else if( lex.Peek() == '*' )
{
lex.Inc();
secondPos = lex.Offset();
// Peek next character( '\' )
if( lex.Peek() == '\\' )
{
lex.Inc();
// Peek next character( '/' )
if( lex.Peek() == '/' )
{
// Delete mark '\*\/' and replace this with '*\'
aBuf.Delete( secondPos, 1 );
aBuf.Delete( firstPos, 1 );
lex = aBuf;
}
}
}
}
firstPos = 0;
secondPos = 0;
} while ( !lex.Eos() );
}
// End of File