mmserv/metadatautility/Src/MetaDataParserID3v24.cpp
changeset 0 71ca22bcf22a
child 11 03a293c97d5c
equal deleted inserted replaced
-1:000000000000 0:71ca22bcf22a
       
     1 /*
       
     2 * Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  This class implements parsing of ID3v2.4 according to the
       
    15 *                specification found in www.id3.org. Note that only a selected
       
    16 *				 frames are supported at this time.
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 
       
    22 // INCLUDE FILES
       
    23 #include    <libc/stdlib.h>
       
    24 #include	"MetaDataParserID3v24.h"
       
    25 
       
    26 // CONSTANTS
       
    27 // (ID3v2.4 specification found in www.id3.org)
       
    28 const TInt KID3v2HeaderLength 			= 10;
       
    29 const TInt KID3v2ExtendedHeaderLength 	= 6;
       
    30 const TInt KID3v2FrameHeaderLength 		= 10;
       
    31 const TInt KID3v2FrameIdLength 			= 4;
       
    32 const TInt KID3v2GenreNameLength 		= 24;
       
    33 
       
    34 _LIT8( KID3v2FrameIdTitle, 			"TIT2" );
       
    35 _LIT8( KID3v2FrameIdArtist, 		"TPE1" );
       
    36 _LIT8( KID3v2FrameIdAlbum, 			"TALB" );
       
    37 _LIT8( KID3v2FrameIdYear, 			"TDRC" );
       
    38 _LIT8( KID3v2FrameIdComment, 		"COMM" );
       
    39 _LIT8( KID3v2FrameIdTrack, 			"TRCK" );
       
    40 _LIT8( KID3v2FrameIdGenre, 			"TCON" );
       
    41 _LIT8( KID3v2FrameIdComposer, 		"TCOM" );
       
    42 _LIT8( KID3v2FrameIdCopyright, 		"TCOP" );
       
    43 _LIT8( KID3v2FrameIdOriginalArtist,	"TOPE" );
       
    44 _LIT8( KID3v2FrameIdUrl, 			"WOAF" );
       
    45 _LIT8( KID3v2FrameIdUserUrl, 		"WXXX" );
       
    46 _LIT8( KID3v2FrameIdJpeg, 			"APIC" );
       
    47 _LIT8( KID3v2FrameIdDuration, 		"TLEN" );
       
    48 _LIT8( KID3v2FrameIdDate, 			"TDRC" ); // same as year
       
    49 _LIT8( KID3v2FrameIdRating,			"POPM" );
       
    50 
       
    51 _LIT8( KID3v2ImageFormatPngMime, 	"image/png" );
       
    52 _LIT8( KID3v2ImageFormatPng, 		"png" );
       
    53 _LIT8( KID3v2ImageFormatJpegMime, 	"image/jpeg" );
       
    54 _LIT8( KID3v2ImageFormatJpgMime, 	"image/jpg" );
       
    55 _LIT8( KID3v2ImageFormatJpeg, 		"jpeg" );
       
    56 
       
    57 
       
    58 // -----------------------------------------------------------------------------
       
    59 //   (ID3v2.4 specification found in www.id3.org)
       
    60 //
       
    61 //   $00   ISO-8859-1 [ISO-8859-1]. Terminated with $00.
       
    62 //   $01   UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All
       
    63 //         strings in the same frame SHALL have the same byteorder.
       
    64 //         Terminated with $00 00.
       
    65 //   $02   UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
       
    66 //         Terminated with $00 00.
       
    67 //   $03   UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00.
       
    68 // -----------------------------------------------------------------------------
       
    69 const TInt KMetaDataParserAsciiEncoding		= 0;
       
    70 const TInt KMetaDataParserUnicodeEncoding	= 1;
       
    71 const TInt KMetaDataParserUnicodeBEEncoding	= 2;
       
    72 const TInt KMetaDataParserUnicode8Encoding	= 3;
       
    73 
       
    74 // ============================ MEMBER FUNCTIONS ===============================
       
    75 
       
    76 // -----------------------------------------------------------------------------
       
    77 // CMetaDataParserID3v24::CMetaDataParserID3v24
       
    78 // C++ default constructor can NOT contain any code, that
       
    79 // might leave.
       
    80 // -----------------------------------------------------------------------------
       
    81 //
       
    82 CMetaDataParserID3v24::CMetaDataParserID3v24(
       
    83 	CMetaDataSource& aSource )
       
    84 	:	CMetaDataParserID3v2(aSource)
       
    85 	{
       
    86     }
       
    87 
       
    88 // -----------------------------------------------------------------------------
       
    89 // CMetaDataParserID3v24::ConstructL
       
    90 // Symbian 2nd phase constructor can leave.
       
    91 // -----------------------------------------------------------------------------
       
    92 //
       
    93 void CMetaDataParserID3v24::ConstructL()
       
    94     {
       
    95 	User::LeaveIfError(iFs.Connect());
       
    96 	iExists = ETrue;
       
    97 #ifdef _DEBUG
       
    98 	RDebug::Print(_L("CMetaDataParserID3v24::ConstructL - Done"));
       
    99 #endif
       
   100     }
       
   101 
       
   102 // -----------------------------------------------------------------------------
       
   103 // CMetaDataParserID3v24::NewL
       
   104 // Two-phased constructor.
       
   105 // -----------------------------------------------------------------------------
       
   106 //
       
   107 CMetaDataParserID3v24* CMetaDataParserID3v24::NewL(
       
   108 	CMetaDataSource& aSource )
       
   109     {
       
   110 #ifdef _DEBUG
       
   111 	RDebug::Print(_L("CMetaDataParserID3v24::NewL"));
       
   112 #endif
       
   113 	CMetaDataParserID3v24* self = new( ELeave ) CMetaDataParserID3v24( aSource );
       
   114     CleanupStack::PushL( self );
       
   115     self->ConstructL();
       
   116     CleanupStack::Pop();
       
   117     return self;
       
   118     }
       
   119 
       
   120 // Destructor
       
   121 CMetaDataParserID3v24::~CMetaDataParserID3v24()
       
   122 	{
       
   123 	iFs.Close();
       
   124 	}
       
   125 
       
   126 // -----------------------------------------------------------------------------
       
   127 // CMetaDataParserID3v24::PrepareToParseL
       
   128 // -----------------------------------------------------------------------------
       
   129 //
       
   130 void CMetaDataParserID3v24::PrepareToParseL()
       
   131     {
       
   132 #ifdef _DEBUG
       
   133 	RDebug::Print(_L("CMetaDataParserID3v24::PrepareToParseL"));
       
   134 #endif
       
   135 	// Most of validation was already done by builder.
       
   136 	TBuf8<KID3v2HeaderLength> header;
       
   137 	iSource->ReadL( 0, header );
       
   138     // ID3v2.4 header consists of following parts:
       
   139 	// File identifier	"ID3"
       
   140 	// Version			$04 00
       
   141 	// Flags			%abcd0000
       
   142 	// Size				4 * %0xxxxxxx
       
   143 
       
   144 	// Read the data length
       
   145 	iFrameDataSize = 0;
       
   146 	for ( TInt i = 6; i < 10; i++ )
       
   147 		{
       
   148 		iFrameDataSize <<= 7;
       
   149 		iFrameDataSize |= header[i] & 0x7f;
       
   150 		}
       
   151 
       
   152 	// Check if extended header is present; bit-b in Flags above
       
   153 	if ( header[5] & 0x40 )
       
   154 		{
       
   155 		TBuf8<KID3v2ExtendedHeaderLength> extHeader;
       
   156 		iSource->ReadL( KID3v2HeaderLength, extHeader );
       
   157 		// ID3v2.4 extended header consists of following parts:
       
   158 		// Extended header size		4 * %0xxxxxxx
       
   159 		// Extended flags			$01
       
   160 		// Size	of padding			$xx
       
   161 
       
   162 		// Read the data length
       
   163 		TInt extHeaderSize = 0;
       
   164 		for ( TInt i = 0; i < 4; i++ )
       
   165 			{
       
   166 			extHeaderSize <<= 7;
       
   167 			extHeaderSize |= extHeader[i] & 0x7f;
       
   168 			}
       
   169 		iFrameOffset = KID3v2HeaderLength + KID3v2ExtendedHeaderLength + extHeaderSize;
       
   170 		}
       
   171 	else
       
   172 		{
       
   173 		iFrameOffset = KID3v2HeaderLength;
       
   174 		}
       
   175 
       
   176 	// iFrameDataSize is the entire size of ID3 tag including the header
       
   177 	iFrameDataSize += iFrameOffset;
       
   178     }
       
   179 
       
   180 // -----------------------------------------------------------------------------
       
   181 // CMetaDataParserID3v24::GetNextFieldL
       
   182 // -----------------------------------------------------------------------------
       
   183 //
       
   184 void CMetaDataParserID3v24::GetNextFieldL(
       
   185 	TMetaDataFieldId& aFieldId,
       
   186 	TInt& aFrameHeaderSize,
       
   187 	TInt& aFrameSize )
       
   188 	{
       
   189 	TBuf8<KID3v2FrameHeaderLength> frameHeader;
       
   190 	iSource->ReadL( iFrameOffset, frameHeader );
       
   191     // ID3v2.4 frame header consists of following parts:
       
   192 	// Frame identifier	$xx xx xx xx
       
   193 	// Size				4 * %0xxxxxxx
       
   194 	// Flags			$xx xx
       
   195 
       
   196 	aFrameSize = 0;
       
   197 
       
   198 	if(!frameHeader.Length())
       
   199 			User::Leave(KErrCorrupt);
       
   200 
       
   201 	for ( TInt i = 4; i < 8; i++ )
       
   202 		{
       
   203 		aFrameSize <<= 7;
       
   204 		aFrameSize |= frameHeader[i] & 0x7f;
       
   205 		}
       
   206 
       
   207 	aFrameHeaderSize = KID3v2FrameHeaderLength;
       
   208 	TPtrC8 frameId = frameHeader.Left( KID3v2FrameIdLength );
       
   209 	_LIT8(KEMPTY, "\0\0\0\0");
       
   210 	TBuf8<10> empty (KEMPTY);
       
   211 	if ( aFrameSize == 0 && frameId == empty)
       
   212 		{
       
   213 		// We have hit the padding -> no more fields to read
       
   214 		aFieldId = EUnknownMetaDataField;
       
   215 		aFrameHeaderSize = 0;
       
   216 		return;
       
   217 		}
       
   218 	else if (aFrameSize == 0)
       
   219 	{
       
   220 		aFieldId = EUnknownMetaDataField;
       
   221 		return;
       
   222 	}
       
   223 
       
   224 	if ( frameId.Compare( KID3v2FrameIdTitle ) == 0 )
       
   225 		{
       
   226 		aFieldId = EMetaDataSongTitle;
       
   227 		}
       
   228 	else if ( frameId.Compare( KID3v2FrameIdArtist ) == 0 )
       
   229 		{
       
   230 		aFieldId = EMetaDataArtist;
       
   231 		}
       
   232 	else if ( frameId.Compare( KID3v2FrameIdAlbum ) == 0 )
       
   233 		{
       
   234 		aFieldId = EMetaDataAlbum;
       
   235 		}
       
   236 	else if ( frameId.Compare( KID3v2FrameIdYear ) == 0 )
       
   237 		{
       
   238 		aFieldId = EMetaDataYear;
       
   239 		}
       
   240 	else if ( frameId.Compare( KID3v2FrameIdComment ) == 0 )
       
   241 		{
       
   242 		aFieldId = EMetaDataComment;
       
   243 		}
       
   244 	else if ( frameId.Compare( KID3v2FrameIdTrack ) == 0 )
       
   245 		{
       
   246 		aFieldId = EMetaDataAlbumTrack;
       
   247 		}
       
   248 	else if ( frameId.Compare( KID3v2FrameIdGenre ) == 0 )
       
   249 		{
       
   250 		aFieldId = EMetaDataGenre;
       
   251 		}
       
   252 	else if ( frameId.Compare( KID3v2FrameIdComposer ) == 0 )
       
   253 		{
       
   254 		aFieldId = EMetaDataComposer;
       
   255 		}
       
   256 	else if ( frameId.Compare( KID3v2FrameIdCopyright ) == 0 )
       
   257 		{
       
   258 		aFieldId = EMetaDataCopyright;
       
   259 		}
       
   260 	else if ( frameId.Compare( KID3v2FrameIdOriginalArtist ) == 0 )
       
   261 		{
       
   262 		aFieldId = EMetaDataOriginalArtist;
       
   263 		}
       
   264 	else if ( frameId.Compare( KID3v2FrameIdUrl ) == 0 )
       
   265 		{
       
   266 		aFieldId = EMetaDataUrl;
       
   267 		}
       
   268 	else if ( frameId.Compare( KID3v2FrameIdUserUrl ) == 0 )
       
   269 		{
       
   270 		aFieldId = EMetaDataUserUrl;
       
   271 		}
       
   272 	else if ( frameId.Compare( KID3v2FrameIdJpeg ) == 0 )
       
   273 		{
       
   274 		aFieldId = EMetaDataJpeg;
       
   275 		}
       
   276 	else if ( frameId.Compare( KID3v2FrameIdDuration ) == 0 )
       
   277 		{
       
   278 		aFieldId = EMetaDataDuration;
       
   279 		}
       
   280 	else if ( frameId.Compare( KID3v2FrameIdDate ) == 0 )
       
   281 		{
       
   282 		aFieldId = EMetaDataDate;
       
   283 		}
       
   284 	else if ( frameId.Compare( KID3v2FrameIdRating ) == 0 )
       
   285 		{
       
   286 		aFieldId = EMetaDataRating;
       
   287 		}
       
   288 	else
       
   289 		{
       
   290 		aFieldId = EUnknownMetaDataField;
       
   291 		}
       
   292 	}
       
   293 
       
   294 // -----------------------------------------------------------------------------
       
   295 // CMetaDataParserID3v23::GetUserUrlL
       
   296 // -----------------------------------------------------------------------------
       
   297 //
       
   298 void CMetaDataParserID3v24::GetUserUrlL(
       
   299 	TInt aSize )
       
   300 	{
       
   301 #ifdef _DEBUG
       
   302 	RDebug::Print(_L("CMetaDataParserID3v23::GetUserUrlL"));
       
   303 #endif
       
   304 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   305 	TPtr8 des( frame->Des() );
       
   306 
       
   307 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   308 
       
   309 	if ( des.Length() < aSize )
       
   310 		{
       
   311 		// Partial frame
       
   312 		User::Leave( KErrCorrupt );
       
   313 		}
       
   314 
       
   315 	TInt encoding = (TInt) (des.Left(1))[0];
       
   316 
       
   317 	if(encoding == 0x00)
       
   318 	{
       
   319 		_LIT8(KNULL, "\0");
       
   320 		TInt descOffset = des.Find(KNULL);
       
   321 		if(descOffset + 2 > aSize)
       
   322 		{
       
   323 			CleanupStack::PopAndDestroy();  // frame
       
   324 			return; // empty frame
       
   325 		}
       
   326 		TPtrC8 info = des.Mid(descOffset + 2);
       
   327 		TInt length = info.Length();
       
   328 		if ( length )
       
   329 			{
       
   330 			HBufC* data16 = HBufC::NewLC( length );
       
   331 			TPtr unicode( data16->Des() );
       
   332 			unicode.Copy( info );
       
   333 			iContainer->AppendL( EMetaDataUserUrl, unicode );
       
   334 			CleanupStack::PopAndDestroy();  // data16
       
   335 			}
       
   336 	}
       
   337 	else
       
   338 	{
       
   339 		_LIT8(KNULL, "\0\0");
       
   340 		TInt descOffset = des.Find(KNULL);
       
   341 		if(descOffset + 3 > aSize)
       
   342 		{
       
   343 			CleanupStack::PopAndDestroy();  // frame
       
   344 			return; // empty frame
       
   345 		}
       
   346 		TPtrC8 info = des.Mid(descOffset + 3);
       
   347 		TInt length = info.Length();
       
   348 		if ( length )
       
   349 			{
       
   350 			HBufC* data16 = HBufC::NewLC( length );
       
   351 			TPtr unicode( data16->Des() );
       
   352 			unicode.Copy( info );
       
   353 			iContainer->AppendL( EMetaDataUserUrl, unicode );
       
   354 			CleanupStack::PopAndDestroy();  // data16
       
   355 			}
       
   356 	}
       
   357 
       
   358 	CleanupStack::PopAndDestroy();  // frame
       
   359 	}
       
   360 
       
   361 // -----------------------------------------------------------------------------
       
   362 // CMetaDataParserID3v24::GetTextInfoL
       
   363 // -----------------------------------------------------------------------------
       
   364 //
       
   365 void CMetaDataParserID3v24::GetTextInfoL(
       
   366 	TMetaDataFieldId aFieldId,
       
   367 	TInt aSize )
       
   368 	{
       
   369 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   370 	TPtr8 des( frame->Des() );
       
   371 
       
   372 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   373 
       
   374 	if ( des.Length() < aSize )
       
   375 		{
       
   376 		// Partial frame
       
   377 		User::Leave( KErrCorrupt );
       
   378 		}
       
   379 
       
   380 	TInt encoding = (TInt) (des.Left(1))[0];
       
   381 	TPtrC8 info = StripTrailingZeroes( des.Mid(1), encoding );
       
   382 	TInt length = info.Length();
       
   383 	if ( length )
       
   384 		{
       
   385 		HBufC* data16 = HBufC::NewLC( length );
       
   386 		TPtr unicode( data16->Des() );
       
   387 		if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone )
       
   388 			{
       
   389 			iContainer->AppendL( aFieldId, unicode );
       
   390 			}
       
   391 		CleanupStack::PopAndDestroy();  // data16
       
   392 		}
       
   393 
       
   394 	CleanupStack::PopAndDestroy();  // frame
       
   395 	}
       
   396 
       
   397 // -----------------------------------------------------------------------------
       
   398 // CMetaDataParserID3v24::GetGenreL
       
   399 // -----------------------------------------------------------------------------
       
   400 //
       
   401 void CMetaDataParserID3v24::GetGenreL(
       
   402 	TInt aSize )
       
   403 	{
       
   404 #ifdef _DEBUG
       
   405 	RDebug::Print(_L("CMetaDataParserID3v24::GetGenreL"));
       
   406 #endif
       
   407 
       
   408 	HandleV2GetGenreL( aSize, KID3v2FrameHeaderLength, KID3v2GenreNameLength  );
       
   409 	}
       
   410 // CMetaDataParserID3v24::GetTextYearL
       
   411 // -----------------------------------------------------------------------------
       
   412 //
       
   413 void CMetaDataParserID3v24::GetTextYearL(
       
   414 	TInt aSize )
       
   415 	{
       
   416 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   417 	TPtr8 des( frame->Des() );
       
   418 
       
   419 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   420 
       
   421 	if ( des.Length() < aSize )
       
   422 		{
       
   423 		// Partial frame
       
   424 		User::Leave( KErrCorrupt );
       
   425 		}
       
   426 
       
   427 	TInt encoding = (TInt) (des.Left(1))[0];
       
   428 	// Timestamp may be one of the following formats:
       
   429 	// yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and yyyy-MM-ddTHH:mm:ss
       
   430 	// We are only interested in year.
       
   431 	TPtrC8 drc = StripTrailingZeroes( des.Mid(1), encoding );
       
   432 	TInt length = drc.Length();
       
   433 	if ( length >= 4) // 4 bytes year
       
   434 		{
       
   435 		TPtrC8 info = drc.Mid(0, 4);
       
   436 		length = info.Length();
       
   437 		HBufC* data16 = HBufC::NewLC( length );
       
   438 		TPtr unicode( data16->Des() );
       
   439 		if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone )
       
   440 			{
       
   441 			iContainer->AppendL( EMetaDataYear, unicode );
       
   442 			}
       
   443 		CleanupStack::PopAndDestroy();  // data16
       
   444 		}
       
   445 
       
   446 	CleanupStack::PopAndDestroy();  // frame
       
   447 	}
       
   448 
       
   449 // -----------------------------------------------------------------------------
       
   450 // CMetaDataParserID3v24::GetCommentL
       
   451 // -----------------------------------------------------------------------------
       
   452 //
       
   453 void CMetaDataParserID3v24::GetCommentL(
       
   454 	TInt aSize )
       
   455 	{
       
   456 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   457 	TPtr8 des( frame->Des() );
       
   458 
       
   459 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   460 
       
   461 	if ( des.Length() < aSize )
       
   462 		{
       
   463 		// Partial frame
       
   464 		User::Leave( KErrCorrupt );
       
   465 		}
       
   466 		
       
   467 	if(aSize <= 4) // emppty frame
       
   468 	{
       
   469 		CleanupStack::PopAndDestroy();  // frame
       
   470 		return;
       
   471 	}
       
   472 	TInt encoding = (TInt) (des.Left(1))[0];
       
   473 	// Skip over TextEncoding(1 byte) and Language(3 bytes)
       
   474 	TPtr8 text = des.MidTPtr(4);
       
   475 	// Skip over Content description from Comment
       
   476 	TInt contentDesLength;
       
   477 	if(encoding == 0 || encoding == 3)
       
   478 		{
       
   479 		_LIT8(KNull, "\0");
       
   480 		contentDesLength = text.Find(KNull);
       
   481 		text = text.MidTPtr(contentDesLength + 1);
       
   482 		}
       
   483 	else
       
   484 		{
       
   485 		_LIT8(KNull, "\0\0");
       
   486 		contentDesLength = text.Find(KNull);
       
   487 		text = text.MidTPtr(contentDesLength + 2);
       
   488 		}
       
   489 	TPtrC8 info = StripTrailingZeroes( text, encoding);
       
   490 	TInt length = info.Length();
       
   491 	if ( length )
       
   492 		{
       
   493 		HBufC* data16 = HBufC::NewLC( length );
       
   494 		TPtr unicode( data16->Des() );
       
   495 		if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone )
       
   496 			{
       
   497 			iContainer->AppendL( EMetaDataComment, unicode );
       
   498 			}
       
   499 		CleanupStack::PopAndDestroy();  // data16
       
   500 		}
       
   501 
       
   502 	CleanupStack::PopAndDestroy();  // frame
       
   503 	}
       
   504 
       
   505 // -----------------------------------------------------------------------------
       
   506 // CMetaDataParserID3v24::GetUrlL
       
   507 // -----------------------------------------------------------------------------
       
   508 //
       
   509 void CMetaDataParserID3v24::GetUrlL(
       
   510 	TInt aSize )
       
   511 	{
       
   512 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   513 	TPtr8 des( frame->Des() );
       
   514 
       
   515 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   516 
       
   517 	if ( des.Length() < aSize )
       
   518 		{
       
   519 		// Partial frame
       
   520 		User::Leave( KErrCorrupt );
       
   521 		}
       
   522 
       
   523 	// Ignore information followed by termination $00
       
   524     TInt trueEnd( des.Locate(0) );
       
   525     if ( trueEnd == KErrNotFound )
       
   526         {
       
   527         trueEnd = des.Length();
       
   528 		}
       
   529 
       
   530 	TPtrC8 info = des.Left( trueEnd );
       
   531 	TInt length = info.Length();
       
   532 	if ( length )
       
   533 		{
       
   534 		HBufC* data16 = HBufC::NewLC( length );
       
   535 		TPtr unicode( data16->Des() );
       
   536 		unicode.Copy( info );
       
   537 		iContainer->AppendL( EMetaDataUrl, unicode );
       
   538 		CleanupStack::PopAndDestroy();  // data16
       
   539 		}
       
   540 
       
   541 	CleanupStack::PopAndDestroy();  // frame
       
   542 	}
       
   543 
       
   544 // -----------------------------------------------------------------------------
       
   545 // CMetaDataParserID3v24::GetJpegL
       
   546 // -----------------------------------------------------------------------------
       
   547 //
       
   548 void CMetaDataParserID3v24::GetJpegL(
       
   549 	TInt aSize )
       
   550 	{
       
   551 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   552 	TPtr8 des( frame->Des() );
       
   553 
       
   554 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   555 
       
   556 	if ( des.Length() < aSize )
       
   557 		{
       
   558 		// Partial frame
       
   559 		User::Leave( KErrCorrupt );
       
   560 		}
       
   561 
       
   562 	TInt encoding = (TInt) (des.Left(1))[0];
       
   563 
       
   564 	TInt mimeLength = des.Mid(1).Locate(0);
       
   565 	if(mimeLength <= 0 )
       
   566 		{
       
   567 		User::Leave(KErrCorrupt);	
       
   568 		}
       
   569 	TPtrC8 mime = des.Mid(1, mimeLength);
       
   570 
       
   571 	if ( ( mime.Compare( KID3v2ImageFormatJpeg ) != 0 ) &&
       
   572 		 ( mime.Compare( KID3v2ImageFormatJpegMime ) != 0 ) && 
       
   573 		 ( mime.Compare( KID3v2ImageFormatJpgMime ) != 0 ) &&
       
   574 		 ( mime.Compare( KID3v2ImageFormatPngMime ) != 0 ) &&
       
   575 		 ( mime.Compare( KID3v2ImageFormatPng ) != 0 )
       
   576 		 )
       
   577 		{
       
   578 		CleanupStack::PopAndDestroy();  // frame
       
   579 		return;
       
   580 		}
       
   581 
       
   582 	if(mimeLength+3 > des.Length())
       
   583 		{
       
   584 		CleanupStack::PopAndDestroy();  // frame
       
   585 		return;
       
   586 		}
       
   587 
       
   588 	TInt pictureType = (TInt) (des.Mid(mimeLength + 2, 1))[0];
       
   589 	if ( !NeedRetrieveAlbumArt(pictureType) )
       
   590 		{
       
   591 		CleanupStack::PopAndDestroy();  // frame
       
   592 		return;
       
   593 		}
       
   594 
       
   595     TInt picOffset;
       
   596     TPtrC8 text8 = des.Mid(mimeLength + 3 );
       
   597     if ( encoding == KMetaDataParserAsciiEncoding )
       
   598         {
       
   599         picOffset = text8.Locate(0);
       
   600         if ( picOffset == KErrNotFound )
       
   601             {
       
   602             CleanupStack::PopAndDestroy();  // frame
       
   603             return;
       
   604             }
       
   605         
       
   606         picOffset++;        // Description termination mark ($00)
       
   607         }
       
   608     else if ( encoding == KMetaDataParserUnicodeEncoding )
       
   609         {
       
   610         _LIT8(KNULL, "\0\0");               // 2 bytes of NULL
       
   611         picOffset = text8.Find(KNULL);
       
   612         if ( picOffset == KErrNotFound )
       
   613             {
       
   614             CleanupStack::PopAndDestroy();  // frame
       
   615             return;
       
   616             }
       
   617         if (picOffset % 2)      // check for offset odd number 
       
   618             {
       
   619             picOffset++;        // add 1 for word boundary
       
   620             }
       
   621 		picOffset += 2;		// Description termination mark ($00 00)
       
   622 		}
       
   623 	else
       
   624 		{
       
   625 		CleanupStack::PopAndDestroy();  // frame
       
   626 		return;
       
   627 		}
       
   628 
       
   629 	TPtrC8 pic = des.Mid(picOffset + mimeLength + 3);
       
   630 	TInt length = pic.Length();
       
   631     if ( length )
       
   632         {
       
   633         // save the offset and the size for retrieving the album art later
       
   634         iAlbumOffset = picOffset + mimeLength + 3;
       
   635         iAlbumType = pictureType;
       
   636         
       
   637         if (iAlbumPtr)
       
   638             {
       
   639             delete iAlbumPtr;       // delete the previous buffer
       
   640             }
       
   641         CleanupStack::Pop();        // frame - pop from Cleanup stack
       
   642         iAlbumPtr = frame;          // save the buffer
       
   643         }
       
   644     else
       
   645         {
       
   646         CleanupStack::PopAndDestroy();  // frame        
       
   647         }
       
   648 	}
       
   649 
       
   650 // -----------------------------------------------------------------------------
       
   651 // CMetaDataParserID3v24::GetDurationL
       
   652 // -----------------------------------------------------------------------------
       
   653 //
       
   654 void CMetaDataParserID3v24::GetDurationL(
       
   655 	TInt aSize )
       
   656 	{
       
   657 #ifdef _DEBUG
       
   658 	RDebug::Print(_L("CMetaDataParserID3v23::GetDurationL"));
       
   659 #endif
       
   660 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   661 	TPtr8 des( frame->Des() );
       
   662 
       
   663 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   664 
       
   665 	if ( des.Length() < aSize )
       
   666 		{
       
   667 		// Partial frame
       
   668 		User::Leave( KErrCorrupt );
       
   669 		}
       
   670 
       
   671 	TInt encoding = (TInt) (des.Left(1))[0];
       
   672 	TPtrC8 info = StripTrailingZeroes( des.Mid(1), encoding ); // $00
       
   673 	TInt length = info.Length();
       
   674 	if ( length )
       
   675 		{
       
   676 		TReal sec = (TReal) atoi((char*)info.Ptr()) / 1000;
       
   677 		TBuf16<10> info1;
       
   678 		info1.Num(sec, TRealFormat (9, 3));
       
   679 		iContainer->AppendL( EMetaDataDuration, info1 );
       
   680 		}
       
   681 
       
   682 	CleanupStack::PopAndDestroy();  // frame
       
   683 	}
       
   684 
       
   685 
       
   686 
       
   687 // -----------------------------------------------------------------------------
       
   688 // CMetaDataParserID3v24::GetTextDateL
       
   689 // -----------------------------------------------------------------------------
       
   690 //
       
   691 void CMetaDataParserID3v24::GetTextDateL(
       
   692 	TInt aSize )
       
   693 	{
       
   694 #ifdef _DEBUG
       
   695 	RDebug::Print(_L("CMetaDataParserID3v24::GetTextDateL"));
       
   696 #endif
       
   697 	GetTextInfoL( EMetaDataDate, aSize );
       
   698 	}
       
   699 
       
   700 // -----------------------------------------------------------------------------
       
   701 // CMetaDataParserID3v24::GetRatingL
       
   702 // -----------------------------------------------------------------------------
       
   703 //
       
   704 void CMetaDataParserID3v24::GetRatingL(	TInt aSize )
       
   705 	{
       
   706 #ifdef _DEBUG
       
   707 	RDebug::Print(_L("CMetaDataParserID3v24::GetRatingL"));
       
   708 #endif
       
   709 	HBufC8* frame = HBufC8::NewLC( aSize );
       
   710 	TPtr8 des( frame->Des() );
       
   711 
       
   712 	iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize );
       
   713 
       
   714 	if ( des.Length() < aSize )
       
   715 		{
       
   716 		// Partial frame
       
   717 		User::Leave( KErrCorrupt );
       
   718 		}
       
   719 	_LIT8(KNull, "\0");
       
   720 	TInt offset = des.Find(KNull);
       
   721 	if(offset == KErrNotFound)
       
   722 		{
       
   723 		CleanupStack::PopAndDestroy();
       
   724 		return;
       
   725 		}
       
   726 	TUint8 rating = des[offset];
       
   727 	if ( rating > 0)
       
   728 		{
       
   729 		TBuf<8> data16;
       
   730 		data16.AppendNum(rating);
       
   731 		iContainer->AppendL( EMetaDataRating, data16 );
       
   732 		}
       
   733 	CleanupStack::PopAndDestroy();  // frame
       
   734 	}
       
   735 
       
   736 // -----------------------------------------------------------------------------
       
   737 // CMetaDataParserID3v24::ConvertToUnicodeL
       
   738 // -----------------------------------------------------------------------------
       
   739 //
       
   740 TInt CMetaDataParserID3v24::ConvertToUnicodeL(
       
   741 	TInt aEncoding,
       
   742 	const TDesC8& aDesc,
       
   743 	TDes16& aUnicode )
       
   744 	{
       
   745 #ifdef _DEBUG
       
   746 	RDebug::Print(_L("CMetaDataParserID3v23::ConvertToUnicodeL"));
       
   747 #endif
       
   748 	TPtrC8 unicodeData;
       
   749     TUint characterSetId = 0;
       
   750 	TInt err;
       
   751 
       
   752 	CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
       
   753 	TInt state = CCnvCharacterSetConverter::KStateDefault;
       
   754 
       
   755 	if ( aEncoding == KMetaDataParserAsciiEncoding )
       
   756 		{
       
   757 		if(iAutoDetectChinese || iAutoDetectRussian || iAutoDetectJapanese)
       
   758 			{
       
   759 			err = AutoDetectL(aDesc, aUnicode);
       
   760 			CleanupStack::PopAndDestroy();	// charSetConv
       
   761 	        return err;
       
   762 			}
       
   763 		else
       
   764 			{
       
   765 			// ISO-8859-1
       
   766 			characterSetId = KCharacterSetIdentifierIso88591;
       
   767 			unicodeData.Set( aDesc );
       
   768 			}
       
   769 		}
       
   770 	else if ( aEncoding == KMetaDataParserUnicodeEncoding )
       
   771 		{
       
   772 		// UTF-16 Big Endian with BOM
       
   773 		TInt bom = UnicodeBOM(aDesc);
       
   774 		if ( bom == KUnicodeBOMBigEndian )
       
   775 			{
       
   776 			//characterSetId = KCharacterSetIdentifierUcs2;
       
   777 			characterSetId = KCharacterSetIdentifierUnicodeBig;
       
   778 			// Skip BOM & Terminate marks
       
   779 			unicodeData.Set( aDesc.Mid( 2, aDesc.Length() - 2 ) );
       
   780 			}
       
   781 		else if ( bom == KUnicodeBOMLittleEndian )
       
   782 			{
       
   783 			characterSetId = KCharacterSetIdentifierUnicodeLittle;
       
   784 			// Skip BOM & Terminate marks
       
   785 			unicodeData.Set( aDesc.Mid( 2, aDesc.Length() - 2 ) );
       
   786 			}
       
   787 		else
       
   788 			{
       
   789 			// UTF-16 Big Endian without BOM
       
   790 			characterSetId = KCharacterSetIdentifierUnicodeBig;
       
   791 			unicodeData.Set( aDesc );
       
   792 			}
       
   793 		}
       
   794 	else if ( aEncoding == KMetaDataParserUnicodeBEEncoding )
       
   795 		{
       
   796 		// UTF-16 Big Endian without BOM
       
   797 		characterSetId = KCharacterSetIdentifierUnicodeBig;
       
   798 		unicodeData.Set( aDesc );
       
   799 		}
       
   800 	else if ( aEncoding == KMetaDataParserUnicode8Encoding )
       
   801 		{
       
   802 		// UTF-8
       
   803 		characterSetId = KCharacterSetIdentifierUtf8;
       
   804 		unicodeData.Set( aDesc );
       
   805 		}
       
   806 	else
       
   807 		{
       
   808 		User::Leave(KErrNotSupported);
       
   809 		}
       
   810 
       
   811 	charSetConv->PrepareToConvertToOrFromL(characterSetId, *iCharacterSet, iFs);
       
   812 	err = charSetConv->ConvertToUnicode(aUnicode, unicodeData, state);
       
   813 
       
   814 #ifdef _DEBUG
       
   815 	RDebug::Print(_L("CMetaDataParserID3v24::ConvertToUnicode :-> Tag Size[%d] Unicode Tag Size[%d]Bytes Unconverted[%d]"),
       
   816 		unicodeData.Length(), aUnicode.Length(), err);
       
   817 #endif
       
   818 
       
   819 	CleanupStack::PopAndDestroy();	// charSetConv
       
   820 	return err;
       
   821 	}
       
   822 
       
   823 //  End of File