upnpmediaserver/contentdirectoryservice/src/upnpelementfactory.cpp
author samhuttu
Mon, 01 Nov 2010 12:37:49 +0200
branchnew development branch with rendering state machine and other goodies
changeset 38 5360b7ddc251
parent 32 3785f754ee62
permissions -rw-r--r--
New development branch with e.g. rendering state machine and a simple Qt example application using it.

/** @file
* Copyright (c) 2005-2006 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:  Element Factory.
*
*/
 

// INCLUDE FILES
#include <sysutil.h>
#include <uri8.h>
#include <xmlengdomparser.h>

#include "upnpelementfactory.h"
#include "upnpcontentdirectoryglobals.h"
#include "upnpstring.h"
#include "upnpprotocolinfo.h"
#include "upnpcommonupnplits.h"
#include "upnpcdutils.h"
#include "upnpprotocolinfolocal.h"

using namespace UpnpDlnaProtocolInfo;

// ============================= LOCAL FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// DestroyRPointerArray
// Used by TCleanupItem to destroy array
// -----------------------------------------------------------------------------
//
void DestroyRArray(TAny* aArray)
{
    RArray<RXmlEngDocument>* array = (RArray<RXmlEngDocument>*) aArray;
    for(TInt i = 0; i < array->Count(); i++ )
            (*array)[i].Close();
    (*array).Close();
}

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

