upnpavcontroller/upnpavcontrollerhelper/src/upnpitemutility.cpp
author Sampo Huttunen <sampo.huttunen@nokia.com>
Thu, 18 Nov 2010 15:46:57 +0200
branchIOP_Improvements
changeset 44 97caed2372ca
parent 38 5360b7ddc251
permissions -rw-r--r--
Fixed AVController, it was accidentally set to search only for renderers. Now also servers are added to device list. Also some minor changes in package definition xml and platform API xml definition files.

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:      Utility for parsing upnp items
*
*/






// INCLUDE FILES
// System
#include <e32std.h>

// dlnasrv / mediaserver api
#include <upnpitem.h>
#include <upnpdlnaprotocolinfo.h>

// dlnasrv / avcontroller helper api
#include "upnpconstantdefs.h" // for KValueNotImplemented
#include "upnpitemutility.h"

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

// CONSTANTS
const TInt KDateStringLength        = 10;
const TInt KDateTimeStringLength    = 19;
const TInt KMaxDateStringLength     = 30;
const TInt KCodeSemicolon           = 58;
_LIT( KSeparator,                   ":" );
_LIT( KNullTime,                    "000000" );
_LIT8( KHttp,                       "http://" );
_LIT8( KCiParam,                    "DLNA.ORG_CI" );

/* removed due to M-DMC CTT test case 7.3.26.2
_LIT8( KAudioSupport,               "audio/" );
_LIT8( KImageSupport,               "image/" );
_LIT8( KVideoSupport,               "video/" );
*/

// ============================ LOCAL FUNCTIONS =============================

