upnpframework/upnputilities/src/upnppathutility.cpp
author Sampo Huttunen <sampo.huttunen@nokia.com>
Wed, 03 Nov 2010 11:45:09 +0200
branchIOP_Improvements
changeset 40 08b5eae9f9ff
permissions -rw-r--r--
merge from Nokia's internal development branch

/*
* Copyright (c) 2002-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 class to get path related info for the media files
*/

// INCLUDE FILES
#include <bautils.h>    
#include "upnpsettingsengine.h"
#include "upnpconstantdefs.h"
#include <upnpstring.h>
#include <upnpitem.h>
#include <upnpdlnaprotocolinfo.h>
#include <pathinfo.h>

#include "upnppathutility.h"
#include "Upnpcommonutils.h"

// CONSTANTS
_LIT( KYearMonthDayFormat,        "%04d\\%02d\\%02d\\");
_LIT( KTitleExtFormat,            "%S%S");
_LIT( KArtistFormat,              "%S\\");
_LIT( KAlbumFormat,               "%S\\");
_LIT( KSlash,                     "\\");
_LIT( KSlashData,                 "\\Data\\");
_LIT( KUnknown,                   "Unknown");

_LIT( KSeparator,                   ":" );
_LIT( KNullTime,                    "000000" );

const TInt KDateStringLength        = 10;
const TInt KDateTimeStringLength    = 19;
const TInt KMaxDateStringLength     = 30;

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

// ---------------------------------------------------------------------------
// CUPnPPathUtility::CUPnPPathUtility
// C++ default constructor can NOT contain any code, that
// might leave.
// ---------------------------------------------------------------------------
//
CUPnPPathUtility::CUPnPPathUtility()
    {
    }

// ---------------------------------------------------------------------------
// CUPnPPathUtility::NewL
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
EXPORT_C CUPnPPathUtility* CUPnPPathUtility::NewL()
    {
    CUPnPPathUtility* self = CUPnPPathUtility::NewLC();
    CleanupStack::Pop();
    return self;
    }

