omadrm/drmengine/roap/src/RoapParser.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:27 +0200
changeset 0 95b198f216e5
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2002-2008 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:  ROAP response parser
*
*/



// INCLUDE FILES
#include <e32base.h>

#include "DeviceHello.h"
#include "JoinDomainReq.h"
#include "JoinDomainResp.h"
#include "LeaveDomainReq.h"
#include "LeaveDomainResp.h"
#ifdef RD_DRM_METERING
#include "MeteringReportReq.h"
#include "MeteringReportResp.h"
#include "MeteringReportRespParser.h"
#endif
#include "RIHello.h"
#include "RegistrationReq.h"
#include "RegistrationResp.h"
#include "RightsReq.h"
#include "RightsResp.h"
#include "RoapTrigger.h"
#include "RoapMessage.h"

#include "RoapParser.h"
#include "RespParser.h"
#include "JoinDomainRespParser.h"
#include "LeaveDomainRespParser.h"
#include "RIHelloParser.h"
#include "RegistrationRespParser.h"
#include "RightsRespParser.h"
#include "RoapTriggerParser.h"
#include "RoapLog.h"

using namespace Roap;

// LOCAL CONSTANTS AND MACROS
#define ELEMENT_COUNT(x) static_cast<TInt>((sizeof(x) / sizeof (x[0])))

const TInt KParserChunkSize = 512;
const TInt KRoapElementCount = ELast;
const TInt KMaxElementNesting = 24;

struct TRoapElements
    {
    const TText8* iString;
    TInt iNumber;
    };

struct TStackState
    {
    TParserStackState iState;
    TRoapElementEnum iStack[KMaxElementNesting];
    };

static const TRoapElements KStatusValues[] =
    {
    {_S8("Success"), ESuccess},
    {_S8("UnknownError"), EUnknownError},
    {_S8("Abort"), EAbort},
    {_S8("NotSupported"), ENotSupported},
    {_S8("AccessDenied"), Roap::EAccessDenied},
    {_S8("NotFound"), ENotFound},
    {_S8("MalformedRequest"), EMalformedRequest},
    {_S8("UnknownRequest"), EUnknownRequest},
    {_S8("UnknownCriticalExtension"), EUnknownCriticalExtension},
    {_S8("UnsupportedVersion"), EUnsupportedVersion},
    {_S8("UnsupportedAlgorithm"), EUnsupportedAlgorithm},
    {_S8("NoCertificateChain"), ENoCertificateChain},
    {_S8("InvalidCertificateChain"), EInvalidCertificateChain},
    {_S8("TrustedRootCertificateNotPresent"), ETrustedRootCertificateNotPresent},
    {_S8("SignatureError"), ESignatureError},
    {_S8("DeviceTimeError"), EDeviceTimeError},
    {_S8("NotRegistered"), ENotRegistered},
    {_S8("InvalidDCFHash"), EInvalidDCFHash},
    {_S8("InvalidDomain"), EInvalidDomain},
    {_S8("DomainFull"), EDomainFull},
    {_S8("MalformedMeteringReport"), EMalformedMeteringReport},
    {_S8("UnableToDecryptMeteringReport"), EUnableToDecryptMeteringReport},
    {_S8("UnableToValidateMeteringReportMAC"), EUnableToValidateMeteringReportMAC},
    };

