mmserv/metadatautility/Src/MetaDataParserID3v24.cpp
changeset 0 71ca22bcf22a
child 11 03a293c97d5c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/metadatautility/Src/MetaDataParserID3v24.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,823 @@
+/*
+* 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 parsing of ID3v2.4 according to the
+*                specification found in www.id3.org. Note that only a selected
+*				 frames are supported at this time.
+*
+*/
+
+
+
+// INCLUDE FILES
+#include    <libc/stdlib.h>
+#include	"MetaDataParserID3v24.h"
+
+// CONSTANTS
+// (ID3v2.4 specification found in www.id3.org)
+const TInt KID3v2HeaderLength 			= 10;
+const TInt KID3v2ExtendedHeaderLength 	= 6;
+const TInt KID3v2FrameHeaderLength 		= 10;
+const TInt KID3v2FrameIdLength 			= 4;
+const TInt KID3v2GenreNameLength 		= 24;
+
+_LIT8( KID3v2FrameIdTitle, 			"TIT2" );
+_LIT8( KID3v2FrameIdArtist, 		"TPE1" );
+_LIT8( KID3v2FrameIdAlbum, 			"TALB" );
+_LIT8( KID3v2FrameIdYear, 			"TDRC" );
+_LIT8( KID3v2FrameIdComment, 		"COMM" );
+_LIT8( KID3v2FrameIdTrack, 			"TRCK" );
+_LIT8( KID3v2FrameIdGenre, 			"TCON" );
+_LIT8( KID3v2FrameIdComposer, 		"TCOM" );
+_LIT8( KID3v2FrameIdCopyright, 		"TCOP" );
+_LIT8( KID3v2FrameIdOriginalArtist,	"TOPE" );
+_LIT8( KID3v2FrameIdUrl, 			"WOAF" );
+_LIT8( KID3v2FrameIdUserUrl, 		"WXXX" );
+_LIT8( KID3v2FrameIdJpeg, 			"APIC" );
+_LIT8( KID3v2FrameIdDuration, 		"TLEN" );
+_LIT8( KID3v2FrameIdDate, 			"TDRC" ); // same as year
+_LIT8( KID3v2FrameIdRating,			"POPM" );
+
+_LIT8( KID3v2ImageFormatPngMime, 	"image/png" );
+_LIT8( KID3v2ImageFormatPng, 		"png" );
+_LIT8( KID3v2ImageFormatJpegMime, 	"image/jpeg" );
+_LIT8( KID3v2ImageFormatJpgMime, 	"image/jpg" );
+_LIT8( KID3v2ImageFormatJpeg, 		"jpeg" );
+
+
+// -----------------------------------------------------------------------------
+//   (ID3v2.4 specification found in www.id3.org)
+//
+//   $00   ISO-8859-1 [ISO-8859-1]. Terminated with $00.
+//   $01   UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All
+//         strings in the same frame SHALL have the same byteorder.
+//         Terminated with $00 00.
+//   $02   UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
+//         Terminated with $00 00.
+//   $03   UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00.
+// -----------------------------------------------------------------------------
+const TInt KMetaDataParserAsciiEncoding		= 0;
+const TInt KMetaDataParserUnicodeEncoding	= 1;
+const TInt KMetaDataParserUnicodeBEEncoding	= 2;
+const TInt KMetaDataParserUnicode8Encoding	= 3;
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::CMetaDataParserID3v24
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMetaDataParserID3v24::CMetaDataParserID3v24(
+	CMetaDataSource& aSource )
+	:	CMetaDataParserID3v2(aSource)
+	{
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::ConstructL()
+    {
+	User::LeaveIfError(iFs.Connect());
+	iExists = ETrue;
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::ConstructL - Done"));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CMetaDataParserID3v24* CMetaDataParserID3v24::NewL(
+	CMetaDataSource& aSource )
+    {
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::NewL"));
+#endif
+	CMetaDataParserID3v24* self = new( ELeave ) CMetaDataParserID3v24( aSource );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Destructor
+CMetaDataParserID3v24::~CMetaDataParserID3v24()
+	{
+	iFs.Close();
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::PrepareToParseL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::PrepareToParseL()
+    {
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::PrepareToParseL"));
+#endif
+	// Most of validation was already done by builder.
+	TBuf8<KID3v2HeaderLength> header;
+	iSource->ReadL( 0, header );
+    // ID3v2.4 header consists of following parts:
+	// File identifier	"ID3"
+	// Version			$04 00
+	// Flags			%abcd0000
+	// Size				4 * %0xxxxxxx
+
+	// Read the data length
+	iFrameDataSize = 0;
+	for ( TInt i = 6; i < 10; i++ )
+		{
+		iFrameDataSize <<= 7;
+		iFrameDataSize |= header[i] & 0x7f;
+		}
+
+	// Check if extended header is present; bit-b in Flags above
+	if ( header[5] & 0x40 )
+		{
+		TBuf8<KID3v2ExtendedHeaderLength> extHeader;
+		iSource->ReadL( KID3v2HeaderLength, extHeader );
+		// ID3v2.4 extended header consists of following parts:
+		// Extended header size		4 * %0xxxxxxx
+		// Extended flags			$01
+		// Size	of padding			$xx
+
+		// Read the data length
+		TInt extHeaderSize = 0;
+		for ( TInt i = 0; i < 4; i++ )
+			{
+			extHeaderSize <<= 7;
+			extHeaderSize |= extHeader[i] & 0x7f;
+			}
+		iFrameOffset = KID3v2HeaderLength + KID3v2ExtendedHeaderLength + extHeaderSize;
+		}
+	else
+		{
+		iFrameOffset = KID3v2HeaderLength;
+		}
+
+	// iFrameDataSize is the entire size of ID3 tag including the header
+	iFrameDataSize += iFrameOffset;
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetNextFieldL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetNextFieldL(
+	TMetaDataFieldId& aFieldId,
+	TInt& aFrameHeaderSize,
+	TInt& aFrameSize )
+	{
+	TBuf8<KID3v2FrameHeaderLength> frameHeader;
+	iSource->ReadL( iFrameOffset, frameHeader );
+    // ID3v2.4 frame header consists of following parts:
+	// Frame identifier	$xx xx xx xx
+	// Size				4 * %0xxxxxxx
+	// Flags			$xx xx
+
+	aFrameSize = 0;
+
+	if(!frameHeader.Length())
+			User::Leave(KErrCorrupt);
+
+	for ( TInt i = 4; i < 8; i++ )
+		{
+		aFrameSize <<= 7;
+		aFrameSize |= frameHeader[i] & 0x7f;
+		}
+
+	aFrameHeaderSize = KID3v2FrameHeaderLength;
+	TPtrC8 frameId = frameHeader.Left( KID3v2FrameIdLength );
+	_LIT8(KEMPTY, "\0\0\0\0");
+	TBuf8<10> empty (KEMPTY);
+	if ( aFrameSize == 0 && frameId == empty)
+		{
+		// We have hit the padding -> no more fields to read
+		aFieldId = EUnknownMetaDataField;
+		aFrameHeaderSize = 0;
+		return;
+		}
+	else if (aFrameSize == 0)
+	{
+		aFieldId = EUnknownMetaDataField;
+		return;
+	}
+
+	if ( frameId.Compare( KID3v2FrameIdTitle ) == 0 )
+		{
+		aFieldId = EMetaDataSongTitle;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdArtist ) == 0 )
+		{
+		aFieldId = EMetaDataArtist;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdAlbum ) == 0 )
+		{
+		aFieldId = EMetaDataAlbum;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdYear ) == 0 )
+		{
+		aFieldId = EMetaDataYear;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdComment ) == 0 )
+		{
+		aFieldId = EMetaDataComment;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdTrack ) == 0 )
+		{
+		aFieldId = EMetaDataAlbumTrack;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdGenre ) == 0 )
+		{
+		aFieldId = EMetaDataGenre;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdComposer ) == 0 )
+		{
+		aFieldId = EMetaDataComposer;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdCopyright ) == 0 )
+		{
+		aFieldId = EMetaDataCopyright;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdOriginalArtist ) == 0 )
+		{
+		aFieldId = EMetaDataOriginalArtist;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdUrl ) == 0 )
+		{
+		aFieldId = EMetaDataUrl;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdUserUrl ) == 0 )
+		{
+		aFieldId = EMetaDataUserUrl;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdJpeg ) == 0 )
+		{
+		aFieldId = EMetaDataJpeg;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdDuration ) == 0 )
+		{
+		aFieldId = EMetaDataDuration;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdDate ) == 0 )
+		{
+		aFieldId = EMetaDataDate;
+		}
+	else if ( frameId.Compare( KID3v2FrameIdRating ) == 0 )
+		{
+		aFieldId = EMetaDataRating;
+		}
+	else
+		{
+		aFieldId = EUnknownMetaDataField;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v23::GetUserUrlL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetUserUrlL(
+	TInt aSize )
+	{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v23::GetUserUrlL"));
+#endif
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+
+	TInt encoding = (TInt) (des.Left(1))[0];
+
+	if(encoding == 0x00)
+	{
+		_LIT8(KNULL, "\0");
+		TInt descOffset = des.Find(KNULL);
+		if(descOffset + 2 > aSize)
+		{
+			CleanupStack::PopAndDestroy();  // frame
+			return; // empty frame
+		}
+		TPtrC8 info = des.Mid(descOffset + 2);
+		TInt length = info.Length();
+		if ( length )
+			{
+			HBufC* data16 = HBufC::NewLC( length );
+			TPtr unicode( data16->Des() );
+			unicode.Copy( info );
+			iContainer->AppendL( EMetaDataUserUrl, unicode );
+			CleanupStack::PopAndDestroy();  // data16
+			}
+	}
+	else
+	{
+		_LIT8(KNULL, "\0\0");
+		TInt descOffset = des.Find(KNULL);
+		if(descOffset + 3 > aSize)
+		{
+			CleanupStack::PopAndDestroy();  // frame
+			return; // empty frame
+		}
+		TPtrC8 info = des.Mid(descOffset + 3);
+		TInt length = info.Length();
+		if ( length )
+			{
+			HBufC* data16 = HBufC::NewLC( length );
+			TPtr unicode( data16->Des() );
+			unicode.Copy( info );
+			iContainer->AppendL( EMetaDataUserUrl, unicode );
+			CleanupStack::PopAndDestroy();  // data16
+			}
+	}
+
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetTextInfoL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetTextInfoL(
+	TMetaDataFieldId aFieldId,
+	TInt aSize )
+	{
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+
+	TInt encoding = (TInt) (des.Left(1))[0];
+	TPtrC8 info = StripTrailingZeroes( des.Mid(1), encoding );
+	TInt length = info.Length();
+	if ( length )
+		{
+		HBufC* data16 = HBufC::NewLC( length );
+		TPtr unicode( data16->Des() );
+		if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone )
+			{
+			iContainer->AppendL( aFieldId, unicode );
+			}
+		CleanupStack::PopAndDestroy();  // data16
+		}
+
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetGenreL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetGenreL(
+	TInt aSize )
+	{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::GetGenreL"));
+#endif
+
+	HandleV2GetGenreL( aSize, KID3v2FrameHeaderLength, KID3v2GenreNameLength  );
+	}
+// CMetaDataParserID3v24::GetTextYearL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetTextYearL(
+	TInt aSize )
+	{
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+
+	TInt encoding = (TInt) (des.Left(1))[0];
+	// Timestamp may be one of the following formats:
+	// yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and yyyy-MM-ddTHH:mm:ss
+	// We are only interested in year.
+	TPtrC8 drc = StripTrailingZeroes( des.Mid(1), encoding );
+	TInt length = drc.Length();
+	if ( length >= 4) // 4 bytes year
+		{
+		TPtrC8 info = drc.Mid(0, 4);
+		length = info.Length();
+		HBufC* data16 = HBufC::NewLC( length );
+		TPtr unicode( data16->Des() );
+		if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone )
+			{
+			iContainer->AppendL( EMetaDataYear, unicode );
+			}
+		CleanupStack::PopAndDestroy();  // data16
+		}
+
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetCommentL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetCommentL(
+	TInt aSize )
+	{
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+		
+	if(aSize <= 4) // emppty frame
+	{
+		CleanupStack::PopAndDestroy();  // frame
+		return;
+	}
+	TInt encoding = (TInt) (des.Left(1))[0];
+	// Skip over TextEncoding(1 byte) and Language(3 bytes)
+	TPtr8 text = des.MidTPtr(4);
+	// Skip over Content description from Comment
+	TInt contentDesLength;
+	if(encoding == 0 || encoding == 3)
+		{
+		_LIT8(KNull, "\0");
+		contentDesLength = text.Find(KNull);
+		text = text.MidTPtr(contentDesLength + 1);
+		}
+	else
+		{
+		_LIT8(KNull, "\0\0");
+		contentDesLength = text.Find(KNull);
+		text = text.MidTPtr(contentDesLength + 2);
+		}
+	TPtrC8 info = StripTrailingZeroes( text, encoding);
+	TInt length = info.Length();
+	if ( length )
+		{
+		HBufC* data16 = HBufC::NewLC( length );
+		TPtr unicode( data16->Des() );
+		if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone )
+			{
+			iContainer->AppendL( EMetaDataComment, unicode );
+			}
+		CleanupStack::PopAndDestroy();  // data16
+		}
+
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetUrlL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetUrlL(
+	TInt aSize )
+	{
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+
+	// Ignore information followed by termination $00
+    TInt trueEnd( des.Locate(0) );
+    if ( trueEnd == KErrNotFound )
+        {
+        trueEnd = des.Length();
+		}
+
+	TPtrC8 info = des.Left( trueEnd );
+	TInt length = info.Length();
+	if ( length )
+		{
+		HBufC* data16 = HBufC::NewLC( length );
+		TPtr unicode( data16->Des() );
+		unicode.Copy( info );
+		iContainer->AppendL( EMetaDataUrl, unicode );
+		CleanupStack::PopAndDestroy();  // data16
+		}
+
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetJpegL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetJpegL(
+	TInt aSize )
+	{
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+
+	TInt encoding = (TInt) (des.Left(1))[0];
+
+	TInt mimeLength = des.Mid(1).Locate(0);
+	if(mimeLength <= 0 )
+		{
+		User::Leave(KErrCorrupt);	
+		}
+	TPtrC8 mime = des.Mid(1, mimeLength);
+
+	if ( ( mime.Compare( KID3v2ImageFormatJpeg ) != 0 ) &&
+		 ( mime.Compare( KID3v2ImageFormatJpegMime ) != 0 ) && 
+		 ( mime.Compare( KID3v2ImageFormatJpgMime ) != 0 ) &&
+		 ( mime.Compare( KID3v2ImageFormatPngMime ) != 0 ) &&
+		 ( mime.Compare( KID3v2ImageFormatPng ) != 0 )
+		 )
+		{
+		CleanupStack::PopAndDestroy();  // frame
+		return;
+		}
+
+	if(mimeLength+3 > des.Length())
+		{
+		CleanupStack::PopAndDestroy();  // frame
+		return;
+		}
+
+	TInt pictureType = (TInt) (des.Mid(mimeLength + 2, 1))[0];
+	if ( !NeedRetrieveAlbumArt(pictureType) )
+		{
+		CleanupStack::PopAndDestroy();  // frame
+		return;
+		}
+
+    TInt picOffset;
+    TPtrC8 text8 = des.Mid(mimeLength + 3 );
+    if ( encoding == KMetaDataParserAsciiEncoding )
+        {
+        picOffset = text8.Locate(0);
+        if ( picOffset == KErrNotFound )
+            {
+            CleanupStack::PopAndDestroy();  // frame
+            return;
+            }
+        
+        picOffset++;        // Description termination mark ($00)
+        }
+    else if ( encoding == KMetaDataParserUnicodeEncoding )
+        {
+        _LIT8(KNULL, "\0\0");               // 2 bytes of NULL
+        picOffset = text8.Find(KNULL);
+        if ( picOffset == KErrNotFound )
+            {
+            CleanupStack::PopAndDestroy();  // frame
+            return;
+            }
+        if (picOffset % 2)      // check for offset odd number 
+            {
+            picOffset++;        // add 1 for word boundary
+            }
+		picOffset += 2;		// Description termination mark ($00 00)
+		}
+	else
+		{
+		CleanupStack::PopAndDestroy();  // frame
+		return;
+		}
+
+	TPtrC8 pic = des.Mid(picOffset + mimeLength + 3);
+	TInt length = pic.Length();
+    if ( length )
+        {
+        // save the offset and the size for retrieving the album art later
+        iAlbumOffset = picOffset + mimeLength + 3;
+        iAlbumType = pictureType;
+        
+        if (iAlbumPtr)
+            {
+            delete iAlbumPtr;       // delete the previous buffer
+            }
+        CleanupStack::Pop();        // frame - pop from Cleanup stack
+        iAlbumPtr = frame;          // save the buffer
+        }
+    else
+        {
+        CleanupStack::PopAndDestroy();  // frame        
+        }
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetDurationL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetDurationL(
+	TInt aSize )
+	{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v23::GetDurationL"));
+#endif
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+
+	TInt encoding = (TInt) (des.Left(1))[0];
+	TPtrC8 info = StripTrailingZeroes( des.Mid(1), encoding ); // $00
+	TInt length = info.Length();
+	if ( length )
+		{
+		TReal sec = (TReal) atoi((char*)info.Ptr()) / 1000;
+		TBuf16<10> info1;
+		info1.Num(sec, TRealFormat (9, 3));
+		iContainer->AppendL( EMetaDataDuration, info1 );
+		}
+
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetTextDateL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetTextDateL(
+	TInt aSize )
+	{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::GetTextDateL"));
+#endif
+	GetTextInfoL( EMetaDataDate, aSize );
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::GetRatingL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataParserID3v24::GetRatingL(	TInt aSize )
+	{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v24::GetRatingL"));
+#endif
+	HBufC8* frame = HBufC8::NewLC( aSize );
+	TPtr8 des( frame->Des() );
+
+	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
+
+	if ( des.Length() < aSize )
+		{
+		// Partial frame
+		User::Leave( KErrCorrupt );
+		}
+	_LIT8(KNull, "\0");
+	TInt offset = des.Find(KNull);
+	if(offset == KErrNotFound)
+		{
+		CleanupStack::PopAndDestroy();
+		return;
+		}
+	TUint8 rating = des[offset];
+	if ( rating > 0)
+		{
+		TBuf<8> data16;
+		data16.AppendNum(rating);
+		iContainer->AppendL( EMetaDataRating, data16 );
+		}
+	CleanupStack::PopAndDestroy();  // frame
+	}
+
+// -----------------------------------------------------------------------------
+// CMetaDataParserID3v24::ConvertToUnicodeL
+// -----------------------------------------------------------------------------
+//
+TInt CMetaDataParserID3v24::ConvertToUnicodeL(
+	TInt aEncoding,
+	const TDesC8& aDesc,
+	TDes16& aUnicode )
+	{
+#ifdef _DEBUG
+	RDebug::Print(_L("CMetaDataParserID3v23::ConvertToUnicodeL"));
+#endif
+	TPtrC8 unicodeData;
+    TUint characterSetId = 0;
+	TInt err;
+
+	CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
+	TInt state = CCnvCharacterSetConverter::KStateDefault;
+
+	if ( aEncoding == KMetaDataParserAsciiEncoding )
+		{
+		if(iAutoDetectChinese || iAutoDetectRussian || iAutoDetectJapanese)
+			{
+			err = AutoDetectL(aDesc, aUnicode);
+			CleanupStack::PopAndDestroy();	// charSetConv
+	        return err;
+			}
+		else
+			{
+			// ISO-8859-1
+			characterSetId = KCharacterSetIdentifierIso88591;
+			unicodeData.Set( aDesc );
+			}
+		}
+	else if ( aEncoding == KMetaDataParserUnicodeEncoding )
+		{
+		// UTF-16 Big Endian with BOM
+		TInt bom = UnicodeBOM(aDesc);
+		if ( bom == KUnicodeBOMBigEndian )
+			{
+			//characterSetId = KCharacterSetIdentifierUcs2;
+			characterSetId = KCharacterSetIdentifierUnicodeBig;
+			// Skip BOM & Terminate marks
+			unicodeData.Set( aDesc.Mid( 2, aDesc.Length() - 2 ) );
+			}
+		else if ( bom == KUnicodeBOMLittleEndian )
+			{
+			characterSetId = KCharacterSetIdentifierUnicodeLittle;
+			// Skip BOM & Terminate marks
+			unicodeData.Set( aDesc.Mid( 2, aDesc.Length() - 2 ) );
+			}
+		else
+			{
+			// UTF-16 Big Endian without BOM
+			characterSetId = KCharacterSetIdentifierUnicodeBig;
+			unicodeData.Set( aDesc );
+			}
+		}
+	else if ( aEncoding == KMetaDataParserUnicodeBEEncoding )
+		{
+		// UTF-16 Big Endian without BOM
+		characterSetId = KCharacterSetIdentifierUnicodeBig;
+		unicodeData.Set( aDesc );
+		}
+	else if ( aEncoding == KMetaDataParserUnicode8Encoding )
+		{
+		// UTF-8
+		characterSetId = KCharacterSetIdentifierUtf8;
+		unicodeData.Set( aDesc );
+		}
+	else
+		{
+		User::Leave(KErrNotSupported);
+		}
+
+	charSetConv->PrepareToConvertToOrFromL(characterSetId, *iCharacterSet, iFs);
+	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;
+	}
+
+//  End of File