mmserv/metadatautility/Src/MetaDataParserWMA.cpp
changeset 0 71ca22bcf22a
child 8 03a293c97d5c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/metadatautility/Src/MetaDataParserWMA.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,976 @@
+/*
+* 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 an ID3v1 and v1.1 parser as specified in
+*                www.id3.org.
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include	"MetaDataParserWMA.h"
+#ifdef _DEBUG
+#include	<e32svr.h>
+#endif
+
+#include <s32mem.h>
+
+// CONSTANTS
+// ASF Header Object GUIDs 
+  
+_LIT8 (KASFContentDescriptionObject, "75B22633668E11CFA6D900AA0062CE6C");
+_LIT8 (KASFExtendedContentDescriptionObject, "D2D0A440E30711D297F000A0C95EA850");
+_LIT8 (KASFHeaderObject, "75B22630668E11CFA6D900AA0062CE6C");
+_LIT8 (KASFFilePropertiesObject, "8CABDCA1A94711CF8EE400C00C205365");
+_LIT8 (KASFHeaderExtensionObject, "5FBF03B5A92E11CF8EE300C00C205365");
+_LIT8 (KASFMetadataLibraryObject, "44231C94949849D1A1411D134E457054");
+_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");
+#ifdef __WINDOWS_MEDIA
+_LIT(KWMProvider, "WM/Provider\0");
+#endif
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::CMetaDataParserWMA
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMetaDataParserWMA::CMetaDataParserWMA(
+	CMetaDataSource& aSource )
+	:	iSource(aSource),
+		iCharacterSetId(0)
+	{
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ConstructL()
+    {
+	if ( ValidateL() )
+		{
+		User::LeaveIfError(iFs.Connect());
+		// Get list of charconv supported character sets
+		iCharacterSet = CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL(iFs);
+		}
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserWMA::ConstructL - Done"));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CMetaDataParserWMA* CMetaDataParserWMA::NewL(
+	CMetaDataSource& aSource )
+    {
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserWMA::NewL"));
+#endif
+	CMetaDataParserWMA* self = new( ELeave ) CMetaDataParserWMA(aSource);
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Destructor
+CMetaDataParserWMA::~CMetaDataParserWMA()
+	{
+		delete iHeaderData;
+		delete iCharacterSet;
+		iFs.Close();
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ParseL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ParseL(
+	const RArray<TMetaDataFieldId>& aWantedFields,
+	CMetaDataFieldContainer& aContainer )
+    {
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserWMA::ParseL"));
+#endif
+	iContainer = &aContainer;
+
+	if(iContentDescriptionObjectExists)
+		{
+		ParseContentDescriptionObject();
+		}
+	if(iExtendedContentDescriptionObjectExists)
+		{
+		ParseExtendedContentDescriptionObjectL();
+		}
+	if(iHeaderExtensionObjectExists)
+		{
+		ParseHeaderExtensionObjectL();
+		if(iMetadataLibraryObjectExists)
+			{
+			ParseMetadataLibraryObjectL();
+			}
+		}	
+	TInt err = KErrNone; // ignore err, as some entry may be extracted without exception
+	if ( aWantedFields.Count() == 0 )
+		{
+		TRAP(err, GetTitleL());
+		TRAP(err, GetAuthorL());
+		TRAP(err, GetCopyrightL());
+		TRAP(err, GetCommentL());
+		TRAP(err, GetJpegL());
+		TRAP(err, GetExtContDesEntryL(EMetaDataRating, iSharedUserRatingOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataAlbum, iAlbumTitleOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataComment, iTextOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataComposer, iComposerOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataGenre, iGenreOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataYear, iYearOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataOriginalArtist, iOriginalArtistOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataAlbumTrack, iTrackNumberOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataUniqueFileIdentifier, iUniqueFileIdentifierOffset));
+		TRAP(err, GetExtContDesEntryL(EMetaDataUrl, iAudioFileURLOffset));
+		TRAP(err, GetDurationL());
+		TRAP(err, GetExtContDesEntryL(EMetaDataDate, iDateOffset));
+	#ifdef __WINDOWS_MEDIA
+		TRAP(err, GetExtContDesEntryL(EMetaDataVendor, iProviderOffset));
+	#endif
+		}
+	else
+		{
+		// Look for it in the wanted field array
+		TInt count( aWantedFields.Count() );
+		for ( TInt i = 0; i < count; i++ )
+			{
+			switch ( aWantedFields[ i ] )
+				{
+				case EMetaDataSongTitle:
+					TRAP(err, GetTitleL());
+					break;
+				case EMetaDataArtist:
+					TRAP(err, GetAuthorL());
+					break;
+				case EMetaDataCopyright:
+					TRAP(err, GetCopyrightL());
+					break;
+				case EMetaDataRating:
+					TRAP(err, GetExtContDesEntryL(EMetaDataRating, iSharedUserRatingOffset));
+					break;
+				case EMetaDataJpeg:
+					TRAP(err, GetJpegL());
+					break;
+				case EMetaDataAlbum:
+					TRAP(err, GetExtContDesEntryL(EMetaDataAlbum, iAlbumTitleOffset));
+					break;
+				case EMetaDataComment:
+					TRAP(err, GetExtContDesEntryL(EMetaDataComment, iTextOffset));
+					break;
+				case EMetaDataComposer:
+					TRAP(err, GetExtContDesEntryL(EMetaDataComposer, iComposerOffset));
+					break;
+				case EMetaDataGenre:
+					TRAP(err, GetExtContDesEntryL(EMetaDataGenre, iGenreOffset));
+					break;
+				case EMetaDataYear:
+					TRAP(err, GetExtContDesEntryL(EMetaDataYear, iYearOffset));
+					break;
+				case EMetaDataOriginalArtist:
+					TRAP(err, GetExtContDesEntryL(EMetaDataOriginalArtist, iOriginalArtistOffset));
+					break;
+				case EMetaDataAlbumTrack:
+					TRAP(err, GetExtContDesEntryL(EMetaDataAlbumTrack, iTrackNumberOffset));
+					break;
+				case EMetaDataUniqueFileIdentifier:
+					TRAP(err, GetExtContDesEntryL(EMetaDataUniqueFileIdentifier, iUniqueFileIdentifierOffset));
+					break;
+				case EMetaDataUrl:
+					TRAP(err, GetExtContDesEntryL(EMetaDataUrl, iAudioFileURLOffset));
+					break;
+				case EMetaDataDuration:
+					TRAP(err, GetDurationL());
+					break;
+				case EMetaDataDate:
+					TRAP(err, GetExtContDesEntryL(EMetaDataDate, iDateOffset));
+					break;
+			#ifdef __WINDOWS_MEDIA
+				case EMetaDataVendor:
+					TRAP(err, GetExtContDesEntryL(EMetaDataVendor, iProviderOffset));
+			#endif
+				default:
+					break;
+				}
+			}
+		}
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ValidateL
+// -----------------------------------------------------------------------------
+//
+TBool CMetaDataParserWMA::ValidateL()
+	{
+	TInt size;
+	iExists = EFalse;
+	User::LeaveIfError( iSource.Size( size ) );
+	if ( size <= 0 )
+		{
+		return EFalse;
+		}
+
+	// ASF_Header_Object GUID 128 bits.
+	TBuf8<32> header; 
+	iSource.ReadL(header, 16);
+	if(header.Length() < 16)
+		{
+		return EFalse;
+		}
+	FormatGUID(header);
+	if(header !=  KASFHeaderObject)
+		{
+		return EFalse;
+		}
+	// read header object size.
+	iSource.ReadL(header, 8);
+	TInt headerSize = ConvertToInt64(header);
+	if(headerSize <= 30)
+		{
+		return EFalse; // header object is empty.
+		}
+	if(headerSize >= size) //Header Size is too high
+		{
+		return EFalse; // header size is more than the file size.
+		}
+	// 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(headerSize); 
+	TPtr8 headerPtr = iHeaderData->Des(); 
+	iSource.ReadL(headerPtr, headerSize - 24);
+	
+	TBuf8<4> objects = iHeaderData->Mid(0, 4);
+	TInt noOfObjects = ConvertToInt32(objects);
+	if(noOfObjects <= 0)
+		{
+		iExists = EFalse;
+		return EFalse; // no objects. 
+		}
+        
+	TInt objOffset = 6;
+	if(objOffset+16 > iHeaderData->Length()) //Header Size is too small
+		{
+		return EFalse;
+		} 
+	TBuf8<32> objGUID = iHeaderData->Mid(objOffset, 16);
+	FormatGUID(objGUID);
+	TBool loop = ETrue;
+	TInt objectCount = 0;
+	while (loop)
+		{
+		if(!iContentDescriptionObjectExists && objGUID == KASFContentDescriptionObject)
+			{
+			iContentDescriptionObjectExists = ETrue;
+			iContentDescriptionOffset = objOffset;
+			}
+		if(!iFilePropertiesObjectExists && objGUID == KASFFilePropertiesObject)
+			{
+			iFilePropertiesObjectExists = ETrue; // must exist
+			iFilePropertiesOffset = objOffset;
+			}
+		if(!iExtendedContentDescriptionObjectExists && objGUID == 
+			KASFExtendedContentDescriptionObject)
+			{
+			iExtendedContentDescriptionObjectExists = ETrue;
+			iExtendedContentDescriptionOffset = objOffset;
+			}
+		if(!iHeaderExtensionObjectExists && objGUID == 
+			KASFHeaderExtensionObject)
+			{
+			iHeaderExtensionObjectExists = ETrue;
+			iHeaderExtensionOffset = objOffset;
+			}	
+		TBuf8<8> size = iHeaderData->Mid(objOffset + 16, 8); 
+		TInt objSize = ConvertToInt64(size); // upper 32 bits?
+		if(0 > objSize)
+			{
+			return EFalse;
+			}
+		objOffset += objSize;
+		if(objOffset >= headerSize - 30 || 
+			(iContentDescriptionObjectExists && iFilePropertiesObjectExists 
+			&& iExtendedContentDescriptionObjectExists && iHeaderExtensionObjectExists) )
+			{
+			loop = EFalse;
+			}
+		else
+			{
+			objGUID = iHeaderData->Mid(objOffset, 16);
+			FormatGUID(objGUID);
+			objectCount++;
+
+			if (objectCount == noOfObjects)
+				{
+				iExists = EFalse;
+				return EFalse;	// gone through all objects		
+				}
+			}
+		}
+	if(iFilePropertiesObjectExists) 
+		{
+		iExists = ETrue;
+		}
+	return iExists;
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::FormatGUID
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::FormatGUID(TDes8 &aGUID)
+{
+	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);
+		}
+}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ConvertToInt64
+// -----------------------------------------------------------------------------
+//
+TInt64 CMetaDataParserWMA::ConvertToInt64(TDesC8& aDes)
+{
+	TInt64 num = 0;
+	TInt i;
+	for(i = 7 ; i >= 0; i--)
+		{
+		num <<= 8;
+		num |= aDes[i];
+		}
+	return num;
+}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ConvertToInt32
+// -----------------------------------------------------------------------------
+//
+TInt CMetaDataParserWMA::ConvertToInt32(TDesC8& aDes)
+{
+	TInt num = 0;
+	for(TInt i = 3 ; i >= 0; i--)
+		{	
+		num <<= 8;
+		num |= aDes[i];
+		}
+	return num;
+}
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ConvertToInt16
+// -----------------------------------------------------------------------------
+//
+TInt CMetaDataParserWMA::ConvertToInt16(TDesC8& aDes)
+{
+	TInt num = 0;
+	for(TInt i = 1 ; i >= 0; i--)
+		{	
+		num <<= 8;
+		num |= aDes[i];
+		}
+	return num;
+}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ConvertDes8toDes16
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ConvertDes8toDes16(const TDesC8& aDes8,TDes16& aDes16)
+	{
+	for(TInt i = 0 ; i < aDes8.Length(); i+=2)
+		{
+		if(aDes16.MaxLength() <= i/2)
+			{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserWMA::ConvertDes8toDes16: i/2[%d] >= aDes16's MaxLength[%d]."),
+			i/2, aDes16.MaxLength());
+#endif
+			return;
+			}
+		aDes16.Append(aDes8[i]);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetTitleL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::GetTitleL()
+	{
+	if (iTitleLength <= 0)
+		{
+		return;
+		}
+	TInt offset = iContentDescriptionOffset + 34;
+	if(iTitleLength - 2 <= 0 || offset + iTitleLength > iHeaderData->Length())
+		{
+		return; // empty title or corrupt title length
+		}
+	TPtrC8 title = iHeaderData->Mid(offset, iTitleLength - 2);
+	HBufC* data16 = HBufC::NewLC( iTitleLength - 2);
+	TPtr titleUnicode( data16->Des() );
+	if ( ConvertToUnicodeL(title, titleUnicode) == KErrNone )
+		{
+		iContainer->AppendL( EMetaDataSongTitle, titleUnicode );
+		}
+	CleanupStack::PopAndDestroy();  // data16
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetArtistL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::GetAuthorL()
+	{
+	if (iAuthorLength <= 0)
+		{
+		return;
+		}
+	TInt offset = iContentDescriptionOffset + 34 + iTitleLength;
+	if(iAuthorLength - 2 <= 0 || offset + iAuthorLength > iHeaderData->Length())
+		{
+		return; // empty author or corrupt author length
+		}
+	TPtrC8 author = iHeaderData->Mid(offset, iAuthorLength - 2);
+	HBufC* data16 = HBufC::NewLC( iAuthorLength - 2);
+	TPtr authorUnicode( data16->Des() );
+	if ( ConvertToUnicodeL(author, authorUnicode) == KErrNone )
+		{
+		iContainer->AppendL( EMetaDataArtist, authorUnicode );
+		}
+	CleanupStack::PopAndDestroy();  // data16
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetCopyrightL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::GetCopyrightL()
+	{
+	if (iCopyrightLength <= 0)
+		{
+		return;
+		}
+	TInt offset = iContentDescriptionOffset + 34 + iTitleLength + iAuthorLength;
+	if(iCopyrightLength - 2 <= 0 || offset + iCopyrightLength > iHeaderData->Length())
+		{
+		return; // empty or corrupt length
+		}
+	TPtrC8 copyright = iHeaderData->Mid(offset, iCopyrightLength - 2);
+	HBufC* data16 = HBufC::NewLC( iCopyrightLength - 2);
+	TPtr copyrightUnicode( data16->Des() );
+	if ( ConvertToUnicodeL(copyright, copyrightUnicode) == KErrNone )
+		{
+		iContainer->AppendL( EMetaDataCopyright, copyrightUnicode );
+		}
+	CleanupStack::PopAndDestroy();  // data16
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetCommentL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::GetCommentL()
+	{
+	if (iDescriptionLength <= 0)
+		{
+		return;
+		}
+	TInt offset = iContentDescriptionOffset + 34 + iTitleLength + iAuthorLength + iCopyrightLength;
+	if(iDescriptionLength - 2 <= 0 || offset + iDescriptionLength > iHeaderData->Length())
+		{
+		return; // empty comment or corrupt comment length
+		}
+	TPtrC8 comments = iHeaderData->Mid(offset, iDescriptionLength - 2);
+	HBufC* data16 = HBufC::NewLC( iDescriptionLength - 2);
+	TPtr commentsUnicode( data16->Des() );
+	if ( ConvertToUnicodeL(comments, commentsUnicode) == KErrNone )
+		{
+		iContainer->AppendL( EMetaDataComment, commentsUnicode );
+		}
+	CleanupStack::PopAndDestroy();  // data16
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetJpegL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::GetJpegL()
+{
+	if (iPictureOffset <= 0)
+	{
+		return;
+	}
+	
+	TInt offset = iPictureOffset;
+	if(!iMetadatLibraryObjectJpegExists)
+		{
+		TPtrC8 dataType = iHeaderData->Mid(offset, 2);
+		offset += 2;
+		TInt dataTypeInt = ConvertToInt16(dataType);
+		if(dataTypeInt != 1)
+			{
+			return;
+			}
+		
+		TPtrC8 lengthData = iHeaderData->Mid(offset, 2);
+		offset += 2;
+		TInt length	= ConvertToInt16(lengthData);
+		if(length <= 0)
+			{
+			return;
+			}		
+		}
+	TPtrC8 picData = iHeaderData->Mid(offset, 1);
+	offset += 1;
+	TInt picType = 0;
+	picType |= picData[0];
+	if(picType != 3)
+	{
+		return; // only Front Album Cover supported
+	}
+	
+	TPtrC8 picLengthData = iHeaderData->Mid(offset, 4);
+	offset += 4;
+	TInt picLength = ConvertToInt32(picLengthData);
+	if(picLength <= 0)
+	{
+		return;
+	}
+	
+	_LIT8(KNULL, "\0\0");
+	TPtrC8 data = iHeaderData->Mid(offset, picLength);
+	TInt pos = data.Find(KNULL);
+	if(pos != 0)
+	{
+		pos++; // for unicode coding for strings. 
+	}
+	// check mime type
+	if(pos != KErrNotFound)
+	{
+		HBufC8 *mimeType = iHeaderData->Mid(offset, pos + 2).AllocLC();
+		offset += pos + 2;
+		HBufC* name16 = HBufC::NewLC( (pos+2)/2);
+		TPtr mimeType16( name16->Des() );
+		ConvertDes8toDes16(*mimeType, mimeType16);
+		_LIT(KJPEG, "image/jpeg\0");
+		_LIT(KJPG, "image/jpg\0");
+		if(mimeType16.Compare(KJPEG) != 0 && mimeType16.Compare(KJPG) != 0)
+		{
+			CleanupStack::PopAndDestroy(2, mimeType);
+			return; // only JPEG & JPG supported
+		}
+		CleanupStack::PopAndDestroy(2); // mimeType16, mimeType
+	}
+		
+	// skip the picture description
+	TPtrC8 picDesc = iHeaderData->Mid(offset, picLength);
+	pos = picDesc.Find(KNULL);
+	if(pos != 0)
+	{
+		pos++; // for unicode coding for strings. 
+	}
+	offset += pos + 2;
+	
+	// picture data 
+	TPtrC8 pic8 = iHeaderData->Mid(offset, picLength);	
+	iContainer->AppendL( EMetaDataJpeg, pic8 );
+}
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetExtContDesEntryL
+// -----------------------------------------------------------------------------
+//
+TBool CMetaDataParserWMA::GetExtContDesEntryL(TMetaDataFieldId aFieldId, TInt aOffset)
+{
+	TBool ret = EFalse;
+	if(iExtendedContentDescriptionCount == 0)
+		{
+		return ret;
+		}
+	TPtrC8 dataType = iHeaderData->Mid(aOffset, 2);
+	TInt dataTypeInt = ConvertToInt16(dataType);
+	if(dataTypeInt == 0x00)
+		{
+		TPtrC8 lengthData = iHeaderData->Mid(aOffset + 2, 2);
+		TInt length	= ConvertToInt16(lengthData);
+		if(length <= 0)
+			{
+			return ret;
+			}
+		TPtrC8 data = iHeaderData->Mid(aOffset + 4, length - 2);
+		HBufC* data16 = HBufC::NewLC(length - 2);
+		TPtr dataUnicode( data16->Des() );
+		if ( ConvertToUnicodeL(data, dataUnicode) == KErrNone )
+			{
+			iContainer->AppendL( aFieldId, dataUnicode );
+			ret = ETrue;
+			}
+		CleanupStack::PopAndDestroy();  // data16
+		}
+	else if(dataTypeInt == 0x03)
+		{
+		TPtrC8 lengthData = iHeaderData->Mid(aOffset + 2, 2);
+		TInt length	= ConvertToInt16(lengthData);
+		if(length != 4)
+			{
+			return ret;
+			}
+		TPtrC8 data = iHeaderData->Mid(aOffset + 4, length);
+		TInt dword = ConvertToInt32(data);
+		const TInt KMaxIntBufferSize = 10;
+		HBufC* data16 = HBufC::NewLC(KMaxIntBufferSize);
+		TPtr dataString( data16->Des() );
+		dataString.Num(dword);
+		iContainer->AppendL( aFieldId, dataString );
+		CleanupStack::PopAndDestroy();  // data16
+		ret = ETrue;
+		}
+	return ret;
+}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::GetDurationL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::GetDurationL()
+	{
+	TInt offset = iFilePropertiesOffset + 16;
+	TPtrC8 size8 = iHeaderData->Mid(offset, 8);
+	TInt size = ConvertToInt64(size8);
+	offset = iFilePropertiesOffset + 88;
+	TPtrC8 flags = iHeaderData->Mid(offset, 4);
+	TInt broadcastBit = (TInt) (flags[0] & 0x01);
+	if(broadcastBit == 1)
+		{
+		return; // duration not valid.
+		}
+	//offset = iFilePropertiesOffset + 48;
+	TPtrC8 duration8 = iHeaderData->Mid(offset - 24, 8); // 100 nanosec units
+	TReal sec = ((TReal)ConvertToInt64(duration8)) / 10000000; // seconds
+	TBuf16<10> des16;
+	des16.Num(sec, TRealFormat (9, 3));
+	iContainer->AppendL( EMetaDataDuration, des16 );
+	}
+
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ConvertToUnicodeL
+// -----------------------------------------------------------------------------
+//
+TInt CMetaDataParserWMA::ConvertToUnicodeL(
+	const TDesC8& aDesc,
+	TDes16& aUnicode )
+	{
+	TPtrC8 unicodeData;
+  TUint characterSetId = 0;
+	CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
+	TInt state = CCnvCharacterSetConverter::KStateDefault;
+
+	// ASF (WMA) file format has UTF-16 LittleEndian characters.
+	characterSetId = KCharacterSetIdentifierUnicodeLittle;
+	unicodeData.Set( aDesc );
+	
+	charSetConv->PrepareToConvertToOrFromL(characterSetId, *iCharacterSet, iFs);
+	TInt err = charSetConv->ConvertToUnicode(aUnicode, unicodeData, state);
+
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::ConvertToUnicode :-> Tag Size[%d] Unicode Tag Size[%d]Bytes Unconverted[%d]"),
+		unicodeData.Length(), aUnicode.Length(), err);
+#endif
+
+	CleanupStack::PopAndDestroy();	// charSetConv
+	return err;
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ParseContentDescriptionObject
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ParseContentDescriptionObject()
+	{
+		TBuf8<2> data = iHeaderData->Mid(iContentDescriptionOffset + 24, 2);
+		iTitleLength = ConvertToInt16(data); 
+		data = iHeaderData->Mid(iContentDescriptionOffset + 26, 2);
+		iAuthorLength = ConvertToInt16(data); 
+		data = iHeaderData->Mid(iContentDescriptionOffset + 28, 2);
+		iCopyrightLength = ConvertToInt16(data); 
+		data = iHeaderData->Mid(iContentDescriptionOffset + 30, 2);
+		iDescriptionLength = ConvertToInt16(data); 
+		data = iHeaderData->Mid(iContentDescriptionOffset + 32, 2);
+		iRatingLength = ConvertToInt16(data);
+		return;
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ParseExtendedContentDescriptionObjectL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ParseExtendedContentDescriptionObjectL()
+	{
+	TBuf8<2> data  =  iHeaderData->Mid(iExtendedContentDescriptionOffset + 24, 2);
+	iExtendedContentDescriptionCount = ConvertToInt16(data);
+	TInt offset = iExtendedContentDescriptionOffset + 26;
+	for(TInt i = 0 ; i < iExtendedContentDescriptionCount; i ++)
+		{
+		TBuf8<2> data1  =  iHeaderData->Mid(offset, 2);
+		offset += 2;
+		TInt nameLength = ConvertToInt16(data1);
+		if(nameLength > 0 && iHeaderData->Length() >= (offset+nameLength))
+			{
+			HBufC8 *name = iHeaderData->Mid(offset, nameLength).AllocLC();
+			offset += nameLength;
+			HBufC* data16 = HBufC::NewLC(nameLength/2 == 0 ? 1 : nameLength/2);
+			TPtr name16( data16->Des() );
+			ConvertDes8toDes16(*name, name16);
+			
+			if(!name16.Compare(KWMAlbumTitle))
+				{
+				iAlbumTitleOffset = offset; 
+				}
+			else if(!name16.Compare(KWMPicture))
+				{
+				iPictureOffset = offset; 
+				}
+			else if(!name16.Compare(KWMText))
+				{
+				iTextOffset = offset; 
+				}
+			else if(!name16.Compare(KWMComposer))
+				{
+				iComposerOffset = offset; 
+				}
+			else if(!name16.Compare(KWMGenre))
+				{
+				iGenreOffset = offset; 
+				}
+			else if(!name16.Compare(KWMYear) || !name16.Compare(KWMYear1))
+				{
+				iYearOffset = offset; 
+				}
+			else if(!name16.Compare(KWMOriginalArtist))
+				{
+				iOriginalArtistOffset = offset; 
+				}
+			else if(!name16.Compare(KWMTrackNumber))
+				{
+				iTrackNumberOffset = offset; 
+				}
+			else if(!name16.Compare(KWMUniqueFileIdentifier))
+				{
+				iUniqueFileIdentifierOffset = offset; 
+				}
+			else if(!name16.Compare(KWMAudioFileURL))
+				{
+				iAudioFileURLOffset = offset; 
+				}
+			else if(!name16.Compare(KWMSharedUserRating))
+				{
+				iSharedUserRatingOffset = offset; 
+				}
+			else if(!name16.Compare(KWMDate))
+				{
+				iDateOffset = offset; 
+				}
+		#ifdef __WINDOWS_MEDIA
+			else if(!name16.Compare(KWMProvider))
+				{
+				iProviderOffset = offset; 
+				}
+		#endif
+
+			offset += 2;
+			TBuf8<2> valueLengthData  =  iHeaderData->Mid(offset, 2);
+			offset += 2;
+			TInt valueLength = ConvertToInt16(valueLengthData);
+			offset += valueLength;
+			CleanupStack::PopAndDestroy(2); //data16, name
+			if(iHeaderData->Length() < offset)
+				{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserWMA::ParseExtendedContentDescriptionObjectL: offset[%d] > iHeaderData's Length[%d]."),
+			offset, iHeaderData->Length());
+#endif
+				return;
+				}
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ParseMetadataLibraryObjectL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ParseMetadataLibraryObjectL()
+	{
+	TBuf8<8> objectSizedata  =  iHeaderData->Mid(iMetadataLibraryOffset + 16, 8);
+	iMetadataLibraryObjectSize = ConvertToInt64(objectSizedata);
+	TBuf8<2> recordsCountdata  =  iHeaderData->Mid(iMetadataLibraryOffset + 24, 2);
+	iMetadataLibraryDescriptionCount = ConvertToInt16(recordsCountdata);
+	TInt offset = iMetadataLibraryOffset + 26;
+	for(TInt i = 0 ; i < iMetadataLibraryDescriptionCount; i ++)
+		{
+		offset += 4; // skipping LanguageID (2 Bytes) and StreamID (2 Bytes) fields
+		//Reading Name Length 
+		TBuf8<2> nameLengthdata  =  iHeaderData->Mid(offset, 2);
+		offset += 2;
+		TInt nameLength = ConvertToInt16(nameLengthdata);
+		TBuf8<2> dataTypedata  =  iHeaderData->Mid(offset, 2);
+		offset += 2;
+		TInt dataType = ConvertToInt16(dataTypedata);
+		TBuf8<4> dataLengthdata  =  iHeaderData->Mid(offset, 4);
+		offset += 4;
+		TInt32 dataLength = ConvertToInt32(dataLengthdata);
+		
+		if(nameLength > 0)
+			{
+			HBufC8 *name = iHeaderData->Mid(offset, nameLength).AllocLC();
+			offset += nameLength;
+			HBufC* data16 = HBufC::NewLC( nameLength/2);
+			TPtr name16( data16->Des() );
+			ConvertDes8toDes16(*name, name16);
+			if(!name16.Compare(KWMPicture))
+				{
+				iPictureOffset = offset;
+				iMetadatLibraryObjectJpegExists = ETrue; 
+				}
+			offset += dataLength;
+			CleanupStack::PopAndDestroy(2); //data16, name
+			}
+		}
+	}
+	
+// -----------------------------------------------------------------------------
+// CMetaDataParserWMA::ParseHeaderExtensionObjectL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserWMA::ParseHeaderExtensionObjectL()
+	{
+	TInt length = iHeaderData->Length();
+    if ( iHeaderExtensionOffset + 46 > length)
+        {
+        return; 
+        }
+        
+	TBuf8<8> objectSizedata  =  iHeaderData->Mid(iHeaderExtensionOffset + 16, 8);
+	iHeaderExtensionObjectSize = ConvertToInt64(objectSizedata);
+	TBuf8<4> headerExtensiondata  =  iHeaderData->Mid(iHeaderExtensionOffset + 42, 4);
+	
+	TInt32 headerExtensionDataSize = ConvertToInt32(headerExtensiondata);
+	if(headerExtensionDataSize != iHeaderExtensionObjectSize - 46)
+	{
+		return;
+	}
+	TInt objOffset = iHeaderExtensionOffset + 46;
+	
+    if ((objOffset < 0) || (objOffset + 16 > length))   // verify objOffset is not negative
+        {
+        return; 
+        }	
+	TBuf8<32> objGUID = iHeaderData->Mid(objOffset, 16);
+	FormatGUID(objGUID);
+	TBool loop = ETrue;
+	while (loop)
+		{
+		if(!iMetadataLibraryObjectExists && objGUID == 
+			KASFMetadataLibraryObject)
+			{
+			iMetadataLibraryObjectExists = ETrue;
+			iMetadataLibraryOffset = objOffset;
+			}
+				
+        if (objOffset + 24 > length)
+            {
+            return; 
+            }	
+			
+		TBuf8<8> size = iHeaderData->Mid(objOffset + 16, 8); 
+		TInt objSize = ConvertToInt64(size); // upper 32 bits?
+		if(objSize == 0)
+			{
+			return;
+			}
+		objOffset += objSize;
+		
+        if ((objOffset < 0) || (objOffset + 16 > length))
+            {
+            return; 
+            }				
+		objGUID = iHeaderData->Mid(objOffset, 16);
+		FormatGUID(objGUID);
+		TInt val = objOffset - iHeaderExtensionOffset; 
+		if((val > 0) && (val < iHeaderExtensionObjectSize))
+			{
+			loop = ETrue;
+			}
+		else
+			{
+			loop = EFalse;
+			}
+		}
+	}	
+
+//  End of File