srsf/vcommandmanager/src/vcxmlparser.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2005-2007 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:  Parser for Voice Commands XML files
*
*/


// INCLUDE FILES
#include <e32math.h>
#include <featmgr.h>
#include <parser.h>
#include <utf.h>
#include "vcxmlparser.h"
#include "vcresource.h"
#include "rubydebug.h"

// CONSTANTS
// XML Tags
_LIT8( KXmlDocumentTag, "nssvcommands" );
_LIT8( KXmlFolderTag, "vcommandfolder" );
_LIT8( KXmlVCommandTag, "vcommand" );
_LIT8( KXmlSpokenTag, "spoken" ); 
_LIT8( KXmlWrittenTag, "written" ); 
_LIT8( KXmlExecutesTag, "executes" );
_LIT8( KXmlCmdlineparamsTag, "cmdlineparams" );
_LIT8( KXmlIconTag, "icon" );
_LIT8( KXmlTooltipTag, "tooltip" );

// XML attributes
_LIT8( KXmlVersionAttr, "version" );
_LIT8( KXmlLocFileAttr, "localizationfile" );
_LIT8( KXmlLocAttr, "locindex" );
_LIT8( KXmlFolderTitleLocAttr, "titlelocindex" );
_LIT8( KXmlFolderIconFileAttr, "iconfile" );
_LIT8( KXmlFolderIconIndexAttr, "iconindex" );
_LIT8( KXmlTtsAttr, "tts" );
_LIT8( KXmlModifiableAttr, "modifiable" );
_LIT8( KXmlUidAttr, "uid" );
_LIT8( KXmlExeAttr, "exe" );

// XML attribute values
_LIT8( KXmlVersionValue, "1.0" );
_LIT8( KXmlTrueValue, "true" );
_LIT8( KXmlFalseValue, "false" );

// XML file MIME type
_LIT8( KMimeType, "text/xml" );