// --------------------------------------------------------------------------
// UPnPItemUtility::BelongsToClass
//---------------------------------------------------------------------------
EXPORT_C TBool UPnPItemUtility::BelongsToClass(
    const CUpnpObject& aObject,
    const TDesC8& aClass )
    {
    TBool beginsWith = 
        ( aObject.ObjectClass().Find( aClass ) == 0 );
    return beginsWith;
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::GetResElements
//---------------------------------------------------------------------------
EXPORT_C void UPnPItemUtility::GetResElements(
    const CUpnpObject& aObject,
    RUPnPElementsArray& aResElementsArray )
    {
    const RUPnPElementsArray& array =
        const_cast<CUpnpObject&>(aObject).GetElements();
    
    for( TInt i = 0; i < array.Count(); i++ )
        {
        if( array[ i ]->Name() == KElementRes() )
            {
            aResElementsArray.Append( array[ i ] );
            }
        }    
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::ResourceFromItemL
//---------------------------------------------------------------------------
EXPORT_C const CUpnpElement& UPnPItemUtility::ResourceFromItemL(
    const CUpnpItem& aItem )
    {
    __LOG( "UpnpItemUtility:ResourceFromItemL" );

    // Obtain list of item's res elements   
    RUPnPElementsArray elms;
    GetResElements( aItem, elms );
    TInt count = elms.Count();

    CUpnpDlnaProtocolInfo* pInfo = NULL;
    TBool found = EFalse;
    TInt i(0);
    // bestCandidate is an index of some res element in the list. This res
    // will be considered as the best candidate for desired res and that
    // candidate will be returned if no res element contains false CI-flag.

    const CUpnpElement* bestCandidate = 0;

    // determine which resource is the original one
    // 1. In DLNA 1.5 case, parse protocolInfo attribute and see if some res 
    //    element has CI-flag false (=not converted so that is what we want)
    // 2. In non-DLNA 1.5 case and in DLNA 1.5 case where CI-flag does not 
    //    exist, do the following:
    //      o filter out other than HTTP GET resources (internal uri's, RTP)
    //      o filter out resources that do not match itemtype (mime type of 
    //        audio file resources should start with "audio/" etc.)
    for( i = 0 ; i < count; i++ )
        {
        // Make sure that it is a HTTP GET resource. Otherwise continue.
        if( elms[ i ]->Value().Left( KHttp.iTypeLength ).Compare( KHttp() ) 
            != 0 )
            {
            continue;
            }

        // Obtain protocolInfo of the res element.
        const CUpnpAttribute* attr = FindAttributeByName(
            *elms[i], KAttributeProtocolInfo() );
        if ( attr ) 
            {           
            TRAP_IGNORE( pInfo = CUpnpDlnaProtocolInfo::NewL( attr->Value() ) );
            if( !pInfo )
                {
                //if pInfo, start next one!
                continue;
                }
            // check if CI parameter is false or it doesn't have CI parameters at all.
            //for upnp item, always the first res element is the best, resolution
            // should be checked in the future
            if ( ( attr->Value().Find( KCiParam() ) != KErrNotFound && 
                 pInfo->CiParameter() == EFalse ) || 
                 attr->Value().Find( KCiParam() ) == KErrNotFound )
                {
                // end loop, we found what we were looking for. 
                found = ETrue;
                delete pInfo; pInfo = NULL;
                break;                
                }

/* removed due to M-DMC CTT test case 7.3.26.2            
            // check that mimetype corresponds to objectType
            TPtrC8 mime = pInfo->ThirdField();
            
            TPtrC8 objectClass = aItem.ObjectClass();
            if ( objectClass.Compare( KClassAudio ) == 0 ) 
                {
                if ( mime.Left( KAudioSupport().Length() ).CompareF( 
                                                    KAudioSupport() ) != 0 ) 
                    {
                    // if mime type does not match to object type, this is 
                    // not the correct resource.
                    delete pInfo; pInfo = NULL;
                    continue;
                    }
                }
            else if ( objectClass.Compare( KClassVideo ) == 0 ) 
                {
                if ( mime.Left( KVideoSupport().Length() ).CompareF( 
                                                    KVideoSupport() ) != 0 ) 
                    {
                    // if mime type does not match to object type, this is 
                    // not the correct resource.
                    delete pInfo; pInfo = NULL;
                    continue;
                    }
                }
            else if ( objectClass.Compare( KClassImage ) == 0 ) 
                {
                if ( mime.Left( KImageSupport().Length() ).CompareF( 
                                                    KImageSupport() ) != 0 ) 
                    {
                    // if mime type does not match to object type, this is 
                    // not the correct resource.
                    delete pInfo; pInfo = NULL;
                    continue;
                    }
                }
 */
            // use the first suitable res field as candidate which will be
            // returned if better is not found.
            // More sophisticated solution would be to compare resolution
            // etc. attributes to determine the best candidate,
            if ( 0 == bestCandidate ) 
                {
                bestCandidate = elms[i];
                }
            delete pInfo; pInfo = NULL;
            }
        else 
            {
            // No mandatory protocolinfo attribute. This is not what we want.
            }
        }
    if ( found ) 
        {
        bestCandidate = elms[i];
        }

    // close the elements array
    elms.Close();

    if( bestCandidate == 0 )
        {
        User::Leave( KErrNotFound );
        }
    return *bestCandidate;
    }


// --------------------------------------------------------------------------
// UPnPItemUtility::FindElementByName
//---------------------------------------------------------------------------
EXPORT_C const CUpnpElement* UPnPItemUtility::FindElementByName(
    const CUpnpObject& aObject, const TDesC8& aName )
    {
    __LOG( "UpnpItemUtility:FindElementByName" );

    CUpnpElement* element = NULL;
    const RUPnPElementsArray& array =
        const_cast<CUpnpObject&>(aObject).GetElements();
    for( TInt i = 0; i < array.Count(); i++ )
        {
        if( array[ i ]->Name() == aName )
            {
            element = array[ i ];
            i = array.Count();
            }
        }
    return element;
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::FindElementByNameL
//---------------------------------------------------------------------------
EXPORT_C const CUpnpElement& UPnPItemUtility::FindElementByNameL(
    const CUpnpObject& aObject, const TDesC8& aName )
    {
    __LOG( "UpnpItemUtility:FindElementByNameL" );

    const CUpnpElement* element = FindElementByName(
        aObject, aName );
    if( !element )
        {
        User::Leave( KErrNotFound );
        }
    return *element;    
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::FindAttributeByName
//---------------------------------------------------------------------------
EXPORT_C const CUpnpAttribute* UPnPItemUtility::FindAttributeByName(
    const CUpnpElement& aElement, const TDesC8& aName )
    {
    __LOG( "UpnpItemUtility:FindAttributeByName" );

    CUpnpAttribute* attribute = NULL;
    const RUPnPAttributesArray& array =
        const_cast<CUpnpElement&>(aElement).GetAttributes();
    
    for( TInt i = 0; i < array.Count(); i++ )
        {
        
        TBufC8<255> buf(array[ i ]->Name());
        if( array[ i ]->Name() == aName )
            {
            attribute = array[ i ];
            i = array.Count();
            }
        }
    return attribute;
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::FindAttributeByNameL
//---------------------------------------------------------------------------
EXPORT_C const CUpnpAttribute& UPnPItemUtility::FindAttributeByNameL(
    const CUpnpElement& aElement, const TDesC8& aName )
    {
    __LOG( "UpnpItemUtility:FindAttributeByNameL" );

    const CUpnpAttribute* attribute = FindAttributeByName(
        aElement, aName );
    if( !attribute )
        {
        User::Leave( KErrNotFound );
        }
    return *attribute;        
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::UpnpDateAsTTime
//---------------------------------------------------------------------------
EXPORT_C TInt UPnPItemUtility::UPnPDateAsTTime(
    const TDesC8& aUpnpDate, TTime& aTime )
    {
    __LOG( "UpnpItemUtility:UpnpDateAsTTime" );

    TRAPD( err, UPnPItemUtility::UPnPDateAsTTimeL( aUpnpDate, aTime ) );
    return err;
    }

// --------------------------------------------------------------------------
// UPnPItemUtility::UpnpDurationAsMilliseconds
//---------------------------------------------------------------------------
EXPORT_C TInt UPnPItemUtility::UPnPDurationAsMilliseconds(
    const TDesC8& aDuration, TInt& aMilliseconds )
    {
    __LOG( "UpnpItemUtility:UpnpDurationAsMilliseconds" );

    TInt retVal = KErrNone;    
    if( aDuration.Length() > 0 )
        {
        // Check if information is actually returned by the device
        if( aDuration.Compare( KValueNotImplemented ) != 0 )
            {        
            TInt time = 0;
            TChar separator( KCodeSemicolon );
            TInt lposit = aDuration.Locate( separator );
            
            if ( lposit != KErrNotFound )
                {
                TInt rposit = aDuration.LocateReverse( separator );
                if( rposit != lposit )
                    {
                    // Hours
                    TLex8 lex( aDuration.Left( lposit ) );
                    retVal = lex.Val( time ); 
                    if( retVal == KErrNone  )
                        {
                        // Convert to ms and add
                        aMilliseconds += time * 3600 * 1000;
                        // Minutes
                        lex.Assign( aDuration.Mid(
                            lposit + 1, rposit - lposit - 1 ) );
                        retVal = lex.Val( time ); 
                        if( retVal == KErrNone )
                            {
                            // Convert to ms and add
                            aMilliseconds += time * 60* 1000;
                            // Seconds
                            lex.Assign( aDuration.Mid(
                                rposit + 1, 2 ) );
                            retVal = lex.Val( time ); 
                            if( retVal  == KErrNone )
                                {
                                // Convert to ms and add
                                aMilliseconds += time * 1000;
                                }
                            }
                        }
                    }
                else
                    {
                    retVal = KErrNotSupported;
                    }        
                }
            else
                {
                retVal = KErrNotSupported;
                }   
            }  
        else
            {
            retVal = KErrNotSupported;
            }
        }
    else
        {
        retVal = KErrNotSupported;
        }
        
    return retVal;
    }

void UPnPItemUtility::UPnPDateAsTTimeL( const TDesC8& aUpnpDate,
    TTime& aTime )
    {
    // This method is capable of handling the most common dc:date formats:
    // CCYY-MM-DD and CCYY-MM-DDThh:mm:ss
    // Rest of the dc:date formats are handled as well, but they might not
    // be converted precisely
    
    TBuf<KMaxDateStringLength> formatDateString;
    HBufC* dateString = HBufC::NewL( aUpnpDate.Length() );
    dateString->Des().Copy( aUpnpDate );

    if( aUpnpDate.Length() >= KDateStringLength )
        {
        // CCYY-MM-DD --> CCYYMMDD
        formatDateString.Copy( dateString->Des().Left( 4 ) ); // Year
        formatDateString.Append( dateString->Des().Mid( 5,2 ) ); // Month
        formatDateString.Append( dateString->Des().Mid( 8,2 ) ); // Day        

        if( aUpnpDate.Length() >= KDateTimeStringLength )
            {
            // hh:mm:ss --> hhmmss
            formatDateString.Append( KSeparator );
            // Hours
            formatDateString.Append( dateString->Des().Mid( 11, 2 ) ); 
            // Minutes
            formatDateString.Append( dateString->Des().Mid( 14, 2 ) );
            // Seconds 
            formatDateString.Append( dateString->Des().Mid( 17, 2 ) ); 
            }
        else
            {
            // hh:mm:ss --> 000000
            formatDateString.Append( KSeparator );
            formatDateString.Append( KNullTime );
            }
        }
    delete dateString;
    
    User::LeaveIfError( aTime.Set( formatDateString ) );
    }