upnpavcontroller/upnpxmlparser/src/upnpxmlparser.cpp
branchnew development branch with rendering state machine and other goodies
changeset 38 5360b7ddc251
parent 0 7f85d04be362
--- a/upnpavcontroller/upnpxmlparser/src/upnpxmlparser.cpp	Fri Sep 17 08:31:21 2010 +0300
+++ b/upnpavcontroller/upnpxmlparser/src/upnpxmlparser.cpp	Mon Nov 01 12:37:49 2010 +0200
@@ -1,697 +1,698 @@
-/*
-* 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
-// 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"
-#include <upnpcontainer.h>
-#include <upnpitem.h>
-#include "upnpelement.h"
-#include "upnpxmlparser.h"
-
-// upnpframework / internal api's
-#include "upnpcdsreselementutility.h"
-
-// 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
-
+/*
+* 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
+