static const TRoapElements KRoapElements[ELast] =
    {
    {_S8("certificate"), ECertificate},
    {_S8("certificateChain"), ECertificateChain},
    {_S8("CipherData"), ECipherData},
    {_S8("CipherValue"), ECipherValue},
    {_S8("contentID"), Roap::EContentID},
    {_S8("dcfHash"), EDcfHash},
    {_S8("deviceDetails"), EDeviceDetails},
    {_S8("deviceID"), EDeviceID},
    {_S8("DigestValue"), EDigestValue},
    {_S8("dn"), EDomainName},
    {_S8("domainAlias"), EDomainAlias},
    {_S8("domainID"), EDomainID},
    {_S8("domainInfo"), EDomainInfo},
    {_S8("domainKey"), EDomainKey},
    {_S8("encKey"), EEncKey},
    {_S8("EncryptionMethod"), EEncryptionMethod},
    {_S8("extension"), EExtension},
    {_S8("extensions"), EExtensions},
    {_S8("hash"), EHash},
    {_S8("id"), EId},
    {_S8("identifier"), EIdentifier},
    {_S8("joinDomain"), EJoinDomain},
    {_S8("joinDomainResponse"), EJoinDomainResponse},
    {_S8("keyIdentifier"), EKeyIdentifier},
    {_S8("leaveDomain"), ELeaveDomain},
    {_S8("leaveDomainResponse"), ELeaveDomainResponse},
    {_S8("mac"), EMac},
    {_S8("manufacturer"), EManufacturer},
    {_S8("model"), EModel},
    {_S8("nonce"), ENonce},
    {_S8("notAfter"), ENotAfter},
    {_S8("ocspResponse"), EOcspResponse},
    {_S8("protectedRO"), EProtectedRO},
    {_S8("registrationRequest"), ERegistrationRequest},
    {_S8("registrationResponse"), ERegistrationResponse},
    {_S8("riAlias"), ERiAlias},
    {_S8("rights"), Roap::ERights},
    {_S8("riHello"), ERiHello},
    {_S8("riID"), ERiID},
    {_S8("riNonce"), ERiNonce},
    {_S8("riURL"), ERiURL},
    {_S8("ro"), ERo},
    {_S8("roAcquisition"), ERoAcquisition},
    {_S8("roapTrigger"), ERoapTrigger},
    {_S8("roapURL"), ERoapURL},
    {_S8("roID"), ERoID},
    {_S8("roInfo"), ERoInfo},
    {_S8("roResponse"), ERoResponse},
    {_S8("selectedAlgorithm"), ESelectedAlgorithm},
    {_S8("selectedVersion"), ESelectedVersion},
    {_S8("serverInfo"), EServerInfo},
    {_S8("signature"), ESignature},
    {_S8("SignatureValue"), ESignatureValue},
    {_S8("supportedAlgorithm"), ESupportedAlgorithm},
    {_S8("time"), ETime},
    {_S8("timeStamp"), ETimeStamp},
    {_S8("trustedAuthorities"), ETrustedAuthorities},
    {_S8("version"), EVersion},
    {_S8("X509SPKIHash"), EX509SPKIHash},
#ifdef RD_DRM_METERING
    {_S8("extendedTrigger"), EExtendedTriggerElement},
    {_S8("meteringReport"), EMeteringReportRequest},
    {_S8("meteringReportResponse"), EMeteringReportResponse},
    {_S8("prURL"), EPrUrl}
#endif
    };

