--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/omads/omadsextensions/dsutils/emailxmlutils/src/NSmlEmailParser.cpp Mon Nov 23 14:46:41 2009 +0200
@@ -0,0 +1,793 @@
+/*
+* Copyright (c) 2004 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: Sources
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <s32buf.h>
+#include <s32file.h>
+
+#include "nsmlxmlparser.h"
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CNSmlEmailParser* CNSmlEmailParser::NewL()
+ {
+ CNSmlEmailParser* self = CNSmlEmailParser::NewLC();
+ CleanupStack::Pop();
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CNSmlEmailParser* CNSmlEmailParser::NewLC()
+ {
+ CNSmlEmailParser* self = new (ELeave) CNSmlEmailParser();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::~CNSmlEmailParser
+// Destructor
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CNSmlEmailParser::~CNSmlEmailParser()
+ {
+ if( iTruncated )
+ delete iTruncated;
+
+ if( iExt )
+ {
+ iExt->ResetAndDestroy();
+ delete iExt;
+ }
+
+ if( iEmailItem ) delete iEmailItem;
+
+ if( iTruncType ) delete iTruncType;
+ if( iTruncName ) delete iTruncName;
+ if( iExtData ) delete iExtData;
+
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::ParseXml
+// Parses through the given XML and puts the data it contains
+// to member variables.
+// Note: The string-values in CNSmlEmailParser are NOT copies, but
+// references to aXml. The method does not check, if member variables
+// already contain data, but just writes it (if some of them are already
+// instantiated dynamically, they should be deleted before this method is called).
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TNSmlParserGeneratorError CNSmlEmailParser::ParseXml( HBufC8* aXml )
+ {
+
+ // pre-process the data (remove cdata over <Data>)
+ TRAPD( cdataErr, PreProcessL(aXml));
+ if (cdataErr != EErrorNone)
+ return (TNSmlParserGeneratorError)cdataErr;
+
+ // reset state
+ iSetValues.Reset();
+ iCurrentState = ENone;
+ iLastState = ENone;
+ TPtrC8 ptr(*aXml);
+
+ // parse
+ TRAPD(err, ParseL( ptr ));
+
+ // return error, if in wrong state
+ if( err == EErrorNone && iCurrentState != ENone )
+ return EInvalidXmlError;
+
+ return CheckError(err);
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::GenerateXml
+// Generates Email-XML using the data in member variables. aXml contains the
+// generated xml when the function returns successfully. Note: caller should not
+// instantiate the HBufC8, since this method first counts the size of the xml to
+// be generated and then instatiates the HBufC8 with a correct maximum size. If
+// the given buffer is not NULL, it is destroyed and a new one is instantiated.
+// However, the caller gets the control of the HBufC8 when the function returns.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TNSmlParserGeneratorError CNSmlEmailParser::GenerateXml( HBufC8*& aXml )
+ {
+
+ TRAPD( err, GenerateEmailXmlL( aXml ) );
+
+ return CheckError(err);
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::GenerateEmailXmlL
+// Private method that does the actual email xml generation
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::GenerateEmailXmlL( HBufC8*& aXml )
+ {
+ ConvertIntoEntitiesL();
+
+ // count the size of the xml
+ TInt size = CountXmlSizeL();
+
+ // create buffer for the xml
+
+ if ( aXml )
+ {
+ delete aXml;
+ aXml = NULL;
+ }
+
+ aXml = HBufC8::NewLC(size);
+ TPtr8 ptr = aXml->Des();
+
+ // append data to buffer
+ AppendElement(ptr, KEmailElement());
+
+ if ( iRead )
+ {
+ AppendElement(ptr, KEmailReadElement(), BooleanToString( iRead ));
+ }
+
+ if ( iForwarded )
+ {
+ AppendElement(ptr, KEmailForwardedElement(), BooleanToString( iForwarded ));
+ }
+
+ if ( iReplied )
+ {
+ AppendElement(ptr, KEmailRepliedElement(), BooleanToString( iReplied ));
+ }
+
+ if (iReceived != Time::NullTTime())
+ {
+ AppendElement(ptr, KEmailReceivedElement(), DateTimeToStringL(iReceived));
+ }
+
+ if (iCreated != Time::NullTTime())
+ {
+ AppendElement(ptr, KEmailCreatedElement(), DateTimeToStringL(iCreated));
+ }
+
+ if (iModified != Time::NullTTime())
+ {
+ AppendElement(ptr, KEmailModifiedElement(), DateTimeToStringL(iModified));
+ }
+
+ if ( iDeleted )
+ {
+ AppendElement(ptr, KEmailDeletedElement(), BooleanToString( iDeleted ));
+ }
+
+ if ( iFlagged )
+ {
+ AppendElement(ptr, KEmailFlaggedElement(), BooleanToString( iFlagged ));
+ }
+
+ if ( iEmailItem )
+ {
+ AppendElement(ptr, KEmailItemElement());
+ ptr.Append(KCDataStart);
+ ptr.Append( *iEmailItem );
+ ptr.Append(KCDataEnd);
+ AppendEndElement(ptr, KEmailItemElement());
+ }
+
+ if ( iTruncated )
+ {
+ iTruncated->GenerateXmlL(ptr, this);
+ }
+
+ if ( iExt )
+ {
+ for (TInt i=0; i < iExt->Count(); ++i)
+ {
+ iExt->At(i)->GenerateXmlL(ptr, this);
+ }
+
+ }
+
+
+ AppendEndElement(ptr, KEmailElement());
+
+ CleanupStack::Pop(); // aXml
+
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::CountXmlSizeL
+// Counts how long the xml string will be if it was generated using
+// the values currently in member variables.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CNSmlEmailParser::CountXmlSizeL()
+ {
+ TInt size = 0;
+
+ size += KCDataStart().Length() + KCDataEnd().Length();
+ size += SizeOfElements( KEmailElement() );
+
+ if ( iRead )
+ {
+ size += SizeOfBoolean( iRead, KEmailReadElement() );
+ }
+
+ if ( iForwarded )
+ {
+ size += SizeOfBoolean( iForwarded, KEmailForwardedElement() );
+ }
+
+ if ( iReplied )
+ {
+ size += SizeOfBoolean( iReplied, KEmailRepliedElement() );
+ }
+
+ if (iReceived != Time::NullTTime())
+ {
+ size += SizeOfDatetime( KEmailReceivedElement() );
+ }
+
+ if (iCreated != Time::NullTTime())
+ {
+ size += SizeOfDatetime( KEmailCreatedElement() );
+ }
+
+ if (iModified != Time::NullTTime())
+ {
+ size += SizeOfDatetime( KEmailModifiedElement() );
+ }
+
+ if ( iDeleted )
+ {
+ size += SizeOfBoolean( iDeleted, KEmailDeletedElement() );
+ }
+
+ if ( iFlagged )
+ {
+ size += SizeOfBoolean( iFlagged, KEmailFlaggedElement() );
+ }
+
+ if ( iEmailItem )
+ {
+ size += SizeOfString( iEmailItem, KEmailItemElement() );
+ size += KCDataStart().Length() + KCDataInnerEnd().Length();
+ }
+
+ if ( iTruncated )
+ {
+ size += iTruncated->CountXmlSizeL( this );
+ }
+
+ if ( iExt )
+ {
+ for (TInt i=0; i < iExt->Count(); ++i)
+ {
+ size += iExt->At(i)->CountXmlSize( this );
+ }
+ }
+
+ return size;
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::AddExtL
+// Adds the given extension to iExt
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CNSmlEmailParser::AddExtL( CNSmlExtData* aExt )
+ {
+ iExt->AppendL(aExt);
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::NextElementL
+// Base class' ParseL method calls this method, when a new element is found. aElement
+// is the name of that element (string inside '<' and '>' characters).
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::NextElementL( TPtrC8 aElement )
+ {
+ if (aElement.Length() == 0)
+ User::Leave(EInvalidXmlError);
+
+ TBool startElement = ETrue;
+
+ if(aElement[0] == KCharacterSlash)
+ {
+ // take off the '/' character from the beginning
+ aElement.Set(aElement.Right(aElement.Length()-1));
+ // end element
+ startElement = EFalse;
+ }
+#ifndef __NO_EMPTY_ELEMENTS_
+ else if (aElement[aElement.Length()-1] == KCharacterSlash)
+ {
+ // take off the '/' character from the end
+ aElement.Set(aElement.Left(aElement.Length()-1));
+
+ // empty element == start element, empty data, end element
+ NextElementL( aElement ); // simulates start element
+ NextDataL( _L8("") ); // simulates empty data
+
+ // create the end element
+ HBufC8* end = HBufC8::NewLC(aElement.Length()+1);
+ TPtr8 ptr = end->Des();
+ ptr.Append( _L8("/") );
+ ptr.Append( aElement );
+
+ NextElementL( ptr ); // simulates end element
+
+ CleanupStack::PopAndDestroy(); // end
+
+ return;
+ }
+#endif
+
+ // variables used for state, init to <Email> and not set
+ TNSmlCurrentEmailElement inner = EEmail;
+ TNSmlCurrentEmailElement outer = EEmail;
+ TBool isSet = EFalse;
+
+ // check which element we've got
+ if( aElement == KEmailElement )
+ {
+ outer = ENone;
+ isSet = iSetValues.iEmail;
+ if ( startElement ) iSetValues.iEmail = ETrue;
+ }
+ else if( aElement == KEmailReadElement )
+ {
+ inner = ERead;
+ isSet = iSetValues.iRead;
+ }
+ else if( aElement == KEmailForwardedElement )
+ {
+ inner = EForwarded;
+ isSet = iSetValues.iForwarded;
+ }
+ else if( aElement == KEmailRepliedElement )
+ {
+ inner = EReplied;
+ isSet = iSetValues.iReplied;
+ }
+ else if( aElement == KEmailReceivedElement )
+ {
+ inner = EReceived;
+ isSet = iSetValues.iReceived;
+ }
+ else if( aElement == KEmailCreatedElement )
+ {
+ inner = ECreated;
+ isSet = iSetValues.iCreated;
+ }
+ else if( aElement == KEmailModifiedElement )
+ {
+ inner = EModified;
+ isSet = iSetValues.iModified;
+ }
+ else if( aElement == KEmailDeletedElement )
+ {
+ inner = EDeleted;
+ isSet = iSetValues.iDeleted;
+ }
+ else if( aElement == KEmailFlaggedElement )
+ {
+ inner = EFlagged;
+ isSet = iSetValues.iFlagged;
+ }
+ else if( aElement == KEmailItemElement )
+ {
+ inner = EEmailItem;
+ isSet = iSetValues.iEmailItem;
+ if ( startElement )
+ HandleNextEmailItemStartL();
+ else
+ HandleNextEmailItemEndL();
+ }
+ else if( aElement == KTruncatedElement )
+ {
+ inner = ETrunc;
+ isSet = iSetValues.iTrunc;
+
+ if ( startElement )
+ {
+ if ( !iTruncated )
+ iTruncated = CNSmlTruncatedData::NewL();
+ iSetValues.iTrunc = ETrue;
+ }
+ }
+ else if( aElement == KTruncatedBodyElement )
+ {
+ inner = ETruncBody;
+ outer = ETrunc;
+ if ( startElement )
+ {
+ if( iTruncType )
+ {
+ delete iTruncType;
+ iTruncType = NULL;
+ }
+ iTruncSize = KErrNotFound;
+
+ iSetValues.iTruncBodySize = EFalse;
+ iSetValues.iTruncBodyType = EFalse;
+ }
+ else
+ {
+ iTruncated->AddBodyL(iTruncSize, iTruncType);
+ }
+ }
+ else if( aElement == KTruncatedAttachElement )
+ {
+ inner = ETruncAttach;
+ outer = ETrunc;
+ if ( startElement )
+ {
+ if( iTruncType )
+ {
+ delete iTruncType;
+ iTruncType = NULL;
+ }
+ if( iTruncName )
+ {
+ delete iTruncName;
+ iTruncName = NULL;
+ }
+ iTruncSize = KErrNotFound;
+
+ iSetValues.iTruncAttachName = EFalse;
+ iSetValues.iTruncAttachType = EFalse;
+ iSetValues.iTruncAttachSize = EFalse;
+ }
+ else
+ {
+ iTruncated->AddAttachmentL(iTruncName, iTruncSize, iTruncType);
+ }
+ }
+ else if( aElement == KTruncatedSizeElement )
+ {
+ if ( (startElement && iCurrentState == ETruncBody)
+ || (!startElement && iCurrentState == ETruncBodySize) )
+ {
+ inner = ETruncBodySize;
+ outer = ETruncBody;
+ isSet = iSetValues.iTruncBodySize;
+ }
+ else if ( (startElement && iCurrentState == ETruncAttach)
+ || (!startElement && iCurrentState == ETruncAttachSize) )
+ {
+ inner = ETruncAttachSize;
+ outer = ETruncAttach;
+ isSet = iSetValues.iTruncAttachSize;
+ }
+ else
+ {
+ User::Leave(EInvalidXmlError); // wrong state
+ }
+ }
+ else if( aElement == KTruncatedTypeElement )
+ {
+ if ( (startElement && iCurrentState == ETruncBody)
+ || (!startElement && iCurrentState == ETruncBodyType) )
+ {
+ inner = ETruncBodyType;
+ outer = ETruncBody;
+ isSet = iSetValues.iTruncBodyType;
+ }
+ else if ( (startElement && iCurrentState == ETruncAttach)
+ || (!startElement && iCurrentState == ETruncAttachType) )
+ {
+ inner = ETruncAttachType;
+ outer = ETruncAttach;
+ isSet = iSetValues.iTruncAttachType;
+ }
+ else
+ {
+ User::Leave(EInvalidXmlError); // wrong state
+ }
+ }
+ else if( aElement == KTruncatedNameElement )
+ {
+ inner = ETruncAttachName;
+ outer = ETruncAttach;
+ isSet = iSetValues.iTruncAttachName;
+ }
+ else if( aElement == KExtElement )
+ {
+ inner = EExt;
+ if ( startElement )
+ {
+ if( iExtData )
+ {
+ delete iExtData;
+ iExtData = NULL;
+ }
+ iExtData = CNSmlExtData::NewL();
+ iSetValues.iXNam = EFalse;
+ }
+ else
+ {
+ if( !iSetValues.iXNam ) User::Leave(EMandatoryFieldNotFound); // xnam not set
+ iExt->AppendL(iExtData);
+ iExtData = NULL;
+ }
+ }
+ else if( aElement == KExtXNamElement )
+ {
+ inner = EExtXNam;
+ outer = EExt;
+ isSet = iSetValues.iXNam;
+ }
+ else if( aElement == KExtXValElement )
+ {
+ inner = EExtXVal;
+ outer = EExt;
+ }
+ else
+ { // unknown element
+ User::Leave(EInvalidXmlError);
+ }
+
+
+ // finally, change state depending on was the element start or end element
+ if ( startElement )
+ {
+ StartElementStateChangeL( outer, inner, isSet );
+ }
+ else
+ {
+ EndElementStateChangeL( inner, outer );
+ }
+
+
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::NextDataL
+// Base class' ParseL method calls this method, when a data is read from xml, but that
+// data is not element name (data inside or between elements).
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::NextDataL( TPtrC8 aData )
+ {
+ switch(iCurrentState)
+ {
+ case ENone:
+ case EEmail:
+ case ETrunc:
+ case ETruncBody:
+ case ETruncAttach:
+ case EExt:
+ LeaveIfNotWhiteSpaceL( aData );
+ break;
+ case ERead:
+ iRead = StringToBooleanL(aData);
+ iSetValues.iRead = ETrue;
+ break;
+ case EForwarded:
+ iForwarded = StringToBooleanL(aData);
+ iSetValues.iForwarded = ETrue;
+ break;
+ case EReplied:
+ iReplied = StringToBooleanL(aData);
+ iSetValues.iReplied = ETrue;
+ break;
+ case EDeleted:
+ iDeleted = StringToBooleanL(aData);
+ iSetValues.iDeleted = ETrue;
+ break;
+ case EFlagged:
+ iFlagged = StringToBooleanL(aData);
+ iSetValues.iFlagged = ETrue;
+ break;
+ case EReceived:
+ iReceived = StringToTTimeL(aData);
+ iSetValues.iReceived = ETrue;
+ break;
+ case ECreated:
+ iCreated = StringToTTimeL(aData);
+ iSetValues.iCreated = ETrue;
+ break;
+ case EModified:
+ iModified = StringToTTimeL(aData);
+ iSetValues.iModified = ETrue;
+ break;
+ case EEmailItem:
+ HandleNextEmailItemDataL( aData ); // implementation dependent behavior
+ iSetValues.iEmailItem = ETrue;
+ break;
+ case ETruncBodySize:
+ iTruncSize = StringToIntegerL(aData);
+ iSetValues.iTruncBodySize = ETrue;
+ break;
+ case ETruncBodyType:
+ iTruncType = aData.AllocL();
+ iSetValues.iTruncBodyType = ETrue;
+ break;
+ case ETruncAttachSize:
+ iTruncSize = StringToIntegerL(aData);
+ iSetValues.iTruncAttachSize = ETrue;
+ break;
+ case ETruncAttachName:
+ iTruncName = aData.AllocL();
+ iSetValues.iTruncAttachName = ETrue;
+ break;
+ case ETruncAttachType:
+ iTruncType = aData.AllocL();
+ iSetValues.iTruncAttachType = ETrue;
+ break;
+ case EExtXNam:
+ iExtData->iXNam = aData.AllocL();
+ iSetValues.iXNam = ETrue;
+ break;
+ case EExtXVal:
+ iExtData->AddXValL(aData.AllocL());
+ break;
+ default:
+ User::Leave(EUnknownError); // should never happen
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::HandleNextEmailItemDataL
+// Next emailitem data
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::HandleNextEmailItemDataL( TPtrC8 aData )
+ {
+ iEmailItem = aData.AllocL();
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::StartElementStateChangeL
+// Checks that the state change (new start element) is legal (right order of
+// elements and element not already set) and changes the state.
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::StartElementStateChangeL(TNSmlCurrentEmailElement aCurrentState,
+ TNSmlCurrentEmailElement aNextState,
+ TBool aIsSet)
+ {
+ if( aIsSet || iCurrentState != aCurrentState || aNextState < iLastState )
+ {
+ User::Leave(EInvalidXmlError);
+ }
+
+ iLastState = iCurrentState;
+ iCurrentState = aNextState;
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::EndElementStateChangeL
+// Checks that the state change (new end element) is legal (right order of
+// elements and element not already set) and changes the state.
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::EndElementStateChangeL(TNSmlCurrentEmailElement aCurrentState,
+ TNSmlCurrentEmailElement aNextState )
+ {
+ if( iCurrentState != aCurrentState )
+ {
+ User::Leave(EInvalidXmlError);
+ }
+
+ iLastState = iCurrentState;
+ iCurrentState = aNextState;
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::ConvertIntoEntitiesL
+// Converts special characters of this email-dataobject to corresponding
+// characters. Emailitem needs not to be changed, since it is always
+// placed inside cdata (when generating xml).
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::ConvertIntoEntitiesL()
+ {
+
+ // truncate info
+ if ( iTruncated )
+ {
+ iTruncated->ConvertIntoEntitiesL(this);
+ }
+
+ // extensions
+ if ( iExt )
+ {
+ for (TInt i=0; i < iExt->Count(); ++i)
+ {
+ iExt->At(i)->ConvertIntoEntitiesL(this);
+ }
+ }
+
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::CNSmlEmailParser
+// Private constructor
+// -----------------------------------------------------------------------------
+//
+CNSmlEmailParser::CNSmlEmailParser()
+ : iReceived(Time::NullTTime()), iCreated(Time::NullTTime()), iModified(Time::NullTTime()),
+ iTruncSize(KErrNotFound)
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CNSmlEmailParser::ConstructL
+// Second phase construction
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::ConstructL()
+ {
+ iExt = new (ELeave) CNSmlExtDataArray(3);
+ }
+
+// -----------------------------------------------------------------------------
+// TNSmlSetEmailValues::TNSmlSetEmailValues
+// -----------------------------------------------------------------------------
+//
+CNSmlEmailParser::TNSmlSetEmailValues::TNSmlSetEmailValues()
+ {
+ Reset();
+ }
+
+
+// -----------------------------------------------------------------------------
+// TNSmlSetEmailValues::Reset
+// -----------------------------------------------------------------------------
+//
+void CNSmlEmailParser::TNSmlSetEmailValues::Reset()
+ {
+ iEmail = EFalse;
+ iRead = EFalse;
+ iForwarded = EFalse;
+ iReplied = EFalse;
+ iDeleted = EFalse;
+ iFlagged = EFalse;
+ iReceived = EFalse;
+ iCreated = EFalse;
+ iModified = EFalse;
+ iEmailItem = EFalse;
+ iTrunc = EFalse;
+ iTruncBodySize = EFalse;
+ iTruncBodyType = EFalse;
+ iXNam = EFalse;
+ iTruncAttachSize = EFalse;
+ iTruncAttachType = EFalse;
+ iTruncAttachName = EFalse;
+ }
+
+// End of File