--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmengine/dm/src/DRMMessageParser.cpp Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,1883 @@
+/*
+* 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: This class implements the BbB-functionality.
+*
+*/
+
+
+// INCLUDE FILES
+
+#include <e32base.h>
+#include <s32file.h>
+#include <s32mem.h>
+#include <caf/caftypes.h>
+#include <wspdecoder.h>
+#include <wspencoder.h>
+
+#ifdef RD_MULTIPLE_DRIVE
+#include <DriveInfo.h>
+#endif
+
+#include "DrmRights.h"
+#include "Oma1DcfCreator.h"
+#include "b64.h"
+#include "DRMMessageParser.h"
+#include "DRMRightsParser.h"
+#include "DRMRightsClient.h"
+#include "DrmKeyStorage.h"
+
+
+// EXTERNAL DATA STRUCTURES
+// EXTERNAL FUNCTION PROTOTYPES
+// CONSTANTS
+// MACROS
+// LOCAL CONSTANTS AND MACROS
+LOCAL_C const TInt KDefaultInputBufferSize = 2048;
+LOCAL_C const TInt KDRMMessageMalformed = KErrGeneral;
+
+_LIT8( KCIDString, "cid:" );
+LOCAL_C const TInt KCIDStringLength = 4;
+
+_LIT8( KFLPrefix, "flk:");
+LOCAL_C const TInt KFLKPrefixLength = 4;
+
+_LIT8( KFLSuffix, "@localhost");
+LOCAL_C const TUint8 KCDContentIDLength = 25; // 4 + 11 + 10
+LOCAL_C const TUint8 KCDPlainIDLength = 11;
+
+LOCAL_C const TInt KInputBufferSize = 2048;
+LOCAL_C const TInt KBoundaryMarkLength = 2;
+
+LOCAL_C const TUint KInitialDCFBufferSize = 4096;
+
+#ifdef RD_MULTIPLE_DRIVE
+_LIT( KTempPath, "%c:\\system\\temp\\" );
+#else
+_LIT( KTempPath, "c:\\system\\temp\\" );
+#endif
+
+_LIT8( KColon, ":" );
+_LIT8( KSemiColon, ";" );
+_LIT8( KNewLine, "\n" );
+_LIT8( KEndLine, "\r\n" );
+LOCAL_C const TUint8 KEndLineLength = 2;
+
+_LIT8( KBoundaryMark, "--" );
+_LIT8( KContentType, "Content-Type" );
+_LIT8( KContentTransferEncoding, "Content-Transfer-Encoding" );
+_LIT8( KEncodingBase64, "base64" );
+_LIT8( KEncoding7bit, "7bit" );
+_LIT8( KEncoding8bit, "8bit" );
+_LIT8( KEncodingBinary, "binary" );
+_LIT8( KDRMXMLRightsType, "application/vnd.oma.drm.rights+xml");
+_LIT8( KDRMWBXMLRightsType, "application/vnd.oma.drm.rights+wbxml" );
+_LIT8( KDRMContentType, "application/vnd.oma.drm.content" );
+_LIT8( KRightsIssuer, "Rights-Issuer" );
+
+_LIT8( KRightsStartTag, "<o-ex:rights");
+
+_LIT8( KROPart1, "Content-Type: application/vnd.oma.drm.rights+xml\r\n\
+Content-Transfer-Encoding: binary\r\n\r\n\
+<o-ex:rights xmlns:o-ex=\"http://odrl.net/1.1/ODRL-EX\" \
+xmlns:o-dd=\"http://odrl.net/1.1/ODRL-DD\" \
+xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#/\">\
+<o-ex:context><o-dd:version>1.0</o-dd:version></o-ex:context>\
+<o-ex:agreement><o-ex:asset><o-ex:context>\
+<o-dd:uid>");
+
+_LIT8( KROPart2, "</o-dd:uid></o-ex:context></o-ex:asset><o-ex:permission>\
+<o-dd:display/><o-dd:play/><o-dd:execute/><o-dd:print/>\
+</o-ex:permission></o-ex:agreement></o-ex:rights>");
+
+const TInt KFLROSize = sizeof(KROPart1) + sizeof(KROPart2);
+
+// MODULE DATA STRUCTURES
+struct TDeleteFileData
+ {
+ RFs aFs;
+ TFileName aName;
+ };
+
+// LOCAL FUNCTION PROTOTYPES
+LOCAL_C void DoResetAndDestroy( TAny* aPtr );
+LOCAL_C void DoResetAndDestroy2( TAny* aPtr );
+LOCAL_C void DoDeleteFile( TAny* aPtr );
+LOCAL_C void ConvertPermissionL( CDRMRights*& aRights,
+ CDRMPermission& aPermission,
+ const TDesC8& aURI );
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+// DoResetAndDestroy
+// Does ResetAndDestroy() to given RPointerArray< CDRMRights >
+// -----------------------------------------------------------------------------
+void DoResetAndDestroy( TAny* aPtr )
+ {
+ __ASSERT_DEBUG( aPtr, User::Invariant() );
+
+ reinterpret_cast< RPointerArray< CDRMRights >* >( aPtr )->ResetAndDestroy();
+ }
+
+void DoResetAndDestroy2( TAny* aPtr )
+ {
+ __ASSERT_DEBUG( aPtr, User::Invariant() );
+
+ reinterpret_cast< RPointerArray< CDRMPermission >* >( aPtr )->ResetAndDestroy();
+ }
+// -----------------------------------------------------------------------------
+// DoDeleteFile
+// Delete the file presented by TDeleteFileData pointer.
+// -----------------------------------------------------------------------------
+void DoDeleteFile( TAny* aPtr )
+ {
+ __ASSERT_DEBUG( aPtr, User::Invariant() );
+ TDeleteFileData* data = reinterpret_cast< TDeleteFileData* >( aPtr );
+ data->aFs.Delete( data->aName );
+ }
+
+void ConvertPermissionL( CDRMRights*& aRights,
+ CDRMPermission& aPermission,
+ const TDesC8& aURI )
+ {
+ CDRMAsset* asset( NULL );
+ CDRMRights* rights( NULL );
+
+ aRights = NULL;
+
+ rights = CDRMRights::NewL();
+ CleanupStack::PushL( rights );
+
+ asset = CDRMAsset::NewL();
+ CleanupStack::PushL( asset );
+
+ asset->iUid = aURI.AllocL();
+
+ if ( aPermission.iParentUID )
+ {
+ asset->iParentRights = aPermission.iParentUID->AllocL();
+ }
+
+ rights->SetPermissionL( aPermission );
+ rights->SetAssetL( *asset );
+
+ CleanupStack::PopAndDestroy(); // asset
+ CleanupStack::Pop(), // rights
+
+ aRights = rights;
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CDRMMessageParser* CDRMMessageParser::NewL( void )
+ {
+ CDRMMessageParser* self = new( ELeave ) CDRMMessageParser();
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop();
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::CDRMMessageParser
+// Constructor.
+// -----------------------------------------------------------------------------
+//
+CDRMMessageParser::CDRMMessageParser() :
+ iDcfCreator( NULL ),
+ iBoundary( NULL ),
+ iContentType( NULL ),
+ iState( ESearchingBoundary ),
+ iInputBuffer( NULL, 0, 0 )
+ {
+ iDCFHeaderSize[ 0 ] = KMaxTUint32;
+ iDCFHeaderSize[ 1 ] = KMaxTUint32;
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CDRMMessageParser::~CDRMMessageParser()
+ {
+ TInt error = KErrNone;
+ TRAP( error, FinalizeMessageParserL() );
+
+ Reset();
+
+ User::Free( const_cast< TUint8* >( iInputBuffer.Ptr() ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CDRMMessageParser::InitializeMessageParserL( RWriteStream& aStream )
+ {
+ Reset();
+
+ iDcfCreator = COma1DcfCreator::NewL();
+
+ iOutputStream = aStream;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::ProcessDataL
+// Choose which operation is required.
+// -----------------------------------------------------------------------------
+EXPORT_C void CDRMMessageParser::ProcessMessageDataL( const TDesC8& aMessageData )
+ {
+ /*
+ * What happens here is:
+ * - a boundary string is located and extracted
+ * - MIME header is read, and based on content-type field the internal
+ * state is set to either EReadingRightsPart or EReadingContentPart.
+ * - after processing the MIME part, internal state is updated again to
+ * EReadingHeaderPart if there are several MIME parts in the DRM
+ * message.
+ * - data is consumed from iInputData in each phase.
+ * - after everything is done, internal state is set to EAllDone.
+ */
+ if ( iState & EBroken )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ if ( iState & EAllDone )
+ {
+ return;
+ }
+
+ iInputData.Set( aMessageData );
+
+ while( iInputData.Length() )
+ {
+ if ( iState & EReadingHeaderPart )
+ {
+ ReadHeaderL();
+ }
+ else
+ {
+ if ( iState & EReadingContentPart )
+ {
+ HandleContentDataL();
+ }
+ else
+ {
+ if ( iState & EReadingRightsPart )
+ {
+ HandleRightsDataL();
+ }
+ else
+ {
+ FindBoundaryL();
+ }
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::FinalizeL
+// Finalize the message parser.
+// -----------------------------------------------------------------------------
+EXPORT_C void CDRMMessageParser::FinalizeMessageParserL()
+ {
+ TInt error( KErrNone );
+
+ if ( iState & EEncryptStreamOk )
+ {
+ if ( iInputBuffer.Length() )
+ {
+ // Message is not parsed fully ==> error.
+ // Try to delete the RO if it is possible.
+ DeletePermission();
+ error = KDRMMessageMalformed;
+ }
+
+ ClearBit( EEncryptStreamOk );
+ iDcfCreator->EncryptFinalizeL();
+
+ iOutputStream.CommitL();
+ }
+
+ Reset();
+
+ User::LeaveIfError( error );
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::ConstructL()
+ {
+ // Make some extra room for crazy b64decode().
+ iInputBuffer.Set( reinterpret_cast< TUint8* >(
+ User::AllocL( KInputBufferSize + 2 ) ),
+ 0,
+ KInputBufferSize );
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::HandleContentDataL
+// Process the content data:
+// - base64 decoding
+// - boundary checks
+// - forward the processed data to ProcessContentDataL
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::HandleContentDataL()
+ {
+ TPtrC8 res( NULL, 0 );
+ TBool cont( ETrue );
+ TInt remainder( 0 );
+
+ // Loop until
+ // - PrepareContentDataL leaves
+ // - boundary end marker is found
+ // - iInputBuffer is not updated anymore.
+ for ( PrepareContentDataL();
+ iInputBuffer.Length() &&
+ ( remainder != iInputBuffer.Length() ) &&
+ cont;
+ PrepareContentDataL() )
+ {
+ TInt pos = iInputBuffer.Find( *iBoundary );
+
+ if ( pos >= 0 )
+ {
+ if ( pos < KBoundaryMarkLength + 1 )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ res.Set( iInputBuffer.Left( pos - KBoundaryMarkLength ) );
+
+ StripEndLineL( res );
+
+ cont = EFalse;
+ }
+ else
+ {
+ // All the data cannot be processed immediately, because
+ // there may be only a part of boundary string in this buffer
+ // and the rest is got from the next input descriptor.
+ remainder = iBoundary->Length() + KBoundaryMarkLength + 1;
+
+ if ( iInputBuffer.Length() <= remainder )
+ {
+ return;
+ }
+
+ res.Set( iInputBuffer.Left( iInputBuffer.Length() -
+ remainder ) );
+ }
+
+ if ( iState & EBase64 )
+ {
+ iUsedFromInput = HandleBase64DataL( res );
+ }
+
+ else
+ {
+ iUsedFromInput = res.Length();
+ }
+
+ ProcessContentDataL( res );
+
+ CompressInputBuffer();
+
+ remainder = iInputBuffer.Length();
+ }
+
+ if ( !cont )
+ {
+ // Discard all the remaining data.
+ ClearBit( EReadingContentPart );
+ SetBit( EAllDone );
+ iInputBuffer.SetLength( 0 );
+ iInputData.Set( NULL, 0 );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::HandleRightsDataL
+// - check if the boundary is reached
+// - check if the whole rights part is read, and allocate memory && copy the RO
+// if so
+// - save the rights object
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::HandleRightsDataL()
+ {
+ TPtrC8 res( NULL, 0 );
+
+ do
+ {
+ res.Set( GetLineL() );
+
+ TInt pos = res.Find( *iBoundary );
+
+ if ( pos >= KBoundaryMarkLength )
+ {
+ if ( res.Left( KBoundaryMarkLength ) == KBoundaryMark )
+ {
+ // Allow empty RO here. If it is not allowed by
+ // HandleRightsMessagePart(), an error is thrown.
+ TBool last = EFalse;
+
+ // Returns always true.
+ IsBoundary( res, last );
+
+ if ( last )
+ {
+ TInt error( KErrNone );
+ RPointerArray< CDRMRights > rights;
+ TPtrC8 ptr( iInputBuffer.Ptr(),
+ pos - KBoundaryMarkLength );
+
+ error = ProcessRightsObject(ptr, rights);
+ rights.ResetAndDestroy();
+
+ if ( !error )
+ {
+ SetBit( EAllDone );
+ }
+ else
+ {
+ SetBrokenStateL( error );
+ }
+ }
+ else
+ {
+ // Save the RO since the CID needs to be either changed
+ // or created.
+ iRightsData = iInputBuffer.Left( iUsedFromInput -
+ res.Length() ).AllocL();
+ }
+
+ CompressInputBuffer();
+
+ ClearBit( EReadingRightsPart );
+ ClearBit( EGotContentType );
+ ClearBit( EGotContentEncoding );
+
+ SetBit( EGotRightsPart );
+ SetBit( EReadingHeaderPart );
+
+ res.Set( NULL, 0 );
+#ifndef __DRM_FULL
+ User::Leave(KErrNotSupported);
+#endif
+ }
+ else
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+ }
+ else
+ {
+ if ( pos >= 0 )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+ }
+ } while ( res.Length() );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::FindBoundaryL
+// Tries to locate the boundary string from the available data in iInputBuffer.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::FindBoundaryL()
+ {
+ TPtrC8 line( NULL, 0 );
+
+ FOREVER
+ {
+ line.Set( GetLineL() );
+
+ if ( line.Length() > KBoundaryMarkLength )
+ {
+ TInt size = 0;
+
+ if ( line.Left( KBoundaryMarkLength ) == KBoundaryMark )
+ {
+ size = line.Length() - KBoundaryMarkLength - 1;
+
+ if ( line[ line.Length() - 2 ] == '\r' )
+ {
+ --size;
+ }
+
+ iBoundary = line.Mid( KBoundaryMarkLength, size ).AllocL();
+
+ SetBit( EGotBoundary );
+ SetBit( EReadingHeaderPart );
+
+ CompressInputBuffer();
+
+ return;
+ }
+ }
+ else
+ {
+ if ( line.Length() == 0 )
+ {
+ return;
+ }
+ }
+
+ // Something else, not interested.
+ CompressInputBuffer();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CDRMMessageParser::ReadHeaderL
+// The boundary is read and the following part is (should be) either a RO part
+// or content part. The data is kept in iInputBuffer until the whole header
+// part of the MIME header part is received. After plain "\r\n" line is
+// received and content-type is defined, iState is updated.
+// ----------------------------------------------------------------------------
+//
+void CDRMMessageParser::ReadHeaderL()
+ {
+ TPtrC8 line( NULL, 0 );
+ TPtrC8 ptr( NULL, 0 );
+
+ FOREVER
+ {
+ ///////////////////////////////////////////////////////////////////
+ // Process the MIME header line-by-line. Process the lines if they
+ // contain some information that is found useful. Update the
+ // internal state according to findings.
+ ///////////////////////////////////////////////////////////////////
+ line.Set( GetLineL() );
+
+ if ( line.Length() )
+ {
+ if ( line == KEndLine || line == KNewLine )
+ {
+ ///////////////////////////////////////////////
+ // MIME header is read. Check what to do next.
+ ///////////////////////////////////////////////
+ if ( iState & EGotContentType )
+ {
+ // Sanity check: Either EReadingRightsPart or
+ // EReadingContentPart must defined.
+ __ASSERT_DEBUG( ( iState & EReadingRightsPart ) ||
+ ( iState & EReadingContentPart ),
+ User::Invariant() );
+
+ ClearBit( EReadingHeaderPart );
+
+ CompressInputBuffer();
+
+ // Check which part was read.
+ // If content part is being processed, some checkings
+ // need to be made.
+ if ( iState & EReadingContentPart )
+ {
+ if ( iContentType->CompareF( KDRMContentType ) == 0 )
+ {
+ if ( iState & EGotRightsPart )
+ {
+ // CD DCF.
+ SetBrokenStateL( KErrCANotSupported );
+ }
+
+ InitDCFBufferL();
+
+ SetBit( EDCFFile );
+ }
+ else
+ {
+ // Non-DCF FL content or normal CD content.
+ // Create or modify the CID, save the RO.
+ HandleFlContentL();
+
+ iDcfCreator->EncryptInitializeL(
+ iOutputStream,
+ *iContentType,
+ iRightsObject );
+ SetBit( EEncryptStreamOk );
+
+ // The RO handle iRightsObject is kept in order
+ // to delete the rights in case of content
+ // encryption error. In that case, this will
+ // generate unnecessary "RO Added / RO Deleted"
+ // notifications, but so what. "More correct"
+ // way of doing would be modifying
+ // EncryptInitialize not to
+ // save the RO, but then the key would have to
+ // be given to it by other means. Since we are
+ // not their "friend" class, we cannot access
+ // their members, and making them to ask our
+ // members when doing EncryptInitialize/Finalize
+ // might cause some problems perhaps.
+ }
+
+ delete iContentType;
+ iContentType = NULL;
+ }
+
+ return;
+ }
+
+ // Empty MIME header.
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ ///////////////////////////////////
+ // Check the line for content-type.
+ ///////////////////////////////////
+ if ( line.Length() > KContentType().Length() &&
+ !( line.Left( KContentType().Length() ).CompareF( KContentType ) ) )
+ {
+ if ( iState & EGotContentType )
+ {
+ // Content-type given twice.
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ ptr.Set( HeaderValueL( line ) );
+
+ SetBit( EGotContentType );
+
+ // Which part this is: rights or the actual content?
+ if ( ( ptr.CompareF( KDRMXMLRightsType ) == 0 ) ||
+ ( ptr.CompareF( KDRMWBXMLRightsType ) == 0 ) )
+ {
+ if ( iState & EGotRightsPart )
+ {
+ // Rights are given twice.
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ SetBit( EReadingRightsPart );
+ }
+ else
+ {
+ if ( iState & EGotContentPart )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ SetBit( EReadingContentPart );
+
+ // Content-type is saved for future use.
+ iContentType = ptr.AllocL();
+ }
+ }
+ else
+ {
+ ////////////////////////////////////////////////
+ // Check the line for content-transfer-encoding.
+ ////////////////////////////////////////////////
+ if ( line.Length() > KContentTransferEncoding().Length() &&
+ !( line.Left( KContentTransferEncoding().Length() ).
+ CompareF( KContentTransferEncoding ) ) )
+ {
+ if ( iState & EGotContentEncoding )
+ {
+ // Double line.
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ ptr.Set( HeaderValueL( line ) );
+
+ SetBit( EGotContentEncoding );
+
+ // Throw an error if content-transfer-encoding
+ // is something we don't support.
+ if ( ptr.CompareF( KEncoding8bit ) &&
+ ptr.CompareF( KEncoding7bit) &&
+ ptr.CompareF( KEncodingBinary ) )
+ {
+ if ( ptr.CompareF( KEncodingBase64 ) )
+ {
+ SetBrokenStateL( KErrCANotSupported );
+ }
+
+ // So it has to be Base64.
+ SetBit( EBase64 );
+ }
+ }
+ else
+ {
+ //////////////////////////////////////////
+ // Check the line for end boundary marker.
+ //////////////////////////////////////////
+ TBool final( EFalse );
+
+ if ( IsBoundary( line, final ) )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ // Else: some X-field, parameter or something else.
+ // The line is ignored.
+ }
+ }
+
+ CompressInputBuffer();
+ }
+
+ else
+ {
+ // No line available yet.
+ return;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::GetLineL
+// Return a descriptor representing a single line ending to \n in iInputBuffer.
+// -----------------------------------------------------------------------------
+//
+TPtrC8 CDRMMessageParser::GetLineL()
+ {
+ TInt pos = 0;
+ TPtrC8 res( NULL, 0 );
+
+ if ( iInputBuffer.Length() > iUsedFromInput )
+ {
+ pos = iInputBuffer.Mid( iUsedFromInput ).Find( KNewLine );
+
+ if ( pos >= 0 )
+ {
+ res.Set( iInputBuffer.Mid( iUsedFromInput, pos - iUsedFromInput + 1 ) );
+ iUsedFromInput = pos + 1;
+ }
+ }
+
+ if ( res.Length() == 0 )
+ {
+ if ( iInputData.Length() )
+ {
+ pos = iInputData.Find( KNewLine );
+
+ if ( pos < 0 )
+ {
+ if ( iInputBuffer.MaxSize() - iInputBuffer.Length() <
+ iInputData.Length() )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ iInputBuffer.Append( iInputData );
+ iInputData.Set( NULL, 0 );
+ }
+ else
+ {
+ if ( iInputBuffer.MaxSize() - iInputBuffer.Length() <
+ pos + 1 )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ iInputBuffer.Append( iInputData.Left( pos + 1 ) );
+ res.Set( iInputBuffer.Mid( iUsedFromInput ) );
+ iUsedFromInput = iInputBuffer.Length();
+
+ iInputData.Set( iInputData.Mid( pos + 1 ) );
+ }
+ }
+ }
+
+ return res;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::HeaderValueL
+// Return a descriptor representing a header value in aLine.
+// -----------------------------------------------------------------------------
+//
+TPtrC8 CDRMMessageParser::HeaderValueL( const TDesC8& aLine )
+ {
+ TInt pos( 0 );
+ TPtrC8 res( NULL, 0 );
+
+ pos = aLine.Find( KColon );
+
+ if ( pos <= 0 )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ pos += 1;
+
+ while ( pos < aLine.Length() &&
+ TChar( aLine[ pos ] ).IsSpace() )
+ {
+ ++pos;
+ }
+
+ // Don't overindex.
+ if ( pos == aLine.Length() )
+ {
+ // Full of whitespaces.
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ // Drop possible parameters.
+ res.Set( aLine.Mid( pos ) );
+ pos = res.Find( KSemiColon );
+
+ if ( pos >= 0 )
+ {
+ res.Set( res.Left( pos ) );
+ }
+
+ pos = res.Length();
+
+ if ( !pos )
+ {
+ // Just parameters, no actual value.
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ // This can't underflow, since otherwise there would be only
+ // semicolon & parameters (checked earlier).
+ while( TChar( res[ pos - 1 ] ).IsSpace() )
+ {
+ --pos;
+ }
+
+ return res.Left( pos );
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::CompressInputBuffer
+// Compress iInputBuffer.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::CompressInputBuffer()
+ {
+ if ( iUsedFromInput )
+ {
+ const TInt size = iInputBuffer.Length() - iUsedFromInput;
+
+ Mem::Copy( const_cast< TUint8* >( iInputBuffer.Ptr() ),
+ iInputBuffer.Ptr() + iUsedFromInput,
+ size );
+
+ iInputBuffer.SetLength( size );
+ iUsedFromInput = 0;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::PrepareContentDataL
+// Fills the iInputBuffer from iInputData.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::PrepareContentDataL()
+ {
+ if ( iInputData.Length() )
+ {
+ if ( iInputBuffer.Length() == iInputBuffer.MaxSize() )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ const TInt size = Min( iInputBuffer.MaxSize() - iInputBuffer.Length(),
+ iInputData.Length() );
+
+ iInputBuffer.Append( iInputData.Left( size ) );
+
+ iInputData.Set( iInputData.Mid( size ) );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::HandleBase64DataL
+// Decode base64 encoded data from and to aData descriptor.
+//
+// -----------------------------------------------------------------------------
+//
+TInt CDRMMessageParser::HandleBase64DataL( TPtrC8& aData )
+ {
+ TUint8* consumed = const_cast< TUint8* >( aData.Ptr() );
+ TUint32 temp1 = 0;
+ TUint8 temp2 = 0;
+
+ for ( temp1 = 0, temp2 = 0; ( TInt )temp1 < aData.Length(); ++temp1 )
+ {
+ if ( ValidB64CharL( *( aData.Ptr() + temp1 ) ) )
+ {
+ ++temp2;
+ if ( temp2 == 4 )
+ {
+ consumed = const_cast< TUint8* >( aData.Ptr() ) + temp1;
+ temp2 = 0;
+ }
+ }
+ }
+
+ if ( consumed != aData.Ptr() )
+ {
+ User::LeaveIfError( b64decode( const_cast< TUint8* >( aData.Ptr() ),
+ consumed - aData.Ptr() + 1,
+ const_cast< TUint8* >( aData.Ptr() ),
+ &temp1 ) );
+
+ aData.Set( aData.Ptr(), temp1 );
+
+ temp1 = consumed - aData.Ptr() + 1;
+ }
+
+ else
+ {
+ aData.Set( aData.Ptr(), 0 );
+ temp1 = 0;
+ }
+
+ return static_cast< TInt >( temp1 );
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::StripEndLineL
+// Remove \r\n from the end of the line. Update aBuf accordingly.
+// It is allowed that only \n exists, since some WAP gateways used to
+// strip \r's.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::StripEndLineL( TPtrC8& aBuf )
+ {
+ TInt newSize( aBuf.Length() );
+
+ if ( aBuf.Right( 1 ) == KNewLine )
+ {
+ --newSize;
+
+ if ( ( aBuf.Length() > 1 ) &&
+ ( aBuf.Right( 2 ) == KEndLine ) )
+ {
+ --newSize;
+ }
+
+ aBuf.Set( aBuf.Left( newSize ) );
+ }
+ else
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::IsBoundary
+// Check if the given line is a boundary line. Also check if the line is
+// the end boundary.
+// -----------------------------------------------------------------------------
+//
+TBool CDRMMessageParser::IsBoundary( const TDesC8& aLine, TBool& aLast ) const
+ {
+ TBool res = EFalse;
+
+ __ASSERT_DEBUG( iBoundary, User::Invariant() );
+
+ if ( iState & EGotBoundary )
+ {
+ if ( aLine.Length() > KBoundaryMarkLength + iBoundary->Length() )
+ {
+ TPtrC8 tmp( NULL, 0 );
+
+ if ( ( aLine.Left( KBoundaryMarkLength ) == KBoundaryMark ) &&
+ ( aLine.Mid( KBoundaryMarkLength, iBoundary->Length() ).
+ Compare( *iBoundary ) == 0 ) )
+ {
+ res = ETrue;
+
+ tmp.Set( aLine.Right( aLine.Length() -
+ KBoundaryMarkLength -
+ iBoundary->Length() ) );
+
+ if ( ( tmp.Length() >= KBoundaryMarkLength ) &&
+ ( tmp.Left( KBoundaryMarkLength ) == KBoundaryMark ) )
+ {
+ aLast = ETrue;
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::HandleFlContentL
+// Process FL/CD rights object.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::HandleFlContentL()
+ {
+ __ASSERT_DEBUG( !( iState & EDCFFile ), User::Invariant() );
+
+ if ( iRightsData )
+ {
+ HBufC8* cid( NULL );
+ HBufC8* buf( NULL );
+
+ // RO was found from DRM message.
+ CreateCDCIDL( cid );
+ CleanupStack::PushL( cid );
+
+ buf = iRightsData;
+ CleanupStack::PushL( buf );
+ iRightsData = NULL;
+
+ ProcessRightsDataL( *cid,
+ *buf );
+
+ CleanupStack::PopAndDestroy(); // buf
+ CleanupStack::PopAndDestroy(); // cid
+ }
+ else
+ {
+ TInt error = RetrieveFlRights();
+ if ( error )
+ {
+ SetBrokenStateL( error );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::ProcessRightsData
+// Process DRM message -style rights object and fetch it to iRightsObject if
+// necessary.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::ProcessRightsDataL(
+ const TDesC8& aCID,
+ const TDesC8& aData )
+ {
+ __ASSERT_DEBUG( !iRightsObject, User::Invariant() );
+
+ TInt start = aData.Find(KRightsStartTag);
+ TInt end = aData.LocateReverse('>');
+
+ if ( start >= 0 && end > start )
+ {
+ TDRMUniqueID localID( 0 );
+ CDrmRightsParser* parser( NULL );
+ CDRMAsset* asset( NULL );
+ RDRMRightsClient client;
+ TPtrC8 ptr( &aData[start], end - start + 1 );
+ TBuf8< KDCFKeySize > key;
+ key.SetLength(KDCFKeySize);
+ RPointerArray< CDRMRights > rights;
+
+ TCleanupItem cleanup( DoResetAndDestroy, &rights );
+ CleanupStack::PushL( cleanup );
+
+ User::LeaveIfError( client.Connect() );
+ CleanupClosePushL( client );
+
+ parser = CDrmRightsParser::NewL();
+ CleanupStack::PushL( parser );
+
+ parser->ParseL( ptr, rights );
+
+ if (rights.Count()==0)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ client.GetRandomDataL(key);
+
+ User::LeaveIfError( client.AddRecord(
+ key,
+ rights[0]->GetPermission(),
+ aCID,
+ localID) );
+
+ iRightsObject = CDRMRights::NewL();
+
+ asset = CDRMAsset::NewLC();
+ asset->iUid = aCID.AllocL();
+
+ iRightsObject->SetAssetL(*asset);
+ iRightsObject->SetPermissionL(rights[0]->GetPermission());
+
+ CleanupStack::PopAndDestroy( 4 ); // asset, parser, client, rights
+ }
+ else
+ {
+ SetBrokenStateL( KErrArgument );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::ProcessContentDataL
+// Handle DCF file's CID manipulation in "DCF in DRM message" case.
+// Send the data to EncryptUpdateL if encryption is needed.
+// -----------------------------------------------------------------------------
+//
+void CDRMMessageParser::ProcessContentDataL( TPtrC8& aData )
+ {
+ // First, check if the content is DCF stuff.
+ if ( iState & EDCFFile )
+ {
+ // Sanity check: DCF File with RO is illegal.
+ __ASSERT_DEBUG( !iRightsObject, User::Invariant() );
+
+ ProcessDCFDataL( aData );
+ }
+ else
+ {
+ // No, plain FL content.
+ iDcfCreator->EncryptUpdateL( aData );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMMessageParser::ValidB64CharL
+// Determine if the given character is valid base64 character, and leave
+// if it is not.
+// -----------------------------------------------------------------------------
+//
+TBool CDRMMessageParser::ValidB64CharL( const TUint8 aChar )
+ {
+ // Allowed characters are '0'...'9', 'A'...'Z', 'a'...'z', '+', '/', '='
+ if ( ( aChar >= 48 && aChar <= 57 ) ||
+ ( aChar >= 65 && aChar <= 90 ) ||
+ ( aChar >= 97 && aChar <= 122 ) ||
+ ( aChar == 43 ) ||
+ ( aChar == 47 ) ||
+ ( aChar == 61 ) )
+ {
+ return ETrue;
+ }
+
+ if ( ( aChar != 0x0D ) && ( aChar != 0x0A ) )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// DRMCommon::ProcessMessage
+//
+// -----------------------------------------------------------------------------
+EXPORT_C TInt CDRMMessageParser::ProcessMessage(
+ HBufC8*& aDRMMessage)
+ {
+ TInt error( KErrNone );
+ TRAP( error, DoProcessMessageL( aDRMMessage ) );
+
+ return error;
+ }
+
+// -----------------------------------------------------------------------------
+// DRMCommon::ProcessRightsObject
+// Processes a rights objects and saves it in the rights database.
+// -----------------------------------------------------------------------------
+EXPORT_C TInt CDRMMessageParser::ProcessRightsObject(
+ const TDesC8& aRightsObject,
+ RPointerArray<CDRMRights>& aRightsDetail)
+ {
+ TInt error( KErrNone );
+ TRAP( error, DoProcessRightsObjectL( aRightsObject,
+ aRightsDetail ) );
+
+ return error;
+ }
+
+void CDRMMessageParser::SetBit( TUint32 aBit )
+ {
+ iState |= aBit;
+ }
+
+void CDRMMessageParser::ClearBit( TUint32 aBit )
+ {
+ iState &= ~aBit;
+ }
+
+void CDRMMessageParser::Reset()
+ {
+ delete iDCFBuffer;
+ iDCFBuffer = NULL;
+
+ delete iDcfCreator;
+ iDcfCreator = NULL;
+
+ delete iRightsData;
+ iRightsData = NULL;
+
+ delete iRightsObject;
+ iRightsObject = NULL;
+
+ delete iBoundary;
+ iBoundary = NULL;
+
+ delete iContentType;
+ iContentType = NULL;
+
+ iInputBuffer.SetLength( 0 );
+
+ iState = ESearchingBoundary;
+ iDCFHeaderSize[ 0 ] = KMaxTUint32;
+ iDCFHeaderSize[ 1 ] = KMaxTUint32;
+ }
+
+void CDRMMessageParser::DoProcessMessageL( HBufC8*& aDRMMessage )
+ {
+ TDeleteFileData fileData;
+ RFileWriteStream output;
+ RFile file;
+ TInt size( 0 );
+
+ User::LeaveIfError( fileData.aFs.Connect() );
+ CleanupClosePushL( fileData.aFs );
+
+ TCleanupItem cleanup( DoDeleteFile, &fileData );
+ CleanupStack::PushL( cleanup );
+
+#ifndef RD_MULTIPLE_DRIVE
+
+ User::LeaveIfError( output.Temp( fileData.aFs,
+ KTempPath,
+ fileData.aName,
+ EFileWrite ) );
+
+#else //RD_MULTIPLE_DRIVE
+
+ TInt driveNumber( -1 );
+ TChar driveLetter;
+ DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber );
+ fileData.aFs.DriveToChar( driveNumber, driveLetter );
+
+ TFileName tempPath;
+ tempPath.Format( KTempPath, (TUint)driveLetter );
+
+ User::LeaveIfError( output.Temp( fileData.aFs,
+ tempPath,
+ fileData.aName,
+ EFileWrite ) );
+
+#endif
+
+ CleanupClosePushL( output );
+
+ InitializeMessageParserL( output );
+ ProcessMessageDataL( *aDRMMessage );
+ FinalizeMessageParserL();
+
+ CleanupStack::PopAndDestroy(); // output
+
+ User::LeaveIfError( file.Open( fileData.aFs, fileData.aName, EFileRead ) );
+ CleanupClosePushL( file );
+
+ User::LeaveIfError( file.Size( size ) );
+
+ if ( size > aDRMMessage->Des().MaxSize() )
+ {
+ HBufC8* tmp( NULL );
+
+ delete aDRMMessage;
+ aDRMMessage = NULL;
+
+ tmp = HBufC8::NewLC( size );
+ TPtr8 data( tmp->Des() );
+
+ User::LeaveIfError( file.Read( data ) );
+ CleanupStack::Pop(); // tmp
+
+ aDRMMessage = tmp;
+ }
+ else
+ {
+ TPtr8 data( aDRMMessage->Des() );
+ User::LeaveIfError( file.Read( data ) );
+ }
+
+ CleanupStack::PopAndDestroy( 3 ); // file, cleanup, fileData.aFs
+ }
+
+void CDRMMessageParser::DoProcessRightsObjectL(
+ const TDesC8& aRightsObject,
+ RPointerArray<CDRMRights>& aRightsDetail )
+ {
+ CDrmRightsParser* parser = NULL;
+ TInt start;
+ TInt end;
+ TPtrC8 ptr(0, 0);
+
+ start = aRightsObject.Find(KRightsStartTag);
+ end = aRightsObject.LocateReverse('>');
+
+ TCleanupItem cleanup( DoResetAndDestroy, &aRightsDetail );
+ CleanupStack::PushL( cleanup );
+
+ if ( start != KErrNotFound && end != KErrNotFound )
+ {
+ // xml
+ parser = CDrmRightsParser::NewL();
+ CleanupStack::PushL(parser);
+
+ ptr.Set(&aRightsObject[start], end - start + 1);
+
+ parser->ParseAndStoreL(ptr, aRightsDetail);
+
+ if (aRightsDetail.Count() == 0)
+ {
+ User::Leave( KErrArgument );
+ }
+
+ CleanupStack::PopAndDestroy(); // parser
+ }
+ else if (start == KErrNotFound )
+ {
+ // wbxml
+ parser = CDrmRightsParser::NewL(CDrmRightsParser::EWbxmlParser);
+ CleanupStack::PushL(parser);
+
+ parser->ParseAndStoreL(aRightsObject, aRightsDetail);
+ if (aRightsDetail.Count() == 0)
+ {
+ User::Leave( KErrArgument );
+ }
+
+ CleanupStack::PopAndDestroy(); // parser
+ }
+ else
+ {
+ User::Leave( KErrArgument );
+ }
+
+ CleanupStack::Pop(); // cleanup
+ }
+
+void CDRMMessageParser::DeletePermission()
+ {
+ if ( iRightsObject )
+ {
+ if ( !( iState & EFLContent ) )
+ {
+ HBufC8* URI = NULL;
+
+ if ( !( iRightsObject->GetContentURI( URI ) ) )
+ {
+ __ASSERT_DEBUG( URI, User::Invariant() );
+
+ RDRMRightsClient client;
+
+ TInt error = client.Connect();
+
+ if ( !error )
+ {
+ // Don't care if it fails.
+ client.DeleteDbEntry( *URI, iRightsObject->GetLocalID() );
+
+ client.Close();
+ }
+
+ delete URI;
+ URI = NULL;
+ }
+ }
+
+ delete iRightsObject;
+ iRightsObject = NULL;
+ }
+ }
+
+void CDRMMessageParser::SetBrokenStateL( const TInt aError )
+ {
+ SetBit( EBroken );
+ DeletePermission();
+
+ User::Leave( aError );
+ }
+
+void CDRMMessageParser::InitDCFBufferL()
+ {
+ iDCFBuffer = HBufC8::New( KInitialDCFBufferSize );
+
+ if ( !iDCFBuffer )
+ {
+ SetBrokenStateL( KErrNoMemory );
+ }
+ }
+
+void CDRMMessageParser::CreateCDCIDL( HBufC8*& aCID )
+ {
+ aCID = HBufC8::NewL( KCDContentIDLength );
+ TPtr8 des( aCID->Des() );
+ TBuf8<KCDPlainIDLength> id;
+ id.SetLength(KCDPlainIDLength);
+
+ RDRMRightsClient client;
+ CleanupClosePushL(client);
+ User::LeaveIfError( client.Connect() );
+ client.GetRandomDataL(id);
+ CleanupStack::PopAndDestroy();
+
+ des = KFLPrefix;
+
+ for (TInt i = 0; i < KCDPlainIDLength; i++)
+ {
+ des.AppendNumFixedWidth( id[i], EDecimal, 1 );
+ }
+
+ des.Append( KFLSuffix );
+ }
+
+TInt CDRMMessageParser::RetrieveFlRights()
+ {
+ __ASSERT_DEBUG( !iRightsObject, User::Invariant() );
+
+ RDRMRightsClient client;
+ TInt error( client.Connect() );
+
+ if ( !error )
+ {
+ TRAP( error, EnsureFLRightsExistL( client, &iRightsObject ) );
+
+ client.Close();
+ }
+
+ return error;
+ }
+
+void CDRMMessageParser::ProcessDCFDataL( TPtrC8& aDCFData )
+ {
+ TBool doCommit( EFalse );
+
+ // Loop until all available data is either cached or processed.
+ // What happens is
+ // - modify Content-URI
+ // - modify DCF header part
+ // - dump the rest of the available data to output.
+ while ( iDCFBuffer->Length() || aDCFData.Length() )
+ {
+ if ( !( iState & EDCFURIModified ) )
+ {
+ //////////////////////////////////////////////////////////////////
+ // Modify ContentURI.
+ //////////////////////////////////////////////////////////////////
+ FillDCFBufferL( aDCFData );
+
+ if ( iDCFBuffer->Length() > 3 )
+ {
+ TInt pos = 0;
+ TUint8* data = const_cast< TUint8* > ( iDCFBuffer->Ptr() );
+
+ if ( data[ 0 ] != 1 )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ // Cache the data until
+ // - version,
+ // - ContentTypeLen,
+ // - ContentURILen,
+ // - ContentType and
+ // - ContentURI
+ // have been received.
+ pos = data[ 1 ] + 3;
+ if ( iDCFBuffer->Length() < pos + data[ 2 ] )
+ {
+ return;
+ }
+
+ // Sanity check. URI has to be more than four ("cid:") octets.
+ if ( data[ 2 ] < 5 )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ if ( Mem::CompareF( &data[ pos ],
+ KCIDStringLength,
+ KCIDString().Ptr(),
+ KCIDStringLength ) == 0 )
+ {
+ // The data length doesn't change, so Mem::Copy() is safe.
+ Mem::Copy( &data[ pos ],
+ KFLPrefix().Ptr(),
+ KFLKPrefixLength );
+
+ iOutputStream.WriteL( iDCFBuffer->Left( pos + data[ 2 ] ) );
+
+ doCommit = ETrue;
+
+ CompressDCFBuffer( pos + data[ 2 ] );
+
+ SetBit( EDCFURIModified );
+ }
+ else
+ {
+ // Discard the broken DCF
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+ }
+ else
+ {
+ // Not enough data yet.
+ return;
+ }
+ }
+ else
+ {
+ //////////////////////////////////////////////////////////////////
+ // URI is now modified. Modify DCF headers if necessary.
+ //////////////////////////////////////////////////////////////////
+ if ( !( iState & EDCFHeadersModified ) )
+ {
+ FillDCFBufferL( aDCFData );
+
+ // Figure out how much data there is in the header part and/or
+ // in the data part.
+ if ( ( iDCFHeaderSize[ 0 ] == KMaxTUint32 ) &&
+ ( iDCFHeaderSize[ 1 ] == KMaxTUint32 ) )
+ {
+ TUint8 used( 0 );
+
+ // uintvar has 1...5 octets and we need two uintvars before
+ // anything can be done. Still, there has to be at least
+ // 12 octets of data in total to make the DCF legal. But here
+ // we just check the two uintvars.
+ if ( iDCFBuffer->Length() < 10 )
+ {
+ // Not enough data yet.
+ // No need to flush aDCFData at this point, since it
+ // simply cannot contain anything at this point.
+ __ASSERT_DEBUG( !aDCFData.Length(), User::Invariant() );
+ break;
+ }
+
+ // Read header field length & data length.
+ for ( TUint8 count = 0; count < 2; ++count )
+ {
+ TInt size( 0 );
+
+ TWspPrimitiveDecoder decoder(
+ iDCFBuffer->Mid( used ) );
+ size = decoder.UintVar( iDCFHeaderSize[ count ] );
+
+ // Sanity check.
+ if ( size < 1 || iDCFHeaderSize[ count ] >= KMaxTInt )
+ {
+ SetBrokenStateL( KDRMMessageMalformed );
+ }
+
+ used += size;
+ }
+
+ CompressDCFBuffer( used );
+ }
+ else
+ {
+ // We know the original header size now.
+ // Wait until the whole header is read.
+ if ( static_cast< TUint32 >( iDCFBuffer->Length() ) <
+ iDCFHeaderSize[ 0 ] )
+ {
+ if ( !aDCFData.Length() )
+ {
+ // All available data is now processed.
+ break;
+ }
+ }
+ else
+ {
+ TUint offset( 0 );
+ TUint length( 0 );
+ HBufC8* newHeader = NULL;
+
+ if ( FindDCFHeader( KRightsIssuer,
+ offset,
+ length ) )
+ {
+ // The header field exists.
+ TInt pos( 0 );
+ TPtr8 trim( const_cast< TUint8* >(
+ iDCFBuffer->Ptr() ) + offset,
+ length,
+ length );
+
+ iDCFHeaderSize[ 0 ] -= length; // remove old data.
+
+ // No colon, no header value.
+ pos = trim.Find( KColon );
+ if ( pos > 0 )
+ {
+ trim.Set( const_cast< TUint8* >( trim.Ptr() ) + pos + 1,
+ trim.Length() - pos - 1,
+ trim.Length() - pos - 1 );
+
+ // Skip whitespaces
+ trim.TrimLeft();
+ trim.TrimRight();
+
+ if ( trim.Length() )
+ {
+ // Something to process
+ newHeader = EncryptDCFFieldLC( trim );
+
+ iDCFHeaderSize[ 0 ] += KRightsIssuer().Length();
+ iDCFHeaderSize[ 0 ] += newHeader->Length();
+ iDCFHeaderSize[ 0 ] += 3; // ":" and CRLF
+ }
+ }
+ }
+
+ // Write the uintvars to output.
+ for ( TUint8 loop = 0; loop < 2; ++loop )
+ {
+ TWspPrimitiveEncoder encoder;
+ HBufC8* var( encoder.UintVarL( iDCFHeaderSize[ loop ] ) );
+
+ CleanupStack::PushL( var );
+
+ iOutputStream.WriteL( *var );
+
+ CleanupStack::PopAndDestroy(); // var
+ }
+
+ // Dump the header data to output stream.
+ iOutputStream.WriteL( iDCFBuffer->Left( offset ) );
+
+ if ( newHeader )
+ {
+ iOutputStream.WriteL( KRightsIssuer );
+ iOutputStream.WriteL( KColon );
+ iOutputStream.WriteL( *newHeader );
+
+ CleanupStack::PopAndDestroy(); // newHeader
+ newHeader = NULL;
+
+ iOutputStream.WriteL( KEndLine );
+ }
+
+ iOutputStream.WriteL(
+ iDCFBuffer->Right( iDCFBuffer->Length() -
+ offset -
+ length ) );
+
+ doCommit = ETrue;
+
+ CompressDCFBuffer( iDCFBuffer->Length() );
+ SetBit( EDCFHeadersModified );
+ }
+ }
+ }
+ else
+ {
+ // Dump the rest of the data.
+ __ASSERT_DEBUG( !( iDCFBuffer->Length() ), User::Invariant() );
+
+ iOutputStream.WriteL( aDCFData );
+
+ aDCFData.Set( NULL, 0 );
+
+ doCommit = ETrue;
+ }
+ }
+ }
+
+ if ( doCommit )
+ {
+ iOutputStream.CommitL();
+ }
+ }
+
+void CDRMMessageParser::FillDCFBufferL( TPtrC8& aData )
+ {
+ if ( aData.Length() )
+ {
+ TInt size( 0 );
+
+ if ( iDCFBuffer->Length() == iDCFBuffer->Des().MaxSize() )
+ {
+ HBufC8* ptr = iDCFBuffer->ReAlloc( iDCFBuffer->Length() +
+ KDefaultInputBufferSize );
+
+ if ( !ptr )
+ {
+ SetBrokenStateL( KErrNoMemory );
+ }
+
+ iDCFBuffer = ptr;
+ }
+
+ size = Min( iDCFBuffer->Des().MaxSize() - iDCFBuffer->Length(),
+ aData.Length() );
+
+ iDCFBuffer->Des().Append( aData.Left( size ) );
+
+ aData.Set( aData.Right( aData.Length() - size ) );
+ }
+ }
+
+void CDRMMessageParser::CompressDCFBuffer( const TInt aHowMuch )
+ {
+ __ASSERT_DEBUG( aHowMuch <= iDCFBuffer->Des().MaxSize(), User::Invariant() );
+
+ *iDCFBuffer = iDCFBuffer->Des().Mid( aHowMuch );
+ }
+ TBool CDRMMessageParser::FindDCFHeader( const TDesC8& aString,
+ TUint& aOffset,
+ TUint& aLength )
+ {
+ TPtrC8 des( const_cast< TUint8* >( iDCFBuffer->Ptr() ),
+ Min( iDCFBuffer->Length(), iDCFHeaderSize[ 0 ] ) );
+
+ aOffset = 0;
+ aLength = 0;
+
+ while ( des.Length() )
+ {
+ TInt pos = des.Find( KEndLine );
+ if ( pos < 0 )
+ {
+ // Last header doesn't end to "\r\n"
+ pos = des.Length();
+ if ( pos < 0 )
+ {
+ return EFalse;
+ }
+ }
+ else
+ {
+ pos += KEndLineLength;
+ }
+
+ if ( ( pos < aString.Length() ) ||
+ ( des.Left( aString.Length() ).CompareF( aString ) != 0 ) )
+ {
+ // Skip the line, since this can't be the one we're looking for.
+ des.Set( des.Right( des.Length() -
+ pos ) );
+ }
+ else
+ {
+ aOffset = des.Ptr() - iDCFBuffer->Ptr();
+ aLength = pos;
+
+ return ETrue;
+ }
+ }
+
+ // Never reached.
+ return EFalse;
+ }
+
+void CDRMMessageParser::EnsureFLRightsExistL(
+ RDRMRightsClient& aClient,
+ CDRMRights** aOutput )
+ {
+ HBufC8* cid( NULL );
+ CDRMRights* perm( NULL );
+ RPointerArray< CDRMPermission > rights( 1 );
+
+ TCleanupItem cleanup( DoResetAndDestroy2, &rights );
+ CleanupStack::PushL( cleanup );
+
+ User::LeaveIfError( aClient.ForwardLockURI( cid ) );
+ CleanupStack::PushL( cid );
+
+ TRAPD( error, aClient.GetDBEntriesL( *cid, rights ) );
+
+ if ( !error )
+ {
+ ConvertPermissionL( perm, *( rights[ 0 ] ), *cid );
+ // No need to pushl 'perm' into cleanup stack.
+ }
+ else if ( error == KErrCANoRights )
+ {
+ HBufC8* fl( NULL );
+ RPointerArray< CDRMRights > rightslist( 1 );
+
+ TCleanupItem cleanup2( DoResetAndDestroy, &rightslist );
+ CleanupStack::PushL( cleanup2 );
+
+ fl = HBufC8::NewLC( KFLROSize + cid->Length() );
+
+ *fl = KROPart1;
+ fl->Des().Append( *cid );
+ fl->Des().Append( KROPart2 );
+
+ User::LeaveIfError( ProcessRightsObject( *fl, rightslist ) );
+
+ CleanupStack::PopAndDestroy(); // fl
+
+ perm = rightslist[ 0 ];
+ rightslist.Remove( 0 );
+
+ CleanupStack::PopAndDestroy(); // cleanup2
+
+ error = KErrNone;
+ }
+
+ CleanupStack::PopAndDestroy(); // cid
+
+ if ( !error )
+ {
+ // There is something.
+ if ( aOutput )
+ {
+ *aOutput = perm;
+ }
+ else
+ {
+ delete perm; perm = NULL;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // cleanup
+ }
+
+
+HBufC8* CDRMMessageParser::EncryptDCFFieldLC( const TDesC8& aOldHeader )
+ {
+ HBufC8* res = NULL;
+ RDRMRightsClient client;
+
+ User::LeaveIfError( client.Connect() );
+ CleanupClosePushL( client );
+
+ // Make sure FL rights exists.
+ EnsureFLRightsExistL( client, NULL );
+
+ User::LeaveIfError(
+ client.EncodeRightsIssuerField( aOldHeader, res ) );
+
+ CleanupStack::PopAndDestroy(); // client
+
+ CleanupStack::PushL( res );
+
+ return res;
+ }
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+// End of File