// ---------------------------------------------------------------------------
// CUPnPPathUtility::NewLC
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
EXPORT_C CUPnPPathUtility* CUPnPPathUtility::NewLC()
    {
    CUPnPPathUtility* self = new( ELeave ) CUPnPPathUtility;
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// CUPnPPathUtility::ConstructL
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------------------------
//
void CUPnPPathUtility::ConstructL()
    {
    iSettingsEngine = CUPnPSettingsEngine::NewL();
    }
    
// ---------------------------------------------------------------------------
// CUPnPPathUtility::~CUPnPPathUtility()
// Destructor
// ---------------------------------------------------------------------------
//
EXPORT_C CUPnPPathUtility::~CUPnPPathUtility()
    {
    delete iSettingsEngine;
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::GetCopyPathDriveL
// Gets the drive for the copy operation
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
EXPORT_C void CUPnPPathUtility::GetCopyPathDriveL( 
             TDriveNumber& aDrive ) const
    {
    iSettingsEngine->GetCopyLocationDriveL( aDrive );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::GetCopyPathL
// Returns the path of the upnp item to be copied
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
EXPORT_C HBufC* CUPnPPathUtility::GetCopyPathL(
               const CUpnpItem& aItem,
               const CUpnpElement& aResource,
               TBool aAppendTitleAndExt ) const
    {
    TDriveNumber drive;
    iSettingsEngine->GetCopyLocationDriveL( drive );   
    return GetCreateCopyPathL( aItem, 
                               aResource, 
                               aAppendTitleAndExt,
                               EFalse,
                               drive );
    }   

// --------------------------------------------------------------------------
// CUPnPPathUtility::GetCopyPathL
// Returns the path of the upnp item to be copied
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
EXPORT_C HBufC* CUPnPPathUtility::GetCopyPathL(
               const CUpnpItem& aItem,
               const CUpnpElement& aResource,
               TBool aAppendTitleAndExt,
               TDriveNumber aDriveNumber ) const
    {
    
    return GetCreateCopyPathL( aItem, 
                               aResource, 
                               aAppendTitleAndExt,
                               EFalse,
                               aDriveNumber );
    }   

// --------------------------------------------------------------------------
// CUPnPPathUtility::CreateCopyPathL
// Returns the path of the upnp item to be copied
// Creates the path if necessary and appends the filename and extension if
// required
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
EXPORT_C HBufC* CUPnPPathUtility::CreateCopyPathL(
               const CUpnpItem& aItem,
               const CUpnpElement& aResource,
               TBool aAppendTitleAndExt ) const
    {
    TDriveNumber drive;
    iSettingsEngine->GetCopyLocationDriveL( drive );
    return GetCreateCopyPathL( aItem, 
                               aResource, 
                               aAppendTitleAndExt,
                               ETrue,
                               drive );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::CreateCopyPathL
// Returns the path of the upnp item to be copied
// Creates the path if necessary and appends the filename and extension if
// required
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
EXPORT_C HBufC* CUPnPPathUtility::CreateCopyPathL(
               const CUpnpItem& aItem,
               const CUpnpElement& aResource,
               TBool aAppendTitleAndExt,
               TDriveNumber aDriveNumber ) const
    {
    return GetCreateCopyPathL( aItem, 
                               aResource, 
                               aAppendTitleAndExt,
                               ETrue,
                               aDriveNumber );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::RemoveEmptyFoldersFromCopyPathL
// Removes empty folders from the copy path 
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
EXPORT_C void CUPnPPathUtility::RemoveEmptyFoldersFromCopyPathL(
                            const TDesC& aCopyPath )
    {  
    TPtrC basePath;
    const TDesC& soundsPath = PathInfo::SoundsPath();
    const TDesC& videosPath = PathInfo::VideosPath();
    const TDesC& imagesPath = PathInfo::ImagesPath();
    const TDesC& othersPath = PathInfo::OthersPath();
    
    TInt baseLength = 0;
    TInt found = KErrNotFound;    
    if ( KErrNotFound != ( found = aCopyPath.Find( 
                                     soundsPath ) ) )
        {
        baseLength = soundsPath.Length();
        }
    else if ( KErrNotFound != ( found = aCopyPath.Find( 
                                    videosPath ) ) )
        {
        baseLength = videosPath.Length();
        }
    else if ( KErrNotFound != ( found = aCopyPath.Find( 
                                    imagesPath ) ) )
        {
        baseLength = imagesPath.Length();
        }
    else if ( KErrNotFound != ( found = aCopyPath.Find( 
                                    othersPath ) ) )
        {
        baseLength = othersPath.Length();
        }

    if ( KErrNotFound != found )
        {
        TPtrC basePath = aCopyPath.Left( found + baseLength );
        TParse parsePath;
        User::LeaveIfError( parsePath.Set( aCopyPath, NULL, NULL ) );
        //Remove filename and extension before passing the copy path
        RemoveEmptyFoldersL( basePath, parsePath.DriveAndPath() );
        }
    
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::GetCreateCopyPathL
// Returns the path of the upnp item to be copied
// Creates the path if necessary and appends the filename and extension if
// required
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
HBufC* CUPnPPathUtility::GetCreateCopyPathL(
               const CUpnpItem& aItem,
               const CUpnpElement& aResource,
               TBool aAppendTitleAndExt,
               TBool aCreatePath,
               TDriveNumber aDriveNumber ) const
    {
       
    HBufC* path = HBufC::NewLC( KMaxPath );
    TPtr refPath = path->Des();
    
    TDriveUnit driveUnit = TDriveUnit( aDriveNumber );
    AppendDataL( refPath, driveUnit.Name() );
    if ( EDriveC == driveUnit )
        {
        //C:\\Data\\(Images/Videos/Sounds)....
        AppendDataL( refPath, KSlashData );
        }
    else
        {
        //\\(Images/Videos/Sounds)....
        AppendDataL( refPath, KSlash );
        }
    
    // Get the protocolinfo-attribute
    const CUpnpAttribute* pInfo = FindAttributeByName(
            aResource, KAttributeProtocolInfo );
    if ( NULL == pInfo )
        {
        User::Leave( KErrArgument );
        }
    
    CUpnpDlnaProtocolInfo* dlnaInfo =
            CUpnpDlnaProtocolInfo::NewL( pInfo->Value() );
    CleanupStack::PushL( dlnaInfo );
    TUPnPItemType fileType = UPnPCommonUtils::FileTypeByMimeTypeL( 
            dlnaInfo->ThirdField() );
    
    switch( fileType )
        {
        case ETypeAudio:
            {
            AppendDataL( refPath, PathInfo::SoundsPath() );
            AppendArtistAlbumL( refPath, aItem );
            break;
            }
        case ETypeVideo:
            {
            AppendDataL( refPath, PathInfo::VideosPath() );
            AppendYearMonthDayL( refPath, aItem );
            break;
            }
        case ETypeImage:
            {
            AppendDataL( refPath, PathInfo::ImagesPath() );
            AppendYearMonthDayL( refPath, aItem );
            break;
            }
        case ETypePlaylist:
        case ETypeOther:
        default:
            {
            AppendDataL( refPath, PathInfo::OthersPath() );
            }                
        }
    if( aCreatePath )
        {
        RFs fs;
        User::LeaveIfError( fs.Connect() );
        CleanupClosePushL(fs);
        BaflUtils::EnsurePathExistsL( fs, refPath );
        CleanupStack::PopAndDestroy(&fs);
        }
    if( aAppendTitleAndExt )
        {
        AppendTitleAndExtL( refPath, *dlnaInfo, aItem );
        }
    
    CleanupStack::PopAndDestroy( dlnaInfo );
    CleanupStack::Pop( path );
    
    return path;
    }   

// --------------------------------------------------------------------------
// CUPnPPathUtility::AppendTitleAndExtL
// Appends title and extension to the path.
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::AppendTitleAndExtL( 
             TDes& aPath, CUpnpDlnaProtocolInfo& aProtocolInfo, 
             const CUpnpItem& aItem ) const
    {
    HBufC* fileExt = UPnPCommonUtils::FileExtensionByMimeTypeL(
            aProtocolInfo.ThirdField() );
    
    User::LeaveIfNull( fileExt );
    CleanupStack::PushL( fileExt );
    
    HBufC* title16 = UpnpString::ToUnicodeL( aItem.Title() );
    CleanupStack::PushL( title16 );
    HBufC* title16checked =
        UPnPCommonUtils::ReplaceIllegalFilenameCharactersL( *title16 );
    CleanupStack::PopAndDestroy( title16 );
    
    CheckBufferSpaceL( aPath, 
            title16checked->Length()+fileExt->Length() );
    
    aPath.AppendFormat( KTitleExtFormat(), title16checked, fileExt );
    
    delete title16checked; title16checked = NULL;
    CleanupStack::PopAndDestroy( fileExt );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::AppendYearMonthDayL
// Appends year, month and day to the path.
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::AppendYearMonthDayL( 
        TDes& aPath, const CUpnpItem& aItem ) const
    {  
    // Get the date-element
    const CUpnpElement* dateElem = FindElementByName(
            aItem, KElementDate );

    TTime date; date.HomeTime();
    TInt offsetMonthDay = 1;
    // Use date element time instead of current time,
    // if element exist
    if ( dateElem != NULL )
        {
        UPnPDateAsTTimeL( dateElem->Value(), date );
        offsetMonthDay = 0;
        }
    TDateTime ymd = date.DateTime();
    CheckBufferSpaceL( aPath, 11 ); //4(year)+2(month)+2(day)+3(\)
        
    aPath.AppendFormat( KYearMonthDayFormat(), 
            ymd.Year(), 
            ymd.Month() + offsetMonthDay, 
            ymd.Day() + offsetMonthDay );
    
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::AppendArtistAlbumL
// Appends artist and album to the path.
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::AppendArtistAlbumL( 
        TDes& aPath, const CUpnpItem& aItem ) const
    {
    
    // Get the artist-element
    const CUpnpElement* artistElem = FindElementByName(
                aItem, KElementArtist );
    if ( NULL != artistElem )
        {
        HBufC* artist = UpnpString::ToUnicodeL( artistElem->Value() );
        CleanupStack::PushL( artist );
        
        HBufC* artistchecked =
            UPnPCommonUtils::ReplaceIllegalDirNameCharactersL( *artist );
        CleanupStack::PopAndDestroy( artist );
        
        CheckBufferSpaceL( aPath, artistchecked->Length()+1 );// 1 for '\'          
        aPath.AppendFormat( KArtistFormat(), artistchecked );
        
        delete artistchecked;
        }
    else
        {
        CheckBufferSpaceL( aPath, KUnknown().Length()+1 );  // 1 for '\'       
        aPath.AppendFormat( KArtistFormat(), &KUnknown() );
        }
    
    // Get the album-element
    const CUpnpElement* albumElem = FindElementByName(
                aItem, KElementAlbum );
    if ( NULL != albumElem )
        {
        HBufC* album = UpnpString::ToUnicodeL( albumElem->Value() );
        CleanupStack::PushL( album );
        
        HBufC* albumchecked =
            UPnPCommonUtils::ReplaceIllegalDirNameCharactersL( *album );
        CleanupStack::PopAndDestroy( album );
        
        CheckBufferSpaceL( aPath, albumchecked->Length()+1 );// 1 for '\'
        aPath.AppendFormat( KAlbumFormat(), albumchecked );
        
        delete albumchecked;
        }
    else
        {
        CheckBufferSpaceL( aPath, KUnknown().Length()+1 );  // 1 for '\'       
        aPath.AppendFormat( KAlbumFormat(), &KUnknown() );
        }
    
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::AppendDataL
// Appends data to the path's buffer.
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::AppendDataL( 
        TDes& aPath, const TDesC& aData ) const
    {  
    CheckBufferSpaceL( aPath, aData );
    aPath.Append( aData );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::CheckBufferSpaceL
// Checks whether the data can be appended to buffer or not.
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::CheckBufferSpaceL( 
        const TDes& aPath, const TDesC& aData ) const
    {
    CheckBufferSpaceL( aPath, aData.Length() );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::CheckBufferSpaceL
// Checks whether the data of the specified length
// can be appended to buffer or not.
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::CheckBufferSpaceL( 
        const TDes& aPath, const TInt& aLength ) const
    {  
    if ( (aPath.Length() + aLength) > aPath.MaxLength() )
        {
        User::Leave( KErrOverflow );
        }
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::FindElementByName
// Finds an element within an object.
//---------------------------------------------------------------------------
const CUpnpElement* CUPnPPathUtility::FindElementByName(
    const CUpnpObject& aObject, const TDesC8& aName ) const
    {
    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;
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::FindAttributeByName
// Finds an attribute within an element.
//---------------------------------------------------------------------------
const CUpnpAttribute* CUPnPPathUtility::FindAttributeByName(
    const CUpnpElement& aElement, const TDesC8& aName ) const
    {
    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;
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::UPnPDateAsTTimeL
// Converts upnp date to TTime object.
//---------------------------------------------------------------------------
void CUPnPPathUtility::UPnPDateAsTTimeL( const TDesC8& aUpnpDate,
    TTime& aTime ) const
    {
    // 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 ) );
    }

// --------------------------------------------------------------------------
// CUPnPPathUtility::RemoveEmptyFoldersL
// Removes empty folders from the  path 
// (other items were commented in a header).
// --------------------------------------------------------------------------
//
void CUPnPPathUtility::RemoveEmptyFoldersL(
        const TDesC& aBasePath, const TDesC& aFullPath )
    {
        
    RFs fs;
    User::LeaveIfError( fs.Connect() );
    CleanupClosePushL(fs);
    
    TParse parsePath;
    User::LeaveIfError( parsePath.Set( aFullPath, NULL, NULL ) );
    while( 0 != aBasePath.Compare( parsePath.DriveAndPath() ) )
        {
        if ( KErrNone != fs.RmDir( parsePath.DriveAndPath() ) ||
             KErrNone != parsePath.PopDir() )
            {
            break;
            }
        }
    CleanupStack::PopAndDestroy(&fs);
     
    }

//  End of File