// -----------------------------------------------------------------------------
// CUpnpElementFactory::~CUpnpElementFactory()
// C++ default destructor. (virtual destructor)
// -----------------------------------------------------------------------------
//
CUpnpElementFactory::~CUpnpElementFactory()
{
    //Close XML document
    iDocument.Close();
    
    iDOMImpl.Close(); 
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::NewL()
// Two-phased constructor
// -----------------------------------------------------------------------------
//
CUpnpElementFactory* CUpnpElementFactory::NewL( const TDesC& aObjectsXmlPath )
{
    CUpnpElementFactory* self = CUpnpElementFactory::NewLC( aObjectsXmlPath );
    CleanupStack::Pop( self );
    return self;
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::NewLC()
// Two-phased constructor
// -----------------------------------------------------------------------------
//
CUpnpElementFactory* CUpnpElementFactory::NewLC( const TDesC& aObjectsXmlPath )
{
    CUpnpElementFactory* self = new (ELeave) CUpnpElementFactory();
    CleanupStack::PushL( self );
    self->ConstructL( aObjectsXmlPath );
    return self;
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::ConstructL()
// Two-phased constructor
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ConstructL(const TDesC& aObjectsXmlPath)
{

    iDOMImpl.OpenL();

    RXmlEngDOMParser parser;
    User::LeaveIfError( parser.Open(iDOMImpl) );
    CleanupClosePushL(parser);
    
    if ( aObjectsXmlPath == KNullDesC() )
        {
        RFs fs;
        User::LeaveIfError(fs.Connect());
        CleanupClosePushL(fs);

        TFileName path;
        User::LeaveIfError(fs.PrivatePath(path));

        // Load dll file
        TFileName objectsXmlFileName( KObjectsXmlFileName() );
        TFileName dllName;
        Dll::FileName( dllName );
        TBuf<2> drive = dllName.Left( 2 ); // Drive letter followed by ':' 
        objectsXmlFileName.Insert( 0, drive );
        
        TParse fp;
        fp.Set(objectsXmlFileName,&path, 0);
        path = fp.FullName();

        iDocument = parser.ParseFileL( path );        
        CleanupStack::PopAndDestroy(&fs);
        }
    else
        {
        iDocument = parser.ParseFileL( aObjectsXmlPath );                
        }
        
    

    CleanupStack::PopAndDestroy(&parser);
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::CUpnpElementFactory()
// Default constructor
// -----------------------------------------------------------------------------
//
CUpnpElementFactory::CUpnpElementFactory()
{

}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::CheckRestrictedValue()
// -----------------------------------------------------------------------------
//
TBool CUpnpElementFactory::CheckRestrictedValue (TPtrC8& restrVal)
    {
    TBool retVal = EFalse;

    if ( 
    (UpnpCD::Kfalse().Compare( restrVal ) != 0) &&
    (UpnpCD::KZero().Compare( restrVal ) != 0) &&
    (UpnpCD::Ktrue().Compare( restrVal ) != 0) &&
    (UpnpCD::KOne().Compare( restrVal ) != 0)
    )
        {
        retVal = ETrue;
        }
    return retVal;
    }


// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateNewObjectL()
// Function to validate a new object given by Control Point, especially 
// upnp:class element field eg. object.item.musictrack
// IMPORTANT: If objects's description is invalid due to missing elements
// it tries to repair it by adding those missing elements.
// -----------------------------------------------------------------------------
//

TUpnpErrorCode CUpnpElementFactory::ValidateNewObjectL( const TXmlEngElement& aNewElement, TBool aNew, TBool aLocalSharing)
{
    TInt i;    
    TPtrC8 objectType = KItem();

    RXmlEngNodeList<TXmlEngElement> elements;
    CleanupClosePushL(elements);
    aNewElement.GetChildElements( elements );
    
    // invalid element if the count of the objects is less than 1 (=0)
    if ( elements.Count() != 1 )
    {
        User::Leave( EInvalidArgs );
    }
    CleanupStack::PopAndDestroy(&elements);
    // try to find the new item from the xml
    TXmlEngElement object;
    UpnpDomInterface::GetElementL( aNewElement, object, KItem() );
    if ( object.IsNull() ) 
    {   
        
        // if it's not an item, it's a container
        UpnpDomInterface::GetElementL( aNewElement, object, KContainer() );
        if ( object.IsNull() )
        {
            // not even a container, leave!
            User::Leave ( EInvalidArgs );
        }
        objectType.Set( KContainer() );
    }
                           
    // restriced value
    TPtrC8 restrVal = UpnpDomInterface::GetAttrValueL( object,  KRestricted );
    
    if (CheckRestrictedValue(restrVal))
        {
        User::Leave ( EBadMetadata);
        }
    
    // for convenience later, take now a reference to the children of the object
    RXmlEngNodeList<TXmlEngElement> children;
    CleanupClosePushL(children);
    object.GetChildElements( children );
            
    // an exception: we can't have <res importUri=".. element in 
    // a new object (set by control point)
    while ( children.HasNext() )
    {
        TXmlEngElement child = children.Next();
        
        if ( IsNotEmptyImportUriL( child ) && aNew ) 
        {
            User::Leave ( EBadMetadata );
        }
        
        //---- check res@duration, 7.3.22 MM DIDL-Lite res@duration Format        
        CheckDurationOfResElementL(child);
        CheckSizeOfResElementL(child);
                    
        RXmlEngNodeList<TXmlEngElement> forbiddenChildren;
        CleanupClosePushL(forbiddenChildren);
        child.GetChildElements( forbiddenChildren );

        if ( forbiddenChildren.HasNext() 
            && child.Name() != KVendorDescriptor ) // ignore <desc></desc>
        {
            User::Leave ( EBadMetadata );
        }
        CleanupStack::PopAndDestroy(&forbiddenChildren);
        if ( child.Name() == KDate8() )
        {
            if (!UpnpCdUtils::ValidateDateL(child.Value())) 
             child.Remove();
        }
        
    }

    // if survived here, we have the new element of type item or container
    // let's analyze its type

    // let's inspect each of types
    // at first, collect object type descriptions from objects xml    
    // to a pointer array
    RArray<TXmlEngElement> objectDescrs;
    CleanupClosePushL( objectDescrs );
    // store class descriptor elements in this array
    ClassesL( object, objectDescrs, objectType );
    
    // validate each separately
    
    ValidatePropertiesL(object, objectDescrs);
    if(aNew)
    {
        ValidateBigImageL(object);
    }
    
    // for each type, check that 
    // this new object has all the required fields
        
    for (i=0; i<objectDescrs.Count(); i++)
    {
        // now we have to go through all the fields of the new item
        // first, for convenience take a pointer to <ps>(properties) element
        
        RXmlEngNodeList<TXmlEngElement> propElems;
        CleanupClosePushL(propElems);
        objectDescrs[i].GetChildElements( propElems );
    

        while ( propElems.HasNext() )
        {
            
            TXmlEngElement ps = propElems.Next(); // ps stands for properties
            if ( ps.Name() == KProperties() )
            {

                // take the properties
                RXmlEngNodeList<TXmlEngElement> properties;
                CleanupClosePushL(properties);
                ps.GetChildElements( properties );
        
                const TDesC8& propertyType = UpnpDomInterface::GetAttrValueL( ps, KType() );

                TBool elementFound(EFalse);

                // check each property
                while ( properties.HasNext() )
                {
                    
                    TXmlEngElement el = properties.Next();

                    elementFound = ValidateElementL (object, propertyType, el, elementFound, aNew, aLocalSharing);
                        
                    // Validate attribute   
                    if ( propertyType == KAttribute() )
                    {
                        elementFound = EFalse;
                        ValidateAttributeL(el, object);
                    }
                }
                CleanupStack::PopAndDestroy(&properties);
            }
        }
        CleanupStack::PopAndDestroy(&propElems);
    }
    CleanupStack::PopAndDestroy(); //objectDescrs.Close();
    CleanupStack::PopAndDestroy(&children);
    
    // now the object 
    // * has the all required fields (if some were missing, they are added)
    // * had a proper xml structure (_not_ using UpnpDomInterface:: functions that do not care)
    // * has for sure a mostly proper object structure 

    return EUndefined;
}

TBool CUpnpElementFactory::ValidateElementL (TXmlEngElement aObject, 
        const TDesC8& aPropertyType, TXmlEngElement aEl, TBool aElementFound, TBool aNew,
        TBool aLocalSharing)
    {
        TBool elementFound = aElementFound;
        RXmlEngNodeList<TXmlEngElement> children;
        // Validate element
        if ( aPropertyType == KElement() )
        {
            elementFound = EFalse;
            
            // Check if this element is requiered
            const TDesC8& required = UpnpDomInterface::GetAttrValueL( aEl, KRequiredObject() );
    
            TPtrC8 elementName = UpnpDomInterface::GetAttrValueL( aEl, KName() );
    
            // If it's required then check it's existence
    
            if ( required == UpnpCD::KOne() || elementName == KRes()  ||  elementName == KAlbumArtURI() )
            {
                if( !KRes().Compare(elementName) ||  !KAlbumArtURI().Compare(elementName))
                {
                    elementFound = ETrue;
                }
                // get children once more, because this kind of list does not have any reset function
                aObject.GetChildElements( children );
    
                elementFound = HandleChildrenL (children, aNew, aLocalSharing, elementFound, aEl);
                    
                // If not found, add it
                if ( !elementFound )
                {
                    User::Leave(EBadMetadata);
                }
            } 
        }
        return elementFound;
    }

TBool CUpnpElementFactory::HandleChildrenL (RXmlEngNodeList<TXmlEngElement> aChildren, TBool aNew, TBool aLocalSharing,
        TBool aElementFound, TXmlEngElement aEl)
    {
    TBool elementFound = aElementFound;
    TPtrC8 elementName = UpnpDomInterface::GetAttrValueL( aEl, KName() );
    
    while ( aChildren.HasNext() )
    {
        TXmlEngElement child = aChildren.Next();
        
        HBufC8* nameWithNs = NameWithNsLC( child );

        if ( *nameWithNs == elementName )
        {
            // local sharing
            if(aNew && *nameWithNs == KRes)
            {
                TUriParser8 up;
                TPtrC8 rv(child.Text());
                if(rv.Length())
                {
                    User::LeaveIfError( up.Parse(child.Text()) );
                    TPtrC8 path( up.Extract(EUriPath) );
                    TPtrC8 scheme( up.Extract(EUriScheme) );

                    if(aLocalSharing)
                    { // local action
                        if( scheme == UpnpHTTP::KSchemeFile8())
                        {
                            // The path can be: /c:/....
                            // or /c/... - without colon.
                            // Both situation are correct but 
                            // in further operations we assume 
                            // there is not any colon next to the drive letter.
                            // Therefore, remove it if second element of path table equals ':'
                            if(path[2] == KColon8()[0])
                            { // There IS a colon next to the drive letter.
                                // Here is an example uri:
                                // file:///c:/...
                                // As you can see the second colon must be removed
                                HBufC8* uri = child.Text().AllocLC();
                                TPtr8 uriPtr(uri->Des());
                                TPtrC8 tmp(uri->Des());
                                TInt second = 2;
                                TInt colonPos = 0;
                                for(TInt i = 0; i < second; i++)
                                {
                                    colonPos += tmp.Find(KColon8) + 1;
                                    tmp.Set( uriPtr.Mid(colonPos) );                                                    
                                }
                                // remove the colon
                                uriPtr.Replace(colonPos - 1, KColon8().Length(), KNullString8);
                                // set TXmlEngElement value
                                child.SetTextL(uriPtr);
                                
                                // clean up             
                                CleanupStack::PopAndDestroy(uri);                                               
                            }

                            // check other  restrictions
                            TUriParser8 up;
                            User::LeaveIfError( up.Parse(child.Text()) );
                            TPtrC8 path( up.Extract(EUriPath) );

                            // sharing from Z: drive is forbidden
                            // second character is a drive letter
                            if(path[1] == KForbiddenDrivez()[0] || path[1] == KForbiddenDriveZ()[0])
                            {
                                User::Leave(EArgumentValue);
                            }
                            
                            // cannot share from private directory
                            if(!path.Match(KForbiddenPrivatePattern))
                            {
                                User::Leave(EArgumentValue);
                            }
                            
                        }
                    }
                    else
                    { // not local action
                        // "file" schema is forbidden here
                        if(scheme == UpnpHTTP::KSchemeFile8())
                        {
                            User::Leave(EArgumentValue);
                        }
                    }
                }
            }


            if ( elementFound ) 
            {
                // multiple values for one element!
                const TDesC8& multiple = UpnpDomInterface::GetAttrValueL( aEl, KMultiple() );
                
                // if it's not allowed for this element, leave!
                if ( !multiple.Length() )
                {
                    User::Leave( EInvalidArgs );
                }
            }
            elementFound = ETrue;
            // mark the element required - if not res
            if( KRes().Compare(elementName) && KAlbumArtURI().Compare(elementName))
            {
                child.AddNewAttributeL(KRequiredAtrName,KTrueValue8);
            }
            
            // nested validation 
            RXmlEngNodeList<TXmlEngElement> nestEls;
            CleanupClosePushL(nestEls);
            aEl.GetChildElements(nestEls);
            CheckNestedElementsL(nestEls, child, aLocalSharing);
            CleanupStack::PopAndDestroy(&nestEls);
        }
        CleanupStack::PopAndDestroy( nameWithNs );
        
    }

    return elementFound;
}


void CUpnpElementFactory::CheckNestedElementsL(RXmlEngNodeList<TXmlEngElement> aNestEls, TXmlEngElement aChild,
        TBool aLocalSharing)
{
    HBufC8* nameWithNs = NameWithNsLC( aChild );
    while(aNestEls.HasNext())
    {
        TXmlEngElement nestPs = aNestEls.Next();
    
        // take the properties
        RXmlEngNodeList<TXmlEngElement> nestProperties;
        nestPs.GetChildElements( nestProperties );
        const TDesC8& nestPropertyType = UpnpDomInterface::GetAttrValueL( nestPs, KType() );
        // Validate attribute   
        if ( nestPropertyType == KAttribute() )
        {
            while(nestProperties.HasNext())
            {   
                TXmlEngElement nestEl = nestProperties.Next();
                //TBool nestElementFound;
    
                //nestElementFound = EFalse;
                
                const TDesC8& nestRequired = UpnpDomInterface::GetAttrValueL( nestEl, KRequiredObject() );
                TPtrC8 nestElementName = UpnpDomInterface::GetAttrValueL( nestEl, KName() );
                if ( nestRequired == UpnpCD::KOne() || nestElementName == KDlnaProfileID)
                {
                    TPtrC8 nestCurrentValue = UpnpDomInterface::GetAttrValueL( aChild, nestElementName );
                    
                    TPtrC8 nameOfAttr;
                    TPtrC8 valOfAttr;
                    nameOfAttr.Set( nestElementName );
                    
                    // Start of 'dlna:profileID' attribute case                                                 
                    if( nameWithNs->Des() == KAlbumArtURI && nestElementName == KDlnaProfileID) // ---------------- 1 ------------
                    {   
                        TXmlEngAttr profId = aChild.AttributeNodeL(KProfileID, KXmlnsDlna);
                        if(profId.NotNull())
                        {
                            if (profId.Value().Compare(KDefaultProfileID))
                            {
                                User::Leave( EBadMetadata );
                            }
                            // setting real name of attribute -> localName
                            nestElementName.Set(KProfileID); // descriptor  
                            nameOfAttr.Set( nestElementName ); // related TString
                                                                                                                                                                                                                                                            
                            // generating a new value of 'dlna:profileID'
                            HBufC8* albumArtURIelemValue = UpnpDomInterface::GetElementValueL(aChild).AllocLC();
                            TPtr8 albumArtURIelemValuePtr( albumArtURIelemValue->Des() );                                                       
                            
                            albumArtURIelemValuePtr.Trim(); // deletes leading and trailing whitespace characters                                                   
                            aChild.SetValueL(albumArtURIelemValuePtr); // sets new trimmed value to albumArtURI
                                                                                                                        
                            CUpnpDlnaProtocolInfo* tempProtocolInfo = NULL;
                            TInt error = iContentDirectory->GetProtocolInfoL( albumArtURIelemValuePtr, tempProtocolInfo );
                            TPtrC8 tempPnParam;
                            if( error >=0 )
                            {
                                tempPnParam.Set( tempProtocolInfo->PnParameter() );
                                    
                                nestCurrentValue.Set(tempPnParam); // descriptor
                                valOfAttr.Set(tempPnParam); // related TString                                                         
                            }
                            else 
                            {
                                User::Leave( EBadMetadata );
                            }                                                       
                            CleanupStack::PopAndDestroy(albumArtURIelemValue);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                            // if albumArtURI doesn't contain profileID -> it creates one and also related namespace
                            // if albumArtURI contains profileID -> it modifies profileID's value
                            aChild.SetAttributeL( nameOfAttr, valOfAttr, KXmlnsDlna(), KDlnaPrefix() );
                                                                                    
                            delete tempProtocolInfo;
                            tempProtocolInfo = NULL;    
                        }
                        
                    } // End of 'dlna:profileID' attribute case
                    else                    
                    {
                        if ( !nestCurrentValue.Length() )  
                        {
                            
                            if(nestElementName == KprotocolInfo)
                            {
                                if( ! aLocalSharing )
                                {
                                    valOfAttr.Set( KEmptyProtocolInfoVal8() );
                                }
                                else 
                                {
                                    User::Leave( EBadMetadata );
                                }
                            }                                                                                                   //------- 2 -----                                                                                    //------- 2 -----                  
                            else
                            {
                                valOfAttr.Set( KNullDesC8() );
                            }
    
                            aChild.AddNewAttributeL( nameOfAttr, valOfAttr );                                                            
                        }
                        else 
                        {
                            if(nestElementName == KprotocolInfo) 
                            {
                                HBufC8* protInfoValue = NULL;
                                TRAPD(err, protInfoValue = ValidateProtocolInfoInResL( nestCurrentValue, aLocalSharing ));
                                if(err)
                                {
                                    User::Leave(EBadMetadata);
                                }
                                CleanupStack::PushL( protInfoValue );
                                valOfAttr.Set( *protInfoValue );
                                aChild.SetAttributeL( nameOfAttr, valOfAttr );
                                CleanupStack::PopAndDestroy( protInfoValue );                                                           
                            }                                                                                                 //------- 3 -----                                                                                         //------- 3 -----
                        }
                    }                                                                                                                                                                                                                                                                                                                                                                                       
                                                                        
    
                    // if not main tag mark the attr is required
                    if( !IsMainObjectTagL(aChild) && nestElementName != KDlnaProfileID)
                    {
                       
                        HBufC8* attrReq = HBufC8::NewLC(
                            nestElementName.Length()
                            +KRequiredAtrSuf().Length() );
                        TPtr8 attrReqPtr(attrReq->Des());
                        attrReqPtr = nestElementName;
                        attrReqPtr.Append(KRequiredAtrSuf);
                        aChild.AddNewAttributeL( attrReqPtr, KTrueValue8 );
                        CleanupStack::PopAndDestroy(attrReq);
                    }
                }
            }
        }
    
    }
}

void CUpnpElementFactory::ValidateAttributeL(TXmlEngElement aElement, TXmlEngElement aObject)
    {
        
        const TDesC8& required = UpnpDomInterface::GetAttrValueL( aElement, KRequiredObject() );
        if ( required == UpnpCD::KOne() )
        {

            const TDesC8& elementName = UpnpDomInterface::GetAttrValueL( aElement, KName() );

            const TDesC8& currentValue = UpnpDomInterface::GetAttrValueL( aObject, elementName );
            
            if ( !currentValue.Length() )  
            {
                TXmlEngAttr attr = aObject.AttributeNodeL( elementName );

                if(attr.NotNull())
                {
                    attr.SetValueL(KNullDesC8);
                }
                else
                {
                    aObject.AddNewAttributeL( elementName, KNullDesC8 );
                }                               
            }
            // if not main tag mark the attr is required
            if(!IsMainObjectTagL(aObject))
            {
                HBufC8* attrReq = HBufC8::NewLC(
                    elementName.Length()+KRequiredAtrSuf().Length() );
                TPtr8 attrReqPtr(attrReq->Des());
                attrReqPtr = elementName;
                attrReqPtr.Append(KRequiredAtrSuf);
                aObject.AddNewAttributeL( attrReqPtr, KTrueValue8 );
                CleanupStack::PopAndDestroy(attrReq);
            }
        }
    }

// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidatePropertiesL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidatePropertiesL( TXmlEngElement aObj,
                                               RArray<TXmlEngElement>& aClassList)
{
    // validate main object's attributes
    ValidateMainAttributesL(aObj, aClassList);
    
    // validate elements
    RXmlEngNodeList<TXmlEngElement> elements;
    CleanupClosePushL(elements);
    aObj.GetChildElements (elements);
    
    // for each element
    while(elements.HasNext())
    {
        TXmlEngElement el = elements.Next();
        ValidateElementL(el, aClassList);
    }
    CleanupStack::PopAndDestroy(&elements);
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateBigImageL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidateBigImageL( TXmlEngElement aObj)
{
    RArray<TXmlEngElement> elms;
    CleanupClosePushL(elms);
    
    if( UpnpDomInterface::GetElementListL(aObj, elms, KRes) )
    {
        for(TInt i = 0; i < elms.Count(); i++)
        {
                
            TXmlEngAttr prInfAttr = elms[i].AttributeNodeL(KprotocolInfo());
            if(prInfAttr.NotNull())
            {
                CUpnpProtocolInfoLocal* protInf = CUpnpProtocolInfoLocal::NewL(
                        UpnpDomInterface::GetAttrValueL(elms[i], KprotocolInfo) );
                CleanupStack::PushL(protInf);
                                                                                   
                /* Only support for DLNA pn-params:
                *  1) JPEG_SM
                *  2) MP3 
                *  3) AAC_ISO_320
                *  4) AVC_MP4_BL_CIF15_AAC_520
                */
                if( protInf->PnParameter() != KDLNA_PN_JPEG_SM &&
                    protInf->PnParameter() != KDLNA_PN_MP3 &&
                    protInf->PnParameter() != KDLNA_PN_AAC_ISO_320 &&
                    protInf->PnParameter() != KDLNA_PN_AVC_MP4_BL_CIF15_AAC_520                     
                  )
                {           
                    // set 4th parameter to "*"
                    protInf->SetFourthFieldL(KAsterisk8);
                    TPtrC8 prInfo = protInf->ProtocolInfoL();
                    HBufC8* prInfTmp = prInfo.Alloc();
                    CleanupStack::PushL(prInfTmp);
                    prInfAttr.SetValueL( *prInfTmp );
                    CleanupStack::PopAndDestroy(prInfTmp);
                }
                // clean up
                CleanupStack::PopAndDestroy(protInf);
            }
        }
    }
    
    // clean up
    CleanupStack::PopAndDestroy(&elms);
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateElementL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidateElementL( TXmlEngElement aElement,
                                            RArray<TXmlEngElement>& aClassList)
{
    if(aElement.Name() == KRes)
    {
        ValidateResElL(aElement, aClassList);
    }
    else
    {
        //  get pattern 
        HBufC8* name = UpnpCdUtils::GetElmNameWithNsL(aElement);
        CleanupStack::PushL(name);
        TXmlEngElement pattern = GetPatternL(*name, aClassList, KElement);
        if(pattern.NotNull())
        {
            ValidateElWithPatternL(aElement, pattern); // leaves on error
        }
        else
        { // attr is not supported - remove
            aElement.Remove();
        }
        // clean up
        CleanupStack::PopAndDestroy(name);
    }
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateMainAttributesL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidateMainAttributesL( TXmlEngElement aObj, 
                                                   RArray<TXmlEngElement>& aClassList)
{
    // list of attributes
    RXmlEngNodeList<TXmlEngAttr> attrList;
    CleanupClosePushL(attrList);
    aObj.GetAttributes(attrList);
    
    // for each attr
    while(attrList.HasNext())
    {
        // get attr
        TXmlEngAttr attr = attrList.Next();
        
        //  get pattern 
        TXmlEngElement pattern = GetPatternL(attr.Name(), aClassList, KAttribute);
        if(pattern.NotNull())
        {
            ValidateAttrWithPatternL(attr, pattern); // leaves on error
        }
        else
        { // attr is not supported - remove
            attr.Remove();
        }
    }
    CleanupStack::PopAndDestroy(&attrList);
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateElWithPatternL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidateResElL( TXmlEngElement aElement, 
                                         RArray<TXmlEngElement>& aClassList)
{
    // list of attributes
    RXmlEngNodeList<TXmlEngAttr> attrList;
    CleanupClosePushL(attrList);
    aElement.GetAttributes(attrList);
    
    // for each attr
    while(attrList.HasNext())
    {
        // get attr
        TXmlEngAttr attr = attrList.Next();
        
        //  get pattern 
        TXmlEngElement pattern = GetPatternForResAttrL(attr.Name(), aClassList);
        if(pattern.NotNull())
        {
            ValidateAttrWithPatternL(attr, pattern); // leaves on error
        }
        else
        { // attr is not supported - remove
            attr.Remove();
        }
    }
    CleanupStack::PopAndDestroy(&attrList);
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateElWithPatternL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidateElWithPatternL(   TXmlEngElement aElement, 
                                                    TXmlEngElement aPattern )
{
    // is required?
    if(IsRequiredL(aPattern) )
    { // cannot be empty
        if( !aElement.Value().Length() || 
            UpnpCdUtils::IsWhiteString( aElement.Value() ) )
        {
            User::Leave(EBadMetadata);
        }
    }
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateAttrWithPatternL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ValidateAttrWithPatternL( TXmlEngAttr aAttr, 
                                                    TXmlEngElement aPattern )
{
    // is required?
    if(IsRequiredL(aPattern) )
    { // cannot be empty
        if( !aAttr.Value().Length() || 
            UpnpCdUtils::IsWhiteString( aAttr.Value() ) )
        {
            User::Leave(EBadMetadata);
        }
    }
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateAttrWithPatternL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
TBool CUpnpElementFactory::IsRequiredL(TXmlEngElement aPattern) 
{
    TXmlEngAttr reqAttr = aPattern.AttributeNodeL(KRequiredObject());
    TBool ret = EFalse;
    if( reqAttr.NotNull() &&
        reqAttr.Value().Length() && 
        reqAttr.Value() == KTrueValue8() )
    {
        ret = ETrue;
    }
    return ret;
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::GetPatternForElL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
TXmlEngElement CUpnpElementFactory::GetPatternL( const TDesC8& aPropertyName,
                                                RArray<TXmlEngElement>& aClassList,
                                                const TDesC8& aType )
{
    TXmlEngElement retEl;
    
    // for each class
    for(TInt i = 0; i < aClassList.Count(); i++)
    {
        TXmlEngElement elPattEl;      
        UpnpDomInterface::GetDirectoryElementL(aClassList[i], elPattEl, KProperties, KType, aType);
        if(elPattEl.NotNull())
        {   
            UpnpDomInterface::GetDirectoryElementL(elPattEl, retEl, KObjectProperty, KObjectName, aPropertyName);
            
            // break if found
            if(retEl.NotNull())
            {
                break;
            }
        }
    }
    
    return retEl;
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::GetPatternForResAttrL()
// Function leaves on error.
// -----------------------------------------------------------------------------
//
TXmlEngElement CUpnpElementFactory::GetPatternForResAttrL(const TDesC8& aPropertyName,
                                                    RArray<TXmlEngElement>& aClassList )
{
    TXmlEngElement retEl;
    
    // for each class
    for(TInt i = 0; i < aClassList.Count(); i++)
    {
        TXmlEngElement resAttrPattEl;     
        UpnpDomInterface::GetDirectoryElementL(aClassList[i], resAttrPattEl, KProperties, KType, KResAttr);
        if(resAttrPattEl.NotNull())
        {   
            UpnpDomInterface::GetDirectoryElementL(resAttrPattEl, retEl, KObjectProperty, KObjectName, aPropertyName);
            
            // break if found
            if(retEl.NotNull())
            {
                break;
            }
        }
    }
    
    return retEl;
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::IsMainObjectTagL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CUpnpElementFactory::IsMainObjectTagL(TXmlEngElement aElement)
{
    TXmlEngElement notNeeded;
    return UpnpDomInterface::GetElementL(aElement, notNeeded, KClassTagName);
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ActiveElementL()
// Gets active element from XML document. An active element
// is a first element different from <DIDL-Lite> element.
// -----------------------------------------------------------------------------
//
TXmlEngElement CUpnpElementFactory::ActiveElementL( const RXmlEngDocument& aDocument )
{
    if( aDocument.IsNull() || aDocument.DocumentElement().IsNull() )
    {
        User::Leave( KErrNotFound );            
    }
        
    if ( aDocument.DocumentElement().Name().CompareF( KDidlLite() ) != 0 )
    {
        return aDocument.DocumentElement();
    }
    else
    {
        TXmlEngElement root = aDocument.DocumentElement();
        RXmlEngNodeList<TXmlEngElement> children;
        CleanupClosePushL(children);
        root.GetChildElements( children );
        children.HasNext();
        CleanupStack::PopAndDestroy(&children);
        return children.Next();
    }
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::ExtractActiveElementL()
// Extracts active element from XML document. 
// An active element is a first element different from <DIDL-Lite> element.
// IMPORTANT: Caller takes responsibility for returned element. 
// -----------------------------------------------------------------------------
//
RXmlEngDocument CUpnpElementFactory::ExtractActiveElementL( const RXmlEngDocument& aDocument )
{
    TXmlEngElement active;
    RXmlEngDocument ret;
    ret.OpenL(iDOMImpl);
    CleanupClosePushL(ret);

    if( aDocument.IsNull() || aDocument.DocumentElement().IsNull() )
    {
        User::Leave( KErrNotFound );            
    }
        
    if ( aDocument.DocumentElement().Name().CompareF( KDidlLite() ) != 0 )
    {
        active = aDocument.DocumentElement().Unlink().AsElement();
    }
    else
    {
        TXmlEngElement root = aDocument.DocumentElement();
        RXmlEngNodeList<TXmlEngElement> children;
        CleanupClosePushL(children);
        root.GetChildElements( children );
        children.HasNext();
        active = children.Next().Unlink().AsElement();
        CleanupStack::PopAndDestroy(&children);
    }
    ret.SetDocumentElement(active);
    
    CleanupStack::Pop(&ret);
    
    return ret;
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::ElementsMatchL()
// Checks if two elements are equal and have exactly the same subtrees.
// -----------------------------------------------------------------------------
//
TBool CUpnpElementFactory::ElementsMatchL( TXmlEngElement aFirst, TXmlEngElement aSecond )
{
    // this function checks following things:
    // 1. element names
    // 2. contents of the elements
    // 3. attributes of the elements
    // 4. child elements of the elements
    
    if ( aFirst.Name().Compare(aSecond.Name()) == 0 )
    {
        // aFirst names match. next: check namespace
        if ( aFirst.Prefix().Compare( aSecond.Prefix()) == 0 )
        {
            if (!aFirst.Text().Compare(aSecond.Text()))
            {
                
                // namespacess match, next: check attributes
                RXmlEngNodeList<TXmlEngAttr> elemAttrs;
                CleanupClosePushL(elemAttrs);
                RXmlEngNodeList<TXmlEngAttr> currAttrs;
                CleanupClosePushL(currAttrs);
                
                aFirst.GetAttributes( elemAttrs );
                aSecond.GetAttributes( currAttrs );
                
                if ( elemAttrs.Count() == currAttrs.Count() )
                {
                    // first step in comparing attributes ready (counts match!)
                    // next, check names and values (for each attribute)

                    while( elemAttrs.HasNext() && currAttrs.HasNext() )
                    {
                        TXmlEngAttr elemAttr = elemAttrs.Next();
                        TXmlEngAttr currAttr = currAttrs.Next();
                        
                        // compare names and values
                        if ( elemAttr.Name().Compare( currAttr.Name() ) )
                        {
                            CleanupStack::PopAndDestroy(&currAttrs);
                            CleanupStack::PopAndDestroy(&elemAttrs);
                            return EFalse;
                        }
                        if ( elemAttr.Value().Compare( currAttr.Value() ) )
                        {
                            CleanupStack::PopAndDestroy(&currAttrs);
                            CleanupStack::PopAndDestroy(&elemAttrs);
                            return EFalse;
                        }
                        
                    }
                    
                    // compare child elements (recursive function call)
                    RXmlEngNodeList<TXmlEngElement> fChildren;
                    CleanupClosePushL(fChildren);
                    RXmlEngNodeList<TXmlEngElement> sChildren;
                    CleanupClosePushL(sChildren);
                                        
                    aFirst.GetChildElements( fChildren );
                    aSecond.GetChildElements( sChildren );
                
                    
                    if ( fChildren.Count() == sChildren.Count() )
                    {
                            while ( fChildren.HasNext() && sChildren.HasNext() )
                            {
                            // call this function again for children
                                TBool matching = ElementsMatchL( fChildren.Next(), sChildren.Next() );

                            // if some of the elements do not match, return false!
                                if (matching == EFalse)
                                {
                                    CleanupStack::PopAndDestroy(&sChildren);
                                    CleanupStack::PopAndDestroy(&fChildren);
                                    CleanupStack::PopAndDestroy(&currAttrs);
                                    CleanupStack::PopAndDestroy(&elemAttrs);
                                    return EFalse;
                                }
                            }
                        // only place to return ETrue
                        // all the checks are made; if survived here, elements match!
                        CleanupStack::PopAndDestroy(&sChildren);
                        CleanupStack::PopAndDestroy(&fChildren);
                        CleanupStack::PopAndDestroy(&currAttrs);
                        CleanupStack::PopAndDestroy(&elemAttrs);
                        return ETrue;
                    }
                    CleanupStack::PopAndDestroy(&sChildren);
                    CleanupStack::PopAndDestroy(&fChildren);
                }
                CleanupStack::PopAndDestroy(&currAttrs);
                CleanupStack::PopAndDestroy(&elemAttrs);
            }
        }
    }
    
    return EFalse;
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::CountElementsL()
// Prepares corresponding RArray<TXmlEngElements> and calls 
// CountElementsL( const TDesC8& aName, RArray<TXmlEngElement>& aArray )
// -----------------------------------------------------------------------------
//
TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray<RXmlEngDocument>& aArray )
{
    TInt count(0);
        
    for(TInt i = 0; i < aArray.Count(); i++)
    {            
        if ( aArray[i].DocumentElement().NotNull() )
        {
            if ( aArray[i].DocumentElement().Name() == aName )
            {
                count++;
            }
        }
            
    }
    return count;
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::CountElementsL()
// Counts elements in array that have the same name.
// -----------------------------------------------------------------------------
//
TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray<TXmlEngElement>& aArray )
{
    TInt count(0);
    
    for (TInt v(0); v<aArray.Count(); v++)
    {
        if ( aArray[v].NotNull() )
        {
            if ( aArray[v].Name() == aName )
            {
                count++;
            }
        }
    }
    
    return count;
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::NameWithNsLC()
// Constructs descriptor with element's name and namespace prefix separated with colon.
// IMPORTANT: As the function name indicates, it leaves pointer to heap descriptor on 
// cleanup stack.
// -----------------------------------------------------------------------------
//
HBufC8* CUpnpElementFactory::NameWithNsLC(const TXmlEngElement& aElement)
{
    const TDesC8& localName = aElement.Name();
    TPtrC8 prefix = aElement.Prefix();

    if ( prefix.Length() > 0)
    {

        HBufC8* nameWithNs = HBufC8::NewLC( 
            localName.Length() + 
            UpnpString::KColon().Length() +
            prefix.Length() );

        nameWithNs->Des().Append( prefix );
        nameWithNs->Des().Append( UpnpString::KColon() );
        nameWithNs->Des().Append( localName );

        return nameWithNs;
    }
    else
    {
        return localName.AllocLC();
    }
}

void CUpnpElementFactory::CheckElementValidity (TXmlEngElement& aElement)
{
    if ( aElement.IsNull() ) 
    {
        // no <class> element! leave
        User::Leave( EBadMetadata );
    }
    
    // check that does the new element have all the required fields for its type
    // and also check that it does not have whatever fields (only optional allowed)
    
    TPtrC8 content = aElement.Text();
    if( !content.Length() )
    {
        User::Leave( EBadMetadata );
    }
}


// -----------------------------------------------------------------------------
// CUpnpElementFactory::ClassesL()
// Gets classes descriptions for given object.
// -----------------------------------------------------------------------------
//
void CUpnpElementFactory::ClassesL( const TXmlEngElement& aObject, RArray<TXmlEngElement>& aArray, const TDesC8& aObjType )
{
    TInt i(0);
    
    // if survived here, we have the new element of type item or container
    // let's analyze its type
    TXmlEngElement type;
    UpnpDomInterface::GetElementL ( aObject, type, KClass() );

    CheckElementValidity (type);
    RPointerArray<TPtrC8> objectFields;
    
    //--- removing white spaces ------------------      
    HBufC8* tempBuffer = type.Text().AllocLC(); 
    TPtr8 tmpPtr(tempBuffer->Des());
    UpnpCdUtils::RemoveWhiteSpacesL(tmpPtr);        
    CleanupStack::Check(tempBuffer);
    type.SetTextL(tmpPtr);  
    //--------------------------------------------
    
    UpnpString::CutToPiecesL(tmpPtr, TChar('.'), objectFields );    
    CleanupStack::Check(tempBuffer);
    // let's inspect each of types
    // at first, collect object type descriptions from objects xml    
    // to a pointer array
    
    TInt NumberOfObjectFields = objectFields.Count();
    
    for ( i=0; i < NumberOfObjectFields; i++ ) 
    {
        // seek for such object type
        TXmlEngElement objectDescription;

        UpnpDomInterface::GetDirectoryElementL( 
                iDocument.DocumentElement(), 
                objectDescription, 
                KElement, 
                KType, 
                *objectFields[i] );
        CleanupStack::Check(tempBuffer);
        // if such type found
        if ( objectDescription.NotNull() ) 
        {
            aArray.Append( objectDescription );
        }
        /* This case is valid for any numeric value of containerID used in CreateObject() action
        *  We do some checking starting from 3rd string of <upnp:class> element, if the string isn't
        *  recognizable, instead of leaving, we trims the value of <upnp:class> element, e.g:
        *  'object.item.imageItem.abcd' -> is trimmed into -> 'object.item.imageItem'
        *  DLNA 7.3.120.4 requirement
        */
        else if( i >= 2 )
        {            
            for( TInt j = NumberOfObjectFields - 1; j >= i; j-- )
            {                            
                TInt pos = tmpPtr.LocateReverse( TChar('.') );                    
                if( pos > KErrNotFound )
                {
                    tmpPtr.Copy( tmpPtr.Left(pos) );                   
                                                
                    delete objectFields[j];
                    objectFields.Remove(j);   
                }                    
            }                                                
            type.SetTextL(tmpPtr); // changing xml                        
            
            break;
        }
        else 
        {
            objectFields.ResetAndDestroy();
            objectFields.Close();
            User::Leave( EBadMetadata );
        }
    }
    CleanupStack::Check(tempBuffer);
    /*  for each type, check that: 
    *   1. it is referenced to its current parent type (e.g. audioItem -> item)
    *   2. this new object has all the required fields
    *   3. relations between object types and values of 'upnp:class':
    *      <item> -> 'object.item' or <container> -> 'object.container'
    */
       
    // we count the number of elements once again, because size of the array might change
    NumberOfObjectFields = objectFields.Count(); 

    for ( i=0; i < NumberOfObjectFields; i++ )
    {
        const TDesC8& field = *objectFields[i];

        // 1. first, check the parent relation 
        // first type must be "object"!
        if ( i==0 ) 
        {
            /* Leave if:
            *  1. first type isn't the 'object' OR
            *  2. 'upnp:class' contains only 'object' type [which in matter of fact isn't instantiable]
            */
            if ( field != KObject() || 
                 field == KObject() && NumberOfObjectFields == 1
            ) 
            {
                // if not "item", leave!
                objectFields.ResetAndDestroy();
                objectFields.Close();
                User::Leave( EBadMetadata );
            }
        }
        // for later types, check the relation really
        else 
        {   
            // checking relations between object types and values of 'upnp:class'
            if( i == 1 && aObjType.Length() > 0 )
            {
                if(  !field.Compare(KItem) && aObjType.Compare(KItem) ||
                     !field.Compare(KContainer) && aObjType.Compare(KContainer)
                )
                {          
                    objectFields.ResetAndDestroy();
                    objectFields.Close();                              
                    User::Leave( EBadMetadata );
                }
            }            
            //----------------------------------------    
            const TDesC8& parent = *objectFields[i-1];
            
            // if we've survived to this point, this parent string
            // should match with the one in the previous object description xml element
            TXmlEngElement iparent;
            UpnpDomInterface::GetElementL ( aArray[i], iparent, KIParent() );
            CleanupStack::Check(tempBuffer);
            TPtrC8 cont = iparent.Text();
        
            // now check the actual relation. leave if strings do not match!
            if ( cont.Length() && parent != cont )
            {
                objectFields.ResetAndDestroy();
                objectFields.Close();
                User::Leave( EBadMetadata );
            }
        }
    }
    CleanupStack::PopAndDestroy(tempBuffer);
    objectFields.ResetAndDestroy();
    objectFields.Close();
    return;
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::IsNotEmptyImportUriL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CUpnpElementFactory::IsNotEmptyImportUriL( const TXmlEngElement& aElement )
{
    TXmlEngAttr importUri;
    
    if ( aElement.Name() == KRes() )
    {
        importUri = aElement.AttributeNodeL( KImportUri8() );
        
        // remove if empty importUri: DLNA Requirement [7.3.134.5]
        TPtrC8 val( importUri.Value() );
        if( UpnpCdUtils::IsWhiteString( val ) )
        {
            importUri.Remove();
        }
    }

    return importUri.NotNull();
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::IsClassElement()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CUpnpElementFactory::IsClassElement( const TXmlEngElement& aElement )
{
    if ( aElement.Name() == KClass() )
    {
        return ETrue;
    }
    else
    {
        return EFalse;
    }
}
// -----------------------------------------------------------------------------
// CUpnpElementFactory::ValidateProtocolInfoInResL
//  Allocates string, which is object type for this object. 
// -----------------------------------------------------------------------------
HBufC8* CUpnpElementFactory::ValidateProtocolInfoInResL( const TDesC8& aProtocolInfo, TBool aLocalSharing )
{
    HBufC8* result = NULL; 
   // CUpnpDlnaProtocolInfo* protocolInfo = CUpnpDlnaProtocolInfo::NewL( (TDesC8&)aProtocolInfo );
    CUpnpProtocolInfoLocal* protocolInfo = CUpnpProtocolInfoLocal::NewL( (TDesC8&)aProtocolInfo );
    CleanupStack::PushL( protocolInfo ); 
    _LIT8(KProtocolInfoHttpGet, "http-get"); 
    protocolInfo->SetFirstFieldL( (TDesC8&)KProtocolInfoHttpGet() ); 
    protocolInfo->SetSecondFieldL( (TDesC8&)KAsterisk8() ); 
    TPtrC8 third = protocolInfo->ThirdField(); 
    if(( third.Find( KSlash8()) == KErrNotFound) && 
      ( third.Compare( KAsterisk8()) != KErrNone))
    {
        if( aLocalSharing)
        {
        User::Leave( EBadMetadata );
        }
        protocolInfo->SetThirdFieldL( (TDesC8&) KAsterisk8());                                  
    }
   // if( protocolInfo->IsDlnaInformationIncluded() ) // Check it !!!
    {
        protocolInfo->SetOpParameterL( UpnpDlnaProtocolInfo::B_VAL , ETrue );
        protocolInfo->SetOpParameterL( UpnpDlnaProtocolInfo::A_VAL , EFalse ); 
    }
    TPtrC8 prInfo = protocolInfo->ProtocolInfoL();
    result =  prInfo.Alloc();
    CleanupStack::PopAndDestroy( protocolInfo ); 
    return result; 
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::GetContentDirectoryReference
// Function gets pointer to CUpnpContentDirectory and puts it into CUpnpElementFactory object  
// -----------------------------------------------------------------------------
void CUpnpElementFactory::GetContentDirectoryReference(CUpnpContentDirectory* aCD)
{
    iContentDirectory = aCD;
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::CheckDurationOfResElement
// If res@duration attribute exists, the method checks whether it has valid format
// -----------------------------------------------------------------------------

void CUpnpElementFactory::CheckDurationOfResElementL(const TXmlEngElement& aElement)
{
    TXmlEngAttr duration;
    
    // if this is the 'res' element            
    if( aElement.Name() == KRes() )
    {
        // and it has res@duration attribute
        duration = aElement.AttributeNodeL( KDuration8() );                                        
        if( duration.NotNull() )
        {
            TCurrentAction action = iContentDirectory->ExecutedAction();                                         
            TPtrC8 val( duration.Value() );
            
            // if res@duration atrribute value is invalid [has improper format]
            if( !UpnpCdUtils::ValidateDurationValue(val) )
            {            
                // remove it from 'res' element if it is CreateObject()
                if( action == ECreateObjectAction )
                {
                    duration.Remove();
                }                
            }
        }
    }   
}

// -----------------------------------------------------------------------------
// CUpnpElementFactory::CheckSizeOfResElement
// If res@size attribute exists, the method checks whether it has valid format
// size should be unsigned int.
// -----------------------------------------------------------------------------
void CUpnpElementFactory::CheckSizeOfResElementL(
    const TXmlEngElement& aElement )
    {
    TXmlEngAttr sizeAttr;

    // if this is the 'res' element            
    if ( aElement.Name() == KRes() )
        {
        // and it has res@size attribute
        sizeAttr = aElement.AttributeNodeL( KSize() );
        if ( sizeAttr.NotNull() )
            {
            TCurrentAction action = iContentDirectory->ExecutedAction();
            TPtrC8 val( sizeAttr.Value() );

            // if res@size atrribute value is invalid [is not an unsigned long]
            TUint32 unsignedLong = 0;

            TLex8 lexULong(val);
            TInt error = lexULong.Val( unsignedLong, EDecimal );
                         
            TInt remainder = lexULong.Remainder().Length();

            if ( error != KErrNone || remainder )
                {
                // remove it from 'res' element if it is CreateObject()
                if ( action == ECreateObjectAction )
                    {
                    sizeAttr.Remove();
                    }
                }
            }
        }

    }

//  End of File