static const TInt KNoTags = 0;
static const TInt KLastTag = 1;

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CVcXmlParser::CVcXmlParser
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CVcXmlParser::CVcXmlParser( RFs& aRFs, MVcXmlParserObserver& aObserver )
 : iObserver( aObserver ), iRFs( aRFs )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CVcXmlParser::ConstructL()
    {
    RUBY_DEBUG_BLOCK( "CVcXmlParser::ConstructL" );
    
    ResetVCommandFolder();
    
    using namespace Xml;
    
    iParser = CParser::NewL( KMimeType, *this );
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CVcXmlParser* CVcXmlParser::NewL( RFs& aRFs, MVcXmlParserObserver& aObserver )
    {
    CVcXmlParser* self = new( ELeave ) CVcXmlParser( aRFs, aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::~CVcXmlParser
// Destructor.
// -----------------------------------------------------------------------------
//
CVcXmlParser::~CVcXmlParser()
    {
    iXmlNesting.Close();
    ResetVCommandInfo();
    delete iResource;
    delete iFolder;
    delete iFolderTitle;
    delete iFolderIconFile;
    delete iAttributeValue;
    delete iParser;
    delete iParameters;
    delete iParameters8;
    delete iAppName;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ParseFileL
// Parses a specific file.
// -----------------------------------------------------------------------------
//
void CVcXmlParser::ParseFileL( const TFileName& aFileName )
    {
    RUBY_DEBUG_BLOCK( "CVcXmlParser::ParseFileL" );
    
    iParser->ParseBeginL();
    
    ParseL( *iParser, iRFs, aFileName );
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnStartDocumentL
// Callback from XML parser when beginning of document has been found
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnStartDocumentL( const Xml::RDocumentParameters& /*aDocParam*/, 
                                     TInt aErrorCode )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::OnStartDocumentL" );
    
    delete iResource;
    iResource = NULL;
    
    if ( ( iXmlNesting.Count() == KNoTags ) && ( aErrorCode == KErrNone ) )
        {
        iXmlNesting.Append( EXmlStarted );
        }
    else
        {
        User::Leave( KErrGeneral );
        }
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnEndDocumentL
// Callback from XML parser when end of document has been reached
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnEndDocumentL( TInt aErrorCode )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::OnEndDocumentL" );
    
    if ( ( iXmlNesting.Count() == KLastTag ) && ( aErrorCode == KErrNone ) )
        {
        iXmlNesting.Reset();
        }
    else
        {
        User::Leave( KErrGeneral );
        }
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnStartElementL
// Callback from XML parser when new element has been found
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnStartElementL( const Xml::RTagInfo& aElement, 
	                                const Xml::RAttributeArray& aAttributes, 
	                                TInt aErrorCode )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::OnStartElementL" );
    __ASSERT_ALWAYS( iXmlNesting.Count() > 0, User::Leave( KErrCorrupt ) );    
    
    User::LeaveIfError( aErrorCode );

    HBufC8* name = ToLowercaseLC( aElement.LocalName().DesC() );

    // Check what was the previous tag
    switch ( iXmlNesting[ iXmlNesting.Count() - 1 ] )
        {
        case EXmlStarted:
            {
            if ( !ResolveDocumentTagL( name->Des(), aAttributes ) )
                {
                User::Leave( KErrNotFound );
                }
            break;
            }
            
        case EXmlDocument:
            {
            if ( !ResolveFolderTagL( name->Des(), aAttributes ) )
                {
                if ( !ResolveVCommandTagL( name->Des(), aAttributes ) )
                    {
                    RUBY_DEBUG0( "VC XML ERROR: <vcommandfolder> or <vcommand> exptected but not found" );
                    User::Leave( KErrNotFound );
                    }
                }
            break;
            }
        
        case EXmlFolder:
            {
            if ( !ResolveVCommandTagL( name->Des(), aAttributes ) )
                {
                RUBY_DEBUG0( "VC XML ERROR: <vcommand> exptected but not found" );
                User::Leave( KErrNotFound );
                }

            // New voice command starts
            ResetVCommandInfo();
             
            break;
            }
        
        case EXmlVCommand:
            {
            if ( !ResolveSpokenTagL( name->Des(), aAttributes ) )
                {
                if ( !ResolveWrittenTagL( name->Des(), aAttributes ) )
                    {
                    if ( !ResolveExecutesTagL( name->Des(), aAttributes ) )
                        {
                        if ( !ResolveCmdlineparamsTag( name->Des(), aAttributes ) )
                            {
                            if ( !ResolveIconTagL( name->Des(), aAttributes ) )
                                {
                                if ( !ResolveTooltipTagL( name->Des(), aAttributes ) )
                                    {
                                    RUBY_DEBUG0( "VC XML ERROR: <spoken> <written> <executes> or <cmdlineparams> exptected but not found" );   
                                    User::Leave( KErrNotFound );
                                    }
                                }
                            }
                        }
                    }
                }
            break;
            }
            
        default:
            {
            
            RUBY_DEBUG0( "VC XML ERROR: Unexpected starting tag found" );
            User::Leave( KErrNotFound );
            
            break;
            }

        }
        
    CleanupStack::PopAndDestroy( name );
 
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnEndElementL
// Callback from XML parser when ending tag has been found
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnEndElementL( const Xml::RTagInfo& aElement, 
                                  TInt aErrorCode )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::OnEndElementL" );
    __ASSERT_ALWAYS( iXmlNesting.Count() > 0, User::Leave( KErrCorrupt ) );
    
    User::LeaveIfError( aErrorCode );
    
    HBufC8* name = ToLowercaseLC( aElement.LocalName().DesC() );
    
    switch ( iXmlNesting[ iXmlNesting.Count() - 1 ] )
        {
        case EXmlDocument:
            {
            PopFromStackIfFoundL( name->Des(), KXmlDocumentTag );
            break;
            }
        
        case EXmlFolder:
            {
            PopFromStackIfFoundL( name->Des(), KXmlFolderTag );
            ResetVCommandFolder();
            break;
            }
        
        case EXmlVCommand:
            {
            PopFromStackIfFoundL( name->Des(), KXmlVCommandTag );
            CheckVoiceCommmandData();
            break;
            }
            
         case EXmlSpoken:
            {
            PopFromStackIfFoundL( name->Des(), KXmlSpokenTag );
            break;
            }
         
         case EXmlWritten:
            {
            PopFromStackIfFoundL( name->Des(), KXmlWrittenTag );
            break;
            }
        
         case EXmlExecutes:
            {
            PopFromStackIfFoundL( name->Des(), KXmlExecutesTag );
            break;
            }
         
         case EXmlCmdlineparams:
            {
            PopFromStackIfFoundL( name->Des(), KXmlCmdlineparamsTag );   
                
            // Convert content of <cmdlineparams> into unicode
            // First trim out unnecessary white space
            TPtr8 des8( iParameters8->Des() );
            des8.Trim();
                
            // Delete previous unicode buffer and create new
            delete iParameters;
            iParameters = NULL;
            iParameters = CnvUtfConverter::ConvertToUnicodeFromUtf8L( des8 );
                
            break;
            }

         case EXmlIcon:
            {
            PopFromStackIfFoundL( name->Des(), KXmlIconTag );
            break;
            }

         case EXmlTooltip:
            {
            PopFromStackIfFoundL( name->Des(), KXmlTooltipTag );
            break;
            }
           
        default:
            {
            RUBY_DEBUG0( "VC XML ERROR: Ending tag found when not expected" );
            User::Leave( KErrGeneral );
            break;
            }

        }
    CleanupStack::PopAndDestroy( name );
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::PopFromStackIfFoundL
// Checks that last item on stack is the expected one
// -----------------------------------------------------------------------------
//
void CVcXmlParser::PopFromStackIfFoundL( const TDesC8& aTagName, const TDesC8& aExpectedTag )
    {
    if ( aTagName != aExpectedTag )
        {
        RUBY_DEBUG0( "VC XML ERROR: Unexpected ending tag found" );
        User::Leave( KErrNotFound );
        }
        
    iXmlNesting.Remove( iXmlNesting.Count() - 1 );    
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnContentL
// Callback from XML parser when element has some content
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnContentL( const TDesC8& aBytes, TInt aErrorCode )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::OnContentL" );
    
    User::LeaveIfError( aErrorCode );
    
    TInt lastTag = iXmlNesting.Count() - 1;
    
    if ( iXmlNesting[ lastTag ] == EXmlCmdlineparams )
        {
        if ( !iParameters8 )
            {
            // Create new buffer
            iParameters8 = HBufC8::NewL( aBytes.Size() );
            TPtr8 des( iParameters8->Des() );
            des.Copy( aBytes );
            }
        else
            {
            // Append at the end of previous stuff
            iParameters8 = iParameters8->ReAllocL( iParameters8->Size() + aBytes.Size() );
            TPtr8 des( iParameters8->Des() );
            des.Append( aBytes );
            }

        RUBY_DEBUG0( "<cmdlineparams> content resolved" );
        }
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnStartPrefixMappingL
// Callback from XML parser
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnStartPrefixMappingL( const RString& /*aPrefix*/, 
	                                      const RString& /*aUri*/, 
	                                      TInt /*aErrorCode*/ )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnEndPrefixMappingL
// Callback from XML parser
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnEndPrefixMappingL( const RString& /*aPrefix*/, 
                                        TInt /*aErrorCode*/ )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnIgnorableWhiteSpaceL
// Callback from XML parser
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnIgnorableWhiteSpaceL( const TDesC8& /*aBytes*/, 
                                           TInt /*aErrorCode*/ )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnSkippedEntityL
// Callback from XML parser
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnSkippedEntityL( const RString& /*aName*/, 
                                     TInt /*aErrorCode*/ )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnProcessingInstructionL
// Callback from XML parser
// -----------------------------------------------------------------------------
//
void CVcXmlParser::OnProcessingInstructionL( const TDesC8& /*aTarget*/, 
                                             const TDesC8& /*aData*/, 
	                                         TInt /*aErrorCode*/ )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::OnError
// Callback from XML parser when general error has occured
// -----------------------------------------------------------------------------
//
#if defined(_DEBUG) && !defined(__RUBY_DEBUG_DISABLED)
void CVcXmlParser::OnError( TInt aErrorCode )
    {
    RUBY_DEBUG1( "CVcXmlParser::OnError general error: [%d]", aErrorCode );
    }
#else
void CVcXmlParser::OnError( TInt /*aErrorCode*/ )
    {
    // Nothing
    }
#endif // #if defined(_DEBUG) && !defined(__RUBY_DEBUG_DISABLED)
    
// -----------------------------------------------------------------------------
// CVcXmlParser::GetExtendedInterface
// Callback from XML parser
// -----------------------------------------------------------------------------
//
TAny* CVcXmlParser::GetExtendedInterface( const TInt32 /*aUid*/ )
    {
    return NULL;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::CheckAttributeL
// Checks the value of certain attribute
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::CheckAttributeL( const Xml::RAttributeArray& aAttributes,
                                     const TDesC8& aAttribute, const TDesC8& aValue )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::CheckAttributeL" );
    
    TBool resolved( EFalse );
    
    // Loop through attribute list
    for ( TInt iCounter = 0 ; iCounter < aAttributes.Count() ; iCounter++ )
        {        
        HBufC8* name = ToLowercaseLC( aAttributes[iCounter].Attribute().LocalName().DesC() );
       
        if ( name->Des() == aAttribute )
            {
            HBufC8* value = ToLowercaseLC( aAttributes[iCounter].Value().DesC() );
            
            // If value is null descriptor, then we just check if attribute exists           
            if ( aValue == KNullDesC8 || value->Des() == aValue )
                {                
                resolved = ETrue;
                }
            
            CleanupStack::PopAndDestroy( value );
            }
        CleanupStack::PopAndDestroy( name );
        }
        
    return resolved;
    }
    
// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveDocumentTagL
// Resolves the content of <nssvcommands>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveDocumentTagL( const TDesC8& aName, 
                                        const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveDocumentTagL" );
    
    TBool resolved( EFalse );
    
    if ( aName == KXmlDocumentTag )
        {
        iXmlNesting.Append( EXmlDocument );
        resolved = CheckAttributeL( aAttributes, KXmlVersionAttr, KXmlVersionValue );
        if ( !resolved )
            {
            RUBY_DEBUG0( "VC XML ERROR: Version information not found or it does not match" );
            User::Leave( KErrGeneral );
            }
        else
            {
            CVcResource* newResource( NULL );
            TPtrC8 locFileAttr( KXmlLocFileAttr );
            TRAPD( error, newResource =
                CVcResource::NewL( iRFs, Find16ValueL( locFileAttr, aAttributes ) ) );

            // Delete old resource object if new was found
            if ( newResource )
                {
                delete iResource;
                iResource = newResource;
                }
        
            if ( error != KErrNone )
                {
                resolved = EFalse;
                RUBY_DEBUG0( "VC XML ERROR: Resource file load error" );
                User::Leave( KErrNotFound );
                }
            }
        }
     else
        {
        RUBY_DEBUG0( "VC XML ERROR: <nssvoicecommands> exptected but not found" );
        User::Leave( KErrNotFound );        
        }
               
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveFolderTagL
// Resolves the content of <vcommandfolder>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveFolderTagL( const TDesC8& aName, 
                                       const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveFolderTagL" );
    
    // Use specific resource file for folder strings if specified
    CVcResource* mainResource = iResource;
    
    CVcResource* newResource( NULL );
    TPtrC locFile = Find16ValueL( KXmlLocFileAttr, aAttributes );
    if ( locFile != KNullDesC )
        {
        newResource = CVcResource::NewL( iRFs, locFile );
        }
                  
    if ( newResource )
        {
        iResource = newResource;
        CleanupStack::PushL( mainResource );
        }    
    
    // Find folder name
    TBool resolved = ResolveLocalizedTagL( aName, aAttributes, KXmlFolderTag, 
                                           EXmlFolder );
    if ( resolved )
        {
        delete iFolder;
        iFolder = iCurrentLocalizedString;
        iCurrentLocalizedString = NULL;
        
        // Find folder title string
        TBool titleFound = GetLocalizedStringL( aAttributes, KXmlFolderTitleLocAttr );
        
        if ( titleFound )
            {
            delete iFolderTitle;
            iFolderTitle = iCurrentLocalizedString;
            iCurrentLocalizedString = NULL;
            }
            
        TBool iconFileFound = ResolveFolderIconFileL( aAttributes );
        RUBY_DEBUG1( "iconFileFound [%d]", iconFileFound );
        iFolderIconIndex = ResolveFolderIconIndexL( aAttributes );
       
        }
        
    // Revert back to use the old resource file
    iResource = mainResource;
    if ( newResource )
        {
        delete newResource;
        CleanupStack::Pop( mainResource );
        }
                
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveVCommandTagL
// Resolves the content of <vcommand>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveVCommandTagL( const TDesC8& aName, 
                                         const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveVCommandTagL" );
    
    TBool resolved( EFalse );
    if ( aName == KXmlVCommandTag )
        {
        resolved = ETrue;
        iXmlNesting.Append( EXmlVCommand );
        }
    
    if ( resolved )
        {
        // TTS on/off  
        resolved = CheckAttributeL( aAttributes, KXmlTtsAttr, KXmlTrueValue );
        if ( resolved )
            {
            // By default, tts is on
            iStartImmediately = ETrue;
            }
        
        // Modifiable on/off
        resolved = CheckAttributeL( aAttributes, KXmlModifiableAttr, KXmlFalseValue );
        if ( resolved )
            {
            iUserCanModify = EFalse;
            }
            
        resolved = ETrue;
        }

    return resolved;
    }


// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveSpokenTagL
// Resolves the content of <spoken>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveSpokenTagL( const TDesC8& aName, 
                                       const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveSpokenTagL" );
    
    TBool resolved = ResolveLocalizedTagL( aName, aAttributes, KXmlSpokenTag, 
                                           EXmlSpoken );

    if ( resolved )
        {
        delete iSpokenText;
        iSpokenText = iCurrentLocalizedString;
        iCurrentLocalizedString = NULL;
        }
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveWrittenTagL
// Resolves the content of <written>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveWrittenTagL( const TDesC8& aName,
                                        const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveWrittenTagL" );
    
    TBool resolved = ResolveLocalizedTagL( aName, aAttributes, KXmlWrittenTag, 
                                           EXmlWritten );
    if ( resolved )
        {
        delete iWrittenText;
        iWrittenText = iCurrentLocalizedString;
        iCurrentLocalizedString = NULL;
        }
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveTooltipTagL
// Resolves the content of <tooltip>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveTooltipTagL( const TDesC8& aName,
                                        const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveTooltipTagL" );
    
    TBool resolved = ResolveLocalizedTagL( aName, aAttributes, KXmlTooltipTag, 
                                           EXmlTooltip );
    if ( resolved )
        {
        delete iTooltipText;
        iTooltipText = iCurrentLocalizedString;
        iCurrentLocalizedString = NULL;
        }
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveLocalizedTagL
// Resolves content of tag which contains localized data
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveLocalizedTagL( const TDesC8& aName,
                                          const Xml::RAttributeArray& aAttributes,
                                          const TDesC8& aExpectedName,
                                          TVcXmlTagNesting aTagEnum )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveLocalizedTagL" );
    
    TBool resolved( EFalse );
    if ( aName == aExpectedName )
        {
        resolved = ETrue;
        iXmlNesting.Append( aTagEnum );
        
        resolved = GetLocalizedStringL( aAttributes, KXmlLocAttr );
        }

    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveExecutesTagL
// Resolves the content of <executes>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveExecutesTagL( const TDesC8& aName,
                                         const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveExecutesTagL" );
    
    TBool resolved( EFalse );
   
    if ( aName == KXmlExecutesTag )
        {
        resolved = ETrue;
        iXmlNesting.Append( EXmlExecutes );

        iAppId = ResolveUidL( aAttributes );
        if ( iAppId == KNullUid )
            {
            resolved = ResolveExeL( aAttributes );
            }
        }

    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveCmdlineparamsTag
// Resolves the content of <cmdlineparams>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveCmdlineparamsTag( const TDesC8& aName, 
                                             const Xml::RAttributeArray& /*aAttributes*/ )
    {
    TBool resolved( EFalse );
    
    if ( aName == KXmlCmdlineparamsTag )
        {
        iXmlNesting.Append( EXmlCmdlineparams );
        delete iParameters;
        delete iParameters8;
        iParameters = NULL;
        iParameters8 = NULL;
        resolved = ETrue;        
        }
        
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveIconTagL
// Resolves the content of <icon>
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveIconTagL( const TDesC8& aName,
                                     const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveIconTagL" );
    
    TBool resolved( EFalse );
    
    if ( aName == KXmlIconTag )
        {
        resolved = ETrue;
        iXmlNesting.Append( EXmlIcon );

        iIcon = ResolveUidL( aAttributes );
        if ( iIcon == KNullUid )
            {
            resolved = EFalse;
            }
        }

    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::Find16ValueL
// Finds a certain attribute and returns its value as unicode
// -----------------------------------------------------------------------------
//
const TDesC& CVcXmlParser::Find16ValueL( const TDesC8& aName, 
                                         const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::Find16ValueL" );
    
    delete iAttributeValue;
    iAttributeValue = NULL;
    
    iAttributeValue = CnvUtfConverter::ConvertToUnicodeFromUtf8L( Find8ValueL( aName, aAttributes ) );
       
    return *iAttributeValue;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::Find8ValueL
// Finds a certain attribute and returns its value as utf-8
// -----------------------------------------------------------------------------
//
const TDesC8& CVcXmlParser::Find8ValueL( const TDesC8& aName, 
                                         const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::Find8ValueL" );
    
    // Loop through attribute list
    for ( TInt iCounter = 0 ; iCounter < aAttributes.Count() ; iCounter++ )
        {
        HBufC8* name = ToLowercaseLC( aAttributes[iCounter].Attribute().LocalName().DesC() );
        
        if ( name->Des() == aName )
            {
            CleanupStack::PopAndDestroy( name );

            return aAttributes[iCounter].Value().DesC();
            }
        CleanupStack::PopAndDestroy( name );
        }
        
    return KNullDesC8;
    }
    
// -----------------------------------------------------------------------------
// CVcXmlParser::ResetVCommandFolder
// Destroys the data of one voice command folder
// -----------------------------------------------------------------------------
//
void CVcXmlParser::ResetVCommandFolder()
    {
    delete iFolder;
    iFolder = HBufC16::New( 0 );
    
    delete iFolderTitle;
    iFolderTitle = HBufC16::New( 0 );
    
    delete iFolderIconFile;
    iFolderIconFile = HBufC16::New( 0 );
    
    iFolderIconIndex = -1;
    
    ResetVCommandInfo();
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResetVCommandInfo
// Destroys the data of one voice command
// -----------------------------------------------------------------------------
//
void CVcXmlParser::ResetVCommandInfo()
    {
    delete iWrittenText;
    iWrittenText = NULL;
    delete iSpokenText;
    iSpokenText = NULL;
    delete iTooltipText;
    iTooltipText = NULL;
    delete iParameters;
    iParameters = NULL;
    delete iParameters8;
    iParameters8 = NULL;
    delete iAppName;
    iAppName = NULL;
    
    iAppId = KNullUid;
    iIcon = KNullUid;
    
    iStartImmediately = EFalse;
    iUserCanModify = ETrue;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::CheckVoiceCommmandData
// Checks if all mandatory data for one voice command is available and makes
// callback based on that
// -----------------------------------------------------------------------------
//
void CVcXmlParser::CheckVoiceCommmandData()
    {
    if ( iWrittenText && ( iAppId != KNullUid || iAppName ) )
        {
        RUBY_DEBUG0( "CVcXmlParser::CheckVoiceCommmandData(): All required data for voice command found ok" );
        
        // folder icon file is optional
        // if it is not present, reference to KNullDesC should be passed
        const TDesC* pFolderIconFile =iFolderIconFile;
        if( !pFolderIconFile )
            {
            pFolderIconFile = &KNullDesC;
            }
        
        iObserver.MvcxpoVoiceCommandFound( *iWrittenText, *iSpokenText, 
                                           *iTooltipText, *iFolder, *iFolderTitle, 
                                           *iParameters, iIcon,
                                           iAppId, *iAppName,
                                           iStartImmediately, iUserCanModify,
                                           *pFolderIconFile, iFolderIconIndex );
        }
    else
        {
        RUBY_DEBUG0( "VC XML ERROR: Mandatory data not found for Voice Command" );
        }
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::GetLocalizedStringL
// Reads localized string from resource file
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::GetLocalizedStringL( const Xml::RAttributeArray& aAttributes,
                                         const TDesC8& aAttributeName )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::GetLocalizedStringL" );
    
    TBool resolved( EFalse );
    iCurrentLocalizedString = NULL;
    
    // Resource file object should have been initialized
    if ( !iResource )
        {
        return resolved;
        }

    // locIndex is key to the localized resource file
    TPtrC8 locAttr( aAttributeName );    
    TPtrC locIndex = Find16ValueL( locAttr, aAttributes );
    
    if ( locIndex != KNullDesC )
        {
        HBufC* command = NULL;
        // Find string from loc file based on key
        TRAPD( error,  command = &iResource->GetCommandL( locIndex ) );
        if ( error == KErrNone )
            {
            // Make a copy of localized string
            TPtr des = command->Des();
            delete iCurrentLocalizedString;
            iCurrentLocalizedString = des.Alloc();
            resolved = ETrue;
            }
        else
            {
            resolved = EFalse;
            iCurrentLocalizedString = NULL;
            RUBY_DEBUG0( "VC XML ERROR: Cannot resolve localized string" );
            User::Leave( KErrGeneral );
            }
        }
        
    return resolved;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveUidL
// Resolves the content of uid="0x1234567" attribute
// -----------------------------------------------------------------------------
//
TUid CVcXmlParser::ResolveUidL( const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveUidL" );
    
    _LIT( KHexIdentifierLowercase, "0x" );
    _LIT( KHexIdentifierUppercase, "0X" );
    const TInt KHexIndentifierLength = 2;
    
    TUid newUid( KNullUid );
    
    TPtrC uidDes = Find16ValueL( KXmlUidAttr, aAttributes );
    
    if ( uidDes != KNullDesC )
        {
        TPtrC ptr( uidDes );
        // Check if string starts with 0x or 0X
        if ( ( uidDes.Find( KHexIdentifierLowercase ) == 0 ) ||
             ( uidDes.Find( KHexIdentifierUppercase ) == 0 ) )
            {
            ptr.Set( uidDes.Right( uidDes.Length() - KHexIndentifierLength ) );
            }
        
        // Do conversion from string to number
        TLex lex( ptr );
        TInt64 intUid( 0 );
        TInt error = lex.Val( intUid, EHex );
        newUid.iUid = intUid;
        }
        
    return newUid;
    }

// -----------------------------------------------------------------------------
// CVcXmlParser::ResolveExeL
// Resolves the content of exe="name.exe" attribute
// -----------------------------------------------------------------------------
//
TBool CVcXmlParser::ResolveExeL( const Xml::RAttributeArray& aAttributes )
    {
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveExeL" );
    
    TBool resolved( EFalse );
    
    TPtrC nameDes = Find16ValueL( KXmlExeAttr, aAttributes );
    if ( nameDes != KNullDesC )
        {
        delete iAppName;
        iAppName = NULL;
        
        iAppName = HBufC::NewL( nameDes.Length() );
        TPtr namePtr = iAppName->Des();
        namePtr.Copy( nameDes );
        
        resolved = ETrue;
        }
        
    return resolved;
    }
    
// -----------------------------------------------------------------------------
// CVcXmlParser::ToLowercaseLC
// Converts given string to lowercase
// -----------------------------------------------------------------------------
//
HBufC8* CVcXmlParser::ToLowercaseLC( const TDesC8& aString )
    {
    // RUBY_DEBUG0( "CVcXmlParser::ToLowercaseLC START" );
    
    // Convert string to lowercase    
    HBufC8* string = HBufC8::NewL( aString.Length() );
    CleanupStack::PushL( string );
    TPtr8 des = string->Des();
    des.Copy( aString );
    des.LowerCase();
    
    //RUBY_DEBUG0( "CVcXmlParser::ToLowercaseLC EXIT" );
    
    return string;
    }

// -----------------------------------------------------------------------------
// Reads the iconfile attribute and constructs the file name or
// sets it to NULL
// 
// @params aAttributes List of XML attributes
// @return ETrue if resolved successfully, EFalse otherwise
// -----------------------------------------------------------------------------
TBool CVcXmlParser::ResolveFolderIconFileL( const Xml::RAttributeArray& aAttributes )
	{
    RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveFolderIconFileL" );
    
    TBool resolved( EFalse );
    delete iFolderIconFile;
    iFolderIconFile = NULL;
    
    TPtrC nameDes = Find16ValueL( KXmlFolderIconFileAttr, aAttributes );
    if ( nameDes != KNullDesC )
        {
        iFolderIconFile = HBufC::NewL( nameDes.Length() );
        TPtr folderIconFilePtr = iFolderIconFile->Des();
        folderIconFilePtr.Copy( nameDes );
        
        resolved = ETrue;
        }
        
    return resolved;
	
	}

// -----------------------------------------------------------------------------
// Reads the iconindex attribute and stores the index or sets it to 0
// 
// @params aAttributes List of XML attributes
// @return ETrue if resolved successfully, EFalse otherwise
// -----------------------------------------------------------------------------
TInt CVcXmlParser::ResolveFolderIconIndexL( const Xml::RAttributeArray& aAttributes )
	{
	RUBY_DEBUG_BLOCKL( "CVcXmlParser::ResolveFolderIconIndexL" );
	
	TInt index = -1;
    
    TPtrC indexDes = Find16ValueL( KXmlFolderIconIndexAttr, aAttributes );
    
    if ( indexDes != KNullDesC )
        {
        TPtrC ptr( indexDes );
        
        // Do conversion from string to number
        TLex lex( ptr );
        TInt error = lex.Val( index );
        if( error != KErrNone )
        	{
        	RUBY_ERROR1( "Converting icon index from string to int resulted in [%d]", error );
        	index = -1;
        	}
        }
        
    return index;	
	}

// End of File