upnpavcontroller/upnpxmlparser/src/upnpxmlparser.cpp
author Sampo Huttunen <sampo.huttunen@nokia.com>
Wed, 24 Nov 2010 09:39:46 +0200
branchIOP_Improvements
changeset 45 a6c41ca11adf
parent 38 5360b7ddc251
permissions -rw-r--r--
Updated the SIS package, there was some BC issue with the earlier version. Also updated the platform UID to S^3 version.

/*
* Copyright (c) 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:      XML SAX Parser for UPnP.
*
*/






// INCLUDE FILES
// system / xml parser api
#include <xml/parser.h>
#include <xml/parserfeature.h>
#include <xml/matchdata.h>
#include <xml/xmlparsererrors.h>

// upnp stack api
#include <upnpstring.h>

// dlnasrv / mediaserver api
#include <upnpcontainer.h>
#include <upnpitem.h>
#include <upnpelement.h>

// dlnasrv / internal api's
#include "upnpcdsreselementutility.h"

// dlnasrv / xmlparser internal
#include "upnpobjectstack.h"
#include "upnpitemtoxml.h"
#include "upnpxmlstringutility.h"
#include "upnpxmlparser.h"

_LIT( KComponentLogfile, "upnpxmlparser.txt");
#include "upnplog.h"


_LIT8( KXmlMimeType,    "text/xml"     );
_LIT8( KLIB2XML,        "libxml2" );

_LIT8( KContainer,      "container"    );
_LIT8( KItem,           "item"         );

_LIT8( KTitle,          "title"        );

_LIT8( KClass,          "class"        );
_LIT8( KContentURI,     "res"          );
_LIT8( KId,             "id"           );
_LIT8( KParentId,       "parentId"     );
_LIT8( KRestricted,     "restricted"   );
_LIT8( KComma,          ":"            );
_LIT8( KTrue,           "1"            );
_LIT8( KDIDL,           "DIDL-Lite"    );
_LIT8( KDesc,           "desc"         );
_LIT8( KDlnaDoc,        "X_DLNADOC"    );
_LIT8( KSpace,          " "            );
_LIT8( KImportUri,      "importUri"    );

