diff -r 000000000000 -r 95b198f216e5 omadrm/drmengine/agentv2/src/DcfCache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmengine/agentv2/src/DcfCache.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,552 @@ +/* +* Copyright (c) 2002-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 DCF cache class +* +*/ + +// INCLUDE FILES +#include +#include +#include +#include +#include "DcfCache.h" +#include "DcfCommon.h" +#include "DrmRightsClient.h" + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CDcfCache::CDcfCache +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +#ifdef ASYNC_READ + +CDcfCache::CDcfCache( + RDRMRightsClient& aRightsClient, + RFile& aFile, + CDcfCommon& aDcf, + TInt aPageSize, + TInt aPageCount ) : +CActive( CActive::EPriorityStandard ), +iFile( aFile ), +iRightsClient(aRightsClient ), +iDcf( aDcf ), +iPageSize( aPageSize ), +iPageCount( aPageCount ), +iDecryptionMode( EServerSide ), +iDes( 0 ), +iAsyncReadingOngoing( EFalse ) + { + } + +#else + +CDcfCache::CDcfCache( + RDRMRightsClient& aRightsClient, + RFile& aFile, + CDcfCommon& aDcf, + TInt aPageSize, + TInt aPageCount ) : +iFile( aFile ), +iRightsClient( aRightsClient ), +iDcf( aDcf ), +iPageSize( aPageSize ), +iPageCount( aPageCount ), +iDecryptionMode( EServerSide ) + { + } +#endif +// ----------------------------------------------------------------------------- +// CDcfCache::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CDcfCache::ConstructL() + { + for ( TInt i = 0; i < iPageCount; i++ ) + { + iPage.AppendL( new ( ELeave ) TUint8[iPageSize] ); + iPageUsageCount.AppendL( -1 ); + iPagePosition.AppendL( -1 ); + } + } + +// ----------------------------------------------------------------------------- +// CDcfCache::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CDcfCache* CDcfCache::NewL( RDRMRightsClient& aRightsClient, RFile& aFile, + CDcfCommon& aDcf, TInt aPageSize, TInt aPageCount ) + { + CDcfCache* self = new ( ELeave ) CDcfCache( aRightsClient, aFile, aDcf, + aPageSize, aPageCount ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::~CDcfCache +// Destructor +// ----------------------------------------------------------------------------- +// +CDcfCache::~CDcfCache() + { + +#ifdef ASYNC_READ + if ( IsActive() ) + { + if ( iAsyncReadingOngoing ) + { + Cancel(); + } + else + { + TRequestStatus* status = &iStatus; + User::RequestComplete( status, KErrNone ); + Cancel(); + } + } +#endif + + iPage.ResetAndDestroy(); + iPage.Close(); + iPagePosition.Close(); + iPageUsageCount.Close(); + } + +// ----------------------------------------------------------------------------- +// CDcfCache::Read +// ----------------------------------------------------------------------------- +// +TInt CDcfCache::Read( TInt& aPos, TDes8& aDes, TInt aLength ) + { + TInt r = KErrNone; + + // Check that the position is valid and the length is valid + if ( aPos < 0 || aLength < 0 ) + { + return KErrArgument; + } + + if ( iPageCount > 0 ) + { + TRAP(r, CachedReadL(aPos, aDes, aLength)); + } + else + { + TRAP(r, UncachedReadL(aPos, aDes, aLength)); + } + if ( r != KErrNone ) + { + RDebug::Printf( "CDcfCache::Read error: %d", r ); + } + return r; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::Read +// ----------------------------------------------------------------------------- +// + +#ifdef ASYNC_READ + +TInt CDcfCache::Read( TInt aPos, TDes8& aDes, TInt aLength, + TRequestStatus& aStatus ) + { + + // Check that the position is valid and the length is valid + if ( aPos < 0 || aLength < 0 ) + { + return KErrArgument; + } + + if ( !IsAdded() ) + { + CActiveScheduler::Add( this ); + } + + if ( iAsyncReadingOngoing ) + { + return KErrInUse; + } + + iError = KErrNone; + + iAsyncReadingOngoing = ETrue; + + iPos = aPos; + iLength = aLength; + iDes = &aDes; + iOperation = EPosRead; + + iAsyncStatus = &aStatus; + *iAsyncStatus = KRequestPending; + + TRequestStatus* ownStatus = &iStatus; + *ownStatus = KRequestPending; + + SetActive(); + User::RequestComplete( ownStatus, KErrNone ); + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::ReadCancel +// ----------------------------------------------------------------------------- +// +void CDcfCache::ReadCancel( TRequestStatus& aStatus ) + { + // only cancel if needed + TRequestStatus* status( &aStatus ); + if ( IsActive() && iAsyncStatus == status ) + { + if ( iAsyncReadingOngoing ) + { + Cancel(); + iAsyncReadingOngoing = EFalse; + iAsyncStatus = NULL; + User::RequestComplete( status, KErrCancel ); + } + } + } + +#endif + +// ----------------------------------------------------------------------------- +// CDcfCache::CachedReadL +// ----------------------------------------------------------------------------- +// +void CDcfCache::CachedReadL( TInt& aPos, TDes8& aDes, TInt aLength ) + { + TInt i; + + // Check that the position is valid and the length is valid + if ( aPos < 0 || aLength < 0 ) + { + User::Leave( KErrArgument ); + } + + aDes.SetLength( 0 ); + while ( aLength > 0 ) + { + for ( i = 0; aLength > 0 && i < iPageCount; i++ ) + { + if ( InPage( i, aPos ) ) + { + CopyOut( i, aDes, aPos, aLength ); + } + } + if ( i == iPageCount && aLength > 0 ) + { + i = GetFreePage(); + if ( iDcf.iEncryptionMethod == EMethodAES_128_CBC ) + { + ReadAndDecryptPageL( i, aPos ); + CopyOut( i, aDes, aPos, aLength ); + } + else + { + ReadPageL( i, aPos ); + CopyOut( i, aDes, aPos, aLength ); + } + } + } + } + +// ----------------------------------------------------------------------------- +// CDcfCache::UncachedReadL +// ----------------------------------------------------------------------------- +// +void CDcfCache::UncachedReadL( TInt& aPos, TDes8& aDes, TInt aLength ) + { + HBufC8* buffer = NULL; + TPtr8 ptr( NULL, 0 ); + TBuf8 iv; + TInt pos; + TInt length; + + // Check that the position is valid and the length is valid + if ( aPos < 0 || aLength < 0 ) + { + User::Leave( KErrArgument ); + } + + if ( aPos + aLength > iDcf.iPlainTextLength ) + { + if ( aPos < iDcf.iPlainTextLength ) + { + aLength = iDcf.iPlainTextLength - aPos; + } + else + { + aLength = 0; + } + } + + if ( iDcf.iEncryptionMethod == EMethodAES_128_CBC ) + { + + // Nothing to read: + if ( aLength == 0 ) + { + aDes.SetLength( aLength ); + return; + } + + buffer = HBufC8::NewLC( aLength + 2 * KDCFKeySize ); + ptr.Set( buffer->Des() ); + pos = ( ( aPos / KDCFKeySize ) * KDCFKeySize ) + iDcf.iOffset; + User::LeaveIfError( iFile.Read( pos, iv, KDCFKeySize ) ); + length = ( ( aLength / KDCFKeySize ) * KDCFKeySize ) + 2 + * KDCFKeySize; + User::LeaveIfError( iFile.Read( ptr, length ) ); + + // Make sure we have the correct amount of data + if ( ptr.Length() % KDCFKeySize ) + { + length = ( ( ptr.Length() / KDCFKeySize ) * KDCFKeySize ); + ptr.SetLength( length ); + } + + // If not enough was read to get any content return an empty descriptor + if ( ptr.Length() == 0 ) + { + aDes.SetLength( 0 ); + CleanupStack::PopAndDestroy( buffer ); + return; + } + + DecryptL( iv, ptr ); + length = Min( aDes.MaxLength(), ptr.Length() - aPos % KDCFKeySize ); + aDes.Copy( ptr.Mid( aPos % KDCFKeySize, length ) ); + if ( aDes.Length() > aLength ) + { + aDes.SetLength( aLength ); + } + CleanupStack::PopAndDestroy( buffer ); + } + else + { + User::LeaveIfError( iFile.Read( aPos + iDcf.iOffset, aDes, aLength ) ); + } + aPos += aDes.Length(); + } + +// ----------------------------------------------------------------------------- +// CDcfCache::GetFreePage +// ----------------------------------------------------------------------------- +// +TInt CDcfCache::GetFreePage() + { + TInt i; + TInt n = -1; + TUint c = KMaxTUint32; + + for ( i = 0; i < iPageCount; i++ ) + { + if ( iPageUsageCount[i] == -1 ) + { + n = i; + break; + } + else if ( iPageUsageCount[i] < c ) + { + c = iPageUsageCount[i]; + n = i; + } + } + return n; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::ReadPageL +// ----------------------------------------------------------------------------- +// +void CDcfCache::ReadPageL( TInt aPage, TInt aPosition ) + { + TInt pos; + TBuf8 iv; + + iPageUsageCount[aPage] = 0; + iPagePosition[aPage] = ( aPosition / iPageSize ) * iPageSize; + pos = iPagePosition[aPage] + iDcf.iOffset; + iFile.Seek( ESeekStart, pos ); + TPtr8 ptr( iPage[aPage], iPageSize ); + User::LeaveIfError( iFile.Read( ptr ) ); + } + +// ----------------------------------------------------------------------------- +// CDcfCache::ReadAndDecryptPageL +// ----------------------------------------------------------------------------- +// +void CDcfCache::ReadAndDecryptPageL( TInt aPage, TInt aPosition ) + { + TInt pos; + TBuf8 iv; + + iPageUsageCount[aPage] = 0; + iPagePosition[aPage] = ( aPosition / iPageSize ) * iPageSize; + pos = iPagePosition[aPage] + iDcf.iOffset; + User::LeaveIfError( iFile.Seek( ESeekStart, pos ) ); + User::LeaveIfError( iFile.Read( iv ) ); + TPtr8 ptr( iPage[aPage], iPageSize ); + pos += KDCFKeySize; + User::LeaveIfError( iFile.Read( ptr ) ); + ptr.SetLength( iPageSize ); + DecryptL( iv, ptr ); + } + +// ----------------------------------------------------------------------------- +// CDcfCache::CopyOut +// ----------------------------------------------------------------------------- +// +void CDcfCache::CopyOut( TInt aPage, TDes8& aDes, TInt& aPosition, + TInt& aLength ) + { + TInt n; + TInt offset; + + aLength = Min( aLength, iDcf.iPlainTextLength - aPosition ); + aLength = Min( aLength, aDes.MaxLength() - aDes.Length() ); + offset = aPosition - iPagePosition[aPage]; + n = Min( aLength, iPageSize - offset ); + aDes.Append( iPage[aPage] + offset, n ); + aLength -= n; + aPosition += n; + iPageUsageCount[aPage]++; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::InPage +// ----------------------------------------------------------------------------- +// +TBool CDcfCache::InPage( TInt aPage, TInt aPosition ) + { + return iPagePosition[aPage] != -1 && iPagePosition[aPage] <= aPosition + && aPosition < iPagePosition[aPage] + iPageSize ? ETrue : EFalse; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::SetKey +// ----------------------------------------------------------------------------- +// +void CDcfCache::SetKey( const TDesC8& aKey ) + { + iKey.Copy( aKey ); + iDecryptionMode = EClientSide; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::DecryptL +// ----------------------------------------------------------------------------- +// +void CDcfCache::DecryptL( const TDesC8& aIv, TPtr8& aPtr ) + { + if ( iDecryptionMode == EClientSide ) + { + CModeCBCDecryptor* cbc( NULL ); + CAESDecryptor* aes( CAESDecryptor::NewLC( iKey ) ); + cbc = CModeCBCDecryptor::NewL( aes, aIv ); + CleanupStack::Pop( aes ); + aes = NULL; + CleanupStack::PushL( cbc ); + for ( TInt count = 0; count < aPtr.Length(); count += KDCFKeySize ) + { + TPtr8 d( aPtr.MidTPtr( count, KDCFKeySize ) ); + cbc->Transform( d ); + } + CleanupStack::PopAndDestroy( cbc ); + } + else + { + User::LeaveIfError( iRightsClient.Decrypt( aIv, aPtr ) ); + } + } + +#ifdef ASYNC_READ + +// ----------------------------------------------------------------------------- +// CDcfCache::RunL +// ----------------------------------------------------------------------------- +// +void CDcfCache::RunL() + { + + switch ( iOperation ) + { + case ENonPosRead: + { + break; + } + + case EPosRead: + { + ReadAsyncL(); + iAsyncReadingOngoing = EFalse; + User::RequestComplete( iAsyncStatus, KErrNone ); + iAsyncStatus = NULL; + break; + } + + default: + { + break; + } + } + } + +// ----------------------------------------------------------------------------- +// CDcfCache::DoCancel +// ----------------------------------------------------------------------------- +// +void CDcfCache::DoCancel() + { + } + +// ----------------------------------------------------------------------------- +// CDcfCache::RunError +// ----------------------------------------------------------------------------- +// +TInt CDcfCache::RunError( TInt aError ) + { + iError = aError; + User::RequestComplete( iAsyncStatus, iError ); + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CDcfCache::ReadAsyncL +// ----------------------------------------------------------------------------- +// + +void CDcfCache::ReadAsyncL() + { + if ( iPageCount > 0 ) + { + TRAP(iError, CachedReadL(iPos, *iDes, iLength)); + } + else + { + TRAP(iError, UncachedReadL(iPos, *iDes, iLength)); + } + } +#endif //ASYNC_READ +// End of File