omadrm/drmengine/dcf/src/Oma2Dcf.cpp
changeset 0 95b198f216e5
child 18 8a03a285ab14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmengine/dcf/src/Oma2Dcf.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,1591 @@
+/*
+* Copyright (c) 2002 - 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Implementation of class representeting discrete OMA2 DCF
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <e32const.h> // KMaxTUint32
+#include <e32cmn.h> // Max, Min
+#include <e32base.h>
+#include <f32file.h>
+#include <utf.h>
+#include <caf/caf.h>
+#include "Oma2Agent.h"
+#include "Oma2Dcf.h"
+#include "Oma2DcfPartInfo.h"
+
+// LOCAL CONSTANTS AND MACROS
+
+#define M4CC( a ) ( ( a[ 0 ] << 24 ) + ( a[ 1 ] << 16 ) + ( a[ 2 ] << 8 ) + a[ 3 ] )
+
+const TUint32 KDiscreteMediaHeaders( M4CC( "odhe" ) );
+const TUint32 KContainer( M4CC( "odrm" ) );
+const TUint32 KContentObject( M4CC( "odda" ) );
+const TUint32 KCommonHeaders( M4CC( "ohdr" ) );
+const TUint32 KMutableInfo( M4CC( "mdri" ) );
+const TUint32 KTransactionTracking( M4CC( "odtt" ) );
+const TUint32 KRightsObject( M4CC( "odrb" ) );
+const TUint32 KGroupId( M4CC( "grpi" ) );
+const TUint32 KUserData( M4CC( "udta" ) );
+
+// supported user data boxes
+_LIT8( KTitle, "titl" );
+_LIT8( KDescription, "dscp" );
+_LIT8( KCopyright, "cprt" );
+_LIT8( KAuthor, "auth" );
+_LIT8( KIconUri, "icnu" );
+_LIT8( KInfoURL, "infu" );
+_LIT8( KPerformer, "perf" );
+_LIT8( KGenre, "gnre" );
+_LIT8( KRating, "rtng" );
+_LIT8( KClassification, "clsf" );
+_LIT8( KKeyword, "kywd" );
+_LIT8( KLocationInformation, "loci" );
+_LIT8( KAlbum, "albm" );
+_LIT8( KRecordingYear, "yrrc" );
+_LIT8( KCoverUri, "cvru" );
+_LIT8( KLyricsURL, "lrcu" );
+
+
+_LIT8( KMdri, "mdri" );
+_LIT8( KOdtt, "odtt" );
+_LIT8( KOdrb, "odrb" );
+
+// textual headers
+_LIT8( KSilentHeader, "Silent" );
+_LIT8( KPreviewHeader, "Preview" );
+_LIT8( KContentURLHeader, "ContentURL" );
+_LIT8( KContentVersionHeader, "ContentVersion" );
+_LIT8( KContentLocationHeader, "Content-Location" );
+
+// supported custom textual headers
+_LIT8( KIconUriHeader, "IconURI" );
+_LIT8( KTitleHeader, "Title" );
+_LIT8( KDescriptionHeader, "Description" );
+_LIT8( KAuthorHeader, "Author" );
+_LIT8( KCopyrightHeader, "Copyright" );
+_LIT8( KInfoURLHeader, "InfoURL" );
+
+// textual headers, methods
+_LIT8( KSilentMethodOnDemand, "on-demand" );
+_LIT8( KSilentMethodInAdvance, "in-advance" );
+_LIT8( KPreviewMethodInstant, "instant" );
+_LIT8( KPreviewMethodPreviewRights, "preview-rights" );
+_LIT8( KEmptyTransactionId, "0000000000000000" );
+
+_LIT8( KTerminator, "\0" );
+_LIT8( KSeparator, ":" );
+_LIT8( KParamSeparator, ";" );
+
+const TInt KBrandingSize( 20 );
+const TInt KMaxBoxHeaderSize( 16 );
+const TInt KLengthBoxSize( 4 );
+const TInt KLengthBoxType( 4 );
+const TInt KLengthBoxSize64( 8 );
+const TInt KLengthVersion( 1 );
+const TInt KLengthFlags( 3 );
+const TInt KLengthEncMethod( 1 );
+const TInt KLengthPadType( 1 );
+const TInt KLengthPlainTextSize( 8 );
+const TInt KLengthDataLengthSize( 8 );
+const TInt KLengthContentIdSize( 2 );
+const TInt KLengthRiUrlSize( 2 );
+const TInt KLengthTextHeadersSize( 2 );
+const TInt KLengthTerminator( 1 );
+
+// Smallest possible ISO based media box size
+// See ISO/IEC 14496-12 and DRM-DCF-CLI-12 in OMA-TS-DRM-DCF-V2_1
+const TUint32 KMinBoxSize( KLengthBoxSize + KLengthBoxType );
+// Largest supported ISO based media box size
+const TUint32 KMaxBoxSize( KMaxTUint32 );
+
+const TUint KUserDataBoxMask( 0x000001 );
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// ReadUint32FromBlock
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TUint32 ReadUint32FromBlock( const TDesC8& aBlock, TInt aOffset )
+    {
+    return ( aBlock[ aOffset ] << 24 ) +
+        ( aBlock[ aOffset + 1 ] << 16 ) +
+        ( aBlock[ aOffset + 2 ] << 8 ) +
+        aBlock[ aOffset + 3 ];
+    }
+
+// -----------------------------------------------------------------------------
+// ReadUint16FromBlock
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TUint16 ReadUint16FromBlock( const TDesC8& aBlock, TInt aOffset )
+    {
+    return ( ( aBlock[ aOffset ] << 8 ) + aBlock[ aOffset + 1 ] );
+    }
+
+// -----------------------------------------------------------------------------
+// WriteIntToBlock
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void WriteIntToBlock( TInt aValue, TDes8& aBlock, TInt aOffset )
+    {
+    aBlock.SetLength( 4 );
+    aBlock[ aOffset ] =     ( aValue & 0xff000000 ) >> 24;
+    aBlock[ aOffset + 1 ] = ( aValue & 0x00ff0000 ) >> 16;
+    aBlock[ aOffset + 2 ] = ( aValue & 0x0000ff00 ) >> 8;
+    aBlock[ aOffset + 3 ] = ( aValue & 0x000000ff );
+    }
+
+// -----------------------------------------------------------------------------
+// ValidateBoxSizeL
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void ValidateBoxSizeL(
+    const TUint32 aSize,
+    const TUint32 aMinSize = KMinBoxSize,
+    const TUint32 aMaxSize = KMaxBoxSize )
+    {
+    TUint32 minSize( Max( aMinSize, KMinBoxSize) );
+    TUint32 maxSize( Min( aMaxSize, KMaxBoxSize ) );
+    if ( aSize < minSize )
+        {
+        User::Leave( KErrArgument );
+        }
+    if ( aSize > maxSize )
+        {
+        User::Leave( KErrArgument );
+        }
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::COma2Dcf
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+COma2Dcf::COma2Dcf():
+    iEncrytionPadding( EPaddingNone ),
+    iSilentRefresh( ENoSilentRefresh ),
+    iPreview( ENoPreview ),
+    iPreviewParameter( NULL ),
+    iSilentParameter( NULL ),
+    iTextualHeaders( NULL ),
+    iContentUrl( NULL ),
+    iContentVersion( NULL ),
+    iContentLocation( NULL ),
+    iTransactionTracking( NULL ),
+    iUserData( NULL ),
+    iAuthor( NULL ),
+    iCopyRight( NULL ),
+    iInfoUri( NULL ),
+    iGroupId( NULL ),
+    iGroupKey( NULL ),
+    iGkEncryptionMethod( EMethodNULL ),
+    iMutablePart( NULL ),
+    iPerformer( NULL ),
+    iGenre( NULL ),
+    iRatingInfo( NULL ),
+    iClassificationInfo( NULL ),
+    iKeyword( NULL ),
+    iLocInfoName( NULL ),
+    iLocInfoAstronomicalBody( NULL ),
+    iLocInfoAdditionalNotes( NULL ),
+    iAlbumTitle( NULL ),
+    iCoverUri( NULL ),
+    iLyricsURL( NULL ),
+    iRecordingYear( 0 ),
+    iAlbumTrack( 0 )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ConstructL(
+    const RFile& aFile,
+    TInt aPart )
+    {
+    CDcfCommon::ConstructL( aFile );
+    ReadPartsL();
+    User::LeaveIfError( OpenPart( aPart ) );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C COma2Dcf* COma2Dcf::NewL(
+    const RFile& aFile,
+    TInt aPart )
+    {
+    COma2Dcf* self( new ( ELeave ) COma2Dcf );
+
+    CleanupStack::PushL( self );
+    self->ConstructL( aFile, aPart );
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// Destructor
+EXPORT_C COma2Dcf::~COma2Dcf()
+    {
+    delete iPreviewParameter;
+    delete iSilentParameter;
+    delete iTextualHeaders;
+    delete iContentUrl;
+    delete iContentVersion;
+    delete iContentLocation;
+    delete iTransactionTracking;
+    delete iUserData;
+    delete iAuthor;
+    delete iCopyRight;
+    delete iInfoUri;
+    delete iGroupId;
+    delete iGroupKey;
+    delete iPerformer;
+    delete iGenre;
+    delete iRatingInfo;
+    delete iClassificationInfo;
+    delete iKeyword;
+    delete iLocInfoName;
+    delete iLocInfoAstronomicalBody;
+    delete iLocInfoAdditionalNotes;
+    delete iAlbumTitle;
+    delete iCoverUri;
+    delete iLyricsURL;
+    delete iMutablePart;
+
+    iRightsObjects.ResetAndDestroy();
+    iRightsObjects.Close();
+    iParts.ResetAndDestroy();
+    iParts.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::IsValidDcf
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool COma2Dcf::IsValidDcf(
+    const TDesC8& aDcfFragment )
+    {
+    TBool r( EFalse );
+
+    if ( aDcfFragment.Length() >= KBrandingSize &&
+        aDcfFragment.Left( KBrandingSize ).Compare( KOma2DcfBranding ) == 0 )
+        {
+        r = ETrue;
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadPartsL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadPartsL( void )
+    {
+    TBuf8<KBrandingSize> buffer;
+    TInt size;
+    TUint32 type;
+    TInt offset;
+    TInt headerSize;
+    COma2DcfPartInfo* part;
+
+    User::LeaveIfError( iFile.Read( 0, buffer, KBrandingSize ) );
+    if ( !IsValidDcf( buffer ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    iVersion = ReadUint32FromBlock( buffer, 12 );
+    offset = KBrandingSize;
+    iParts.Reset();
+    do
+        {
+        ReadBoxSizeAndTypeL( offset, size, type, headerSize );
+        if ( headerSize > 0 )
+            {
+            part = COma2DcfPartInfo::NewL();
+            part->iType = type;
+            part->iSize = size;
+            part->iOffset = offset;
+            CleanupStack::PushL( part );
+            if ( type == KContainer )
+                {
+                ReadPartInfoL( part, offset );
+                iParts.Append( part );
+                CleanupStack::Pop( part );
+                }
+            else if ( type == KMutableInfo )
+                {
+                iMutablePart = part;
+                CleanupStack::Pop( part );
+                ReadMutableInfoL( offset, size );
+                }
+            else
+                {
+                CleanupStack::PopAndDestroy( part );
+                }
+            }
+        offset += size;
+        }
+    while ( offset < iLength && headerSize > 0 );
+
+    delete iContentID;
+    iContentID = NULL;
+    delete iMimeType;
+    iMimeType = NULL;
+
+    if ( iParts.Count() == 0 ||
+        iParts[ 0 ]->iContentId == NULL ||
+        iParts[ 0 ]->iMimeType == NULL )
+        {
+        User::LeaveIfError( KErrArgument );
+        }
+    iContentID = iParts[ 0 ]->iContentId->AllocL();
+    iMimeType = iParts[ 0 ]->iMimeType->AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::CheckUniqueId
+// -----------------------------------------------------------------------------
+//
+TInt COma2Dcf::CheckUniqueId( const TDesC& aUniqueId )
+    {
+    TInt r( CDcfCommon::CheckUniqueId( aUniqueId ) );
+
+    if ( r == KErrNotFound )
+        {
+        HBufC8* id( NULL );
+        TRAPD( err,
+            id = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aUniqueId ) );
+        if ( err == KErrNone )
+            {
+            r = KErrNotFound;
+            for ( TInt i( 0 );
+                i < iParts.Count() && r == KErrNotFound;
+                i++ )
+                {
+                if ( !id->Compare( *iParts[ i ]->iContentId ) )
+                    {
+                    r = i;
+                    }
+                }
+            delete id;
+            }
+        else
+            {
+            r = err;
+            }
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::OpenPart
+// -----------------------------------------------------------------------------
+//
+TInt COma2Dcf::OpenPart(
+    const TDesC& aUniqueId )
+    {
+    return OpenPart( CheckUniqueId( aUniqueId ) );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::OpenPart
+// -----------------------------------------------------------------------------
+//
+TInt COma2Dcf::OpenPart(
+    TInt aPart )
+    {
+    TInt r( KErrNone );
+    TInt size( 0 );
+
+    if ( aPart >= 0 && aPart < iParts.Count() )
+        {
+        TRAP( r, ReadContainerL( iParts[ aPart ]->iOffset, size ) );
+        }
+    else
+        {
+        r = KErrNotFound;
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::GetPartIdsL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::GetPartIdsL( RPointerArray<HBufC8>& aPartList )
+    {
+    aPartList.ResetAndDestroy();
+    for ( TInt i( 0 ); i < iParts.Count(); i++ )
+        {
+        aPartList.Append( iParts[ i ]->iContentId->AllocL() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadContainerL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadContainerL(
+    TInt aOffset,
+    TInt& aSize )
+    {
+    TUint32 type( 0 );
+    TInt size( 0 );
+
+    ReadBoxSizeAndTypeL( aOffset, aSize, type, size );
+    VerifyTypeL( type, KContainer );
+    aOffset += size + KLengthVersion + KLengthFlags;
+    ReadDiscreteMediaHeaderL( aOffset, size );
+    aOffset += size;
+    ReadContentObjectL( aOffset, size );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadDiscreteMediaHeaderL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadDiscreteMediaHeaderL(
+    TInt aOffset,
+    TInt& aSize )
+    {
+    TBuf8<1> valBuf;
+    TBuf8<4> udtaBuf;
+    TInt size( 0 );
+    TUint32 type( 0 );
+    TUint8 length( 0 );
+    TPtr8 ptr( 0, 0 );
+
+    TBuf8< KLengthVersion + KLengthFlags > buffer;
+    TUint32 version_and_flags( 0 );
+
+    ReadBoxSizeAndTypeL( aOffset, aSize, type, size );
+    VerifyTypeL( type, KDiscreteMediaHeaders );
+
+    // read flags and version
+    aOffset += size;
+    User::LeaveIfError( iFile.Read( aOffset, buffer ) );
+    version_and_flags = ReadUint32FromBlock( buffer, 0 );
+    aOffset += KLengthVersion + KLengthFlags;
+
+    // read ContentType
+    delete iMimeType;
+    iMimeType = NULL;
+
+    // input validation
+    if ( aOffset < 0 )
+        {
+        // RFile::Read will panic if offset is negative
+        User::Leave( KErrArgument );
+        }
+
+    User::LeaveIfError( iFile.Read( aOffset, valBuf, 1 ) );
+    length = valBuf[ 0 ];
+    aOffset += 1;
+    iMimeType = HBufC8::NewMax( length );
+    User::LeaveIfNull( iMimeType );
+    ptr.Set( iMimeType->Des() );
+    User::LeaveIfError( iFile.Read( ptr, length ) );
+    aOffset += length;
+
+    // read Common headers
+    ReadCommonHeadersL( aOffset, size );
+
+    // user data box would follow here
+    if ( version_and_flags & KUserDataBoxMask )
+        {
+        aOffset += size;
+        User::LeaveIfError( iFile.Read( aOffset, udtaBuf, 4 ) );
+        size = ReadUint32FromBlock( udtaBuf, 0 );
+        ReadUserDataL( aOffset, size );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadContentObjectL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadContentObjectL(
+    TInt aOffset,
+    TInt& aSize )
+    {
+    TBuf8<KMaxBoxHeaderSize> valBuf;
+    TInt size( 0 );
+    TUint32 type( 0 );
+
+    ReadBoxSizeAndTypeL( aOffset, aSize, type, size );
+    VerifyTypeL( type, KContentObject );
+    aOffset += size + KLengthVersion + KLengthFlags;
+
+    // read data length
+
+    // input validation
+    if ( aOffset < 0 )
+        {
+        // RFile::Read will panic if offset is negative
+        User::Leave( KErrArgument );
+        }
+
+    User::LeaveIfError( iFile.Read( aOffset, valBuf, KLengthDataLengthSize ) );
+    if ( ReadUint32FromBlock( valBuf, 0 ) != 0 )
+        {
+        // the size is larger than 2^32-1, we can't handle this.
+        User::Leave( KErrOverflow );
+        }
+    else
+        {
+        iDataLength = ReadUint32FromBlock( valBuf, KLengthDataLengthSize / 2 );
+        if ( iPlainTextLengthValid )
+            {
+            iPadding = iDataLength - iPlainTextLength;
+            }
+        }
+    iOffset = aOffset + KLengthDataLengthSize;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadCommonHeadersL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadCommonHeadersL(
+    TInt aOffset,
+    TInt& aSize )
+    {
+    TBuf8< KMaxBoxHeaderSize > valBuf;
+    TInt size( 0 );
+    TInt boxEnd( 0 );
+    TUint32 type( 0 );
+    TInt offset( 0 );
+    TUint16 riURLLength( 0 );
+    TUint16 contentIdLength( 0 );
+    TUint16 textualHeadersLength( 0 );
+    TUint16 length( 0 );
+    HBufC8* buf( NULL );
+    TPtr8 ptr( 0, 0 );
+
+    ReadBoxSizeAndTypeL( aOffset, aSize, type, size );
+    VerifyTypeL( type, KCommonHeaders );
+    boxEnd = aOffset + aSize;
+    aOffset += size + KLengthVersion + KLengthFlags;
+
+    length = KLengthEncMethod + KLengthPadType + KLengthPlainTextSize
+        + KLengthContentIdSize + KLengthRiUrlSize + KLengthTextHeadersSize;
+    buf = HBufC8::NewLC( length );
+    ptr.Set( buf->Des() );
+
+    // input validation
+    if ( aOffset < 0 )
+        {
+        // RFile::Read will panic if offset is negative
+        User::Leave( KErrArgument );
+        }
+    User::LeaveIfError( iFile.Read( aOffset, ptr, length ) );
+
+    offset = 0;
+    iEncryptionMethod = static_cast< TEncryptionMethod >( ( *buf )[ 0 ] );
+    offset += KLengthEncMethod;
+    iEncrytionPadding = static_cast< TEncryptionPadding >( ( *buf )[ 1 ] );
+    offset += KLengthPadType;
+
+    iPlainTextLength = ReadUint32FromBlock( ptr, offset );
+    offset +=  KLengthPlainTextSize / 2;
+    if ( iPlainTextLength != 0 )
+        {
+        User::Leave( KErrOverflow );
+        }
+    else
+        {
+        iPlainTextLength = ReadUint32FromBlock( ptr, offset );
+        if ( iPlainTextLength > 0 )
+            {
+            iPlainTextLengthValid = ETrue;
+            }
+        else
+            {
+            iPlainTextLengthValid = EFalse;
+            }
+        offset +=  KLengthPlainTextSize / 2;
+        }
+
+    contentIdLength = ReadUint16FromBlock( ptr, offset );
+    offset += KLengthContentIdSize;
+    riURLLength = ReadUint16FromBlock( ptr, offset );
+    offset += KLengthRiUrlSize;
+    textualHeadersLength  = ReadUint16FromBlock( ptr, offset );
+    offset += KLengthTextHeadersSize;
+    CleanupStack::PopAndDestroy( buf );
+    buf = NULL;
+
+    aOffset += offset;
+    delete iContentID;
+    iContentID = NULL;
+    iContentID = HBufC8::NewMax( contentIdLength );
+    User::LeaveIfNull( iContentID );
+    ptr.Set( iContentID->Des() );
+    User::LeaveIfError( iFile.Read( aOffset, ptr, contentIdLength ) );
+    aOffset += contentIdLength;
+
+    delete iRightsIssuerURL;
+    iRightsIssuerURL = NULL;
+    if ( riURLLength > 0 )
+        {
+        iRightsIssuerURL = HBufC8::NewL( riURLLength );
+        ptr.Set( iRightsIssuerURL->Des() );
+        User::LeaveIfError( iFile.Read( aOffset, ptr, riURLLength ) );
+        aOffset += riURLLength;
+        }
+
+    delete iTextualHeaders;
+    iTextualHeaders = NULL;
+    if ( textualHeadersLength > 0 )
+        {
+        iTextualHeaders = HBufC8::NewL( textualHeadersLength );
+        ptr.Set( iTextualHeaders->Des() );
+        User::LeaveIfError( iFile.Read( aOffset, ptr, textualHeadersLength ) );
+        aOffset += textualHeadersLength;
+        ParseTextualHeadersL( ptr );
+        }
+
+    ReadExtendedHeadersL( aOffset, boxEnd );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ParseTextualHeadersL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ParseTextualHeadersL(
+    const TDesC8& aMemoryBlock )
+    {
+    HBufC8* buf1( NULL );
+    HBufC8* method( NULL );
+    TInt r( KErrNone );
+    TInt silentOffset( 0 );
+    TInt previewOffset( 0 );
+
+    silentOffset = ReadOneTextualHeaderL(
+        aMemoryBlock, KSilentHeader, buf1, r );
+    if ( r != KErrNotFound && buf1 )
+        {
+        CleanupStack::PushL( buf1 );
+        SetHeaderWithParameterL( *buf1, method, iSilentParameter );
+        CleanupStack::PopAndDestroy( buf1 );
+        buf1 = NULL;
+        if ( method )
+            {
+            if ( !method->Compare( KSilentMethodOnDemand ) )
+                {
+                iSilentRefresh = EOnDemand;
+                }
+            else if ( !method->Compare( KSilentMethodInAdvance ) )
+                {
+                iSilentRefresh = EInAdvance;
+                }
+            else
+                {
+                delete method;
+                User::Leave( KErrArgument );
+                }
+            delete method;
+            method = NULL;
+            }
+        }
+    else
+        {
+        iSilentRefresh = ENoSilentRefresh;
+        delete iSilentParameter;
+        iSilentParameter = 0;
+        }
+
+    previewOffset = ReadOneTextualHeaderL(
+        aMemoryBlock, KPreviewHeader, buf1, r );
+    if ( r != KErrNotFound && buf1 )
+        {
+        CleanupStack::PushL( buf1 );
+        SetHeaderWithParameterL( *buf1, method, iPreviewParameter );
+        CleanupStack::PopAndDestroy( buf1 );
+        buf1 = NULL;
+        if ( method )
+            {
+            if ( !method->CompareF( KPreviewMethodInstant ) )
+                {
+                iPreview = EInstantPreview;
+                }
+            else if ( !method->CompareF( KPreviewMethodPreviewRights ) )
+                {
+                iPreview = EPreviewRights;
+                }
+            else
+                {
+                delete method;
+                User::Leave( KErrArgument );
+                }
+            delete method;
+            method = NULL;
+            }
+        }
+    else
+        {
+        iPreview = ENoPreview;
+        delete iPreviewParameter;
+        iPreviewParameter = NULL;
+        }
+
+    iPreviewOverridesSilentRefresh = EFalse;
+    if ( iSilentRefresh != ENoSilentRefresh && iPreview != ENoPreview )
+        {
+        if ( previewOffset < silentOffset )
+            {
+            iPreviewOverridesSilentRefresh = ETrue;
+            }
+        }
+
+    ReadOneTextualHeaderL(
+        aMemoryBlock, KContentLocationHeader, iContentLocation, r );
+    if ( r == KErrNotFound )
+        {
+        delete iContentLocation;
+        iContentLocation = NULL;
+        }
+
+    ReadOneTextualHeaderL( aMemoryBlock, KContentURLHeader, iContentUrl, r );
+    if ( r == KErrNotFound )
+        {
+        delete iContentUrl;
+        iContentUrl = NULL;
+        }
+
+    ReadOneTextualHeaderL(
+        aMemoryBlock, KContentVersionHeader, iContentVersion, r );
+    if ( r == KErrNotFound )
+        {
+        delete iContentVersion;
+        iContentVersion = NULL;
+        }
+
+    // custom headers ->
+    ReadOneTextualHeaderL( aMemoryBlock, KInfoURLHeader, iInfoUri, r );
+    if ( r == KErrNotFound )
+        {
+        delete iInfoUri;
+        iInfoUri = NULL;
+        }
+
+    // custom header
+    ReadOneTextualHeaderL( aMemoryBlock, KTitleHeader, iTitle, r );
+    if ( r == KErrNotFound )
+        {
+        delete iTitle;
+        iTitle = NULL;
+        }
+
+    ReadOneTextualHeaderL( aMemoryBlock, KIconUriHeader, iIconUri, r );
+    if ( r == KErrNotFound )
+        {
+        delete iIconUri;
+        iIconUri = NULL;
+        }
+
+    ReadOneTextualHeaderL( aMemoryBlock, KAuthorHeader, iAuthor, r );
+    if ( r == KErrNotFound )
+        {
+        delete iAuthor;
+        iAuthor = NULL;
+        }
+
+    ReadOneTextualHeaderL( aMemoryBlock, KDescriptionHeader, iDescription, r );
+    if ( r == KErrNotFound )
+        {
+        delete iDescription;
+        iDescription = NULL;
+        }
+
+    ReadOneTextualHeaderL( aMemoryBlock, KCopyrightHeader, iCopyRight, r );
+    if ( r == KErrNotFound )
+        {
+        delete iCopyRight;
+        iCopyRight = NULL;
+        }
+
+
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::SetHeaderWithParameterL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::SetHeaderWithParameterL(
+    const TDesC8& aValue,
+    HBufC8*& aMethod,
+    HBufC8*& aParameter )
+    {
+    TInt offset( 0 );
+
+    delete aMethod;
+    aMethod = NULL;
+    delete aParameter;
+    aParameter = NULL;
+
+    offset = aValue.Find( KParamSeparator );
+    if ( offset == KErrNotFound || offset == 0 )
+        {
+        aMethod = aValue.AllocL();
+        }
+    else
+        {
+        aMethod = aValue.Left( offset ).AllocLC();
+        aParameter = aValue.Mid( offset + 1 ).AllocL();
+        CleanupStack::Pop( aMethod );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadOneTextualHeaderL
+// -----------------------------------------------------------------------------
+//
+TInt COma2Dcf::ReadOneTextualHeaderL(
+    const TDesC8& aBlock,
+    const TDesC8& aName,
+    HBufC8*& aBuf,
+    TInt& aError )
+    {
+    TInt offset( aBlock.Find( aName ) );
+
+    delete aBuf;
+    aBuf = NULL;
+    if ( offset == KErrNotFound )
+        {
+        aError = KErrNotFound;
+        return offset;
+        }
+    else
+        {
+        if ( offset + aName.Length() < aBlock.Length() &&
+            aBlock.Mid( offset + aName.Length(), 1 ) == KSeparator )
+            {
+            TInt length( 0 );
+            length =
+                aBlock.Mid( offset + aName.Length() + 1 ).Find( KTerminator );
+            if ( length == KErrNotFound )
+                {
+                User::Leave( KErrArgument );
+                }
+            else
+                {
+                aBuf = HBufC8::NewL( length );
+                *aBuf = aBlock.Mid( offset + aName.Length() + 1, length );
+                }
+            }
+        }
+    aError = KErrNone;
+    return offset;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadExtendedHeadersL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadExtendedHeadersL(
+    TInt aOffset,
+    TInt aEndOfBox )
+    {
+    TInt size( 1 );
+    TInt groupIdSize( 0 );
+    TInt groupKeySize( 0 );
+    TUint32 type( 0 );
+    TInt headerSize( 0 );
+    TInt dataSize( 0 );
+    TInt offset( 0 );
+    TPtr8 ptr( 0, 0 );
+    HBufC8* buffer( NULL );
+
+    delete iGroupId;
+    iGroupId = NULL;
+    delete iGroupKey;
+    iGroupKey = NULL;
+
+    while ( size > 0 && aOffset < aEndOfBox && iGroupId == NULL )
+        {
+        size = 0;
+        ReadBoxSizeAndTypeL( aOffset, size, type, headerSize );
+        if ( type == KGroupId )
+            {
+            dataSize = size - headerSize - KLengthVersion - KLengthFlags;
+            offset = aOffset + headerSize + KLengthVersion + KLengthFlags;
+            // input validation
+            if ( dataSize < 0 || dataSize > KMaxTInt / 2 )
+                {
+                User::Leave( KErrArgument );
+                }
+            buffer = HBufC8::NewLC( dataSize );
+            ptr.Set( buffer->Des() );
+            User::LeaveIfError( iFile.Read( offset, ptr, dataSize ) );
+            // input validation
+            if ( ptr.Length() == 0 )
+                {
+                User::Leave( KErrArgument );
+                }
+            iGkEncryptionMethod = static_cast< TEncryptionMethod >( ptr[ 2 ] );
+            groupIdSize = ReadUint16FromBlock( ptr, 0 );
+            if ( 5 + groupIdSize > ptr.Length() )
+                {
+                User::Leave( KErrArgument );
+                }
+            iGroupId = ptr.Mid( 5, groupIdSize ).AllocL();
+            groupKeySize = ReadUint16FromBlock( ptr, 3 );
+            if ( 5 + groupIdSize + groupKeySize > ptr.Length() )
+                {
+                User::Leave( KErrArgument );
+                }
+            iGroupKey = ptr.Mid( 5 + groupIdSize, groupKeySize ).AllocL();
+
+            // Set the content ID of this file to the group ID
+            delete iContentID;
+            iContentID = NULL;
+            iContentID = iGroupId->AllocL();
+
+            CleanupStack::PopAndDestroy( buffer );
+            }
+        aOffset += size;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadMutableInfoL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadMutableInfoL(
+    TInt aOffset,
+    TInt& aSize )
+    {
+    TInt size( 0 );
+    TInt dataSize( 0 );
+    TUint32 type( 0 );
+    TInt headerSize( 0 );
+    TPtr8 ptr( 0, 0 );
+    HBufC8* buffer1( NULL );
+    TInt boxEnd( 0 );
+    TInt offset( 0 );
+
+    delete iTransactionTracking;
+    iTransactionTracking = NULL;
+    iRightsObjects.ResetAndDestroy();
+
+    ReadBoxSizeAndTypeL( aOffset, aSize, type, headerSize );
+    VerifyTypeL( type, KMutableInfo );
+
+    if ( !iMutablePart )
+        {
+        iMutablePart = COma2DcfPartInfo::NewL();
+        iMutablePart->iType = type;
+        iMutablePart->iSize = aSize;
+        iMutablePart->iOffset = aOffset;
+        }
+
+
+    boxEnd = aOffset + aSize;
+    aOffset += headerSize;
+
+    do
+        {
+        ReadBoxSizeAndTypeL( aOffset, size, type, headerSize );
+        if ( headerSize > 0 )
+            {
+            dataSize = size - headerSize - KLengthVersion - KLengthFlags;
+            offset = aOffset + headerSize + KLengthVersion + KLengthFlags;
+            // input validation
+            if ( dataSize < 0 || dataSize > KMaxTInt / 2 )
+                {
+                User::Leave( KErrArgument );
+                }
+            if ( type == KTransactionTracking && !iTransactionTracking )
+                {
+                buffer1 = HBufC8::NewLC( dataSize );
+                ptr.Set( buffer1->Des() );
+                User::LeaveIfError( iFile.Read( offset, ptr, dataSize ) );
+                CleanupStack::Pop( buffer1 );
+                iTransactionTracking = buffer1;
+                }
+            else if ( type == KRightsObject )
+                {
+                buffer1 = HBufC8::NewLC( dataSize );
+                ptr.Set( buffer1->Des() );
+                User::LeaveIfError( iFile.Read( offset, ptr, dataSize ) );
+                CleanupStack::Pop( buffer1 );
+                iRightsObjects.Append( buffer1 );
+                }
+            }
+        aOffset += size;
+
+        }
+    while ( headerSize > 0 && aOffset < boxEnd && offset <= iLength );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadBoxSizeAndTypeL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadBoxSizeAndTypeL(
+    TInt aOffset,
+    TInt& aSize,
+    TUint32& aType,
+    TInt& aHeaderSize )
+    {
+    TBuf8< KLengthBoxSize + KLengthBoxType > buffer;
+
+    aHeaderSize = 0;
+    // input validation
+    if ( aOffset < 0 || aOffset > iLength )
+        {
+        // Valid offset can never be negative
+        // or greater than length of the opened file.
+        User::Leave( KErrArgument );
+        }
+    User::LeaveIfError( iFile.Read( aOffset, buffer ) );
+    if ( buffer.Length() == KLengthBoxSize + KLengthBoxType )
+        {
+        aSize = ReadUint32FromBlock( buffer, 0 );
+        aType = ReadUint32FromBlock( buffer, 4 );
+        aHeaderSize = KLengthBoxSize + KLengthBoxType;
+
+        if ( aSize == 1 )
+            {
+            buffer.SetLength( 0 );
+            User::LeaveIfError( iFile.Read( buffer ) );
+            if ( buffer.Length() < KLengthBoxSize + KLengthBoxType )
+                {
+                User::Leave( KErrArgument );
+                }
+            if ( ReadUint32FromBlock( buffer, 0 ) > 0 )
+                {
+                User::Leave( KErrOverflow );
+                }
+            aSize = ReadUint32FromBlock( buffer, 4 );
+            aHeaderSize += KLengthBoxSize64;
+            }
+        else if ( aSize == 0 )
+            {
+            aSize = iLength - aOffset;
+            }
+        else if ( aType == KContainer )
+            {
+            // oma drm container box must always have large length field set
+            // See DRM-DCF-CLI-15 in OMA-TS-DRM-DCF-V2_1.
+            User::Leave( KErrArgument );
+            }
+        }
+    // Valid box size can never be smaller than discovered header size.
+    // Nor can it be larger than largest supported ISO based media box size.
+    ValidateBoxSizeL( aSize, aHeaderSize, KMaxBoxSize - aOffset );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::VerifyTypeL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::VerifyTypeL( TUint32 aType, TUint32 aRefType )
+    {
+    if ( aRefType != aType )
+        {
+        User::Leave( KErrArgument );
+        };
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::SetTransactionIdL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void COma2Dcf::SetTransactionIdL(
+    const TDesC8& aTransactionId )
+    {
+    // Overwrite existing ID, otherwise, recreate the whole MDRI box
+    if ( iTransactionTracking )
+        {
+        TInt size( 0 );
+        TUint32 type( 0 );
+        TInt headerSize( 0 );
+        TInt offset( 0 );
+
+        offset = iMutablePart->iOffset;
+        // Read mutable box headers and skip them
+        ReadBoxSizeAndTypeL( offset, size, type, headerSize );
+        offset += headerSize;
+        do
+            {
+            ReadBoxSizeAndTypeL( offset, size, type, headerSize );
+            if ( type != KTransactionTracking )
+                {
+                offset += size;
+                }
+            }
+        while ( headerSize > 0 &&
+            type != KTransactionTracking && offset <= iLength );
+
+
+        if ( type == KTransactionTracking )
+            {
+            offset += headerSize + KLengthVersion + KLengthFlags;
+            User::LeaveIfError( iFile.Write( offset, aTransactionId ) );
+            }
+        }
+    else
+        {
+        RewriteMutableInfoL( aTransactionId, iRightsObjects );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::SetRightsObjectsL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void COma2Dcf::SetRightsObjectsL(
+    RPointerArray<HBufC8>& aRoList )
+    {
+    // Always recreate the whole MDRI box, it's simpler
+    if ( iTransactionTracking )
+        {
+        RewriteMutableInfoL( *iTransactionTracking, aRoList );
+        }
+    else
+        {
+        RewriteMutableInfoL( KNullDesC8, aRoList );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::RewriteMutableInfoL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::RewriteMutableInfoL(
+    const TDesC8& aTransactionId,
+    RPointerArray<HBufC8>& aRoList )
+    {
+    TInt offset( 0 );
+    TBuf8<4> buffer;
+    TInt sizeOfRoBoxes( 0 );
+    TInt roBoxSize( 0 );
+    TInt tidBoxSize( 0 );
+    TInt mutableBoxSize( 0 );
+
+    // Remove the existing box
+    if ( iMutablePart )
+        {
+        User::LeaveIfError( iFile.SetSize( iMutablePart->iOffset ) );
+        }
+
+    // Append the box to the end of the file
+    User::LeaveIfError( iFile.Size( offset ) );
+
+    for ( TInt i( 0 ); i < aRoList.Count(); i++ )
+        {
+        sizeOfRoBoxes += aRoList[ i ]->Size() +
+            KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags;
+        }
+    tidBoxSize = 16 +
+        KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags;
+    mutableBoxSize =
+        KLengthBoxSize + KLengthBoxType + tidBoxSize + sizeOfRoBoxes;
+
+    // MDRI box
+    WriteIntToBlock( mutableBoxSize, buffer, 0 );
+    User::LeaveIfError( iFile.Write( offset, buffer ) );
+    User::LeaveIfError( iFile.Write( KMdri ) );
+
+    // ODTT box ( always written )
+    WriteIntToBlock( tidBoxSize, buffer, 0 );
+    User::LeaveIfError( iFile.Write( buffer ) );
+    User::LeaveIfError( iFile.Write( KOdtt ) );
+    buffer.FillZ();
+    User::LeaveIfError( iFile.Write( buffer ) );
+    if ( aTransactionId.Size() > 0 )
+        {
+        User::LeaveIfError( iFile.Write( aTransactionId ) );
+        }
+    else
+        {
+        User::LeaveIfError( iFile.Write( KEmptyTransactionId ) );
+        }
+
+    // ODRB box
+    if ( sizeOfRoBoxes > 0 )
+        {
+        for ( TInt i( 0 ); i < aRoList.Count(); i++ )
+            {
+            roBoxSize = aRoList[ i ]->Size() +
+                KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags;
+            WriteIntToBlock( roBoxSize, buffer, 0 );
+            User::LeaveIfError( iFile.Write( buffer ) );
+            User::LeaveIfError( iFile.Write( KOdrb ) );
+            buffer.FillZ();
+            User::LeaveIfError( iFile.Write( buffer ) );
+            User::LeaveIfError( iFile.Write( *aRoList[ i ] ) );
+            }
+        }
+
+    // Reread the MDRI box
+    User::LeaveIfError( iFile.Size( iLength ) );
+    ReadMutableInfoL( offset, mutableBoxSize );
+    }
+
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadPartInfoL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadPartInfoL(
+    COma2DcfPartInfo* aPart,
+    TInt aOffset )
+    {
+    TBuf8<4> buffer;
+    TUint32 size( 0 );
+    TPtr8 ptr( NULL, 0 );
+
+    // ODRM box header
+    buffer.SetLength( 0 );
+
+    // input validation
+    if ( aOffset < 0 )
+        {
+        // RFile::Read will panic if offset is negative
+        User::Leave( KErrArgument );
+        }
+
+    iFile.Read( aOffset, buffer, 4 );
+    size = ReadUint32FromBlock( buffer, 0 );
+    aOffset += KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags;
+    if ( size == 1 )
+        {
+        aOffset += KLengthBoxSize64;
+        }
+
+    // Discrete headers box header
+    buffer.SetLength( 0 );
+    iFile.Read( aOffset, buffer, 4 );
+    if ( buffer.Length() < 4 )
+        {
+        User::Leave( KErrArgument );
+        }
+    size = ReadUint32FromBlock( buffer, 0 );
+    aOffset += KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags;
+    if ( size == 1 )
+        {
+        aOffset += KLengthBoxSize64;
+        }
+
+    // Content type
+    buffer.SetLength( 0 );
+    iFile.Read( aOffset, buffer, 1 );
+    if ( buffer.Length() < 1 )
+        {
+        User::Leave( KErrArgument );
+        }
+    aPart->iMimeType = HBufC8::NewL( buffer[ 0 ] );
+    ptr.Set( aPart->iMimeType->Des() );
+    iFile.Read( ptr, buffer[ 0 ] );
+    aOffset += 1 + buffer[ 0 ];
+
+    // Common headers box header
+    buffer.SetLength( 0 );
+    iFile.Read( aOffset, buffer, 4 );
+    if ( buffer.Length() < 4 )
+        {
+        User::Leave( KErrArgument );
+        }
+    size = ReadUint32FromBlock( buffer, 0 );
+    aOffset += KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags;
+    if ( size == 1 )
+        {
+        aOffset += KLengthBoxSize64;
+        }
+
+    // Content ID
+    aOffset += KLengthEncMethod + KLengthPadType + KLengthPlainTextSize;
+    buffer.SetLength( 0 );
+    iFile.Read( aOffset, buffer, 2 );
+    if ( buffer.Length() < 2 )
+        {
+        User::Leave( KErrArgument );
+        }
+    aPart->iContentId = HBufC8::NewL( ReadUint16FromBlock( buffer, 0 ) );
+    ptr.Set( aPart->iContentId->Des() );
+    aOffset += KLengthContentIdSize + KLengthRiUrlSize + KLengthTextHeadersSize;
+    iFile.Read( aOffset, ptr, ReadUint16FromBlock( buffer, 0 ) );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadUserDataL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadUserDataL(
+    TInt aOffset,
+    TInt& aSize )
+    {
+    TInt size( 0 );
+    TUint32 type( 0 );
+    TPtr8 ptr( 0, 0 );
+
+    ReadBoxSizeAndTypeL( aOffset, aSize, type, size );
+    VerifyTypeL( type, KUserData );
+    aOffset += size;
+
+    delete iUserData;
+    iUserData = NULL;
+    iUserData = HBufC8::NewL( aSize );
+    User::LeaveIfNull( iUserData );
+
+    ptr.Set( iUserData->Des() );
+    User::LeaveIfError( iFile.Read( aOffset, ptr, aSize ) );
+    aOffset += aSize;
+
+    ParseUserDataSubBoxesL( ptr );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ParseUserDataSubBoxesL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ParseUserDataSubBoxesL(
+    const TDesC8& aMemoryBlock )
+    {
+
+    // there MAY be zero to several boxes
+    // depending on language definition.
+    // here only the first boxes are read out.
+
+    iUserDataLanguageDefined = ETrue;
+
+    // if not found from textual custom headers, try to read out from udta
+    if ( !iTitle )
+        {
+        ReadOneUserDataBoxL( aMemoryBlock, KTitle, iTitle );
+        }
+
+    // if not found from textual custom headers, try to read out from udta
+    if ( !iDescription )
+        {
+        ReadOneUserDataBoxL( aMemoryBlock, KDescription, iDescription );
+        }
+
+    // if not found from textual custom headers, try to read out from udta
+    if ( !iCopyRight )
+        {
+        ReadOneUserDataBoxL( aMemoryBlock, KCopyright, iCopyRight );
+        }
+
+    // if not found from textual custom headers, try to read out from udta
+    if ( !iAuthor )
+        {
+        ReadOneUserDataBoxL( aMemoryBlock, KAuthor, iAuthor );
+        }
+
+    ReadOneUserDataBoxL( aMemoryBlock, KPerformer, iPerformer );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KGenre, iGenre );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KRating, iRatingInfo );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KClassification, iClassificationInfo );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KKeyword, iKeyword );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KLocationInformation, iLocInfoName );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KAlbum, iAlbumTitle );
+
+
+    // These boxes do not contain language information ->
+
+    iUserDataLanguageDefined = EFalse;
+
+    // if not found from textual custom headers, try to read out from udta
+    if ( !iIconUri )
+        {
+        ReadOneUserDataBoxL( aMemoryBlock, KIconUri, iIconUri );
+        }
+
+    ReadOneUserDataBoxL( aMemoryBlock, KInfoURL, iInfoUri );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KCoverUri, iCoverUri );
+
+    ReadOneUserDataBoxL( aMemoryBlock, KLyricsURL, iLyricsURL );
+
+
+    TInt yearOffset( iUserData->Find( KRecordingYear ) );
+    if ( yearOffset != KErrNotFound )
+        {
+        yearOffset += sizeof( tBoxHeaderStr ) - KLengthBoxSize;
+        iRecordingYear = ReadUint16FromBlock( iUserData->Des(), yearOffset );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2Dcf::ReadOneUserDataBoxL
+// -----------------------------------------------------------------------------
+//
+void COma2Dcf::ReadOneUserDataBoxL(
+    const TDesC8& aBlock,
+    const TDesC8& aName,
+    HBufC8*& aBuffer )
+    {
+
+    TInt offset( aBlock.Find( aName ) );
+    TUint32 length( 0 );
+    HBufC8* subBlock( NULL );
+    TInt subOffset( 0 );
+    TBuf8<12> buffer;
+
+    delete aBuffer;
+    aBuffer = NULL;
+
+    if ( offset == KErrNotFound )
+        {
+        return;
+        }
+    else
+        {
+
+        TUint8* pData( const_cast< TUint8* >( aBlock.Ptr() ) );
+        offset -= KLengthBoxSize;
+        pData += offset;
+
+        buffer.SetLength( 0 );
+        buffer.Copy( pData, 12 );
+
+        tBoxHeaderStr* SubBox = ( tBoxHeaderStr* ) buffer.Ptr();
+        length = SWAP32( SubBox->size );
+
+        subBlock = aBlock.Mid( offset, length ).AllocLC();
+
+        subOffset += sizeof( tBoxHeaderStr );
+
+        if ( aName == KClassification )
+            {
+            TUint32 classificationEntity(
+                ReadUint32FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( classificationEntity );
+
+            TUint16 classificationTable(
+                ReadUint16FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( classificationTable );
+            }
+
+        if ( aName == KRating )
+            {
+            TUint32 ratingEntity(
+                ReadUint32FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( ratingEntity );
+
+            TUint32 ratingCriteria(
+                ReadUint32FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( ratingCriteria );
+            }
+
+        if ( iUserDataLanguageDefined )
+            {
+            TUint16 PadAndLanguage(
+                ReadUint16FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( PadAndLanguage );
+            }
+
+
+        if ( aName == KKeyword )
+            {
+            // we return all keywords here
+            aBuffer = HBufC8::NewL( length );
+            TUint8 keywordCnt( subBlock->Des()[ subOffset ] );
+            TUint8 keywordSize( 0 );
+
+            subOffset += sizeof( keywordCnt );
+
+            for ( TInt count( 0 ); count < keywordCnt; count++ )
+                {
+                keywordSize = subBlock->Des()[ subOffset ];
+                subOffset += sizeof( keywordSize );
+                aBuffer->Des().Append(
+                    subBlock->Des().Mid( subOffset, keywordSize ) );
+                subOffset += keywordSize;
+                keywordSize = 0;
+                }
+            }
+
+        else if ( aName == KAlbum )
+            {
+            TInt tracknbrFound(
+                subBlock->Des().Mid( subOffset ).Find( KTerminator ) );
+
+            if ( ( tracknbrFound == KErrNotFound ) ||
+                ( tracknbrFound ==
+                  ( subBlock->Des().Length()-subOffset ) - 1 ) )
+                {
+                aBuffer = subBlock->Des().Mid( subOffset ).AllocL();
+                iAlbumTrack = NULL;
+                }
+            else
+                {
+                aBuffer =
+                    subBlock->Des().Mid( subOffset, tracknbrFound ).AllocL();
+                subOffset += tracknbrFound + KLengthTerminator;
+                iAlbumTrack = subBlock->Des()[ subOffset ];
+                }
+            }
+
+        else if ( aName == KLocationInformation )
+            {
+            TInt found( subBlock->Des().Mid( subOffset ).Find( KTerminator ) );
+            aBuffer = subBlock->Des().Mid( subOffset, found ).AllocL();
+            subOffset += found + KLengthTerminator;
+
+            TUint8 role( subBlock->Des()[ subOffset ] );
+            subOffset += sizeof( role );
+            TUint32 longitude(
+                ReadUint32FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( longitude );
+            TUint32 latitude(
+                ReadUint32FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( latitude );
+            TUint32 altitude(
+                ReadUint32FromBlock( subBlock->Des(), subOffset ) );
+            subOffset += sizeof( altitude );
+
+            found = subBlock->Des().Mid( subOffset ).Find( KTerminator );
+
+            // iLocInfoAstronomicalBody =
+            //    subBlock->Des().Mid( subOffset, found ).AllocL();
+            subOffset += found + KLengthTerminator;
+
+            found = subBlock->Des().Mid( subOffset ).Find( KTerminator );
+            // iLocInfoAdditionalNotes =
+            //    subBlock->Des().Mid( subOffset, found ).AllocL();
+            }
+        else
+            {
+            aBuffer = subBlock->Des().Mid( subOffset ).AllocL();
+            }
+        CleanupStack::PopAndDestroy( subBlock );
+        }
+    }
+
+
+//  End of File