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