// --------------------------------------------------------------------------
// CUPnPXMLParser::CUPnPXMLParser()
// See upnpxmlparser.h
// --------------------------------------------------------------------------
CUPnPXMLParser::CUPnPXMLParser()
    {
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::ConstructL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::ConstructL()
    {
    __LOG( "CUPnPXMLParser::CostructL" );
    iStack = CUPnPObjectStack::NewL();
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::NewL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
EXPORT_C CUPnPXMLParser* CUPnPXMLParser::NewL()
    {
    CUPnPXMLParser* self = CUPnPXMLParser::NewLC();
    CleanupStack::Pop( self );    
    return self;
    }


// --------------------------------------------------------------------------
// CUPnPXMLParser::NewLC
// See upnpxmlparser.h
// --------------------------------------------------------------------------
EXPORT_C CUPnPXMLParser* CUPnPXMLParser::NewLC()
    {   
    CUPnPXMLParser* self = new( ELeave ) CUPnPXMLParser();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }
    
// --------------------------------------------------------------------------
// CUPnPXMLParser::~CUPnPXMLParser
// See upnpxmlparser.h
// --------------------------------------------------------------------------
CUPnPXMLParser::~CUPnPXMLParser()
    {
    __LOG( "CUPnPXMLParser::~CUPnPXMLParser" );
    if ( iStack )
        {
        iStack->ResetAndDestroy();
        delete iStack;
        }
    
    delete iElementValue;
    delete iNewElement;
    
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::ResetMember
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::ResetMember()
    {
    iResultRoot->ResetAndDestroy();
    iResultRoot = NULL;
    iStack->ResetAndDestroy(); 
    delete iStack;
    iStack = NULL;

    delete iElementValue; iElementValue = NULL;
    delete iNewElement; iNewElement = NULL;
    iTitle = 0;
    iObjectClass = 0;
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::ParseResultDataL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
EXPORT_C void CUPnPXMLParser::ParseResultDataL( 
    RPointerArray<CUpnpObject>& aResultArray,
    const TDesC8& aData )
    {
    __LOG( "CUPnPXMLParser::ParseResultDataL, begin" );
    
    if ( !aData.Length() )
        {
        User::Leave( KErrArgument );
        }

    iResultRoot = &aResultArray;

    // Create parser 
    CMatchData* matchData = CMatchData::NewLC();
    matchData->SetMimeTypeL( KXmlMimeType ); 
    matchData->SetVariantL( KLIB2XML ); 
    CParser* parser = CParser::NewLC( *matchData, *this );
    parser->EnableFeature( Xml::EReportNamespaceMapping );
    
    TRAPD( err, Xml::ParseL( *parser,aData ) );
    // if the xml contained control character
    if( EXmlInvalidToken == err )
        {
        __LOG1 ( "CUPnPXMLParser::ParseResultDataL Can not Parse \
        		error code %d " ,err );
        HBufC8* FiltrateBuffer = 
            UpnpXmlStringUtility::RemoveXmlControlCharactersL( aData );
        //if remove some control characters.
        if( FiltrateBuffer )
            {
            CleanupStack::PushL( FiltrateBuffer );
            ResetMember();

            iStack = CUPnPObjectStack::NewL();
            iResultRoot = &aResultArray;

            Xml::ParseL( *parser, *FiltrateBuffer );
            CleanupStack::PopAndDestroy( FiltrateBuffer );
            }
        else
            {
            User::Leave( err );
            }
        }
    else if ( KErrNone != err )
        {
        User::Leave( err );
        }
    CleanupStack::PopAndDestroy( parser );
    CleanupStack::PopAndDestroy( matchData );
    
    iResultRoot = NULL;           
    __LOG( "CUPnPXMLParser::ParseResultDataL, end" );
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::ItemAsXMLLC
// See upnpxmlparser.h
// --------------------------------------------------------------------------
EXPORT_C HBufC8* CUPnPXMLParser::ItemAsXmlLC( const CUpnpItem& aItem )
    {
    CUpnpItemToXML* tmpXmlItem =  CUpnpItemToXML::NewLC( aItem );
    HBufC8* raw  = tmpXmlItem->AsXmlL();
    CleanupStack::PushL( raw );
    
    HBufC8* encoded = UpnpString::EncodeXmlStringL( raw );
    CleanupStack::PopAndDestroy( raw );
    CleanupStack::PushL( encoded );
    
    HBufC8* tagged = tmpXmlItem->CreateUnDecodedXmlL( *encoded );
    CleanupStack::PopAndDestroy( encoded );
    CleanupStack::PopAndDestroy( tmpXmlItem );
    CleanupStack::PushL( tagged );
    
    return tagged;
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::XmlForCreateObjectLC
// See upnpxmlparser.h
// --------------------------------------------------------------------------
EXPORT_C HBufC8* CUPnPXMLParser::XmlForCreateObjectLC(
    const CUpnpItem& aItem )
    {
    CUpnpItemToXML* tmpXmlItem = CUpnpItemToXML::NewLC( aItem );
    HBufC8* tempXmlDataBlock = tmpXmlItem->AsResultArgumentL();
    CleanupStack::PopAndDestroy( tmpXmlItem );
    CleanupStack::PushL( tempXmlDataBlock );
    
    return tempXmlDataBlock;
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::ContainerToXmlLC
// See upnpxmlparser.h
// --------------------------------------------------------------------------
EXPORT_C HBufC8* CUPnPXMLParser::ContainerToXmlLC(
    const CUpnpContainer& /*aContainer*/ )
    {
    // Not implemented
    User::Leave( KErrNotSupported );
    
    return NULL;
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnStartDocumentL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnStartDocumentL( 
                                const RDocumentParameters& /*aDocParam*/, 
                                TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnEndDocumentL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnEndDocumentL( TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnStartElementL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnStartElementL( const RTagInfo& aElement, 
                                      const RAttributeArray& aAttributes,
                                      TInt aErrorCode )
    {
    __LOG1( "CUPnPXMLParser::OnStartElementL, error code: %d", aErrorCode );
    if ( aErrorCode != KErrNone )
        {
        return;
        }
    const TDesC8& desName = aElement.LocalName().DesC();
    const TDesC8& prefix = aElement.Prefix().DesC();
    
    // Delete content, since there may be some stuff between the elements
    // (comments, whitespace etc.)
    delete iElementValue; iElementValue = NULL;    
      
    if ( !desName.CompareF( KContainer ) ) // Container element
        {
        CUpnpContainer* tmpContainer = CUpnpContainer::NewL();
        CleanupStack::PushL( tmpContainer );

        SetAttributesL( *tmpContainer, aAttributes );
        //push into the stack, ownership is transferred                      
        iStack->PushL( tmpContainer ); 
        
        CleanupStack::Pop( tmpContainer );
        }
    else if ( !desName.CompareF( KItem ) ) // Item element
        {
        CUpnpItem* tmpItem = CUpnpItem::NewL();
        CleanupStack::PushL( tmpItem );

        SetAttributesL( *tmpItem, aAttributes );                      
        //push into the stack, ownership is transferred                      
        iStack->PushL( tmpItem );
        
        CleanupStack::Pop( tmpItem );
        }
    else if( !desName.CompareF( KTitle ) ) // Title element
        {
        // check that we have item or container. cause leave if not
        if ( iStack->Count() == 0)
            {
            User::Leave( KErrArgument );
            }
        // We should have an item or a container already!
        //__ASSERTD( iStack->Top(), __FILE__, __LINE__ );
        iTitle = ETrue;
        }
    else if( !desName.CompareF( KClass ) ) // Object class element
        {
        // check that we have item or container. cause leave if not
        if ( iStack->Count() == 0)
            {
            User::Leave( KErrArgument );
            }
        // We should have an item or a container already!
       // __ASSERTD( iStack->Top(), __FILE__, __LINE__ );
        iObjectClass = ETrue;
        }
    // Ignore DIDL-Lite, desc and X_DLNADOC -elements (DLNA req)
    else if( desName.Compare( KDIDL ) == KErrNone ||
             desName.Compare( KDesc ) == KErrNone ||
             desName.Compare( KDlnaDoc ) == KErrNone    
           )
        {
        // Ignore
        }
    else 
        {
        // check that we have item or container. cause leave if not
        if ( iStack->Count() == 0)
            {
            User::Leave( KErrArgument );
            }
        
        // We should have an item or a container already!    
        //__ASSERTD( iStack->Top(), __FILE__, __LINE__ );
        
        if( prefix.Length() > 0 ) // If there is a namespace (upnp: etc)
            {
            HBufC8* name = HBufC8::NewLC( prefix.Length() +
            KComma().Length() + desName.Length() ) ;
            name->Des().Copy( prefix );
            name->Des().Append( KComma );
            name->Des().Append( desName );
            
            // Create a new element
            __ASSERTD( !iNewElement, __FILE__, __LINE__ );
            iNewElement = CUpnpElement::NewL( *name );
        
            CleanupStack::PopAndDestroy( name );
            }
        else
            {
            // Create a new element
            __ASSERTD( !iNewElement, __FILE__, __LINE__ );
            iNewElement = CUpnpElement::NewL( desName );
            }
        
        // Set attributes for element
        SetAttributesL( aAttributes );
        }
    __LOG( "CUPnPXMLParser::OnEndElementL, end" );
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnEndElementL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnEndElementL( const RTagInfo& aElement, 
                                    TInt aErrorCode )
    {
    __LOG( "CUPnPXMLSAXParser::OnEndElementL(), begin" );
    if ( aErrorCode != KErrNone )
        {
        return;
        }
        
    const TDesC8& desName = aElement.LocalName().DesC();    
    if ( !desName.CompareF( KContainer ) || !desName.CompareF( KItem ) )
        {
        iResultRoot->AppendL( iStack->Top() );
        iStack->Pop(); // Remove object from stack.
        }
    else if( KErrNone != desName.CompareF( KDIDL ))
        {        
        CUpnpObject* obj = (CUpnpObject*)iStack->Top();
        __ASSERTD( obj, __FILE__, __LINE__ );
             
        if ( iElementValue )
            {
            SetValueToElementL( *obj, *iElementValue );
            }
        else
            {
            SetValueToElementL( *obj, KNullDesC8 );
            }    
        
        delete iElementValue; iElementValue = NULL;    
        }    
    __LOG( "CUPnPXMLSAXParser::OnEndElementL(), end" );
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnContentL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnContentL( const TDesC8& aBytes, TInt aErrorCode )
    {
    __LOG( "CUPnPXMLSAXParser::OnContentL(), begin" );
    if ( !iStack->Count() || aErrorCode != KErrNone )
        {
        return;
        }
    
    if( !iElementValue ) //if 1st time
        {
        iElementValue = HBufC8::NewL(aBytes.Length());
        iElementValue->Des().Copy(aBytes); 
        }
    else
        {
        HBufC8* previousValue = iElementValue;
        iElementValue = HBufC8::NewL( previousValue->Des().Length() +
                                      aBytes.Length() );
        iElementValue->Des().Append( *previousValue );
        iElementValue->Des().Append( aBytes );
        delete previousValue;
        } 
    __LOG( "CUPnPXMLSAXParser::OnContentL(), end" );
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnStartPrefixMappingL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnStartPrefixMappingL( const RString& /*aPrefix*/, 
                                               const RString& /*aUri*/, 
                                               TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnEndPrefixMappingL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnEndPrefixMappingL( const RString& /*aPrefix*/, 
                                             TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnIgnorableWhiteSpaceL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnIgnorableWhiteSpaceL( const TDesC8& /*aBytes*/, 
                                                TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnSkippedEntityL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnSkippedEntityL( const RString& /*aName*/, 
                                          TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnProcessingInstructionL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnProcessingInstructionL( const TDesC8& /*aTarget*/, 
                                                  const TDesC8& /*aData*/, 
                                                  TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::OnError
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::OnError( TInt /*aErrorCode*/ )
    {
    // No implementation needed
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::GetExtendedInterface
// See upnpxmlparser.h
// --------------------------------------------------------------------------
TAny* CUPnPXMLParser::GetExtendedInterface( const TInt32 /*aUid*/ )
    {    
    // No implementation needed
    return NULL;
    }

// --------------------------------------------------------------------------
// CUPnPXMLParser::SetAttributesL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::SetAttributesL( CUpnpObject& aObject, 
    const RAttributeArray& aAttributes )
    {
    __LOG( "CUPnPXMLParser::SetAttributesL" );
    
    if ( iStack->Count() )
        {
        // Object has a parent.
        // Should not really happen, but implemented anyways
        __LOG( "Object has a parent!" );
        
        if ( iStack->Top()->ObjectType() != EUPnPContainer )
            {
            User::Leave( KErrArgument );
            }
        CUpnpContainer* container = (CUpnpContainer*)iStack->Top();
        container->AppendObjectL( aObject );
        }
        
    RAttribute attribute;
    TInt count = aAttributes.Count();
    for ( TInt i = 0 ; i < count; i++ ) // Read attributes.
        {
        attribute = aAttributes[ i ];
        const TDesC8& name = attribute.Attribute().LocalName().DesC();
        
        if( !name.CompareF( KId ) )
            {
            aObject.SetIdL( attribute.Value().DesC() );
            }
        if( !name.CompareF( KParentId ) )
            {
            aObject.SetParentIdL( attribute.Value().DesC() );
            }            
        if( !name.CompareF( KRestricted ) ) 
            {
            if ( !attribute.Value().DesC().CompareF( KTrue ) ) // restricted
                {
                aObject.SetRestricted( ETrue );
                }
            else // no restriction
                {
                aObject.SetRestricted( EFalse );
                }
            }
        }
    __LOG( "CUPnPXMLParser::SetAttributesL - End" );
    }
    
// --------------------------------------------------------------------------
// CUPnPXMLParser::SetValueToElementL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::SetValueToElementL( CUpnpObject& aItem,
    const TDesC8& aValue )
    {
    __LOG( "CUPnPXMLParser::SetValueToElementL()" );

    if( iTitle )
        {
        __LOG( "SetValueToElementL() - title element" );
        aItem.SetTitleL( aValue );
        iTitle = EFalse;
        }
    else if( iObjectClass )
        {
        __LOG( "SetValueToElementL() - objectclass element" );
        aItem.SetObjectClassL( aValue );  
        iObjectClass = EFalse;
        }
    // See if it's the res-element   
    else if( iNewElement && // NULL Check
             iNewElement->Name().Compare( KContentURI ) == KErrNone )
        {
        __LOG( "SetValueToElementL() - res element" ); 
                
        // Check that uri is absolute
        if( UpnpCdsResElementUtility::IsUriAbsolute( aValue ) )
            {
            __LOG( "valid res-element" );
            iNewElement->SetValueL( aValue );
            aItem.AddElementL( iNewElement ); // Ownership is transferred
            iNewElement = NULL;                
            }
        else
            { 
            // if CreateObjectResponse, there is importuri
            // no need to check res-element
            TInt found = EFalse;
            RUPnPAttributesArray elArray = iNewElement->GetAttributes();
            TInt count = elArray.Count(); 
            for( TInt i = 0; i < count; i++ )
                {
                if( elArray[ i ]->Name() == KImportUri )
                    {
                    i = count;
                    found = ETrue;
                    __LOG( "SetValueToElementL() - ImportUri found" );
                    }
                }
                              
            if( found )     
                {
                __LOG( "no res-element but import uri found" );
                iNewElement->SetValueL( KNullDesC8 );
                aItem.AddElementL( iNewElement ); // Ownership is transferred
                iNewElement = NULL;                   
                }  
            else
                {
                __LOG( "invalid res-element" );
                delete iNewElement;
                iNewElement = NULL;                
                }           
            }
  
        }
    else 
        {
        __LOG( "SetValueToElementL() - unknown element" );
        if( iNewElement )
            {
            // Check for empty values
            if( aValue == KNullDesC8 || aValue == KSpace )
                {
                // Do not add empty values
                delete iNewElement; iNewElement = NULL;                
                }
            else
                {
                iNewElement->SetValueL( aValue );
                aItem.AddElementL( iNewElement ); // Ownership is transferred
                iNewElement = NULL;                
                }    
            }
        }
        
    __LOG( "CUPnPXMLParser::SetValueToElementL() End" ); 
    }

    
// --------------------------------------------------------------------------
// CUPnPXMLParser::SetAttributesL
// See upnpxmlparser.h
// --------------------------------------------------------------------------
void CUPnPXMLParser::SetAttributesL( const RAttributeArray& aAttributes )
    {
    __LOG( "CUPnPXMLParser::SetAttributesL" );
    
    RAttribute attribute;
    TInt count = aAttributes.Count();
    for ( TInt i = 0; i < count ; i++ )
        {
        attribute = aAttributes[i];
        const TDesC8& name = attribute.Attribute().LocalName().DesC();
        CUpnpAttribute* att = CUpnpAttribute::NewLC();
        att->SetNameL( name );
        att->SetValueL( attribute.Value().DesC() );
        __ASSERTD( iNewElement, __FILE__, __LINE__ );
        iNewElement->AddAttributeL( att );
        CleanupStack::Pop( att );     
        }
    __LOG( "CUPnPXMLParser::SetAttributesL End" );    
    }
    
// end of file