// The stack states have to be sorted with descending length. The
// MatchStackState function searches for the first matching state.
static const TStackState KParserStackStates[] =
    {
    // 4 elements --------------------------------------------------------------
    {ERiIdRoResponseState, {EHash, EKeyIdentifier, ERiID, ERoResponse, ELast}},
    {ERiIdJoinDomainResponseState, {EHash, EKeyIdentifier, ERiID, EJoinDomainResponse, ELast}},
    // 3 elements --------------------------------------------------------------
#ifdef RD_DRM_METERING
    {EPostResponseUrlState, {EPrUrl, EExtension, EExtensions, ELast}},
#endif
    {EDeviceIdState, {EHash, EKeyIdentifier, EDeviceID, ELast}},
    {ETrustedAuthoritiesState, {EHash, EKeyIdentifier, ETrustedAuthorities, ELast}},
    {EPeerKeyIdentifierRIHelloState, {EIdentifier, EExtension, EExtensions, ELast}},
    {ETransactionIdState, {EId, EExtension, EExtensions, ELast}},
    {ETransactionIdContentIdState, {Roap::EContentID, EExtension, EExtensions, ELast}},
    {EWhiteListState, {EDomainName, EExtension, EExtensions, ELast}},
    {EDeviceDetailsState, {EDeviceDetails, EExtensions, ERiHello, ELast}},
    {ERiIdState, {EHash, EKeyIdentifier, ERiID, ELast}},
    {EEncKeyState, {ECipherValue, ECipherData, EEncKey, ELast}},
    {EDomainKeyEncryptionMethodState, {EEncryptionMethod, EEncKey, EDomainKey, ELast}},
    {EMacJoinDomainResponseState, {EMac, EDomainKey, EDomainInfo, ELast}},
    // 2 elements --------------------------------------------------------------
    {EDomainKeyEncKeyState, {EEncKey, EDomainKey, ELast}},
    {ECertificateState, {ECertificate, ECertificateChain, ELast}},
    {ESignatureRoResponseState, {ESignature, ERoResponse, ELast}},
    {EExtensionState, {EExtension, EExtensions, ELast}},
    // 1 element ---------------------------------------------------------------
    {ERiAliasState, {ERiAlias, ELast}},
    {EDomainAliasState, {EDomainAlias, ELast}},
    {ERiHelloState, {ERiHello, ELast}},
    {ESelectedVersionState, {ESelectedVersion, ELast}},
    {ERiNonceState, {ERiNonce, ELast}},
    {EOcspResponseState, {EOcspResponse, ELast}},
    {ERiUrlState, {ERiURL, ELast}},
    {ESignatureState, {ESignature, ELast}},
    {ERegistrationResponseState, {ERegistrationResponse, ELast}},
    {ERoResponseState, {ERoResponse, ELast}},
    {EJoinDomainResponseState, {EJoinDomainResponse, ELast}},
    {ELeaveDomainResponseState, {ELeaveDomainResponse, ELast}},
    {EDomainIdState, {EDomainID, ELast}},
    {ENonceState, {ENonce, ELast}},
    {ENotAfterState, {ENotAfter, ELast}},
    {EDomainKeyState, {EDomainKey, ELast}},
    {ERoapTriggerState, {ERoapTrigger, ELast}},
    {ERoapUrlState, {ERoapURL, ELast}},
    {ERegistrationRequestState, {ERegistrationRequest, ELast}},
    {ERoAcquisitionState, {ERoAcquisition, ELast}},
    {EJoinDomainState, {EJoinDomain, ELast}},
    {ELeaveDomainState, {ELeaveDomain, ELast}},
    {ERoIdState, {ERoID, ELast}},
    {EContentIdState, {Roap::EContentID, ELast}},
    {ESignatureValueState, {ESignatureValue, ELast}},
    {EDigestValueState, {EDigestValue, ELast}},
    {EServerInfoState, {EServerInfo, ELast}},
    {ESupportedAlgorithmState, {ESupportedAlgorithm, ELast}},
    {ESelectedAlgorithmState, {ESelectedAlgorithm, ELast}},
#ifdef RD_DRM_METERING
    {EExtendedTriggerElementState, {EExtendedTriggerElement, ELast}},
    {EMeteringReportRequestState, {EMeteringReportRequest, ELast}},
    {EMeteringReportResponseState, {EMeteringReportResponse, ELast}}
#endif
    };

_LIT8(KParserMimeType, "text/xml");
_LIT8(KDomainKey, "domainKey");
_LIT8(KMac, "mac>");
_LIT8(KMacEnd, "</mac>");

// ============================ auto_handde helper class =======================
//Auto handle for easening handle release on exceptional exit situations
template<class T> class auto_handle
    {
    public:

    auto_handle() {}
    auto_handle(T aHandle) : iHandle( aHandle ) {}
    auto_handle( auto_handle<T>& aHandle) : iHandle( aHandle.release() ) {}
    ~auto_handle() { iHandle.Close(); }
    const T& operator()() const { return iHandle; }
    T& operator()() { return iHandle; }
    T get() const { return iHandle; }
    T release() { T temp = iHandle; iHandle = 0; return temp; }

    private:
    T iHandle;
    };


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

