omadrm/drmengine/dm/src/DRMMessageParser.cpp
changeset 0 95b198f216e5
child 12 8a03a285ab14
--- /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