Updated the SIS package, there was some BC issue with the earlier version. Also updated the platform UID to S^3 version.
/*
* 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 CUpnpSharingAlgorithmImpl.
*
*/
// INCLUDE FILES, SYSTEM
#include <upnpdlnaprofiler.h>
#include <upnpitem.h>
#include "upnpcommonutils.h"
#include "upnpmetadatafetcher.h"
#include "upnpfileutility.h"
#include <escapeutils.h> // ConvertFromUnicodeToUtf8L
#include <bautils.h> // File existence check
#include "upnpconstantdefs.h"
#include <mm/mmcleanup.h> // for array cleanup
// INCLUDE FILES, USER
#include "upnpcontainerresolver.h"
#include "upnpsharingao.h"
#include "upnpcdsreaderao.h"
#include "upnpsharingalgorithmimpl.h"
#include "upnpsharingalgorithmconstants.h"
#include "upnplog.h"
#include "upnpcdsliteobject.h"
#include "upnpcdsliteobjectarray.h"
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithm::NewL
// --------------------------------------------------------------------------
//
CUpnpSharingAlgorithmImpl* CUpnpSharingAlgorithmImpl::NewL()
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::NewL" );
CUpnpSharingAlgorithmImpl* self = CUpnpSharingAlgorithmImpl::NewLC();
CleanupStack::Pop( self );
return self;
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::NewLC
// Two-phased constructor
// --------------------------------------------------------------------------
//
CUpnpSharingAlgorithmImpl* CUpnpSharingAlgorithmImpl::NewLC()
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::NewLC" );
CUpnpSharingAlgorithmImpl* self =
new ( ELeave ) CUpnpSharingAlgorithmImpl();
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::~CUpnpSharingAlgorithmImpl
// --------------------------------------------------------------------------
//
CUpnpSharingAlgorithmImpl::~CUpnpSharingAlgorithmImpl()
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::\
~CUpnpSharingAlgorithmImpl" );
delete iContainerResolver;
delete iSharingAO;
delete iSharedContentArray;
iMediaServer.Close();
}
// --------------------------------------------------------------------------
// CCUpnpSharingAlgorithmImpl::ConstructL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::ConstructL()
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::\
ConstructL" );
// connect to server
User::LeaveIfError( iMediaServer.Connect() );
// Start server if not yet started
StartServer();
// An array to list all the shared files on the CDS
iSharedContentArray = CUpnpCdsLiteObjectArray::NewL();
// container structure resolver
// contentarray is always up-to-date
iContainerResolver =
CUpnpContainerResolver::NewL( *iSharedContentArray );
CUpnpCdsReaderAO* cdsReader =
CUpnpCdsReaderAO::NewL( *iSharedContentArray );
CleanupStack::PushL( cdsReader );
cdsReader->ReadCdsStructureL();
CleanupStack::PopAndDestroy( cdsReader );
// Active object for sharing and unsharing the items
iSharingAO = CUpnpSharingAO::NewL();
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::ShareFileL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::ShareFileL(
const TFileName & aFileName )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
ShareFileL" );
// Check that file exists. Leaves with KErrArgument if not exist.
CheckFileExistenceL( aFileName );
// Check that file is not protected. Leaves with KAccessDenied if yes.
CheckFileProtectionL( aFileName );
if ( !IsFileSharedL( aFileName ) )
{
// Start server if not yet started
StartServer();
// create upnpitem...
CUpnpItem* upnpItem =
UPnPMetadataFetcher::CreateItemFromFileLC( aFileName );
// Resolve container structure
RPointerArray<CUpnpContainer> containerArray =
iContainerResolver->ResolveContainerStructureL( *upnpItem );
CleanupResetAndDestroyPushL( containerArray );
if ( containerArray.Count() )
{
// Share containers
ShareContainersL( containerArray );
// parent container id for item is the last shared container id
TPtrC8 itemParentContainerId =
containerArray[ containerArray.Count()-1 ]->Id();
// ... and share it
iSharingAO->ShareFileL( itemParentContainerId, upnpItem );
// Add the file to the shared content array
iSharedContentArray->AppendL( upnpItem );
}
else
{
// All containers exists already.
// Resolver put parentid to item
iSharingAO->ShareFileL( upnpItem->ParentId(), upnpItem );
// Add the file to the shared content array
iSharedContentArray->AppendL( upnpItem );
}
// SHARE reference containers and items
ShareReferenceObjectsL( upnpItem );
// Cleanup
CleanupStack::PopAndDestroy( &containerArray );
CleanupStack::PopAndDestroy( upnpItem );
}
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::UnshareFileL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::UnshareFileL(
const TFileName& aFileName )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::UnshareFileL" );
// Convert the filename to 8bit
HBufC8* filename = EscapeUtils::ConvertFromUnicodeToUtf8L( aFileName );
CleanupStack::PushL( filename );
// Search the array for the item
TInt arrayindex = iSharedContentArray->FindByName( *filename );
// Continue only if the file was found
if ( arrayindex >= 0 )
{
// Start server if not yet started
StartServer();
// Get the object reference
CUpnpCdsLiteObject& object =
iSharedContentArray->ObjectAtL( arrayindex );
// unshare references first
UnshareReferenceObjectsL( object );
// Checks the container tree and unshares if needed
// First container id to be checked is item's parentid
TBool containerUnshared =
UnshareEmptyContainersL( object.ParentId() );
// if container is not unshared the item needs to be unshared
if ( !containerUnshared )
{
// Leave if ObjectId not found
if( object.ObjectId() == KNullDesC8 )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
UnshareFileL, ObjectId not found!" );
User::Leave( KErrCorrupt );
}
TInt objectIdInt( KErrNotFound );
User::LeaveIfError(
objectIdInt = UPnPCommonUtils::DesC8ToInt( object.ObjectId() ));
// Unshare the item
iSharingAO->UnshareFileL( objectIdInt );
// index must be retrieved again because reference item removal
// changes indexes
arrayindex =
iSharedContentArray->FindByObjectId(object.ObjectId());
// Remove the file from the shared content array
iSharedContentArray->RemoveObjectAtL( arrayindex );
}
else
{
// index must be retrieved again because removal of containers
// change indexes
arrayindex = iSharedContentArray->FindByName( *filename );
// item was also unshared when container was unshared
// it's enough to remove item from contentarray
iSharedContentArray->RemoveObjectAtL( arrayindex );
}
}
// Cleanup
CleanupStack::PopAndDestroy( filename );
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::IsFileSharedL
// --------------------------------------------------------------------------
//
TBool CUpnpSharingAlgorithmImpl::IsFileSharedL(
const TFileName& aFileName )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::\
IsFileSharedL" );
TBool returnValue = EFalse;
// Convert the filename to 8bit
HBufC8* tempFilename =
EscapeUtils::ConvertFromUnicodeToUtf8L( aFileName );
CleanupStack::PushL( tempFilename );
// Search the file from the array
TInt index = iSharedContentArray->FindByName( *tempFilename );
if( index >= 0 )
{
returnValue = ETrue;
}
// Clean up
CleanupStack::PopAndDestroy( tempFilename );
return returnValue;
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::CheckFileExistenceL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::CheckFileExistenceL(
const TFileName& aFileName )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::\
CheckFileExistenceL" );
TBool fileExists( EFalse );
RFs fsSession;
User::LeaveIfError( fsSession.Connect() ); // connect session
CleanupClosePushL( fsSession );
// check that file exists
fileExists = BaflUtils::FileExists( fsSession, aFileName );
CleanupStack::PopAndDestroy( &fsSession );
if ( !fileExists )
{
User::Leave( KErrArgument );
}
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::UnshareEmptyContainersL
// --------------------------------------------------------------------------
//
TBool CUpnpSharingAlgorithmImpl::UnshareEmptyContainersL( TDesC8& aParentId )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithmImpl::\
UnshareEmptyContainersL" );
TBool containerUnshared( EFalse );
// get top container id that does not contain item
// starting from container where item is.
RPointerArray<CUpnpCdsLiteObject> containerList =
iContainerResolver->ResolveEmptyContainersL( aParentId );
CleanupClosePushL( containerList );
TInt containerCount = containerList.Count();
if ( containerCount )
{
// Get top containerId which needs to be unshared.
TPtrC8 containerIdStr = containerList[containerCount-1]->ObjectId();
TInt objectIdInt( KErrNotFound );
User::LeaveIfError(
objectIdInt = UPnPCommonUtils::DesC8ToInt( containerIdStr ));
// unshares all objecs under this container with single call
TRAPD( error, iSharingAO->UnshareContainerL( objectIdInt ));
if ( !error )
{
for ( TInt i = 0; i < containerCount; i++ )
{
// get container's array index
TInt arrayIndex =
iSharedContentArray->FindByObjectId(
containerList[i]->ObjectId() );
// Remove the container from the shared content array
iSharedContentArray->RemoveObjectAtL( arrayIndex );
}
}
containerUnshared = ETrue;
}
CleanupStack::PopAndDestroy( &containerList );
return containerUnshared;
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::ShareContainersL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::ShareContainersL(
RPointerArray<CUpnpContainer>& aContainerArray )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
ShareContainersL" );
TPtrC8 previousContainerId( KNullDesC8 );
// Share containers
for ( TInt i = 0; i < aContainerArray.Count(); i++ )
{
CUpnpContainer* container = aContainerArray[i];
// first container ( index = 0 ) have parent id ready
if ( container->ParentId() == KNullDesC8 )
{
// parentid is previously shared container id
container->SetParentIdL( previousContainerId );
}
TInt error( KErrNone );
TRAP( error, iSharingAO->ShareContainerL( container ));
if ( error )
{
// remove shared objects from server because of error
RemoveSharedObjectsL( aContainerArray );
User::LeaveIfError( error );
}
// container got id on sharing - keep it safe for next container
// because it it used as parent container id
previousContainerId.Set( container->Id());
// no errors - append containers to cdsliteobjectarray
TRAP( error, iSharedContentArray->AppendL( container ));
if ( error )
{
// remove shared objects from array because of error
RemoveSharedObjectsL( aContainerArray );
User::LeaveIfError( error );
}
}
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::ShareReferenceObjectsL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::ShareReferenceObjectsL( CUpnpItem* aItem )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
ShareReferenceObjectsL" );
// Get cds object from array. Reference item ids will be
// added to this item
TInt index = iSharedContentArray->FindByObjectId( aItem->Id() );
CUpnpCdsLiteObject& object = iSharedContentArray->ObjectAtL( index );
// reset id because a new one will be given when reference is shared
aItem->SetIdL( KNullDesC8 );
// reset refid field because item is reference
aItem->SetRefIdL( KNullDesC8 );
// reset title
aItem->SetTitleL( KNullDesC8 );
// reset parentId
aItem->SetParentIdL( KNullDesC8 );
if ( aItem->ObjectClass() == KClassAudioMusicTrack )
{
// Resolve genre containers
RPointerArray<CUpnpContainer> refContainers =
iContainerResolver->ResolveReferenceContainersL( EGenreType,
*aItem );
CleanupResetAndDestroyPushL( refContainers );
if ( refContainers.Count() ||
aItem->ParentId() != KNullDesC8 )
{
// share container(s) and item
ShareReferenceObjectL( refContainers, object, *aItem );
}
CleanupStack::PopAndDestroy( &refContainers );
// reset parentId
aItem->SetParentIdL( KNullDesC8 );
// Resolve album containers
refContainers =
iContainerResolver->ResolveReferenceContainersL( EAlbumType,
*aItem );
CleanupResetAndDestroyPushL( refContainers );
if ( refContainers.Count() ||
aItem->ParentId() != KNullDesC8 )
{
// share container(s) and item
ShareReferenceObjectL( refContainers, object, *aItem );
}
CleanupStack::PopAndDestroy( &refContainers );
// reset parentId
aItem->SetParentIdL( KNullDesC8 );
// Resolve artist containers
refContainers =
iContainerResolver->ResolveReferenceContainersL( EArtistType,
*aItem );
CleanupResetAndDestroyPushL( refContainers );
if ( refContainers.Count() ||
aItem->ParentId() != KNullDesC8 )
{
// share container(s) and item
ShareReferenceObjectL( refContainers, object, *aItem );
}
CleanupStack::PopAndDestroy( &refContainers );
// reset parentId
aItem->SetParentIdL( KNullDesC8 );
// Resolve artist containers
refContainers =
iContainerResolver->ResolveReferenceContainersL( EMusicByDateType,
*aItem );
CleanupResetAndDestroyPushL( refContainers );
if ( refContainers.Count() ||
aItem->ParentId() != KNullDesC8 )
{
// share container(s) and item
ShareReferenceObjectL( refContainers, object, *aItem );
}
CleanupStack::PopAndDestroy( &refContainers );
}
else if ( aItem->ObjectClass() == KClassImage )
{
// reset parentId
aItem->SetParentIdL( KNullDesC8 );
// resolve date container
RPointerArray<CUpnpContainer> refContainers =
iContainerResolver->ResolveReferenceContainersL( EImageByDateType,
*aItem );
CleanupResetAndDestroyPushL( refContainers );
if ( refContainers.Count() ||
aItem->ParentId() != KNullDesC8 )
{
// share container(s) and item
ShareReferenceObjectL( refContainers, object, *aItem );
}
CleanupStack::PopAndDestroy( &refContainers );
}
else if ( aItem->ObjectClass() == KClassVideo )
{
// reset parentId
aItem->SetParentIdL( KNullDesC8 );
// resolve date container
RPointerArray<CUpnpContainer> refContainers =
iContainerResolver->ResolveReferenceContainersL( EVideoByDateType,
*aItem );
CleanupResetAndDestroyPushL( refContainers );
if ( refContainers.Count() )
{
// share container(s) and item
ShareReferenceObjectL( refContainers, object, *aItem );
}
CleanupStack::PopAndDestroy( &refContainers );
}
else
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
ShareReferenceObjectsL object class not defined" );
}
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::UnshareReferenceObjectsL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::UnshareReferenceObjectsL(
CUpnpCdsLiteObject& aOriginalObject )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
UnshareReferenceObjectsL" );
TInt refIndex( KErrNotFound );
do
{
// find reference items created from original item
refIndex = iSharedContentArray->FindRefItemIdByOriginalIdL(
aOriginalObject.ObjectId() );
if ( refIndex != KErrNotFound )
{
CUpnpCdsLiteObject& refObject =
iSharedContentArray->ObjectAtL( refIndex );
// Checks the container tree and unshares if needed
// First container id to be checked is item's parentid
TBool containerUnshared =
UnshareEmptyContainersL( refObject.ParentId() );
// if container is not unshared the item needs to be unshared
if ( !containerUnshared )
{
// Leave if ObjectId not found
if( refObject.ObjectId() == KNullDesC8 )
{
__LOG( "[CUpnpSharingAlgorithm]\t \
CUpnpSharingAlgorithm::UnshareFileL, ObjectId not found!" );
User::Leave( KErrCorrupt );
}
TInt objectIdInt( KErrNotFound );
User::LeaveIfError( objectIdInt =
UPnPCommonUtils::DesC8ToInt( refObject.ObjectId() ));
// Unshare the item
iSharingAO->UnshareFileL( objectIdInt );
// Remove the file from the shared content array
iSharedContentArray->RemoveObjectAtL( refIndex );
}
else
{
// index has changed because container(s) was unshared
refIndex = iSharedContentArray->FindByObjectId(
refObject.ObjectId() );
// item was also unshared when container was unshared
// it's enough to remove item from contentarray
iSharedContentArray->RemoveObjectAtL( refIndex );
}
}
} while ( refIndex != KErrNotFound );
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::ShareReferenceObjectL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::ShareReferenceObjectL(
RPointerArray<CUpnpContainer>& aContainerArray,
CUpnpCdsLiteObject& aOriginalObject,
CUpnpItem& aItem )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
ShareReferenceObjectL" );
TPtrC8 refParentId( KNullDesC8 );
TInt parentContainerId( KErrNotFound );
TInt count = aContainerArray.Count();
if ( count )
{
// reference container must be non-restricted
aContainerArray[count-1]->SetRestricted(EFalse);
// share containers
ShareContainersL( aContainerArray );
refParentId.Set( aContainerArray[count-1]->Id() );
User::LeaveIfError(
parentContainerId = UPnPCommonUtils::DesC8ToInt( refParentId ));
}
else // share just item
{
refParentId.Set( aItem.ParentId() );
User::LeaveIfError(
parentContainerId = UPnPCommonUtils::DesC8ToInt( refParentId ));
}
TInt originalItemId( KErrNotFound );
User::LeaveIfError( originalItemId = UPnPCommonUtils::DesC8ToInt(
aOriginalObject.ObjectId() ));
iSharingAO->ShareReferenceL( parentContainerId, originalItemId, &aItem );
// Add the file to the shared content array
iSharedContentArray->AppendL( &aItem );
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::RemoveSharedObjectsL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::RemoveSharedObjectsL(
RPointerArray<CUpnpContainer>& aContainerArray )
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
RemoveSharedObjectsL" );
// Unshare starting from first container
TPtrC8 containerIdStr = aContainerArray[0]->Id();
TInt objectIdInt( KErrNotFound );
User::LeaveIfError(
objectIdInt= UPnPCommonUtils::DesC8ToInt( containerIdStr ));
// unshares all objecs under this container with single call
iSharingAO->UnshareContainerL( objectIdInt );
for ( TInt i = 0; i < aContainerArray.Count(); i++)
{
// Remove object from the shared content array
iSharedContentArray->RemoveL( aContainerArray[i] );
}
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::ReadSharedContent
// --------------------------------------------------------------------------
//
CUpnpCdsLiteObjectArray& CUpnpSharingAlgorithmImpl::ReadSharedContent()
{
return *iSharedContentArray;
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::StartServer
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::StartServer()
{
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
StartServer" );
// start offline if not started
TInt status( RUpnpMediaServerClient::EStopped );
iMediaServer.Status( status );
if ( status == RUpnpMediaServerClient::EStopped )
{
iMediaServer.StartOffline();
__LOG( "[CUpnpSharingAlgorithm]\t CUpnpSharingAlgorithm::\
StartServer started offline" );
}
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::Close
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::Close()
{
delete this;
}
// --------------------------------------------------------------------------
// CUpnpSharingAlgorithmImpl::CheckFileProtectionL
// --------------------------------------------------------------------------
//
void CUpnpSharingAlgorithmImpl::CheckFileProtectionL(
const TFileName& aFileName )
{
if ( UPnPFileUtility::IsFileProtectedL( aFileName ) )
{
User::Leave( KErrAccessDenied );
}
}
// End of file