omadrm/drmengine/server/src/DRMRightsData.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 15 Mar 2010 12:41:43 +0200
branchRCL_3
changeset 18 8a03a285ab14
parent 0 95b198f216e5
child 84 b09186059647
permissions -rw-r--r--
Revision: 201009 Kit: 201010

/*
* Copyright (c) 2004 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:  Datatype for Rights Constraint
*
*/



// INCLUDE FILES
#include <s32file.h>
#include <s32std.h>
#include <caf/caf.h>

#include "DRMPointerArray.h"
#include "DRMCommonData.h"
#include "DrmPermission.h"
#include "DRMRightsData.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS
const TInt KEncryptionKeySize = 16;

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

class TPermData
    {
    public: // Constructor
    TPermData( HBufC8* aParentId, const TInt aIndex, TBool aIsValid ) :
        iParentId( aParentId ),
        iIndex( aIndex ),
        iIsValid( aIsValid ) { };

    public: // Member variables
    HBufC8* iParentId;
    TInt iIndex;
    TBool iIsValid;
    };


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

// -----------------------------------------------------------------------------
// CDRMRightsData::NewLC
// -----------------------------------------------------------------------------
//
CDRMRightsData* CDRMRightsData::NewLC( CDRMCommonData* aData,
                                       const TDesC8& aKey,
                                       const TFileName& aRightsFile,
                                       RFs& aFileServer )
    {
    CDRMRightsData* self = new( ELeave ) CDRMRightsData( aData, aFileServer );
    CleanupStack::PushL( self );
    self->ConstructL( aRightsFile, aKey );

    return self;
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::NewL
// -----------------------------------------------------------------------------
//
CDRMRightsData* CDRMRightsData::NewL( CDRMCommonData* aData,
                                      const TDesC8& aKey,
                                      const TFileName& aRightsFile,
                                      RFs& aFileServer )
    {
    CDRMRightsData* self = NewLC( aData, aKey, aRightsFile, aFileServer );
    CleanupStack::Pop();

    return self;
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::OpenLC
// -----------------------------------------------------------------------------
//
CDRMRightsData* CDRMRightsData::OpenLC( const TFileName& aRightsFile,
                                        RFs& aFileServer )
    {
    CDRMCommonData* common = CDRMCommonData::NewL();

    CDRMRightsData* self = new( ELeave ) CDRMRightsData( common, aFileServer );
    CleanupStack::PushL( self );
    self->ConstructL( aRightsFile );

    return self;
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::OpenL
// -----------------------------------------------------------------------------
//
CDRMRightsData* CDRMRightsData::OpenL( const TFileName& aRightsFile,
                                       RFs& aFileServer )
    {
    CDRMRightsData* self = OpenLC( aRightsFile, aFileServer );
    CleanupStack::Pop();

    return self;
    };

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CDRMRightsData::~CDRMRightsData()
    {
    // Permanent File Store
    if( iStore )
        {;
        delete iStore;
        iStore = NULL;
        }

    // index array
    iArray.Close();

    // Common Data
    if( iData )
        {
        delete iData;
        iData = NULL;
        }
    };


// -----------------------------------------------------------------------------
// CDRMRightsData::GetCommonDataL
// -----------------------------------------------------------------------------
//
const CDRMCommonData* CDRMRightsData::GetCommonDataL() const
    {
    return iData;
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::UpdateCommonDataL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::UpdateCommonDataL( CDRMCommonData* aData )
    {
    RStoreWriteStream stream;

    // If not data is given, that is an error
    if( !aData )
        {
        User::Leave( KErrArgument );
        }

    // Open the stream
    stream.ReplaceLC( *iStore, iCommonId );

    // Delete the old data if it's around
    // if the old data has been modified, write it as such
    if( iData != aData )
        {
        if( iData )
            {
            delete iData;
            iData = NULL;
            }
        iData = aData;
        }

    // Write the data to the stream
    iData->ExternalizeL( stream );

    // commit the stream
    stream.CommitL();

    // commit the store
    iStore->CommitL();

    // pop the stream
    CleanupStack::PopAndDestroy();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::StoreNewPermissionL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::StoreNewPermissionL( CDRMPermission& aPermission,
                                          TDRMUniqueID& aStream )
    {
    TStreamId sid;
    TStreamId rootId;
    RStoreWriteStream stream;
    RStoreWriteStream rootStream;

    // Create a new stream to the store:
    sid = stream.CreateLC( *iStore );

    aPermission.iUniqueID = sid.Value();
    aStream = sid.Value();

    // Externalize the permission data
    aPermission.ExternalizeL( stream );
    stream.CommitL();

    // add the id to the array
    iArray.InsertInUnsignedKeyOrder( aStream );

    // Get the stream id of the root
    rootId = iStore->Root();

    // Open the root stream
    rootStream.ReplaceLC( *iStore, rootId );

    // Store the changed index
    StoreIndexL( rootStream );
    rootStream.CommitL();

    // Commit the store
    iStore->CommitL();

    CleanupStack::PopAndDestroy();  // root stream
    CleanupStack::PopAndDestroy();  // stream

    iStore->CompactL();
    iStore->CommitL();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::UpdatePermissionL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::UpdatePermissionL( const CDRMPermission& aPermission )
    {
    TStreamId sid( aPermission.iUniqueID );
    RStoreWriteStream stream;
    TInt index = 0;

    // get the id from the array if it doesn't exist, error
    index = iArray.FindInUnsignedKeyOrder( aPermission.iUniqueID );

    if( index == KErrNotFound )
        {
        User::Leave( KErrCANoPermission );
        }

    // Replace the existing stream
    stream.ReplaceLC( *iStore, sid );

    // Externalize the permission data
    aPermission.ExternalizeL( stream );

    // Required by the ReplaceLC
    stream.CommitL();

    // Commit the store
    iStore->CommitL();

    CleanupStack::PopAndDestroy();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::FetchPermissionL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::FetchPermissionL( CDRMPermission& aPermission,
                                       const TDRMUniqueID& aStream ) const
    {
    TStreamId sid( aStream );
    RStoreReadStream stream;
    TInt index = 0;

    // get the id from the array if it doesn't exist, error
    index = iArray.FindInUnsignedKeyOrder( aStream );

    if( index == KErrNotFound )
        {
        User::Leave( KErrCANoPermission );
        }

    // Open the root stream
    stream.OpenLC( *iStore, sid );

    // Read the common id
    aPermission.InternalizeL( stream );

    // Close the stream
    CleanupStack::PopAndDestroy();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::DeletePermissionL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::DeletePermissionL( const TDRMUniqueID& aStream )
    {
    TStreamId sid( aStream );
    TStreamId rootId;
    TInt index = 0;
    RStoreWriteStream rootStream;

    // get the id from the array if it doesn't exist, error
    index = iArray.FindInUnsignedKeyOrder( aStream );

    if( index == KErrNotFound )
        {
        User::Leave( KErrCANoPermission );
        }

    // Delete the stream from the store
    iStore->DeleteL( sid );

    iArray.Remove( index );


    // Get the stream id of the root
    rootId = iStore->Root();

    // Open the root stream
    rootStream.ReplaceLC( *iStore, rootId );

    // Store the changed index
    StoreIndexL( rootStream );
    rootStream.CommitL();

    // Commit the store
    iStore->CommitL();

    CleanupStack::PopAndDestroy();  // root stream

    // Compact and commit the changes
    iStore->CompactL();
    iStore->CommitL();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::FetchAllPermissionsL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::FetchAllPermissionsL( RPointerArray<CDRMPermission>&
                                           aPointerArray)
    {
    CDRMPermission* perm = NULL;

    if ( iArray.Count() == 0)
        {
        User::Leave( KErrCANoPermission );
        }

    for( TInt count = 0; count < iArray.Count(); count++ )
        {
        perm = CDRMPermission::NewLC();
        FetchPermissionL( *perm, iArray[ count ] );
        aPointerArray.AppendL( perm );
        CleanupStack::Pop();
        }
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::DeleteAllPermissionsL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::DeleteAllPermissionsL()
    {
    TStreamId rootId;
    RStoreWriteStream rootStream;

    // Delete all permissions from the store
    for( TInt i = 0; i < iArray.Count(); i++ )
        {
        TStreamId sid( iArray[i] );
        iStore->DeleteL( sid );
        }

    // Reset the array
    iArray.Reset();

    // Get the stream id of the root
    rootId = iStore->Root();

    // Open the root stream
    rootStream.ReplaceLC( *iStore, rootId );

    // Store the changed index
    StoreIndexL( rootStream );
    rootStream.CommitL();

    // Commit the store
    iStore->CommitL();

    CleanupStack::PopAndDestroy();  // root stream

    // Compact and Commit the store
    iStore->CompactL();
    iStore->CommitL();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::DeleteExpiredPermissionsL
// Deletes all rights objects which have been expired
// if the given time aTime is Time::NullTTime() then
// deletes only non time based rights
// -----------------------------------------------------------------------------
//
TInt CDRMRightsData::DeleteExpiredPermissionsL( const TTime& aTime, TBool& aParents )
    {
    CDRMPermission* permission = NULL;
    RStoreReadStream stream;
    TStreamId rootId;
    RStoreWriteStream rootStream;
    TBool remove = EFalse;
    TInt k = 0;
    TBool performDelete = ETrue;

    // A list for the permissions:
    CDRMPointerArray<CDRMPermission>* permList = CDRMPointerArray<CDRMPermission>::NewLC();
    permList->SetAutoCleanup( ETrue );
    CDRMPointerArray<TPermData>* permDataList = CDRMPointerArray<TPermData>::NewLC();
    permDataList->SetAutoCleanup( ETrue );

    // Fill the array:
    for( TInt j = 0  ; j < iArray.Count(); j++ )
        {
        TPermData* perm = NULL;
        // Create the sid:
        TStreamId psid( iArray[j] );

        // Open the correct stream
        stream.OpenLC( *iStore, psid );

        permission = CDRMPermission::NewLC();

        // Read the permission
        permission->InternalizeL( stream );

        permList->AppendL( permission );
        CleanupStack::Pop(); // permission

        // if the permission has a parent check if we found now or have found an
        // expired one or a valid one,
        // store info if required
        if( permission->iParentUID )
            {
            if( !aParents )
                {
                aParents = ETrue;
                }

            for( k = 0; k < permDataList->Count(); k++ )
                {
                if( !(*permDataList)[k]->iParentId->Compare( *permission->iParentUID ) )
                    {
                    if( !(*permDataList)[k]->iIsValid && !permission->Expired( aTime ) )
                        {
                        (*permDataList)[k]->iParentId = permission->iParentUID;
                        (*permDataList)[k]->iIndex = j;
                        (*permDataList)[k]->iIsValid = ETrue;
                        }
                    break;
                    }
                }

            // if it's not found, add it:
            if( k == permDataList->Count() )
                {
                if( !permission->Expired( aTime ) )
                    {
                    perm = new(ELeave) TPermData( permission->iParentUID, j, ETrue);
                    }
                else
                    {
                    perm = new(ELeave) TPermData( permission->iParentUID, j, EFalse);
                    }
                CleanupStack::PushL( perm );
                permDataList->AppendL( perm );
                CleanupStack::Pop(); // perm
                }
            }

        // Close the stream
        CleanupStack::PopAndDestroy();  // stream
        }


    // Delete all expired permissions from the store
    for( TInt i = iArray.Count() - 1 ; i >= 0; i-- )
        {
        permission = (*permList)[i];

        // Check if the permission is expired
        // if it is, check if it has a parent and if it can be deleted
        if( permission->Expired( aTime ) )
            {
            // if it has a parent go through the list and see if this can be deleted
            // or not
            if( permission->iParentUID )
                {
                performDelete = EFalse;
                for( k = 0; k < permDataList->Count(); k++ )
                    {
                    TPermData* aData = (*permDataList)[k];

                    // since it's set up like this a pointer comparison is enough:
                    if( !(*permDataList)[k]->iParentId->Compare( *permission->iParentUID  ) )
                        {
                        if( i != (*permDataList)[k]->iIndex )
                            {
                            performDelete = ETrue;
                            }
                        }
                    }
                }

            if( performDelete )
                {
                // Create the sid:
                TStreamId sid( iArray[i] );

                iStore->Delete( sid );

                // remove from the array
                iArray.Remove( i );

                if( !remove )
                    {
                    remove = ETrue;
                    }
                }
            }
        performDelete = ETrue;
        }

    CleanupStack::PopAndDestroy( 2 ); // permDataList, permList

    // Write the data into the the file
    // if some of the rights have been removed
    if( remove )
        {
        // Get the stream id of the root
        rootId = iStore->Root();

        // Open the root stream
        rootStream.ReplaceLC( *iStore, rootId );

        // Store the changed index
        StoreIndexL( rootStream );
        rootStream.CommitL();

        // Commit the store
        iStore->CommitL();

        CleanupStack::PopAndDestroy();  // root stream

        // Compact and Commit the store
        iStore->CompactL();
        iStore->CommitL();
        }

    return iArray.Count();
    }


// -----------------------------------------------------------------------------
// CDRMRightsData::StoreKeyL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::StoreKeyL()
    {
    RStoreWriteStream stream;
    TUint32 size = 0;

    stream.OpenLC( *iStore, iKeyId );

    if( iKeyExists )
        {
        size = KEncryptionKeySize;
        }

    stream.WriteUint32L( size );

    if( size )
        {
        stream.WriteL( iKey, KEncryptionKeySize );
        }

    stream.CommitL();
    iStore->CommitL();

    CleanupStack::PopAndDestroy();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::GetKeyL
// -----------------------------------------------------------------------------
//
HBufC8* CDRMRightsData::GetKeyL() const
    {
    HBufC8* key = NULL;

    if( iKeyExists )
        {
        key = HBufC8::NewL( KEncryptionKeySize );
        *key = iKey;
        }

    return key;
    }

// -----------------------------------------------------------------------------
// CDRMRightsData::FetchKeyL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::FetchKeyL()
    {
    RStoreReadStream stream;
    TUint32 size = 0;

    // Open the root stream
    stream.OpenLC( *iStore, iKeyId );

    size = stream.ReadUint32L();

    if( !size )
        {
        iKeyExists = EFalse;
        }
    else
        {
        stream.ReadL( iKey, KEncryptionKeySize );
        iKeyExists = ETrue;
        }

    CleanupStack::PopAndDestroy();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::CreateAndInitializeStoreL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::CreateAndInitializeStoreL( const TFileName& aRightsStore )
    {
    TStreamId rootId;
    RStoreWriteStream stream;
    RStoreWriteStream stream2;
    RStoreWriteStream rootStream;
    TUint32 size = 0;

    // Create and initialize the permanent file store
    iStore = CPermanentFileStore::ReplaceL( iFileServer, aRightsStore,
                                            EFileRead|EFileWrite );
    iStore->SetTypeL( KPermanentFileStoreLayoutUid );
    iStore->CommitL();

    // Create the root stream:
    rootId = rootStream.CreateLC( *iStore );
    rootStream.CommitL();
    iStore->SetRootL( rootId );
    iStore->CommitL();

    // Create the common data
    iCommonId = stream.CreateLC( *iStore );
    iData->ExternalizeL( stream );
    stream.CommitL();
    iStore->CommitL();

    CleanupStack::PopAndDestroy(); // stream

    // Create the key
    iKeyId = stream2.CreateLC( *iStore );

    // if the key exists set the key size accordingly
    if( iKeyExists )
        {
        size = KEncryptionKeySize;
        }
    stream2.WriteUint32L( size );

    if( size )
        {
        stream2.WriteL( iKey, KEncryptionKeySize );
        }
    stream2.CommitL();
    iStore->CommitL();

    CleanupStack::PopAndDestroy(); // stream2
    CleanupStack::PopAndDestroy(); // rootStream

    // Create the index now that we have all the data
    rootId = iStore->Root();

    rootStream.ReplaceLC(*iStore, rootId);
    StoreIndexL( rootStream );
    rootStream.CommitL();
    iStore->CommitL();

    // Commit the changes to the store as well
    CleanupStack::PopAndDestroy(); // rootStream
    };


// -----------------------------------------------------------------------------
// CDRMRightsData::StoreIndexL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::StoreIndexL( RWriteStream& aStream ) const
    {
    // Write the common id to the stream
    iCommonId.ExternalizeL( aStream );

    // Write the key id to the stream
    iKeyId.ExternalizeL( aStream );

    // Write the array size and possibly the array to the stream
    aStream.WriteInt32L( iArray.Count() );

    for( TInt count = 0; count < iArray.Count(); count++ )
        {
        aStream.WriteUint32L( iArray[ count ] );
        }
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::FetchIndexL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::FetchIndexL()
    {
    TStreamId rootId;
    RStoreReadStream stream;
    TInt count = 0;
    TDRMUniqueID id;

    // Get the stream id of the root
    rootId = iStore->Root();

    // Open the root stream
    stream.OpenLC( *iStore, rootId );

    // Do the actual reading, reading also the key id and the common id

    // Read the common id
    iCommonId.InternalizeL( stream );

    // Read the key id
    iKeyId.InternalizeL( stream );

    // read the count of the array:
    iArray.Reset();

    count = stream.ReadInt32L();

    for( ; count > 0; count-- )
        {
        id = stream.ReadUint32L();
        iArray.InsertInUnsignedKeyOrder( id );
        }

    // Close the stream
    CleanupStack::PopAndDestroy();
    };

// -----------------------------------------------------------------------------
// CDRMRightsData::FetchCommonDataL
// -----------------------------------------------------------------------------
//
void CDRMRightsData::FetchCommonDataL()
    {
    RStoreReadStream stream;

    // Open the root stream
    stream.OpenLC( *iStore, iCommonId );

    iData->InternalizeL( stream );

    CleanupStack::PopAndDestroy();
    };


// -----------------------------------------------------------------------------
// Default Constructor - First phase.
// Can be used by itself to generate an empty object
// -----------------------------------------------------------------------------
//
CDRMRightsData::CDRMRightsData( CDRMCommonData* aData, RFs& aFileServer ) :
    iFileServer( aFileServer ), iData( aData )
    {
    };

// -----------------------------------------------------------------------------
// 2nd phase Constructor
// -----------------------------------------------------------------------------
//
void CDRMRightsData::ConstructL( const TFileName& aRightsStore )
    {
    // Open the file store
    iStore = CPermanentFileStore::OpenL( iFileServer, aRightsStore, EFileRead|EFileWrite );

    // Get the index
    FetchIndexL();

    // Get the common data
    FetchCommonDataL();

    // Get the key
    FetchKeyL();
    };

// -----------------------------------------------------------------------------
// 2nd phase Constructor
// -----------------------------------------------------------------------------
//
void CDRMRightsData::ConstructL( const TFileName& aRightsStore,
                                 const TDesC8& aKey )
    {

    // Check if the key is given or a null desc
    if( aKey.Length() )
        {
        iKey = aKey;
        iKeyExists = ETrue;
        }
    else
        {
        iKeyExists = EFalse;
        }

    // Creates the required stores and indexes
    CreateAndInitializeStoreL( aRightsStore );
    };


// End of File