upnpsharing/upnpsharingalgorithm/src/upnpcontainerresolver.cpp
branchIOP_Improvements
changeset 40 08b5eae9f9ff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpsharing/upnpsharingalgorithm/src/upnpcontainerresolver.cpp	Wed Nov 03 11:45:09 2010 +0200
@@ -0,0 +1,819 @@
+/*
+* Copyright (c) 2009 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:  Implementation of the class CUpnpContainerResolver.
+*
+*/
+
+#include "upnpconstantdefs.h"        // upnpobject class types
+#include <utf.h>                     // for CnvUtfConverter
+#include <bautils.h>                 // for BaflUtils
+#include <pathinfo.h>                // for PathInfo
+#include <upnpitem.h>                // for CUpnpItem
+#include <upnpelement.h>             // for CUpnpElement
+#include "upnpitemutility.h"         // for CUpnpItemUtility
+#include <upnpsharingalgorithm.rsg>
+#include <mm/mmcleanup.h>            // for array cleanup
+
+#include "upnpcontainerresolver.h"
+#include "upnpsharingalgorithmconstants.h"
+#include "upnplog.h"
+#include "upnpcdsliteobject.h"
+
+const TInt KDateStringLength = 10;
+const TInt KMaxDateStringLength = 30;
+const TInt KMonthAndDayLength = 2;
+const TInt KMonthAndDayDigitLimit = 10;
+const TInt KSeparatorLength = 1;
+const TInt KDateYearLength = 4;
+const TInt KSecondSeparatorPosition = 7;
+
+_LIT( KZero, "0" );
+
+// Year, e.g. "2008"
+_LIT( KDateTimeYear,"%Y%3" );
+
+// Month, e.g. "October"
+_LIT( KDateTimeMonth,"%N%2" );
+
+// Day, e.g. "4th Mon"
+_LIT( KDateTimeDay,"%X%*D%1 %*E" );
+
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::NewL
+// --------------------------------------------------------------------------
+//
+CUpnpContainerResolver* CUpnpContainerResolver::NewL(
+    CUpnpCdsLiteObjectArray& aCdsLiteObjectArray )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::NewL" );
+
+    CUpnpContainerResolver* self =
+        new ( ELeave ) CUpnpContainerResolver( aCdsLiteObjectArray );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::ResolveContainerStructureL
+// --------------------------------------------------------------------------
+//
+RPointerArray<CUpnpContainer>
+    CUpnpContainerResolver::ResolveContainerStructureL( CUpnpItem& aItem )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+ResolveContainerStructureL" );
+
+    // List of needed containers
+    RPointerArray<CUpnpContainer> containers;
+    CleanupResetAndDestroyPushL( containers );
+
+    RPointerArray<HBufC8> containerNames;
+    CleanupResetAndDestroyPushL( containerNames );
+
+    HBufC8* itemParent = NULL;
+
+    if ( aItem.ObjectClass() == KClassAudioMusicTrack )
+        {
+        // Fill container name array, containers must be in
+        // hierarchical order staring from root
+        AppendContainerNameToArrayL( containerNames,
+                                     R_UPNP_SHARE_MUSIC_TEXT );
+        AppendContainerNameToArrayL( containerNames,
+                                     R_UPNP_SHARE_ALL_TEXT );
+
+        // Create non-existing containers
+        itemParent = CreateContainersL( containerNames,
+                                        containers,
+                                        KMusicClassContainer );
+        CleanupStack::PushL( itemParent );
+        }
+    else if ( aItem.ObjectClass() == KClassImage )
+        {
+        AppendContainerNameToArrayL( containerNames,
+                                     R_UPNP_SHARE_IMAGE_TEXT );
+        AppendContainerNameToArrayL( containerNames,
+                                     R_UPNP_SHARE_ALL_TEXT );
+
+        itemParent = CreateContainersL( containerNames,
+                                        containers,
+                                        KImageClassContainer );
+        CleanupStack::PushL( itemParent );
+        }
+    else if ( aItem.ObjectClass() == KClassVideo )
+        {
+        AppendContainerNameToArrayL( containerNames,
+                                     R_UPNP_SHARE_VIDEO_TEXT );
+        AppendContainerNameToArrayL( containerNames,
+                                     R_UPNP_SHARE_ALL_TEXT );
+
+        itemParent = CreateContainersL( containerNames,
+                                        containers,
+                                        KVideoClassContainer );
+        CleanupStack::PushL( itemParent );
+        }
+
+    // If new containers are not needed, set item parent id here,
+    // because caller does not know the item parent container
+    if ( !containers.Count() )
+        {
+        aItem.SetParentIdL( *itemParent );
+        }
+    if ( itemParent )
+        {
+        CleanupStack::PopAndDestroy( itemParent );
+        }
+
+    // Cleanup
+    CleanupStack::PopAndDestroy( &containerNames );
+    CleanupStack::Pop( &containers );
+
+    return containers;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::ResolveReferenceContainersL
+// --------------------------------------------------------------------------
+//
+RPointerArray<CUpnpContainer>
+    CUpnpContainerResolver::ResolveReferenceContainersL( TInt aType,
+                                                         CUpnpItem& aItem )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+ResolveReferenceContainersL" );
+
+    // List of needed containers
+    RPointerArray<CUpnpContainer> containers;
+    CleanupResetAndDestroyPushL( containers );
+
+    RPointerArray<HBufC8> containerNames;
+    CleanupResetAndDestroyPushL( containerNames );
+
+    HBufC8* itemParent = NULL;
+    TInt error( KErrNone );
+
+    // Get object elements from where metadata is fetched
+    const RUPnPElementsArray& elements = aItem.GetElements();
+
+    switch( aType )
+        {
+        case EGenreType :
+            {
+            // Fill container name array, containers must be in
+            // hierarchical order starting from root
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_MUSIC_TEXT );
+            // Append "By Genre" container
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_BY_GENRE_TEXT );
+
+            // Modify "Genre" element and append it to the array
+            TRAP( error, ModifyAndAppendElementL( containerNames,
+                                                  elements,
+                                                  KElementGenre ));
+
+            // If metadata is missing, containers are not created
+            if ( error == KErrNone )
+                {
+                // Create non-existing containers
+                itemParent = CreateContainersL( containerNames,
+                                                containers,
+                                                KMusicClassContainer );
+                CleanupStack::PushL( itemParent );
+                }
+            break;
+            }
+        case EAlbumType :
+            {
+            // Fill container name array, containers must be in
+            // hierarchical order staring from root
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_MUSIC_TEXT );
+            // Append "By Album" container
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_BY_ALBUM_TEXT );
+
+            // Modify "Album" element and append it to the array
+            TRAP( error, ModifyAndAppendElementL( containerNames,
+                                                  elements,
+                                                  KElementAlbum ));
+
+            // If metadata is missing, containers are not created
+            if ( error == KErrNone )
+                {
+                // Create non-existing containers
+                itemParent = CreateContainersL( containerNames,
+                                                containers,
+                                                KMusicClassContainer );
+                CleanupStack::PushL( itemParent );
+                }
+            break;
+            }
+        case EArtistType :
+            {
+            // Fill container name array, containers must be in
+            // hierarchical order staring from root
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_MUSIC_TEXT );
+            // Append "By Artist" container
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_BY_ARTIST_TEXT );
+
+            // Modify "Artist" element and append it to the array
+            TRAP( error, ModifyAndAppendElementL( containerNames,
+                                                  elements,
+                                                  KElementArtist ));
+
+            // If metadata is missing, containers are not created
+            if ( error == KErrNone )
+                {
+                // Create non-existing containers
+                itemParent = CreateContainersL( containerNames,
+                                                containers,
+                                                KMusicClassContainer );
+                CleanupStack::PushL( itemParent );
+                }
+            break;
+            }
+        case EMusicByDateType :
+            {
+            // Fill container name array, containers must be in
+            // hierarchical order staring from root
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_MUSIC_TEXT );
+            // Append "By Date" container
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_BY_DATE_TEXT );
+
+            TTime time;
+            HBufC8* elementValue = GetElementL( elements, KElementDate );
+            if ( elementValue )
+                {
+                CleanupStack::PushL( elementValue );
+                HBufC8* adjustedDate = AdjustDateL( *elementValue );
+                CleanupStack::PopAndDestroy( elementValue );
+                CleanupStack::PushL( adjustedDate );
+
+                error = UPnPItemUtility::UPnPDateAsTTime( *adjustedDate,
+                                                          time );
+
+                CleanupStack::PopAndDestroy( adjustedDate );
+
+                if ( error == KErrNone &&
+                     adjustedDate->Length() > 0 )
+                    {
+                    TBuf<KMaxDateStringLength> finalTime;
+
+                    // Append Year container
+                    time.FormatL( finalTime, KDateTimeYear );
+                    HBufC8* timeStr =
+                        CnvUtfConverter::ConvertFromUnicodeToUtf8L(
+                        finalTime );
+                    CleanupStack::PushL( timeStr );
+                    containerNames.Append( timeStr );
+                    CleanupStack::Pop( timeStr );
+
+                    // Create non-existing containers
+                    itemParent = CreateContainersL( containerNames,
+                                                    containers,
+                                                    KMusicClassContainer );
+                    CleanupStack::PushL( itemParent );
+                    }
+                }
+            else
+                {
+                error = KErrNotFound;
+                }
+
+            break;
+            }
+        case EImageByDateType :
+            {
+            // Fill container name array, containers must be in
+            // hierarchical order staring from root
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_IMAGE_TEXT );
+
+            error = AddByDateContainersL( containerNames, elements );
+
+            // If metadata is missing, containers are not created
+            if ( error == KErrNone )
+                {
+                // Create non-existing containers
+                itemParent = CreateContainersL( containerNames,
+                                                containers,
+                                                KImageClassContainer );
+                CleanupStack::PushL( itemParent );
+                }
+            break;
+            }
+        case EVideoByDateType :
+            {
+            // Fill container name array, containers must be in
+            // hierarchical order staring from root
+            AppendContainerNameToArrayL( containerNames,
+                                         R_UPNP_SHARE_VIDEO_TEXT );
+
+            error = AddByDateContainersL( containerNames, elements );
+
+            // If metadata is missing, containers are not created
+            if ( error == KErrNone )
+                {
+                // Create non-existing containers
+                itemParent = CreateContainersL( containerNames,
+                                                containers,
+                                                KVideoClassContainer );
+                CleanupStack::PushL( itemParent );
+                }
+            break;
+            }
+        default:
+            {
+            User::Leave( KErrNotSupported );
+            break;
+            }
+        }
+
+    // If new containers are not needed, set item parent id here,
+    // because caller does not know the item parent container.
+    // If metadata is not found, item is left untouched.
+    if ( !containers.Count() &&
+         error == KErrNone )
+        {
+        aItem.SetParentIdL( *itemParent );
+        }
+
+    if ( itemParent )
+        {
+        CleanupStack::PopAndDestroy( itemParent );
+        }
+
+    // Cleanup
+    CleanupStack::PopAndDestroy( &containerNames );
+    CleanupStack::Pop( &containers );
+
+    return containers;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::ResolveEmptyContainersL
+// --------------------------------------------------------------------------
+//
+RPointerArray<CUpnpCdsLiteObject>
+    CUpnpContainerResolver::ResolveEmptyContainersL( TDesC8& aContainerId )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+ResolveEmptyContainersL" );
+
+    RPointerArray<CUpnpCdsLiteObject> emptyContainers;
+    TBool empty( ETrue );
+    const TDesC8* parentId = &aContainerId;
+
+    // Search empty containers from the array
+    while ( empty &&
+            parentId->Match( KRootContainer ) == KErrNotFound )
+        {
+        TInt count = iCdsLiteObjectArray.ChildCount( aContainerId );
+        if ( iCdsLiteObjectArray.ChildCount( *parentId ) > 1 )
+            {
+            // There is more than one item inside container
+            // Current container must not be removed, exit loop
+            empty = EFalse;
+            }
+        else
+            {
+            // Get object index from CDS object array
+            TInt objectIndex =
+                iCdsLiteObjectArray.FindByObjectId( *parentId );
+
+            // Append correct container from CDS object array
+            emptyContainers.Append(
+                &iCdsLiteObjectArray.ObjectAtL( objectIndex ) );
+
+            // Get parent container id of the current container
+            parentId =
+                &iCdsLiteObjectArray.ObjectAtL( objectIndex ).ParentId();
+            }
+        }
+    return emptyContainers;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::ConstructL
+// --------------------------------------------------------------------------
+//
+void CUpnpContainerResolver::ConstructL()
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+ConstructL" );
+
+    // Open file server session
+    User::LeaveIfError( iFs.Connect() );
+
+    TFileName resourceFileName( KSharingAlgorithmRscFile );
+
+    // Get the exact filename of the resource file
+    BaflUtils::NearestLanguageFile( iFs, resourceFileName );
+
+    TInt err( KErrNone );
+    // Open resource file
+    TRAP( err, iResourceFile.OpenL( iFs, resourceFileName ) );
+
+    if ( err != KErrNone )
+        {
+        // If not found, try to read resource file from memory card
+        resourceFileName.Copy( PathInfo::MemoryCardRootPath() );
+        resourceFileName.Delete( 2, 2 ); // remove //
+        resourceFileName.Append( KSharingAlgorithmRscFile );
+        iResourceFile.OpenL( iFs, resourceFileName );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CCUpnpContainerResolver::~CUpnpContainerResolver
+// --------------------------------------------------------------------------
+//
+CUpnpContainerResolver::~CUpnpContainerResolver()
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+~CUpnpContainerResolver" );
+
+    // Close resource file
+    iResourceFile.Close();
+
+    // Close file server session
+    iFs.Close();
+    }
+
+// --------------------------------------------------------------------------
+// CCUpnpContainerResolver::CreateContainerL
+// --------------------------------------------------------------------------
+//
+CUpnpContainer* CUpnpContainerResolver::CreateContainerL(
+    const TDesC8& aTitle,
+    const TDesC8& aClass )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+CreateContainerL" );
+
+    CUpnpContainer* container = CUpnpContainer::NewL();
+    CleanupStack::PushL( container );
+
+    // Set container info
+    container->SetTitleL( aTitle );
+    container->SetObjectClassL( aClass );
+
+    CleanupStack::Pop( container );
+
+    return container;
+    }
+
+// --------------------------------------------------------------------------
+// CCUpnpContainerResolver::CreateContainersL
+// --------------------------------------------------------------------------
+//
+HBufC8* CUpnpContainerResolver::CreateContainersL(
+        RPointerArray<HBufC8>& aContainerNames,
+        RPointerArray<CUpnpContainer>& aContainers,
+        const TDesC8& aMediaClass )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+CreateContainersL" );
+
+    HBufC8* parentId = NULL;
+    TInt index( 1 );
+
+    // Find first media container, e.g. "Music"
+    TInt objectIndex ( iCdsLiteObjectArray.FindByMediaClassAndParentId(
+        aMediaClass, KRootContainer ) );
+
+    if ( objectIndex == KErrNotFound )
+        {
+        // Create media root container and append it to the container array.
+        // Parent container is root container ("0")
+        if ( aContainerNames.Count() )
+            {
+            CUpnpContainer* container = CreateContainerL(
+                                          *aContainerNames[0], aMediaClass );
+            CleanupStack::PushL( container );
+            aContainers.Append( container );
+            CleanupStack::Pop( container );
+            }
+        parentId = KRootContainer().AllocL();
+        }
+    else
+        {
+        // Remember media root container id
+        parentId = iCdsLiteObjectArray.ObjectAtL(
+                            objectIndex ).ObjectId().AllocL();
+        }
+
+    // Find the first container that does not exist
+    for ( ; index < aContainerNames.Count(); index++ )
+        {
+        // Container is found by container name and parent id.
+        // If search cannot find the container, it needs to be created.
+        objectIndex = iCdsLiteObjectArray.FindByNameAndParentId(
+            *aContainerNames[index], *parentId );
+
+        if ( objectIndex == KErrNotFound )
+            {
+            break;
+            }
+        else
+            {
+            // Remember last found container id
+            parentId = iCdsLiteObjectArray.ObjectAtL(
+                                    objectIndex ).ObjectId().AllocL();
+            }
+        }
+
+    // Create needed containers
+    for ( TInt index2( index ); index2 < aContainerNames.Count(); index2++ )
+        {
+        CUpnpContainer* container = CreateContainerL(
+                                     *aContainerNames[index2], aMediaClass );
+        CleanupStack::PushL( container );
+        aContainers.Append( container );
+        CleanupStack::Pop( container );
+        }
+
+    // Use the last found object id as parent id of the first new container
+    if ( aContainers.Count() )
+        {
+        aContainers[0]->SetParentIdL( *parentId );
+        }
+
+    return parentId;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::ReadResourceTextL
+// --------------------------------------------------------------------------
+//
+HBufC8* CUpnpContainerResolver::ReadResourceTextL( TInt aResourceId )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+ReadResourceTextL" );
+
+    // Load resource text
+    HBufC8* resourceString8 = iResourceFile.AllocReadLC( aResourceId );
+
+    TResourceReader theReader;
+    theReader.SetBuffer( resourceString8 );
+    HBufC16* resourceString16 = theReader.ReadHBufC16L();
+    CleanupStack::PushL( resourceString16 );
+
+    HBufC8* returnString8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L(
+        resourceString16->Des() );
+
+    CleanupStack::PopAndDestroy( resourceString16 );
+    CleanupStack::PopAndDestroy( resourceString8 );
+
+    return returnString8;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::GetElementL
+// --------------------------------------------------------------------------
+//
+HBufC8* CUpnpContainerResolver::GetElementL(
+        const RUPnPElementsArray& aElements,
+        const TDesC8& aElement )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+GetElementL" );
+
+    HBufC8* elementValue = NULL;
+
+    // Find the element
+    for( TInt index = 0; index < aElements.Count(); index++ )
+        {
+        if( aElements[index]->Name().Match( aElement ) == KErrNone )
+            {
+            elementValue = aElements[index]->Value().AllocL();
+            index = aElements.Count();
+            }
+        }
+
+    return elementValue;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::AdjustDateL
+// --------------------------------------------------------------------------
+//
+HBufC8* CUpnpContainerResolver::AdjustDateL( const TDesC8& aDate )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+AdjustDateL" );
+
+    HBufC* date = CnvUtfConverter::ConvertToUnicodeFromUtf8L( aDate );
+    CleanupStack::PushL( date );
+    TBuf<KMaxDateStringLength> modifiedDate;
+
+    TBuf<KMonthAndDayLength> month;
+    TBuf<KMonthAndDayLength> day;
+
+    if( aDate.Length() >= KDateStringLength )
+        {
+        // Month and day are decreased by 1, because
+        // both are started from zero in TTime::Set()
+        // Formats date e.g. 2008-10-30 --> 2008-09-29
+
+        // Add year and separator e.g. "2008-"
+        modifiedDate.Copy( date->Des().Left(
+            ( KDateYearLength + KSeparatorLength ) ) );
+
+        // Adjust month "10" --> "9"
+        month.Append( date->Des().Mid(
+            ( KDateYearLength + KSeparatorLength ),
+            KMonthAndDayLength) );
+        TLex monthLex( month );
+        TInt monthInt( 0 );
+        monthLex.Val( monthInt );
+        monthInt--;
+        TBuf<KMonthAndDayLength> adjustedMonth;
+        adjustedMonth.Num( monthInt );
+
+        // Month and day values need to contain
+        // two digits. Append extra zero, if needed,
+        // e.g. "9" --> "09"
+        if ( monthInt < KMonthAndDayDigitLimit )
+            {
+            modifiedDate.Append( KZero );
+            }
+
+        // Add modified month string
+        modifiedDate.Append( adjustedMonth );
+
+        // Add separator "-" that is between month and day
+        modifiedDate.Append( date->Des().Mid(
+            KSecondSeparatorPosition,
+            KSeparatorLength ) );
+
+        // Adjust day e.g. "30" --> "29"
+        day.Append( date->Des().Mid(
+            ( KSecondSeparatorPosition + KSeparatorLength ),
+            KMonthAndDayLength) );
+        TLex dayLex( day );
+        TInt dayInt( 0 );
+        dayLex.Val( dayInt );
+        dayInt--;
+        TBuf<KMonthAndDayLength> adjustedDay;
+        adjustedDay.Num( dayInt );
+
+        if ( dayInt < KMonthAndDayDigitLimit )
+            {
+            modifiedDate.Append( KZero );
+            }
+
+        // Add modified day string
+        modifiedDate.Append( adjustedDay );
+        }
+
+    CleanupStack::PopAndDestroy( date );
+
+    HBufC8* adjustedDate =
+        CnvUtfConverter::ConvertFromUnicodeToUtf8L( modifiedDate );
+
+    return adjustedDate;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::AddByDateContainersL
+// --------------------------------------------------------------------------
+//
+TInt CUpnpContainerResolver::AddByDateContainersL(
+                                RPointerArray<HBufC8>& aContainerNames,
+                                const RUPnPElementsArray& aElements )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+AddByDateContainersL" );
+
+    TInt metadataError( KErrNone );
+    TTime time;
+
+    // Append "By Date" container
+    aContainerNames.AppendL(
+        ReadResourceTextL( R_UPNP_SHARE_BY_DATE_TEXT ) );
+
+    HBufC8* elementValue = GetElementL( aElements, KElementDate );
+    if ( elementValue )
+        {
+        CleanupStack::PushL( elementValue );
+        // Get date element and adjust it to match TTime::Set() time
+        HBufC8* adjustedDate = AdjustDateL( *elementValue );
+        CleanupStack::PopAndDestroy( elementValue );
+        CleanupStack::PushL( adjustedDate );
+
+        if ( adjustedDate->Length() <= 0 )
+            {
+            metadataError = KErrNotFound;
+            }
+
+        // Convert date to TTime
+        TInt adjustError ( UPnPItemUtility::UPnPDateAsTTime(
+            *adjustedDate, time ) );
+
+        CleanupStack::PopAndDestroy( adjustedDate );
+
+        if ( adjustError == KErrNone &&
+             metadataError == KErrNone )
+            {
+            TBuf<KMaxDateStringLength> finalTime;
+
+            // Append Year container
+            time.FormatL( finalTime, KDateTimeYear );
+            aContainerNames.Append(
+                CnvUtfConverter::ConvertFromUnicodeToUtf8L(
+                    finalTime ) );
+
+            // Append Month container
+            time.FormatL( finalTime, KDateTimeMonth );
+            aContainerNames.Append(
+                CnvUtfConverter::ConvertFromUnicodeToUtf8L(
+                    finalTime ) );
+
+            // Append Day container
+            time.FormatL( finalTime, KDateTimeDay );
+            aContainerNames.Append(
+                CnvUtfConverter::ConvertFromUnicodeToUtf8L(
+                    finalTime ) );
+            }
+        }
+    else
+        {
+        metadataError = KErrNotFound;
+        }
+
+    return metadataError;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::ModifyAndAppendElementL
+// --------------------------------------------------------------------------
+//
+void CUpnpContainerResolver::ModifyAndAppendElementL(
+                                RPointerArray<HBufC8>& aContainerNames,
+                                const RUPnPElementsArray& aElements,
+                                const TDesC8& aElementType )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+ModifyAndAppendElementL" );
+
+    // Find correct element
+    HBufC8* elementValue = GetElementL( aElements, aElementType );
+    CleanupStack::PushL( elementValue );
+    if ( !elementValue ||
+         elementValue->Length() <= 0 )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    // Set all letters to lower case
+    elementValue->Des().LowerCase();
+
+    // Capitalize the first letter of the string
+    elementValue->Des().Capitalize();
+
+    // Append modified element value to container names array.
+    // aContainerNames array is responsible for deleteting objects in it.
+    // Transfer ownership.
+    aContainerNames.AppendL( elementValue );
+
+    CleanupStack::Pop( elementValue );
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpContainerResolver::AppendContainerNameToArrayL
+// --------------------------------------------------------------------------
+//
+void CUpnpContainerResolver::AppendContainerNameToArrayL(
+                                            RPointerArray<HBufC8>& aArray,
+                                            TInt aResourceTextId )
+    {
+    __LOG( "[CUpnpSharingAlgorithm]\t CUpnpContainerResolver::\
+AppendContainerNameToArrayL" );
+
+    HBufC8* name = ReadResourceTextL( aResourceTextId );
+    CleanupStack::PushL( name );
+    aArray.AppendL( name );
+    CleanupStack::Pop( name );
+    }
+
+// End of file