wmdrm/wmdrmengine/asf/src/asf.cpp
changeset 0 95b198f216e5
child 60 916cdf3599c4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wmdrm/wmdrmengine/asf/src/asf.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,772 @@
+/*
+* Copyright (c) 2006 - 2007 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 asf file handler class
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <e32base.h>
+#include <f32file.h>
+#include <utf.h>
+#include <caf/caf.h>
+#include "asf.h"
+
+#define _LOGGING_FILE L"asf.txt"
+
+#include "logfn.h"
+
+// LOCAL CONSTANTS AND MACROS
+
+#define M4CC(a) ((a[0] << 24) + (a[1] << 16) + (a[2] << 8) + a[3])
+
+_LIT8 (KASFHeaderObject, "75B22630668E11CFA6D900AA0062CE6C");
+_LIT8 (KASFFilePropertiesObject, "8CABDCA1A94711CF8EE400C00C205365");
+_LIT8 (KASFContentDescriptionObject, "75B22633668E11CFA6D900AA0062CE6C");
+_LIT8 (KASFExtendedContentDescriptionObject, "D2D0A440E30711D297F000A0C95EA850");
+_LIT8 (KASFContentEncryptionObject, "2211B3FBBD2311D2B4B700A0C955FC6E");
+_LIT8 (KASFExtendedContentEncryptionObject, "298AE61426224C17B935DAE07EE9289C");
+_LIT8 (KASFDigitalSignatureObject, "2211B3FCBD2311D2B4B700A0C955FC6E");
+
+_LIT(KWMAlbumTitle,           "WM/AlbumTitle\0");
+_LIT(KWMPicture,              "WM/Picture\0");
+_LIT(KWMText,                 "WM/Text\0");
+_LIT(KWMComposer,             "WM/Composer\0");
+_LIT(KWMGenre,                "WM/Genre\0");
+_LIT(KWMYear,                 "WM/Year\0");
+_LIT(KWMYear1,                "WM/OriginalReleaseYear\0");
+_LIT(KWMOriginalArtist,       "WM/OriginalArtist\0");
+_LIT(KWMTrackNumber,          "WM/TrackNumber\0");
+_LIT(KWMUniqueFileIdentifier, "WM/UniqueFileIdentifier\0");
+_LIT(KWMAudioFileURL,         "WM/AudioFileURL\0");
+_LIT(KWMSharedUserRating,     "WM/SharedUserRating\0");
+_LIT(KWMDate,                 "WM/OriginalReleaseTime\0");
+
+_LIT8(KWrmHeader, "W\0R\0M\0H\0E\0A\0D\0E\0R\0");
+
+_LIT(KAsfMimeType, "application/vnd.drm.asf");
+_LIT(KWmaMimeType, "audio/x-ms-wma");
+_LIT(KWmvMimeType, "video/x-ms-wmv");
+
+_LIT(KAsfExtension, ".asf");
+_LIT(KWmaExtension, ".wma");
+_LIT(KWmvExtension, ".wmv");
+
+#define SET_PTR16(ptr, descriptor, offset, length) \
+    ptr.Set( reinterpret_cast<const TUint16*>( (descriptor).Ptr() + (offset) ), length );
+
+/*
+* 16 B Obj GUID
+* 8  B Obj Size
+* xx B Obj Data
+*/
+const TInt KObjectID( 16 );
+const TInt KObjectSize( 8 );
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+LOCAL_C TUint32 ReadUint64FromBlockL( const TDesC8& aBlock, TInt aOffset );
+LOCAL_C TUint32 ReadUint32FromBlockL( const TDesC8& aBlock, TInt aOffset );
+LOCAL_C TUint16 ReadUint16FromBlockL( const TDesC8& aBlock, TInt aOffset );
+
+LOCAL_C HBufC16* HBuf16FromBlockL(
+    const TDesC8& aBlock,
+    TInt aOffset,
+    TInt aLength );
+
+LOCAL_C TUint32 ReadUint64FromBlockL( const TDesC8& aBlock, TInt aOffset )
+    {
+    if ( aBlock.Length() <= ( aOffset + 3 ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    return ( aBlock[aOffset + 3] << 24 ) +
+           ( aBlock[aOffset + 2] << 16 ) +
+           ( aBlock[aOffset + 1] << 8 ) +
+             aBlock[aOffset];
+    }
+
+LOCAL_C TUint32 ReadUint32FromBlockL( const TDesC8& aBlock, TInt aOffset )
+    {
+    if ( aBlock.Length() <= ( aOffset + 3 ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    return ( aBlock[aOffset + 3] << 24 ) +
+           ( aBlock[aOffset + 2] << 16 ) +
+           ( aBlock[aOffset + 1] << 8 ) +
+             aBlock[aOffset];
+    }
+
+LOCAL_C TUint16 ReadUint16FromBlockL( const TDesC8& aBlock, TInt aOffset )
+    {
+    if ( aBlock.Length() <= ( aOffset + 1 ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    return ( aBlock[aOffset + 1] << 8 ) + 
+             aBlock[aOffset];
+    }
+
+LOCAL_C HBufC16* HBuf16FromBlockL(
+    const TDesC8& aBlock,
+    TInt aOffset,
+    TInt aLength )
+    {
+    if ( aBlock.Length() < ( aOffset + aLength ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    HBufC16* buffer( HBufC16::NewL( aLength / 2 + 1 ) );
+    TPtr ptr( buffer->Des() );
+    
+    for ( TInt i( 0 ) ; i < aLength; i+=2 )
+        {
+        ptr.Append( aBlock[aOffset + i] );
+	    }
+	
+	return buffer;
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAsf::CAsf
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAsf::CAsf():
+    iTitle( NULL ),
+    iAuthor( NULL ),
+    iCopyright( NULL ),
+    iDescription( NULL ),
+    iRating( NULL ),
+    iAlbumTitle( NULL ),
+    iPicture( NULL ),
+    iText( NULL ),
+    iComposer( NULL ),
+    iGenre( NULL ),
+    iOriginalArtist( NULL ),
+    iTrackNumber( NULL ),
+    iUniqueFileID( NULL ),
+    iAudioFileUrl( NULL ),
+    iSharedUserRating( NULL ),
+    iDate( NULL ),
+    iYear( NULL ),
+    iIsDrmProtected( EFalse ),
+    iIsValidated( EFalse ),
+    iHeaderData( NULL ),
+    iSecretData( NULL ),
+    iProtectionType( NULL ),
+    iKeyId( NULL ),
+    iLicenseUrl( NULL ),
+    iExtendedContentEncryptionObject( NULL ),
+    iContentDescriptionObjectExists( EFalse ),
+    iFilePropertiesObjectExists( EFalse ),
+    iExtendedContentDescriptionObjectExists( EFalse ),
+    iExtendedContentEncryptionObjectExists( EFalse ),
+    iContentEncryptionObjectExists( EFalse ),
+    iMimeType( KAsfMimeType )
+    {
+    LOGFN( "CAsf::CAsf" );
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CAsf::ConstructL( const TDesC& aFileName )
+    {
+    TInt r = KErrNone;
+
+    LOGFN( "CAsf::ConstructL" );
+    LOG( aFileName );
+    User::LeaveIfError( iFs.Connect() );
+    r = iFile.Open( iFs, aFileName, EFileStream | EFileRead | EFileShareReadersOrWriters );
+    if( r == KErrInUse )
+        {
+        r = iFile.Open( iFs, aFileName, EFileStream | EFileRead | EFileShareAny);
+        if ( r == KErrInUse )
+            {
+            r = iFile.Open( iFs, aFileName, EFileStream | EFileRead |
+                EFileShareReadersOnly);
+            }
+        }
+    User::LeaveIfError( r );
+    InitializeL();
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CAsf::ConstructL( const RFile& aFile )
+    {
+    LOGFN( "CAsf::ConstructL (2)" );
+    iFile.Duplicate( aFile );
+    iFile.Size( iLength );
+    InitializeL();
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::InitializeL
+//
+// -----------------------------------------------------------------------------
+//
+void CAsf::InitializeL()
+    {
+    TFileName name;
+
+    LOGFN( "CAsf::InitializeL" );
+    iFile.FullName( name );
+    if ( name.Right( 4 ).CompareF( KWmaExtension ) == 0 )
+        {
+        iMimeType.Set( KWmaMimeType );
+        }
+    else if ( name.Right( 4 ).CompareF( KWmvExtension ) == 0 ||
+        name.Right( 4 ).CompareF( KAsfExtension ) == 0 )
+        {
+        iMimeType.Set( KWmvMimeType );
+        }
+
+    ValidateL();
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CAsf* CAsf::NewL( const RFile& aFile )
+    {
+    LOGFN( "CAsf::NewL" );
+    CAsf* self = new (ELeave) CAsf;
+    CleanupStack::PushL( self );
+    self->ConstructL( aFile );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CAsf* CAsf::NewL( const TDesC& aFileName )
+    {
+    LOGFN( "CAsf::NewL (2)" );
+    CAsf* self = new (ELeave) CAsf;
+    CleanupStack::PushL( self );
+    self->ConstructL( aFileName );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::~CAsf
+// Destructor
+// -----------------------------------------------------------------------------
+//
+
+EXPORT_C CAsf::~CAsf()
+    {
+    LOGFN( "CAsf::~CAsf" );
+    if ( iFile.SubSessionHandle() != KNullHandle )
+        {
+        iFile.Close();
+        }
+    if ( iFs.Handle() != KNullHandle )
+        {
+        iFs.Close();
+        }
+
+    delete iHeaderData;
+    delete iSecretData;
+    delete iProtectionType;
+    delete iKeyId;
+    delete iLicenseUrl;
+    delete iExtendedContentEncryptionObject;
+    delete iDigitalSignatureObject;
+    delete iSignedData;
+
+    // Content description Object
+    delete iTitle;
+    delete iAuthor;
+    delete iCopyright;
+    delete iDescription;
+    delete iRating;
+
+    // Extended Content description Object
+    delete iAlbumTitle;
+    delete iPicture;
+    delete iText;
+    delete iComposer;
+    delete iGenre;
+    delete iYear;
+    delete iOriginalArtist;
+    delete iTrackNumber;
+    delete iUniqueFileID;
+    delete iAudioFileUrl;
+    delete iSharedUserRating;
+    delete iDate;
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CAsf::IsProtected( const TDesC8& aAsfHeader )
+    {
+    LOGFN( "CAsf::IsProtected" );
+    if ( aAsfHeader.Find( KWrmHeader ) == KErrNotFound )
+        {
+        return EFalse;
+        }
+    else
+        {
+        return ETrue;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAsf::ValidateL
+//
+// -----------------------------------------------------------------------------
+//
+void CAsf::ValidateL()
+    {
+    // ASF_Header_Object GUID 128 bits.
+    TBuf8<32> header;
+
+    LOGFN( "CAsf::ValidateL" );
+    iFile.Read( 0, header, KObjectID );
+    if ( header.Length() < KObjectID )
+        {
+        User::Leave( KErrOverflow );
+        }
+    FormatGUID( header );
+    if ( header !=  KASFHeaderObject )
+        {
+        User::Leave( KErrArgument );
+        }
+    
+    // read header object size.
+    iFile.Read( header, KObjectSize );
+    iHeaderSize = ReadUint64FromBlockL( header, 0 );
+    if ( iHeaderSize <= 30 || iHeaderSize > KMaxTInt / 2 - 1 )
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    // read header object
+    // 2~31 = 2 GB, size of header would not be greater than this,
+    // also, HBufC does not have a NewL with TInt64 as arguement.
+    iHeaderData = HBufC8::NewL( iHeaderSize );
+    TPtr8 headerPtr = iHeaderData->Des();
+    iFile.Read( headerPtr, iHeaderSize - ( KObjectID + KObjectSize ) );
+
+    iNbrOfObjects = ReadUint32FromBlockL( *iHeaderData, 0 );
+    if ( iNbrOfObjects <= 0 )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    TInt objOffset( 6 );
+    if ( iHeaderData->Length() < ( objOffset + KObjectID ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    //Read next object GUID
+    TBuf8<32> objGUID = iHeaderData->Mid( objOffset, KObjectID );
+    FormatGUID( objGUID );
+    TBool loop( ETrue );
+
+    //Loop until all needed headers are handled or top level header is finished
+    while ( loop )
+        {
+        //Read current object size
+        TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, objOffset + KObjectID ) );
+        if ( objSize < 24 )
+            {
+            User::Leave( KErrArgument );
+            }
+        
+        if ( !iContentDescriptionObjectExists && objGUID == 
+             KASFContentDescriptionObject )
+            {
+            iContentDescriptionObjectExists = ETrue;
+            iContentDescriptionOffset = objOffset;
+            ParseContentDescriptionObjectL();
+            }
+        else if ( !iFilePropertiesObjectExists && objGUID == 
+             KASFFilePropertiesObject )
+            {
+            iFilePropertiesObjectExists = ETrue; // must exist
+            iFilePropertiesOffset = objOffset;
+            iFilePropertiesEndOffset = iFilePropertiesOffset + objSize;
+            }
+        else if ( !iExtendedContentDescriptionObjectExists && objGUID ==
+             KASFExtendedContentDescriptionObject )
+            {
+            iExtendedContentDescriptionObjectExists = ETrue;
+            iExtendedContentDescriptionOffset = objOffset;
+            ParseExtendedContentDescriptionObjectL();
+            }
+        else if ( !iExtendedContentEncryptionObjectExists && objGUID ==
+             KASFExtendedContentEncryptionObject )
+            {
+            iExtendedContentEncryptionObjectExists = ETrue;
+            iExtendedContentEncryptionOffset = objOffset;
+            iIsDrmProtected = ETrue;
+            TInt eCEODataOffset( objOffset + KObjectID + KObjectSize + 4 );
+            TInt eCEODataLength( objSize - ( KObjectID + KObjectSize + 4 ) );
+            if ( iHeaderData->Length() < eCEODataOffset + eCEODataLength ||
+                 eCEODataLength < 0)
+                {
+                User::Leave( KErrArgument );
+                }
+            iExtendedContentEncryptionObject = iHeaderData->Mid( eCEODataOffset,
+                                                                 eCEODataLength ).AllocL();
+            }
+        else if ( !iContentEncryptionObjectExists && objGUID ==
+             KASFContentEncryptionObject )
+            {
+            iContentEncryptionObjectExists = ETrue;
+            iContentEncryptionOffset = objOffset;
+            iIsDrmProtected = ETrue;
+            ParseContentEncryptionObjectL();
+            }
+        else if ( !iDigitalSignatureObjectExists && objGUID ==
+             KASFDigitalSignatureObject )
+            {
+            iDigitalSignatureObjectExists = ETrue;
+            iDigitalSignatureOffset = objOffset;
+            
+            TInt dSODataOffset( objOffset + KObjectID + KObjectSize + 8 );
+            TInt dSODataLength( objSize - ( KObjectID + KObjectSize + 8 ) );
+            if ( iHeaderData->Length() < dSODataOffset + dSODataLength ||
+                 dSODataLength < 0 )
+                {
+                User::Leave( KErrArgument );
+                }
+            iDigitalSignatureObject = iHeaderData->Mid( dSODataOffset,
+                                                        dSODataLength ).AllocL();
+            
+            if ( iHeaderData->Length() < iFilePropertiesEndOffset + ( iDigitalSignatureOffset - iFilePropertiesEndOffset ) ||
+                 iDigitalSignatureOffset - iFilePropertiesEndOffset < 0 ||
+                 iFilePropertiesEndOffset < 0 )
+                {
+                iDigitalSignatureObjectExists = EFalse;
+                iDigitalSignatureOffset = 0;
+                delete iDigitalSignatureObject;
+                iDigitalSignatureObject = NULL;
+                }
+            else
+                {
+                iSignedData = 
+                    iHeaderData->Mid( iFilePropertiesEndOffset,
+                                      iDigitalSignatureOffset - iFilePropertiesEndOffset ).AllocL();
+                }
+            }
+        
+        //Move object offset to the end of the current header object  
+        objOffset += objSize;
+        //End loop, if top level header is finished or all needed headers are handled
+        if ( objOffset >= iHeaderSize - 30 ||
+            ( iContentDescriptionObjectExists &&
+              iFilePropertiesObjectExists &&
+              iExtendedContentDescriptionObjectExists &&
+              iExtendedContentEncryptionObjectExists &&
+              iDigitalSignatureObjectExists ) )
+            {
+            loop = EFalse;
+            }
+        //Loop isn't finished, read next object GUID
+        else
+            {
+            if ( iHeaderData->Length() < ( objOffset + KObjectID ) || objOffset < 0 )
+                {
+                User::Leave( KErrArgument );
+                }
+            objGUID = iHeaderData->Mid( objOffset, KObjectID );
+            FormatGUID( objGUID );
+            }
+        }
+    if ( iFilePropertiesObjectExists )
+        {
+        iIsValidated = ETrue;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAsf::FormatGUID
+// -----------------------------------------------------------------------------
+//
+void CAsf::FormatGUID( TDes8 &aGUID )
+    {
+    LOGFN( "CAsf::FormatGUID" );
+
+    TBuf8<16> copyGUID( aGUID );
+    TInt i;
+    for( i = 0; i < 4; i++ )
+        {
+        copyGUID[i] = aGUID[3-i];
+        }
+    for( i = 4; i < 6; i++ )
+        {
+        copyGUID[i] = aGUID[9 - i];
+        }
+    for ( i = 6; i < 8; i++ )
+        {
+        copyGUID[i] = aGUID[13 - i];
+        }
+    for( i = 8; i < 16 ; i++ )
+        {
+        copyGUID[i] = aGUID[i];
+        }
+    aGUID.Delete( 0, 32 );
+    for( i = 0; i < 16; i++ )
+        {
+        aGUID.AppendNumFixedWidthUC( copyGUID[i], EHex, 2 );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::ParseContentDescriptionObject
+// -----------------------------------------------------------------------------
+//
+void CAsf::ParseContentDescriptionObjectL()
+    {
+    LOGFN( "CAsf::ParseContentDescriptionObjectL" );
+    TInt offset( iContentDescriptionOffset + KObjectID );
+    TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, offset ) );
+
+    if ( iHeaderData->Length() < iContentDescriptionOffset + objSize )
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    offset += KObjectSize;
+    iTitleLength = ReadUint16FromBlockL( *iHeaderData, offset );
+    offset += 2;
+    iAuthorLength = ReadUint16FromBlockL( *iHeaderData, offset );
+    offset += 2;
+    iCopyrightLength = ReadUint16FromBlockL( *iHeaderData, offset );
+    offset += 2;
+    iDescriptionLength = ReadUint16FromBlockL( *iHeaderData, offset );
+    offset += 2;
+    iRatingLength = ReadUint16FromBlockL( *iHeaderData, offset );
+    offset += 2;
+
+    TInt length( iTitleLength + iAuthorLength + iCopyrightLength + iDescriptionLength + iRatingLength );
+    if ( length > objSize - ( KObjectID + KObjectSize + 10 ) )
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    iTitle = HBuf16FromBlockL( *iHeaderData, offset, iTitleLength );
+    offset += iTitleLength;
+    iAuthor = HBuf16FromBlockL( *iHeaderData, offset, iAuthorLength );
+    offset += iAuthorLength;
+    iCopyright = HBuf16FromBlockL( *iHeaderData, offset, iCopyrightLength );
+    offset += iCopyrightLength;
+    iDescription = HBuf16FromBlockL( *iHeaderData, offset, iDescriptionLength );
+    offset += iDescriptionLength;
+    iRating = HBuf16FromBlockL( *iHeaderData, offset, iRatingLength );
+    offset += iRatingLength;
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::ParseContentEncryptionObject
+// -----------------------------------------------------------------------------
+//
+void CAsf::ParseContentEncryptionObjectL()
+    {
+    LOGFN( "CAsf::ParseContentEncryptionObject" );
+    TInt offset( iContentEncryptionOffset + KObjectID );
+    TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, offset ) );
+
+    if ( iHeaderData->Length() < iContentEncryptionOffset + objSize ) 
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    offset += KObjectSize;
+    TInt len( ReadUint32FromBlockL( *iHeaderData, offset ) );
+    offset += 4;
+    if ( iHeaderData->Length() < ( offset + len ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    iSecretData = iHeaderData->Mid( offset, len ).AllocL();
+    offset += len;
+
+    len = ReadUint32FromBlockL( *iHeaderData, offset );
+    offset += 4;
+    if ( iHeaderData->Length() < ( offset + len ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    iProtectionType = iHeaderData->Mid( offset, len ).AllocL();
+    offset += len;
+
+    len = ReadUint32FromBlockL( *iHeaderData, offset );
+    offset += 4;
+    if ( iHeaderData->Length() < ( offset + len ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    iKeyId = iHeaderData->Mid( offset, len ).AllocL();
+    offset += len;
+
+    len = ReadUint32FromBlockL( *iHeaderData, offset );
+    offset += 4;
+    if ( iHeaderData->Length() < ( offset + len ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    iLicenseUrl = iHeaderData->Mid( offset, len ).AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::ParseExtendedContentDescriptionObjectL
+// -----------------------------------------------------------------------------
+//
+void CAsf::ParseExtendedContentDescriptionObjectL()
+    {
+    TInt i;
+    
+    LOGFN( "CAsf::ParseExtendedContentDescriptionObjectL" );
+    TInt offset( iExtendedContentDescriptionOffset + KObjectID );
+    TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, offset ) );
+
+    if ( iHeaderData->Length() < iExtendedContentDescriptionOffset + objSize )
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    offset += KObjectSize;
+    iExtendedContentDescriptionCount = ReadUint16FromBlockL( *iHeaderData, offset );
+    offset += 2;
+
+    for ( i = 0 ; i < iExtendedContentDescriptionCount; i++ )
+        {
+        TInt nameLength( ReadUint16FromBlockL( *iHeaderData, offset ) );
+        offset += 2;
+        HBufC16* name16( HBuf16FromBlockL( *iHeaderData, offset, nameLength ) );
+        offset += nameLength;
+        CleanupStack::PushL( name16 );
+        if( !name16->CompareF( KWMAlbumTitle ) )
+            {
+            iAlbumTitle = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMPicture ) )
+            {
+            iPicture = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMText) )
+            {
+            iText = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMComposer ) )
+            {
+            iComposer = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMGenre ) )
+            {
+            iGenre = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMYear ) || !name16->CompareF( KWMYear1 ) )
+            {
+            if ( !iYear )
+                {
+                iYear = ReadExtendedContentObjectL( offset );
+                }
+            }
+        else if( !name16->CompareF( KWMOriginalArtist) )
+            {
+            iOriginalArtist = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMTrackNumber ) )
+            {
+            iTrackNumber = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMUniqueFileIdentifier ) )
+            {
+            iUniqueFileID = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMAudioFileURL ) )
+            {
+            iAudioFileUrl = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMSharedUserRating ) )
+            {
+            iSharedUserRating = ReadExtendedContentObjectL( offset );
+            }
+        else if( !name16->CompareF( KWMDate ) )
+            {
+            iDate = ReadExtendedContentObjectL( offset );
+            }
+        CleanupStack::PopAndDestroy( name16 );
+
+        offset += 2; // data type
+        TInt valueLength( ReadUint16FromBlockL( *iHeaderData, offset ) );
+        offset += 2;
+        offset += valueLength;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAsf::ReadExtendedContentObjectL
+// -----------------------------------------------------------------------------
+//
+HBufC16* CAsf::ReadExtendedContentObjectL( TInt aOffset )
+    {
+    HBufC16* buffer( NULL );
+
+    LOGFN( "CAsf::ReadExtendedContentObjectL" );
+    TInt dataTypeInt( ReadUint16FromBlockL( *iHeaderData, aOffset ) );
+    if ( dataTypeInt == 0x00 )
+        {
+        TInt length( ReadUint16FromBlockL( *iHeaderData, aOffset + 2 ) );
+        if ( length > 0 )
+            {
+            buffer = HBuf16FromBlockL( *iHeaderData, aOffset + 4, length - 2 );
+            }
+        }
+    else if ( dataTypeInt == 0x02 || dataTypeInt == 0x03 )
+        {
+        TUint32 dword( ReadUint32FromBlockL( *iHeaderData, aOffset + 4 ) );
+        buffer = HBufC::NewL( 16 );
+        TPtr dataString( buffer ->Des() );
+        dataString.Num( dword );
+        }
+    else if ( dataTypeInt == 0x05 )
+        {
+        TUint16 word( ReadUint16FromBlockL( *iHeaderData, aOffset + 4 ) );
+        buffer = HBufC::NewL( 8 );
+        TPtr dataString( buffer->Des() );
+        dataString.Num( word ) ;
+        }
+    return buffer;
+    }
+
+//  End of File