diff -r 000000000000 -r 3e07fef1e154 testexecfw/useremul/src/XmlHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testexecfw/useremul/src/XmlHandler.cpp Mon Mar 08 15:03:44 2010 +0800 @@ -0,0 +1,791 @@ +/*------------------------------------------------------------------ + - + * Software Name : UserEmulator + * Version : v4.2.1309 + * + * Copyright (c) 2009 France Telecom. All rights reserved. + * This software is distributed under the License + * "Eclipse Public License - v 1.0" the text of which is available + * at the URL "http://www.eclipse.org/legal/epl-v10.html". + * + * Initial Contributors: + * France Telecom + * + * Contributors: + *------------------------------------------------------------------ + - + * File Name: XmlHandler.cpp + * + * Created: 13/08/2009 + * Author(s): Marcell Kiss, Reshma Sandeep Das + * + * Description: + * XML Parser implementation + * There are two methods to parse XML document, i.e.; + * - StartParsingL() -> parse XML document without active object. + * - StartParsingWithAoL() -> parse XML document with active object. + *------------------------------------------------------------------ + - + * + */ + +// System Includes +#include +#include +#include +#include +#include +#include +#include + +// User Includes +#include +#include "XmlHandler.h" +#include "Utils.h" +#include "UserEmulatorAppUi.h" + +//Constants +/** + * XML Tags + */ +_LIT8(KAction,"action"); +_LIT8(KName,"name"); +_LIT8(KType,"type"); +_LIT8(KParams,"params"); +_LIT8(KPrintLog,"print"); +_LIT8(KKeys,"keys"); +_LIT8(KLoop,"loop"); +_LIT8(KCount,"count"); +_LIT8(KScreenShot,"screenshot"); + +/** + * Action Types + */ +_LIT( KParamActionsApp, "app" ); +_LIT( KParamActionsView, "view" ); +_LIT( KParamActionsJavaApp, "javaapp" ); +_LIT( KParamActionsWait, "wait" ); +_LIT( KParamActionsOrient, "orientation" ); +_LIT( KParamActionsScreenReset, "screenreset" ); +_LIT( KParamActionsPointerEvent, "pointerevent" ); +_LIT( KParamActionsKeyPress, "keypress" ); +_LIT( KParamCloseApp, "closeapp"); +_LIT( KParamActionsLoop, "loop"); +_LIT( KParamActionsLoopEnd, "loopend"); + +/** + * Keys + */ +_LIT(KLeftSoftKey,"LSK"); +_LIT(KRightSoftKey,"RSK"); +_LIT(KMiddleSoftKey,"MSK"); +_LIT(KDownArrowKey,"DAK"); +_LIT(KUpArrowKey,"UAK"); +_LIT(KRightArrowKey,"RAK"); +_LIT(KLeftArrowKey,"LAK"); +_LIT(KKeySpace,"SP"); +_LIT(KKeyBackSpace,"BS"); +_LIT(KKeyGreaterThan, "gt"); +_LIT(KKeyAmpersand,"amp"); +_LIT(KKeyLessThan,"lt"); +_LIT(KKeyOkKey,"OK"); +_LIT(KKeyMenu,"MENU"); //EAKeyApplication0 +_LIT(KKeyYes,"KYES"); //EKeyYes +_LIT(KKeyNo,"KNO"); //EKeyNo +_LIT(KKeyCamera,"CAM"); +_LIT(KKeyHash,"#"); + +/** + * General Constants + */ +_LIT(KOpeningTag, "<" ); +_LIT(KClosingTag, ">" ); +_LIT(KSlash, "/" ); +_LIT(KEndOfLine, "\f" ); // CEikEdwin uses '\f' as EOF mark. + +_LIT(KF842,"0xF842"); +_LIT(KF843,"0xF843"); +_LIT(Ka7,"0xa7"); +_LIT(KF80A,"0xF80A"); +_LIT(KF809,"0xF809"); +_LIT(KF808,"0xF808"); +_LIT(KF807,"0xF807"); +_LIT(K0008,"0x0008"); +_LIT(K0020,"0x0020"); +_LIT(K0026,"0x0026"); +_LIT(K003C,"0x003C"); +_LIT(K003E,"0x003E"); +_LIT(KF852,"0xF852"); +_LIT(KF862,"0xF862"); +_LIT(KF863,"0xF863"); +_LIT(KF893,"0xF893"); + + +_LIT8(KXmlMimeType, "text/xml" ); + +const TInt KMaxFileNameLength=200; + + +// METHODS DEFINITION +// ----------------------------------------------------------------------------- +// CXmlHandler::NewL +// Creates the instance of class and returns it. +// ----------------------------------------------------------------------------- +// + +CXmlHandler* CXmlHandler::NewL( MXmlHandlerObserver& aObserver, RPointerArray& aActionList) + { + CXmlHandler* self = CXmlHandler::NewLC( aObserver ,aActionList); + CleanupStack::Pop(); + return self; + } + +// ----------------------------------------------------------------------------- +// CXmlHandler::NewLC +// Creates the instance of class and pushes it to the CleanupStack and return +// it. +// ----------------------------------------------------------------------------- +// +CXmlHandler* CXmlHandler::NewLC( MXmlHandlerObserver& aObserver , + RPointerArray& aActionList) + { + CXmlHandler* self = new ( ELeave ) CXmlHandler( aObserver, aActionList); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// ----------------------------------------------------------------------------- +// CXmlHandler::~CXmlHandler +// Cancels any outstanding requests and deletes members. +// ----------------------------------------------------------------------------- +// +CXmlHandler::~CXmlHandler() +{ + Cancel(); + delete iParser; + delete iDisplayResult; + delete iBuffer; + delete iContent; + iContent=NULL; +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::CXmlHandler +// Calls base classes constructor with priority value. Add class to the +// active sheduler. +// ----------------------------------------------------------------------------- +// +CXmlHandler::CXmlHandler( MXmlHandlerObserver& aObserver ,RPointerArray& aActionList) + :CActive( EPriorityStandard ), + iObserver( aObserver ), + iParser( 0 ), + iDisplayResult( 0 ), + iState( EIdle ), + iActionList(aActionList), + iActionListIndex(0) +{ + iIndex = 0; + + CActiveScheduler::Add( this ); +} +// ----------------------------------------------------------------------------- +// CXmlHandler::DoCancel +// From CActive. Cancels any outstanding request according the engine state. +// ----------------------------------------------------------------------------- +// +void CXmlHandler::DoCancel() +{ + TRAP_IGNORE(iParser->ParseEndL()); + iFile.Close(); + delete iBuffer; + iBuffer = 0; +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::RunL +// From CActive. Handles the state changes and notifing the observer. +// ----------------------------------------------------------------------------- +// +void CXmlHandler::RunL() + { + if ( KErrNone == iStatus.Int() ) + { + // If the buffer length is zero, it means we have reached + // the end of the file. + if ( iBuffer->Length() == 0) + { + iParser->ParseEndL(); + iFile.Close(); + delete iBuffer; + iBuffer = 0; + } + + // Otherwise, we continue reading the next chunk of the XML file. + else + { + // Parse the next "part" of the XML document. + iParser->ParseL( *iBuffer ); + + // Read the next chunk of the file. + TPtr8 bufferPtr( iBuffer->Des() ); + iFile.Read( bufferPtr, KBuffer1024, iStatus ); + + // Don't forget to call this.. + SetActive(); + } + } + else + { + iObserver.OnParseCompletedL( iStatus.Int(), iState ); + } + } + +// ----------------------------------------------------------------------------- +// CXmlHandler::ConstructL +// Construction of parser and buffer allocations +// ----------------------------------------------------------------------------- +// +void CXmlHandler::ConstructL() + { + iDisplayResult = HBufC::NewL( KBuffer1024 ); + iContent = HBufC8::NewL(KBuffer128); + } + +// ----------------------------------------------------------------------------- +// CXmlHandler::StartParsingL +// Function to start parsing the XML script without active object +// ----------------------------------------------------------------------------- +// +TInt CXmlHandler::StartParsingL( const TDesC& aFileName ) + { + // If file name is too long then don't parse it just mark it as a failed script + TInt pos=aFileName.LocateReverse('\\'); + if(aFileName.Right(aFileName.Length()-pos).Length()>KMaxFileNameLength) + { + TRAPD(err, iObserver.OnParseCompletedL( KErrGeneral,EOnError )); + return err; + } + + RFile file; + User::LeaveIfError( file.Open( CCoeEnv::Static()->FsSession(), aFileName, + EFileRead ) ); + CleanupClosePushL( file ); + + iDisplayResult->Des().Zero(); + TInt size; + User::LeaveIfError( file.Size( size ) ); + delete iBuffer; + iBuffer = 0; + iBuffer = HBufC8::NewL( size ); + TPtr8 bufferPtr( iBuffer->Des() ); + User::LeaveIfError( file.Read( bufferPtr ) ); + + file.Close(); + CleanupStack::PopAndDestroy(); // file + + delete iParser; + iParser= NULL; + iParser = CParser::NewL( KXmlMimeType, *this ); + + iActionListIndex = iActionList.Count(); + TRAPD(err,iParser->ParseBeginL()); + if(err!=KErrNone) + return err; + TRAPD(err1,iParser->ParseL( *iBuffer )); + if(err1!=KErrNone) + return err1; + TRAPD(err2,iParser->ParseEndL()); + if(err2!=KErrNone) + return err2; + + return KErrNone; + + } + +// ----------------------------------------------------------------------------- +// CXmlHandler::StartParsingWithAoL +// Function to start parsing the XML script +// ----------------------------------------------------------------------------- +// + +void CXmlHandler::StartParsingWithAoL( const TDesC& aFileName ) + { + // Remember to cancel any outstanding request first. + if ( IsActive() ) + { + Cancel(); + } + // If file name is too long then don't parse it just mark it as a failed script + TInt pos=aFileName.LocateReverse('\\'); + if(aFileName.Right(aFileName.Length()-pos).Length()>KMaxFileNameLength) + { + + TRAPD(err, iObserver.OnParseCompletedL( KErrGeneral,EOnError )); + return; + } + User::LeaveIfError( iFile.Open( CCoeEnv::Static()->FsSession(), aFileName, + EFileRead ) ); + + // Create a buffer to store the file content. + // Note that this method uses active object to read the file. + // So we have to call SetActive() at the end. Then we call CParser::ParseL() + // in RunL() method. + iDisplayResult->Des().Zero(); + delete iBuffer; + iBuffer = 0; + iBuffer = HBufC8::NewL( KBuffer1024 ); + TPtr8 bufferPtr( iBuffer->Des() ); + iFile.Read( bufferPtr, KBuffer1024, iStatus ); + SetActive(); + + // Tell the parser that we are about to parse a XML document. + iParser->ParseBeginL(); + } + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnStartDocumentL +// Callback to indicate start of the document +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnStartDocumentL( const RDocumentParameters& /*aDocParam*/, + TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + // Nothing for now + } + else + { + iObserver.OnParseCompletedL( aErrorCode, EOnStartElement ); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnEndDocumentL +// Callback to indicate end of the document +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnEndDocumentL( TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + // Create action object + CAction *action = new(ELeave) CAction(); + CleanupStack::PushL(action); + iActionList.AppendL(action); + + CleanupStack::Pop(); // action + action->iType = EActionTypeEndScript; + } + iObserver.OnParseCompletedL( aErrorCode , EOnEndElement); +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnStartElementL +// Callback to indicate an element has been parsed +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnStartElementL( const RTagInfo& aElement, + const RAttributeArray& aAttributes, TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + const TDesC8& name = aElement.LocalName().DesC(); + + iContent->Des().Zero(); + + TInt i; + + if (name == KAction || name == KLoop) + { + // Create action object + CAction *action = new(ELeave) CAction(); + CleanupStack::PushL(action); + + if(name == KLoop) + { + for (i=0; i tmp; + tmp.Copy(attribValue); + + if(attribName == KCount) + { + action->iType = EActionTypeLoopStart; + if(attribValue == KInfinite) + tmp.Copy(KMinus1); + + action->iParams = tmp.AllocL(); + } + } + } + + iActionList.AppendL(action); + + CleanupStack::Pop(); // action + iAction = action; + + + } + else if (name == KName) + iContentType = EContentName; + else if (name == KType) + iContentType = EContentType; + else if (name == KParams) + iContentType = EContentParams; + else if (name == KPrintLog) + iContentType = EContentPrintLog; + else if (name == KKeys) + iContentType = EContentKeys; + else if (name == KScreenShot) + iContentType = EContentScreenshot; + else + { + } + } + else + { + iObserver.OnParseCompletedL( aErrorCode, EOnStartElement ); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnEndElementL +// Callback to indicate the end of the element has been reached. +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnEndElementL( const RTagInfo &aElement, TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + // If we find the end of an element, we write it to the screen, + // for example: "" + const TDesC8& name = aElement.LocalName().DesC(); + + TPtr8 des(iContent->Des()); + CUtils::StripSpaces(des); + + HBufC *txt = CnvUtfConverter::ConvertToUnicodeFromUtf8L(*iContent); + CleanupStack::PushL(txt); + + if (name == KAction) + { + iAction = NULL; + } + else if (name == KLoop) + { + //reset the flag iLoopExists + CAction *action = new(ELeave) CAction(); + CleanupStack::PushL(action); + action->iType = EActionTypeLoopEnd; + iActionList.AppendL(action); + + CleanupStack::Pop(); // action + iAction = action; + } + else if (name == KType && iContentType == EContentType && iAction) + { + TLex lex(txt->Des()); + lex.SkipSpace(); + TPtrC token = lex.NextToken(); + if (token == KParamActionsView) + iAction->iType = EActionTypeView; + else if (token == KParamActionsApp) + iAction->iType = EActionTypeApp; + else if (token == KParamActionsJavaApp) + iAction->iType = EActionTypeJavaApp; + else if (token == KParamActionsPointerEvent) + iAction->iType = EActionTypePointerEvent; + else if (token == KParamActionsWait) + iAction->iType = EActionTypeWait; + else if (token == KParamActionsOrient) + iAction->iType = EActionTypeOrientationChange; + else if (token == KParamActionsScreenReset) + iAction->iType = EActionTypeScreenReset; + else if (token == KParamActionsKeyPress) + iAction->iType = EActionTypeKeys; + else if (token == KParamCloseApp) + iAction->iType = EActionCloseApp; + } + else if (name == KParams && iContentType == EContentParams && iAction) + { + delete iAction->iParams; + iAction->iParams=NULL; + iAction->iParams = txt->Des().AllocL(); + } + else if (name == KPrintLog && iContentType == EContentPrintLog && iAction) + { + delete iAction->iPrintLog; + iAction->iPrintLog=NULL; + iAction->iPrintLog = txt->Des().AllocL(); + } + else if (name == KScreenShot && iContentType == EContentScreenshot && iAction) + { + delete iAction->iScreenshotTag; + iAction->iScreenshotTag = NULL; + iAction->iScreenshotTag = txt->Des().AllocL(); + } + else if (name == KKeys && iContentType == EContentKeys && iAction) + { + TLex lex(txt->Des()); + TBuf keyName(KN); + + for (lex.SkipSpace(); !lex.Eos(); lex.SkipSpace()) + { + TPtrC token = lex.NextToken(); + keyName.FillZ(); + keyName.Copy(token); + + if(token.Compare(KLeftSoftKey) == 0 ) + keyName.Copy(KF842); + else if(token.Compare(KRightSoftKey) == 0 ) + keyName.Copy(KF843); + else if(token.Compare(KMiddleSoftKey) == 0 ) + keyName.Copy(Ka7); + else if(token.Compare(KDownArrowKey) == 0 ) + keyName.Copy(KF80A); + else if(token.Compare(KUpArrowKey) == 0 ) + keyName.Copy(KF809); + else if(token.Compare(KRightArrowKey) == 0 ) + keyName.Copy(KF808); + else if(token.Compare(KLeftArrowKey) == 0 ) + keyName.Copy(KF807); + else if(token.Compare(KKeyBackSpace) == 0 ) + keyName.Copy(K0008); + else if(token.Compare(KKeySpace) == 0 ) + keyName.Copy(K0020); + else if(token.Compare(KKeyAmpersand) == 0 ) + keyName.Copy(K0026); + else if(token.Compare(KKeyLessThan) == 0 ) + keyName.Copy(K003C); + else if(token.Compare(KKeyGreaterThan) == 0 ) + keyName.Copy(K003E); + else if(token.Compare(KKeyMenu) == 0 ) + keyName.Copy(KF852); + else if(token.Compare(KKeyYes) == 0 ) + keyName.Copy(KF862); + else if(token.Compare(KKeyNo) == 0 ) + keyName.Copy(KF863); + else if(token.Compare(KKeyCamera) == 0 ) + keyName.Copy(KF893); + else if(token.Compare(KKeyHash) == 0 ) + keyName.Copy(_L("0x23")); + + if (keyName.Left(2) == KHEX) + { + //Special keys + TLex lex2(keyName.Mid(2)); + TUint value; + if (lex2.Val(value,EHex) == KErrNone) + iAction->iKeys.AppendL(value); + } + else + { + //alpha numeric keys and symbols + for(TInt i=0; iiKeys.AppendL(value); + } + } + } + } + else + { + } + CleanupStack::PopAndDestroy(); // txt + iContentType = EContentNone; + } + else + { + iObserver.OnParseCompletedL( aErrorCode,EOnEndElement ); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnContentL +// Callback that sends the content of the element +// ----------------------------------------------------------------------------- +// + +void CXmlHandler::OnContentL( const TDesC8 &aBytes, TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + while (iContent->Des().MaxLength() < iContent->Des().Length()+aBytes.Length()) + { + iContent = iContent->ReAllocL(iContent->Des().Length()*3/2); + } + iContent->Des().Append(aBytes); + } + else + { + iObserver.OnParseCompletedL( aErrorCode, EOnContent); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnStartPrefixMappingL +// This method is a notification of the beginning of the scope of a prefix-URI +// Namespace mapping. This method is always called before the corresponding +// OnStartElementL method. +// ----------------------------------------------------------------------------- +// + +void CXmlHandler::OnStartPrefixMappingL( const RString& /*aPrefix*/, + const RString& /*aUri*/, TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + } + else + { + iObserver.OnParseCompletedL( aErrorCode,EOnStartPrefixMapping ); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnEndPrefixMappingL +// This method is a notification of the end of the scope of a prefix-URI mapping. +// This method is called after the corresponding DoEndElementL method. +// ----------------------------------------------------------------------------- +// + +void CXmlHandler::OnEndPrefixMappingL( const RString& /*aPrefix*/, + TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + } + else + { + iObserver.OnParseCompletedL( aErrorCode,EOnEndPrefixMapping ); + } +} +// ----------------------------------------------------------------------------- +// CXmlHandler::OnEndPrefixMappingL +// This method is a notification of ignorable whitespace in element content. +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnIgnorableWhiteSpaceL( const TDesC8& /*aBytes*/, + TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + } + else + { + iObserver.OnParseCompletedL( aErrorCode, EOnIgnorableWhiteSpace ); + } +} +// ----------------------------------------------------------------------------- +// CXmlHandler::OnSkippedEntityL +// This method is a notification of a skipped entity. If the parser encounters an +// external entity it does not need to expand it - it can return the entity as aName +// for the client to deal with. +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnSkippedEntityL( const RString& /*aName*/, + TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + } + else + { + iObserver.OnParseCompletedL( aErrorCode, EOnSkippedEntity ); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnProcessingInstructionL +// This method is a receive notification of a processing instruction. +// ----------------------------------------------------------------------------- +// + +void CXmlHandler::OnProcessingInstructionL( const TDesC8& /*aTarget*/, + const TDesC8& /*aData*/, TInt aErrorCode ) +{ + if ( KErrNone == aErrorCode ) + { + } + else + { + iObserver.OnParseCompletedL( aErrorCode, EOnProcessingInstruction ); + } +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnError +// This method indicates an error has occurred. +// ----------------------------------------------------------------------------- +// +void CXmlHandler::OnError( TInt aErrorCode ) +{ + _LIT( KErrorMessage, "*** OnError ***\f" ); + TRAPD(error, AppendTextL( KErrorMessage )); + + iAction = NULL; + //reset the flag iLoopExists + for(TInt i = iActionList.Count() - 1; i >= iActionListIndex; i--) + { + CAction *action = iActionList.operator [](iActionListIndex); + if(action) + { + delete action; + action = NULL; + } + iActionList.Remove(iActionListIndex); + } + TRAPD(err, iObserver.OnParseCompletedL( aErrorCode,EOnError )); +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::OnError +// This method obtains the interface matching the specified uid. +// ----------------------------------------------------------------------------- +// + +TAny* CXmlHandler::GetExtendedInterface( const TInt32 /*aUid*/ ) +{ + return NULL; +} + +// ----------------------------------------------------------------------------- +// CXmlHandler::AppendTextL +// Function to expand the actual buffer size +// ----------------------------------------------------------------------------- +// + +void CXmlHandler::AppendTextL( const TDesC& aText ) +{ + TPtr displayResultPtr( iDisplayResult->Des() ); + if ( displayResultPtr.Length() + aText.Length() > displayResultPtr.MaxLength() ) + { + TRAPD(err, iDisplayResult = iDisplayResult->ReAllocL( displayResultPtr.MaxLength() + + KBuffer1024 )); + displayResultPtr.Set( iDisplayResult->Des() ); + } + displayResultPtr.Append( aText ); +} + +// ----------------------------------------------------------------------------- +// CAction::~CAction +// Destructor for the CAction class +// ----------------------------------------------------------------------------- +// +CAction::~CAction() +{ + delete iParams; + iParams=NULL; + delete iPrintLog; + iPrintLog = NULL; + delete iScreenshotTag; + iScreenshotTag = NULL; + iKeys.Close(); +} +// End of File