// -----------------------------------------------------------------------------
// CRoapParser::CRoapParser
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CRoapParser::CRoapParser():
    iParser(NULL),
    iResponseParser(NULL)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CRoapParser::ConstructL()
    {
    TInt i;

    iParser = CParser::NewL(KParserMimeType, *this);
    for (i = 0; i < KRoapElementCount; i++)
        {
        TPtrC8 ptr(KRoapElements[i].iString, User::StringLength(
            KRoapElements[i].iString));
        iRoapElements[KRoapElements[i].iNumber] =
            iParser->StringPool().OpenStringL(ptr);
        }
    }

// -----------------------------------------------------------------------------
// CRoapParser::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CRoapParser* CRoapParser::NewL()
    {
    CRoapParser* self = new( ELeave ) CRoapParser;

    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }


// Destructor
CRoapParser::~CRoapParser()
    {
    TInt i;
    for (i = 0; i < ELEMENT_COUNT(KRoapElements); i++)
        {
        iRoapElements[KRoapElements[i].iNumber].Close();
        }
    delete iParser;
    delete iContent;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseMeteringRespL
// -----------------------------------------------------------------------------
//
#ifndef RD_DRM_METERING
CMeteringResp* CRoapParser::ParseMeteringRespL( const TDesC8& /*aMessage*/ )
    {
    return NULL;
    }
#else
CMeteringResp* CRoapParser::ParseMeteringRespL( const TDesC8& aMessage )
    {
    LOG( _L("CRoapParser::ParseMeteringRespL") );
    CMeteringResp* r = CMeteringResp::NewL();
    CleanupStack::PushL(r);
    TMeteringRespParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    CleanupStack::Pop(r);
    return r;
    }
#endif
// -----------------------------------------------------------------------------
// CRoapParser::ParseJoinDomainRespL
// -----------------------------------------------------------------------------
//
CJoinDomainResp* CRoapParser::ParseJoinDomainRespL(
    const TDesC8& aMessage, RPointerArray<HBufC8>& aDomainKeyElements)
    {
    LOG( _L("CRoapParser::ParseJoinDomainRespL") );

    CJoinDomainResp* r = CJoinDomainResp::NewL();
    CleanupStack::PushL(r);
    TJoinDomainRespParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    if ( r->iStatus == ESuccess )
        {
        User::LeaveIfError(
            ExtractDomainKeyElements(aMessage, aDomainKeyElements));
        }
    CleanupStack::Pop(r);
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseLeaveDomainRespL
// -----------------------------------------------------------------------------
//
CLeaveDomainResp* CRoapParser::ParseLeaveDomainRespL(
    const TDesC8& aMessage)
    {
    LOG( _L("CRoapParser::ParseLeaveDomainRespL") );

    CLeaveDomainResp* r = CLeaveDomainResp::NewL();
    CleanupStack::PushL(r);
    TLeaveDomainRespParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    CleanupStack::Pop(r);
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseRegistrationResp
// -----------------------------------------------------------------------------
//
CRegistrationResp* CRoapParser::ParseRegistrationRespL(
    const TDesC8& aMessage)
    {
    LOG( _L("CRoapParser::ParseRegistrationRespL") );

    CRegistrationResp* r = CRegistrationResp::NewL();
    CleanupStack::PushL(r);
    TRegistrationRespParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    CleanupStack::Pop(r);
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseRightsRespL
// -----------------------------------------------------------------------------
//
CRightsResp* CRoapParser::ParseRightsRespL(
    const TDesC8& aMessage)
    {
    LOG( _L("CRoapParser::ParseRightsRespL") );

    CRightsResp* r = CRightsResp::NewL();
    CleanupStack::PushL(r);
    TRightsRespParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    CleanupStack::Pop(r);
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseRIHelloL
// -----------------------------------------------------------------------------
//
CRIHello* CRoapParser::ParseRIHelloL(
    const TDesC8& aMessage)
    {
    LOG( _L("CRoapParser::ParseRIHelloL") );

    CRIHello* r = CRIHello::NewL();
    CleanupStack::PushL(r);
    TRIHelloParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    CleanupStack::Pop(r);
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseRoapTriggerL
// -----------------------------------------------------------------------------
//
CRoapTrigger* CRoapParser::ParseRoapTriggerL(
    const TDesC8& aMessage)
    {
    LOG( _L("CRoapParser::ParseRoapTriggerL") );

    CRoapTrigger* r = CRoapTrigger::NewL();
    CleanupStack::PushL(r);
    TRoapTriggerParser p(r);
    iResponseParser = &p;
    ParseL(aMessage);
    CleanupStack::Pop(r);
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ParseL
// -----------------------------------------------------------------------------
//
void CRoapParser::ParseL(
    const TDesC8& aMessage)
    {
    TInt i;
    TInt n;

    iElementStackDepth = 0;
    delete iContent;
    iContent = NULL;
    iParser->ParseBeginL();
    i = 0;
    while (i < aMessage.Length())
        {
        n = Min(aMessage.Length() - i, KParserChunkSize);
        iParser->ParseL(aMessage.Mid(i, n));
        i += n;
        }
    iParser->ParseEndL();
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnStartDocumentL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnStartDocumentL(
    const RDocumentParameters& /*aDocParam*/,
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnEndDocumentL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnEndDocumentL(
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnStartElementL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnStartElementL(
    const RTagInfo& aElement,
    const RAttributeArray& aAttributes,
    TInt /*aErrorCode*/)
    {
    TInt i;
    TInt state;

    if (iContent)
        {
        delete iContent;
        iContent = NULL;
        iContent = HBufC8::NewL(0);
        }

    for (i = 0; i < KRoapElementCount; i++)
        {
        if (aElement.LocalName() == iRoapElements[i])
            {
            iElementStack[iElementStackDepth] =
                static_cast<TRoapElementEnum>(i);
            iElementStackDepth++;
            state = MatchStackState();
            iResponseParser->OnStartElementL(*this, state, aElement,
                aAttributes);
            if (iElementStackDepth == KMaxElementNesting)
                {
                User::Leave(EXmlUnexpectedState);
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnEndElementL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnEndElementL(
    const RTagInfo& aElement,
    TInt /*aErrorCode*/)
    {
    TInt i;
    TInt state;

    for (i = 0; i < KRoapElementCount; i++)
        {
        if (aElement.LocalName() == iRoapElements[i])
            {
            state = MatchStackState();
            iResponseParser->OnEndElementL(*this, state, aElement);
            iElementStackDepth--;
            if (iElementStackDepth < 0)
                {
                User::Leave(EXmlUnexpectedState);
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnContentL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnContentL(
    const TDesC8& aBytes,
    TInt /*aErrorCode*/)
    {
    if ( !iContent )
        {
        iContent = HBufC8::NewL(aBytes.Size());
        *iContent = aBytes;
        }
    else
        {
        iContent = iContent->ReAllocL(iContent->Size() + aBytes.Size());
        TPtr8 c(iContent->Des());
        c.Append(aBytes);
        }
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnStartPrefixMappingL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnStartPrefixMappingL(
    const RString& /*aPrefix*/,
    const RString& /*aUri*/,
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnEndPrefixMappingL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnEndPrefixMappingL(
    const RString& /*aPrefix*/,
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnIgnorableWhiteSpaceL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnIgnorableWhiteSpaceL(
    const TDesC8& /*aBytes*/,
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnSkippedEntityL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnSkippedEntityL(
    const RString& /*aName*/,
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnProcessingInstructionL
// -----------------------------------------------------------------------------
//
void CRoapParser::OnProcessingInstructionL(
    const TDesC8& /*aTarget*/,
    const TDesC8& /*aData*/,
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnOutOfData
// -----------------------------------------------------------------------------
//
void CRoapParser::OnOutOfData()
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::OnError
// -----------------------------------------------------------------------------
//
void CRoapParser::OnError(
    TInt /*aErrorCode*/)
    {
    }

// -----------------------------------------------------------------------------
// CRoapParser::GetExtendedInterface
// -----------------------------------------------------------------------------
//
TAny* CRoapParser::GetExtendedInterface(
    const TInt32 /*aUid*/)
    {
    return NULL;
    }

// -----------------------------------------------------------------------------
// CRoapParser::MatchStackState
// -----------------------------------------------------------------------------
//
TParserStackState CRoapParser::MatchStackState(void)
    {
    TInt i;
    TInt j;
    TInt k;
    TParserStackState r = EUnknownState;

    for (i = 0;
        r == EUnknownState &&
        i < ELEMENT_COUNT(KParserStackStates); i++)
        {
        for (j = iElementStackDepth - 1, k = 0;
            j > 0 && KParserStackStates[i].iStack[k] != ELast;
            j--, k++)
            {
            if (iElementStack[j] != KParserStackStates[i].iStack[k])
                {
                break;
                }
            }
        if ((j == 0 && iElementStack[j] == KParserStackStates[i].iStack[k]) ||
            KParserStackStates[i].iStack[k] == ELast)
            {
            r = KParserStackStates[i].iState;
            }
        }
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::GetAttributeValueL
// -----------------------------------------------------------------------------
//
HBufC8* CRoapParser::GetAttributeValueL(
    const RAttributeArray& aAttrList,
    const TDesC8& aAttrName)
    {
    HBufC8* r = NULL;
    RAttribute a;
    TInt i;

    for (i = 0; !r && i < aAttrList.Count(); i++)
        {
        a = aAttrList[i];
        if (a.Attribute().LocalName().DesC().Compare(aAttrName) == 0)
            {
            r = a.Value().DesC().AllocL();
            }
        }
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ConvertRoapStatus
// -----------------------------------------------------------------------------
//
TRoapStatus CRoapParser::ConvertRoapStatus(
    const TDesC8& aStatus)
    {
    TInt i;
    TRoapStatus r = EUnknownStatus;

    for (i = 0; r == EUnknownStatus && i < ELEMENT_COUNT(KStatusValues); i++)
        {
        if (aStatus.Compare(TPtrC8(KStatusValues[i].iString,
            aStatus.Size())) == 0)
            {
            r = static_cast<TRoapStatus>(KStatusValues[i].iNumber);
            }
        }
    return r;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ExtractElement
// Note: uses auto_handle helper class
// -----------------------------------------------------------------------------
//
TPtrC8 CRoapParser::ExtractElement(
    const TDesC8& aMessage, const TDesC8& aElement, TInt& aOffset ) const
    {
    LOG( _L("CRoapParser::ExtractElement") );

    TPtrC8 temp( KNullDesC8 );
    TInt pos = ( 0 );
    TInt startPos = ( 0 );
    TInt endPos = ( 0 );
    TInt ret( 0 );
    TInt startLength ( 0 );
    const TInt KSpaceForDelimiters( 3 ); // max "</" aElement ">"

    auto_handle< RBuf8 > tagToBeFound;
    // Must be nonleaving since this function is nonleaving
    ret = tagToBeFound().Create( aElement.Length() + KSpaceForDelimiters );
    if ( ret != KErrNone )
        {
        aOffset = -1;
        return KNullDesC8();
        }

    //First we try to find start tag (as localname)
    tagToBeFound().SetLength( 0 );
    tagToBeFound().AppendFormat( _L8( "<%S" ), &aElement );

    temp.Set( aMessage.Mid( aOffset ) );


    startPos = temp.Find( tagToBeFound() );

    if ( startPos < 0 )
        {//Not found, let's try with namespace start
        tagToBeFound().SetLength( 0 );
        tagToBeFound().AppendFormat( _L8( ":%S" ), &aElement );
        pos = temp.Find( tagToBeFound() );
        if ( pos < 0 )
            {//Not possible to find valid tag with given name
            aOffset = -1;
            return KNullDesC8();
            }
        temp.Set( aMessage.Left( pos ) );
        startPos = temp.LocateReverse('<');
        if ( startPos < 0 )
            {
            aOffset = -1;
            return KNullDesC8();
            }
        //Calculate length for the new string to be stored
        ret = tagToBeFound().ReAlloc(
            ( pos - startPos ) + aElement.Length() + KSpaceForDelimiters );
        if ( ret != KErrNone )
            {
            aOffset = -1;
            return KNullDesC8();
            }
        tagToBeFound().SetLength( 0 );
        tagToBeFound().Append( temp.Mid( startPos ) );
        tagToBeFound().AppendFormat( _L8( ":%S" ), &aElement );
        }

    startLength = tagToBeFound().Length(); //needed in later calculations
    startPos += aOffset;
    temp.Set( aMessage.Mid( startPos + startLength ) );

    //Now find the end element. First prepare element to be found
    tagToBeFound().Insert( 1, _L8( "/" ) ); // '/' after '<'
    tagToBeFound().Append( _L8( ">" ) ); // '>' as last


    endPos = temp.Find(tagToBeFound());
    if ( endPos < 0)
        {
        aOffset = -1;
        return KNullDesC8();
        }
    endPos += startPos + startLength + tagToBeFound().Length();

    temp.Set( aMessage.Mid(startPos, endPos - startPos) );

    aOffset = endPos;
    LOG( _L( "Extracted element" ) );
    LOGHEX( temp.Ptr(), temp.Length() );

    //auto_handle closes and frees allocated resources
    return temp;
    }

// -----------------------------------------------------------------------------
// CRoapParser::ExtractDomainKeyElements
// -----------------------------------------------------------------------------
//
TInt CRoapParser::ExtractDomainKeyElements(
    const TDesC8& aMessage, RPointerArray<HBufC8>& aDomainKeyElements ) const
    {
    LOG( _L("CRoapParser::ExtractDomainKeyElements") );

    TPtrC8 temp(KNullDesC8);
    TPtrC8 elementPtr(KNullDesC8);
    TInt pos = 0;
    HBufC8* element = NULL;
    TInt err = KErrNone;
    TPtr8 ptr(0, 0);
    TInt macStart = 0;
    TInt macEnd = 0;

    // extract DomainKey elements to aDomainKeyElements array
    while (true)
        {
        elementPtr.Set( ExtractElement( aMessage, KDomainKey(), pos ) );

        if( pos < 0 )
            {
            // no more DomainKeys present
            if(aDomainKeyElements.Count())
                {
                return KErrNone;
                }
            else
                {
                aDomainKeyElements.ResetAndDestroy();
                return KErrRoapServerFatal;
                }
            }

        element = elementPtr.Alloc();
        if(!element)
            {
            return KErrNoMemory;
            }

        // remove mac element from found DomainKeyElement
        macStart = element->Find( KMac );
        temp.Set(element->Left(macStart));
        macStart = temp.LocateReverse('<');
        macEnd = element->Find( KMacEnd ) + KMacEnd().Length();
        if ( macStart < 0 || macEnd < 0 )
            {
            aDomainKeyElements.ResetAndDestroy();
            return KErrRoapServerFatal;
            }
        ptr.Set( element->Des() );
        ptr.Replace( macStart, macEnd - macStart, KNullDesC8 );

        err = aDomainKeyElements.Append(element);
        if(err)
            {
            delete element;
            element = NULL;
            aDomainKeyElements.ResetAndDestroy();
            return err;
            }
        }
    }

//  End of File