mmserv/metadatautility/Src/MetaDataParserWMA.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 an ID3v1 and v1.1 parser as specified in
       
    15 *                www.id3.org.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 
       
    22 // INCLUDE FILES
       
    23 #include	"MetaDataParserWMA.h"
       
    24 #ifdef _DEBUG
       
    25 #include	<e32svr.h>
       
    26 #endif
       
    27 
       
    28 #include <s32mem.h>
       
    29 
       
    30 // CONSTANTS
       
    31 // ASF Header Object GUIDs 
       
    32   
       
    33 _LIT8 (KASFContentDescriptionObject, "75B22633668E11CFA6D900AA0062CE6C");
       
    34 _LIT8 (KASFExtendedContentDescriptionObject, "D2D0A440E30711D297F000A0C95EA850");
       
    35 _LIT8 (KASFHeaderObject, "75B22630668E11CFA6D900AA0062CE6C");
       
    36 _LIT8 (KASFFilePropertiesObject, "8CABDCA1A94711CF8EE400C00C205365");
       
    37 _LIT8 (KASFHeaderExtensionObject, "5FBF03B5A92E11CF8EE300C00C205365");
       
    38 _LIT8 (KASFMetadataLibraryObject, "44231C94949849D1A1411D134E457054");
       
    39 _LIT(KWMAlbumTitle, "WM/AlbumTitle\0");
       
    40 _LIT(KWMPicture,	"WM/Picture\0");
       
    41 _LIT(KWMText,		"WM/Text\0");
       
    42 _LIT(KWMComposer,	"WM/Composer\0");
       
    43 _LIT(KWMGenre,		"WM/Genre\0");
       
    44 _LIT(KWMYear,		"WM/Year\0");
       
    45 _LIT(KWMYear1,		"WM/OriginalReleaseYear\0"); 
       
    46 _LIT(KWMOriginalArtist,	"WM/OriginalArtist\0");
       
    47 _LIT(KWMTrackNumber,	"WM/TrackNumber\0");
       
    48 _LIT(KWMUniqueFileIdentifier,	"WM/UniqueFileIdentifier\0");
       
    49 _LIT(KWMAudioFileURL,	"WM/AudioFileURL\0");
       
    50 _LIT(KWMSharedUserRating, "WM/SharedUserRating\0");
       
    51 _LIT(KWMDate, "WM/OriginalReleaseTime\0");
       
    52 #ifdef __WINDOWS_MEDIA
       
    53 _LIT(KWMProvider, "WM/Provider\0");
       
    54 #endif
       
    55 
       
    56 
       
    57 // ============================ MEMBER FUNCTIONS ===============================
       
    58 
       
    59 // -----------------------------------------------------------------------------
       
    60 // CMetaDataParserWMA::CMetaDataParserWMA
       
    61 // C++ default constructor can NOT contain any code, that
       
    62 // might leave.
       
    63 // -----------------------------------------------------------------------------
       
    64 //
       
    65 CMetaDataParserWMA::CMetaDataParserWMA(
       
    66 	CMetaDataSource& aSource )
       
    67 	:	iSource(aSource),
       
    68 		iCharacterSetId(0)
       
    69 	{
       
    70     }
       
    71 
       
    72 // -----------------------------------------------------------------------------
       
    73 // CMetaDataParserWMA::ConstructL
       
    74 // Symbian 2nd phase constructor can leave.
       
    75 // -----------------------------------------------------------------------------
       
    76 //
       
    77 void CMetaDataParserWMA::ConstructL()
       
    78     {
       
    79 	if ( ValidateL() )
       
    80 		{
       
    81 		User::LeaveIfError(iFs.Connect());
       
    82 		// Get list of charconv supported character sets
       
    83 		iCharacterSet = CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL(iFs);
       
    84 		}
       
    85 #ifdef _DEBUG
       
    86 	RDebug::Print(_L("CMetaDataParserWMA::ConstructL - Done"));
       
    87 #endif
       
    88     }
       
    89 
       
    90 // -----------------------------------------------------------------------------
       
    91 // CMetaDataParserWMA::NewL
       
    92 // Two-phased constructor.
       
    93 // -----------------------------------------------------------------------------
       
    94 //
       
    95 CMetaDataParserWMA* CMetaDataParserWMA::NewL(
       
    96 	CMetaDataSource& aSource )
       
    97     {
       
    98 #ifdef _DEBUG
       
    99 	RDebug::Print(_L("CMetaDataParserWMA::NewL"));
       
   100 #endif
       
   101 	CMetaDataParserWMA* self = new( ELeave ) CMetaDataParserWMA(aSource);
       
   102     CleanupStack::PushL( self );
       
   103     self->ConstructL();
       
   104     CleanupStack::Pop();
       
   105     return self;
       
   106     }
       
   107 
       
   108 // Destructor
       
   109 CMetaDataParserWMA::~CMetaDataParserWMA()
       
   110 	{
       
   111 		delete iHeaderData;
       
   112 		delete iCharacterSet;
       
   113 		iFs.Close();
       
   114 	}
       
   115 
       
   116 // -----------------------------------------------------------------------------
       
   117 // CMetaDataParserWMA::ParseL
       
   118 // -----------------------------------------------------------------------------
       
   119 //
       
   120 void CMetaDataParserWMA::ParseL(
       
   121 	const RArray<TMetaDataFieldId>& aWantedFields,
       
   122 	CMetaDataFieldContainer& aContainer )
       
   123     {
       
   124 #ifdef _DEBUG
       
   125 	RDebug::Print(_L("CMetaDataParserWMA::ParseL"));
       
   126 #endif
       
   127 	iContainer = &aContainer;
       
   128 
       
   129 	if(iContentDescriptionObjectExists)
       
   130 		{
       
   131 		ParseContentDescriptionObject();
       
   132 		}
       
   133 	if(iExtendedContentDescriptionObjectExists)
       
   134 		{
       
   135 		ParseExtendedContentDescriptionObjectL();
       
   136 		}
       
   137 	if(iHeaderExtensionObjectExists)
       
   138 		{
       
   139 		ParseHeaderExtensionObjectL();
       
   140 		if(iMetadataLibraryObjectExists)
       
   141 			{
       
   142 			ParseMetadataLibraryObjectL();
       
   143 			}
       
   144 		}	
       
   145 	TInt err = KErrNone; // ignore err, as some entry may be extracted without exception
       
   146 	if ( aWantedFields.Count() == 0 )
       
   147 		{
       
   148 		TRAP(err, GetTitleL());
       
   149 		TRAP(err, GetAuthorL());
       
   150 		TRAP(err, GetCopyrightL());
       
   151 		TRAP(err, GetCommentL());
       
   152 		TRAP(err, GetJpegL());
       
   153 		TRAP(err, GetExtContDesEntryL(EMetaDataRating, iSharedUserRatingOffset));
       
   154 		TRAP(err, GetExtContDesEntryL(EMetaDataAlbum, iAlbumTitleOffset));
       
   155 		TRAP(err, GetExtContDesEntryL(EMetaDataComment, iTextOffset));
       
   156 		TRAP(err, GetExtContDesEntryL(EMetaDataComposer, iComposerOffset));
       
   157 		TRAP(err, GetExtContDesEntryL(EMetaDataGenre, iGenreOffset));
       
   158 		TRAP(err, GetExtContDesEntryL(EMetaDataYear, iYearOffset));
       
   159 		TRAP(err, GetExtContDesEntryL(EMetaDataOriginalArtist, iOriginalArtistOffset));
       
   160 		TRAP(err, GetExtContDesEntryL(EMetaDataAlbumTrack, iTrackNumberOffset));
       
   161 		TRAP(err, GetExtContDesEntryL(EMetaDataUniqueFileIdentifier, iUniqueFileIdentifierOffset));
       
   162 		TRAP(err, GetExtContDesEntryL(EMetaDataUrl, iAudioFileURLOffset));
       
   163 		TRAP(err, GetDurationL());
       
   164 		TRAP(err, GetExtContDesEntryL(EMetaDataDate, iDateOffset));
       
   165 	#ifdef __WINDOWS_MEDIA
       
   166 		TRAP(err, GetExtContDesEntryL(EMetaDataVendor, iProviderOffset));
       
   167 	#endif
       
   168 		}
       
   169 	else
       
   170 		{
       
   171 		// Look for it in the wanted field array
       
   172 		TInt count( aWantedFields.Count() );
       
   173 		for ( TInt i = 0; i < count; i++ )
       
   174 			{
       
   175 			switch ( aWantedFields[ i ] )
       
   176 				{
       
   177 				case EMetaDataSongTitle:
       
   178 					TRAP(err, GetTitleL());
       
   179 					break;
       
   180 				case EMetaDataArtist:
       
   181 					TRAP(err, GetAuthorL());
       
   182 					break;
       
   183 				case EMetaDataCopyright:
       
   184 					TRAP(err, GetCopyrightL());
       
   185 					break;
       
   186 				case EMetaDataRating:
       
   187 					TRAP(err, GetExtContDesEntryL(EMetaDataRating, iSharedUserRatingOffset));
       
   188 					break;
       
   189 				case EMetaDataJpeg:
       
   190 					TRAP(err, GetJpegL());
       
   191 					break;
       
   192 				case EMetaDataAlbum:
       
   193 					TRAP(err, GetExtContDesEntryL(EMetaDataAlbum, iAlbumTitleOffset));
       
   194 					break;
       
   195 				case EMetaDataComment:
       
   196 					TRAP(err, GetExtContDesEntryL(EMetaDataComment, iTextOffset));
       
   197 					break;
       
   198 				case EMetaDataComposer:
       
   199 					TRAP(err, GetExtContDesEntryL(EMetaDataComposer, iComposerOffset));
       
   200 					break;
       
   201 				case EMetaDataGenre:
       
   202 					TRAP(err, GetExtContDesEntryL(EMetaDataGenre, iGenreOffset));
       
   203 					break;
       
   204 				case EMetaDataYear:
       
   205 					TRAP(err, GetExtContDesEntryL(EMetaDataYear, iYearOffset));
       
   206 					break;
       
   207 				case EMetaDataOriginalArtist:
       
   208 					TRAP(err, GetExtContDesEntryL(EMetaDataOriginalArtist, iOriginalArtistOffset));
       
   209 					break;
       
   210 				case EMetaDataAlbumTrack:
       
   211 					TRAP(err, GetExtContDesEntryL(EMetaDataAlbumTrack, iTrackNumberOffset));
       
   212 					break;
       
   213 				case EMetaDataUniqueFileIdentifier:
       
   214 					TRAP(err, GetExtContDesEntryL(EMetaDataUniqueFileIdentifier, iUniqueFileIdentifierOffset));
       
   215 					break;
       
   216 				case EMetaDataUrl:
       
   217 					TRAP(err, GetExtContDesEntryL(EMetaDataUrl, iAudioFileURLOffset));
       
   218 					break;
       
   219 				case EMetaDataDuration:
       
   220 					TRAP(err, GetDurationL());
       
   221 					break;
       
   222 				case EMetaDataDate:
       
   223 					TRAP(err, GetExtContDesEntryL(EMetaDataDate, iDateOffset));
       
   224 					break;
       
   225 			#ifdef __WINDOWS_MEDIA
       
   226 				case EMetaDataVendor:
       
   227 					TRAP(err, GetExtContDesEntryL(EMetaDataVendor, iProviderOffset));
       
   228 			#endif
       
   229 				default:
       
   230 					break;
       
   231 				}
       
   232 			}
       
   233 		}
       
   234     }
       
   235 
       
   236 // -----------------------------------------------------------------------------
       
   237 // CMetaDataParserWMA::ValidateL
       
   238 // -----------------------------------------------------------------------------
       
   239 //
       
   240 TBool CMetaDataParserWMA::ValidateL()
       
   241 	{
       
   242 	TInt size;
       
   243 	iExists = EFalse;
       
   244 	User::LeaveIfError( iSource.Size( size ) );
       
   245 	if ( size <= 0 )
       
   246 		{
       
   247 		return EFalse;
       
   248 		}
       
   249 
       
   250 	// ASF_Header_Object GUID 128 bits.
       
   251 	TBuf8<32> header; 
       
   252 	iSource.ReadL(header, 16);
       
   253 	if(header.Length() < 16)
       
   254 		{
       
   255 		return EFalse;
       
   256 		}
       
   257 	FormatGUID(header);
       
   258 	if(header !=  KASFHeaderObject)
       
   259 		{
       
   260 		return EFalse;
       
   261 		}
       
   262 	// read header object size.
       
   263 	iSource.ReadL(header, 8);
       
   264 	TInt headerSize = ConvertToInt64(header);
       
   265 	if(headerSize <= 30)
       
   266 		{
       
   267 		return EFalse; // header object is empty.
       
   268 		}
       
   269 	if(headerSize >= size) //Header Size is too high
       
   270 		{
       
   271 		return EFalse; // header size is more than the file size.
       
   272 		}
       
   273 	// read header object
       
   274 	// 2~31 = 2 GB, size of header would not be greater than this,
       
   275 	// also, HBufC does not have a NewL with TInt64 as arguement.
       
   276 	iHeaderData = HBufC8::NewL(headerSize); 
       
   277 	TPtr8 headerPtr = iHeaderData->Des(); 
       
   278 	iSource.ReadL(headerPtr, headerSize - 24);
       
   279 	
       
   280 	TBuf8<4> objects = iHeaderData->Mid(0, 4);
       
   281 	TInt noOfObjects = ConvertToInt32(objects);
       
   282 	if(noOfObjects <= 0)
       
   283 		{
       
   284 		iExists = EFalse;
       
   285 		return EFalse; // no objects. 
       
   286 		}
       
   287         
       
   288 	TInt objOffset = 6;
       
   289 	if(objOffset+16 > iHeaderData->Length()) //Header Size is too small
       
   290 		{
       
   291 		return EFalse;
       
   292 		} 
       
   293 	TBuf8<32> objGUID = iHeaderData->Mid(objOffset, 16);
       
   294 	FormatGUID(objGUID);
       
   295 	TBool loop = ETrue;
       
   296 	TInt objectCount = 0;
       
   297 	while (loop)
       
   298 		{
       
   299 		if(!iContentDescriptionObjectExists && objGUID == KASFContentDescriptionObject)
       
   300 			{
       
   301 			iContentDescriptionObjectExists = ETrue;
       
   302 			iContentDescriptionOffset = objOffset;
       
   303 			}
       
   304 		if(!iFilePropertiesObjectExists && objGUID == KASFFilePropertiesObject)
       
   305 			{
       
   306 			iFilePropertiesObjectExists = ETrue; // must exist
       
   307 			iFilePropertiesOffset = objOffset;
       
   308 			}
       
   309 		if(!iExtendedContentDescriptionObjectExists && objGUID == 
       
   310 			KASFExtendedContentDescriptionObject)
       
   311 			{
       
   312 			iExtendedContentDescriptionObjectExists = ETrue;
       
   313 			iExtendedContentDescriptionOffset = objOffset;
       
   314 			}
       
   315 		if(!iHeaderExtensionObjectExists && objGUID == 
       
   316 			KASFHeaderExtensionObject)
       
   317 			{
       
   318 			iHeaderExtensionObjectExists = ETrue;
       
   319 			iHeaderExtensionOffset = objOffset;
       
   320 			}	
       
   321 		TBuf8<8> size = iHeaderData->Mid(objOffset + 16, 8); 
       
   322 		TInt objSize = ConvertToInt64(size); // upper 32 bits?
       
   323 		if(0 > objSize)
       
   324 			{
       
   325 			return EFalse;
       
   326 			}
       
   327 		objOffset += objSize;
       
   328 		if(objOffset >= headerSize - 30 || 
       
   329 			(iContentDescriptionObjectExists && iFilePropertiesObjectExists 
       
   330 			&& iExtendedContentDescriptionObjectExists && iHeaderExtensionObjectExists) )
       
   331 			{
       
   332 			loop = EFalse;
       
   333 			}
       
   334 		else
       
   335 			{
       
   336 			objGUID = iHeaderData->Mid(objOffset, 16);
       
   337 			FormatGUID(objGUID);
       
   338 			objectCount++;
       
   339 
       
   340 			if (objectCount == noOfObjects)
       
   341 				{
       
   342 				iExists = EFalse;
       
   343 				return EFalse;	// gone through all objects		
       
   344 				}
       
   345 			}
       
   346 		}
       
   347 	if(iFilePropertiesObjectExists) 
       
   348 		{
       
   349 		iExists = ETrue;
       
   350 		}
       
   351 	return iExists;
       
   352 	}
       
   353 
       
   354 // -----------------------------------------------------------------------------
       
   355 // CMetaDataParserWMA::FormatGUID
       
   356 // -----------------------------------------------------------------------------
       
   357 //
       
   358 void CMetaDataParserWMA::FormatGUID(TDes8 &aGUID)
       
   359 {
       
   360 	TBuf8<16> copyGUID(aGUID);
       
   361 	TInt i;
       
   362 	for(i = 0; i < 4; i++)
       
   363 		{
       
   364 		copyGUID[i] = aGUID[3-i];
       
   365 		}
       
   366 	for(i = 4; i < 6; i++)
       
   367 		{
       
   368 		copyGUID[i] = aGUID[9 - i];
       
   369 		}
       
   370 	for (i = 6; i < 8; i++)
       
   371 		{
       
   372 		copyGUID[i] = aGUID[13 - i];
       
   373 		}
       
   374 	for(i = 8; i < 16 ; i++)
       
   375 		{
       
   376 		copyGUID[i] = aGUID[i];
       
   377 		}
       
   378 	aGUID.Delete(0, 32);
       
   379 	for(i = 0; i <16; i++)
       
   380 		{
       
   381 			aGUID.AppendNumFixedWidthUC(copyGUID[i], EHex, 2);
       
   382 		}
       
   383 }
       
   384 
       
   385 // -----------------------------------------------------------------------------
       
   386 // CMetaDataParserWMA::ConvertToInt64
       
   387 // -----------------------------------------------------------------------------
       
   388 //
       
   389 TInt64 CMetaDataParserWMA::ConvertToInt64(TDesC8& aDes)
       
   390 {
       
   391 	TInt64 num = 0;
       
   392 	TInt i;
       
   393 	for(i = 7 ; i >= 0; i--)
       
   394 		{
       
   395 		num <<= 8;
       
   396 		num |= aDes[i];
       
   397 		}
       
   398 	return num;
       
   399 }
       
   400 
       
   401 // -----------------------------------------------------------------------------
       
   402 // CMetaDataParserWMA::ConvertToInt32
       
   403 // -----------------------------------------------------------------------------
       
   404 //
       
   405 TInt CMetaDataParserWMA::ConvertToInt32(TDesC8& aDes)
       
   406 {
       
   407 	TInt num = 0;
       
   408 	for(TInt i = 3 ; i >= 0; i--)
       
   409 		{	
       
   410 		num <<= 8;
       
   411 		num |= aDes[i];
       
   412 		}
       
   413 	return num;
       
   414 }
       
   415 
       
   416 
       
   417 // -----------------------------------------------------------------------------
       
   418 // CMetaDataParserWMA::ConvertToInt16
       
   419 // -----------------------------------------------------------------------------
       
   420 //
       
   421 TInt CMetaDataParserWMA::ConvertToInt16(TDesC8& aDes)
       
   422 {
       
   423 	TInt num = 0;
       
   424 	for(TInt i = 1 ; i >= 0; i--)
       
   425 		{	
       
   426 		num <<= 8;
       
   427 		num |= aDes[i];
       
   428 		}
       
   429 	return num;
       
   430 }
       
   431 
       
   432 // -----------------------------------------------------------------------------
       
   433 // CMetaDataParserWMA::ConvertDes8toDes16
       
   434 // -----------------------------------------------------------------------------
       
   435 //
       
   436 void CMetaDataParserWMA::ConvertDes8toDes16(const TDesC8& aDes8,TDes16& aDes16)
       
   437 	{
       
   438 	for(TInt i = 0 ; i < aDes8.Length(); i+=2)
       
   439 		{
       
   440 		if(aDes16.MaxLength() <= i/2)
       
   441 			{
       
   442 #ifdef _DEBUG
       
   443 	RDebug::Print(_L("CMetaDataParserWMA::ConvertDes8toDes16: i/2[%d] >= aDes16's MaxLength[%d]."),
       
   444 			i/2, aDes16.MaxLength());
       
   445 #endif
       
   446 			return;
       
   447 			}
       
   448 		aDes16.Append(aDes8[i]);
       
   449 		}
       
   450 	}
       
   451 
       
   452 // -----------------------------------------------------------------------------
       
   453 // CMetaDataParserWMA::GetTitleL
       
   454 // -----------------------------------------------------------------------------
       
   455 //
       
   456 void CMetaDataParserWMA::GetTitleL()
       
   457 	{
       
   458 	if (iTitleLength <= 0)
       
   459 		{
       
   460 		return;
       
   461 		}
       
   462 	TInt offset = iContentDescriptionOffset + 34;
       
   463 	if(iTitleLength - 2 <= 0 || offset + iTitleLength > iHeaderData->Length())
       
   464 		{
       
   465 		return; // empty title or corrupt title length
       
   466 		}
       
   467 	TPtrC8 title = iHeaderData->Mid(offset, iTitleLength - 2);
       
   468 	HBufC* data16 = HBufC::NewLC( iTitleLength - 2);
       
   469 	TPtr titleUnicode( data16->Des() );
       
   470 	if ( ConvertToUnicodeL(title, titleUnicode) == KErrNone )
       
   471 		{
       
   472 		iContainer->AppendL( EMetaDataSongTitle, titleUnicode );
       
   473 		}
       
   474 	CleanupStack::PopAndDestroy();  // data16
       
   475 	}
       
   476 
       
   477 // -----------------------------------------------------------------------------
       
   478 // CMetaDataParserWMA::GetArtistL
       
   479 // -----------------------------------------------------------------------------
       
   480 //
       
   481 void CMetaDataParserWMA::GetAuthorL()
       
   482 	{
       
   483 	if (iAuthorLength <= 0)
       
   484 		{
       
   485 		return;
       
   486 		}
       
   487 	TInt offset = iContentDescriptionOffset + 34 + iTitleLength;
       
   488 	if(iAuthorLength - 2 <= 0 || offset + iAuthorLength > iHeaderData->Length())
       
   489 		{
       
   490 		return; // empty author or corrupt author length
       
   491 		}
       
   492 	TPtrC8 author = iHeaderData->Mid(offset, iAuthorLength - 2);
       
   493 	HBufC* data16 = HBufC::NewLC( iAuthorLength - 2);
       
   494 	TPtr authorUnicode( data16->Des() );
       
   495 	if ( ConvertToUnicodeL(author, authorUnicode) == KErrNone )
       
   496 		{
       
   497 		iContainer->AppendL( EMetaDataArtist, authorUnicode );
       
   498 		}
       
   499 	CleanupStack::PopAndDestroy();  // data16
       
   500 	}
       
   501 
       
   502 // -----------------------------------------------------------------------------
       
   503 // CMetaDataParserWMA::GetCopyrightL
       
   504 // -----------------------------------------------------------------------------
       
   505 //
       
   506 void CMetaDataParserWMA::GetCopyrightL()
       
   507 	{
       
   508 	if (iCopyrightLength <= 0)
       
   509 		{
       
   510 		return;
       
   511 		}
       
   512 	TInt offset = iContentDescriptionOffset + 34 + iTitleLength + iAuthorLength;
       
   513 	if(iCopyrightLength - 2 <= 0 || offset + iCopyrightLength > iHeaderData->Length())
       
   514 		{
       
   515 		return; // empty or corrupt length
       
   516 		}
       
   517 	TPtrC8 copyright = iHeaderData->Mid(offset, iCopyrightLength - 2);
       
   518 	HBufC* data16 = HBufC::NewLC( iCopyrightLength - 2);
       
   519 	TPtr copyrightUnicode( data16->Des() );
       
   520 	if ( ConvertToUnicodeL(copyright, copyrightUnicode) == KErrNone )
       
   521 		{
       
   522 		iContainer->AppendL( EMetaDataCopyright, copyrightUnicode );
       
   523 		}
       
   524 	CleanupStack::PopAndDestroy();  // data16
       
   525 	}
       
   526 
       
   527 // -----------------------------------------------------------------------------
       
   528 // CMetaDataParserWMA::GetCommentL
       
   529 // -----------------------------------------------------------------------------
       
   530 //
       
   531 void CMetaDataParserWMA::GetCommentL()
       
   532 	{
       
   533 	if (iDescriptionLength <= 0)
       
   534 		{
       
   535 		return;
       
   536 		}
       
   537 	TInt offset = iContentDescriptionOffset + 34 + iTitleLength + iAuthorLength + iCopyrightLength;
       
   538 	if(iDescriptionLength - 2 <= 0 || offset + iDescriptionLength > iHeaderData->Length())
       
   539 		{
       
   540 		return; // empty comment or corrupt comment length
       
   541 		}
       
   542 	TPtrC8 comments = iHeaderData->Mid(offset, iDescriptionLength - 2);
       
   543 	HBufC* data16 = HBufC::NewLC( iDescriptionLength - 2);
       
   544 	TPtr commentsUnicode( data16->Des() );
       
   545 	if ( ConvertToUnicodeL(comments, commentsUnicode) == KErrNone )
       
   546 		{
       
   547 		iContainer->AppendL( EMetaDataComment, commentsUnicode );
       
   548 		}
       
   549 	CleanupStack::PopAndDestroy();  // data16
       
   550 	}
       
   551 
       
   552 
       
   553 // -----------------------------------------------------------------------------
       
   554 // CMetaDataParserWMA::GetJpegL
       
   555 // -----------------------------------------------------------------------------
       
   556 //
       
   557 void CMetaDataParserWMA::GetJpegL()
       
   558 {
       
   559 	if (iPictureOffset <= 0)
       
   560 	{
       
   561 		return;
       
   562 	}
       
   563 	
       
   564 	TInt offset = iPictureOffset;
       
   565 	if(!iMetadatLibraryObjectJpegExists)
       
   566 		{
       
   567 		TPtrC8 dataType = iHeaderData->Mid(offset, 2);
       
   568 		offset += 2;
       
   569 		TInt dataTypeInt = ConvertToInt16(dataType);
       
   570 		if(dataTypeInt != 1)
       
   571 			{
       
   572 			return;
       
   573 			}
       
   574 		
       
   575 		TPtrC8 lengthData = iHeaderData->Mid(offset, 2);
       
   576 		offset += 2;
       
   577 		TInt length	= ConvertToInt16(lengthData);
       
   578 		if(length <= 0)
       
   579 			{
       
   580 			return;
       
   581 			}		
       
   582 		}
       
   583 	TPtrC8 picData = iHeaderData->Mid(offset, 1);
       
   584 	offset += 1;
       
   585 	TInt picType = 0;
       
   586 	picType |= picData[0];
       
   587 	if(picType != 3)
       
   588 	{
       
   589 		return; // only Front Album Cover supported
       
   590 	}
       
   591 	
       
   592 	TPtrC8 picLengthData = iHeaderData->Mid(offset, 4);
       
   593 	offset += 4;
       
   594 	TInt picLength = ConvertToInt32(picLengthData);
       
   595 	if(picLength <= 0)
       
   596 	{
       
   597 		return;
       
   598 	}
       
   599 	
       
   600 	_LIT8(KNULL, "\0\0");
       
   601 	TPtrC8 data = iHeaderData->Mid(offset, picLength);
       
   602 	TInt pos = data.Find(KNULL);
       
   603 	if(pos != 0)
       
   604 	{
       
   605 		pos++; // for unicode coding for strings. 
       
   606 	}
       
   607 	// check mime type
       
   608 	if(pos != KErrNotFound)
       
   609 	{
       
   610 		HBufC8 *mimeType = iHeaderData->Mid(offset, pos + 2).AllocLC();
       
   611 		offset += pos + 2;
       
   612 		HBufC* name16 = HBufC::NewLC( (pos+2)/2);
       
   613 		TPtr mimeType16( name16->Des() );
       
   614 		ConvertDes8toDes16(*mimeType, mimeType16);
       
   615 		_LIT(KJPEG, "image/jpeg\0");
       
   616 		_LIT(KJPG, "image/jpg\0");
       
   617 		if(mimeType16.Compare(KJPEG) != 0 && mimeType16.Compare(KJPG) != 0)
       
   618 		{
       
   619 			CleanupStack::PopAndDestroy(2, mimeType);
       
   620 			return; // only JPEG & JPG supported
       
   621 		}
       
   622 		CleanupStack::PopAndDestroy(2); // mimeType16, mimeType
       
   623 	}
       
   624 		
       
   625 	// skip the picture description
       
   626 	TPtrC8 picDesc = iHeaderData->Mid(offset, picLength);
       
   627 	pos = picDesc.Find(KNULL);
       
   628 	if(pos != 0)
       
   629 	{
       
   630 		pos++; // for unicode coding for strings. 
       
   631 	}
       
   632 	offset += pos + 2;
       
   633 	
       
   634 	// picture data 
       
   635 	TPtrC8 pic8 = iHeaderData->Mid(offset, picLength);	
       
   636 	iContainer->AppendL( EMetaDataJpeg, pic8 );
       
   637 }
       
   638 
       
   639 
       
   640 // -----------------------------------------------------------------------------
       
   641 // CMetaDataParserWMA::GetExtContDesEntryL
       
   642 // -----------------------------------------------------------------------------
       
   643 //
       
   644 TBool CMetaDataParserWMA::GetExtContDesEntryL(TMetaDataFieldId aFieldId, TInt aOffset)
       
   645 {
       
   646 	TBool ret = EFalse;
       
   647 	if(iExtendedContentDescriptionCount == 0)
       
   648 		{
       
   649 		return ret;
       
   650 		}
       
   651 	TPtrC8 dataType = iHeaderData->Mid(aOffset, 2);
       
   652 	TInt dataTypeInt = ConvertToInt16(dataType);
       
   653 	if(dataTypeInt == 0x00)
       
   654 		{
       
   655 		TPtrC8 lengthData = iHeaderData->Mid(aOffset + 2, 2);
       
   656 		TInt length	= ConvertToInt16(lengthData);
       
   657 		if(length <= 0)
       
   658 			{
       
   659 			return ret;
       
   660 			}
       
   661 		TPtrC8 data = iHeaderData->Mid(aOffset + 4, length - 2);
       
   662 		HBufC* data16 = HBufC::NewLC(length - 2);
       
   663 		TPtr dataUnicode( data16->Des() );
       
   664 		if ( ConvertToUnicodeL(data, dataUnicode) == KErrNone )
       
   665 			{
       
   666 			iContainer->AppendL( aFieldId, dataUnicode );
       
   667 			ret = ETrue;
       
   668 			}
       
   669 		CleanupStack::PopAndDestroy();  // data16
       
   670 		}
       
   671 	else if(dataTypeInt == 0x03)
       
   672 		{
       
   673 		TPtrC8 lengthData = iHeaderData->Mid(aOffset + 2, 2);
       
   674 		TInt length	= ConvertToInt16(lengthData);
       
   675 		if(length != 4)
       
   676 			{
       
   677 			return ret;
       
   678 			}
       
   679 		TPtrC8 data = iHeaderData->Mid(aOffset + 4, length);
       
   680 		TInt dword = ConvertToInt32(data);
       
   681 		const TInt KMaxIntBufferSize = 10;
       
   682 		HBufC* data16 = HBufC::NewLC(KMaxIntBufferSize);
       
   683 		TPtr dataString( data16->Des() );
       
   684 		dataString.Num(dword);
       
   685 		iContainer->AppendL( aFieldId, dataString );
       
   686 		CleanupStack::PopAndDestroy();  // data16
       
   687 		ret = ETrue;
       
   688 		}
       
   689 	return ret;
       
   690 }
       
   691 
       
   692 // -----------------------------------------------------------------------------
       
   693 // CMetaDataParserWMA::GetDurationL
       
   694 // -----------------------------------------------------------------------------
       
   695 //
       
   696 void CMetaDataParserWMA::GetDurationL()
       
   697 	{
       
   698 	TInt offset = iFilePropertiesOffset + 16;
       
   699 	TPtrC8 size8 = iHeaderData->Mid(offset, 8);
       
   700 	TInt size = ConvertToInt64(size8);
       
   701 	offset = iFilePropertiesOffset + 88;
       
   702 	TPtrC8 flags = iHeaderData->Mid(offset, 4);
       
   703 	TInt broadcastBit = (TInt) (flags[0] & 0x01);
       
   704 	if(broadcastBit == 1)
       
   705 		{
       
   706 		return; // duration not valid.
       
   707 		}
       
   708 	//offset = iFilePropertiesOffset + 48;
       
   709 	TPtrC8 duration8 = iHeaderData->Mid(offset - 24, 8); // 100 nanosec units
       
   710 	TReal sec = ((TReal)ConvertToInt64(duration8)) / 10000000; // seconds
       
   711 	TBuf16<10> des16;
       
   712 	des16.Num(sec, TRealFormat (9, 3));
       
   713 	iContainer->AppendL( EMetaDataDuration, des16 );
       
   714 	}
       
   715 
       
   716 
       
   717 
       
   718 // -----------------------------------------------------------------------------
       
   719 // CMetaDataParserWMA::ConvertToUnicodeL
       
   720 // -----------------------------------------------------------------------------
       
   721 //
       
   722 TInt CMetaDataParserWMA::ConvertToUnicodeL(
       
   723 	const TDesC8& aDesc,
       
   724 	TDes16& aUnicode )
       
   725 	{
       
   726 	TPtrC8 unicodeData;
       
   727   TUint characterSetId = 0;
       
   728 	CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
       
   729 	TInt state = CCnvCharacterSetConverter::KStateDefault;
       
   730 
       
   731 	// ASF (WMA) file format has UTF-16 LittleEndian characters.
       
   732 	characterSetId = KCharacterSetIdentifierUnicodeLittle;
       
   733 	unicodeData.Set( aDesc );
       
   734 	
       
   735 	charSetConv->PrepareToConvertToOrFromL(characterSetId, *iCharacterSet, iFs);
       
   736 	TInt err = charSetConv->ConvertToUnicode(aUnicode, unicodeData, state);
       
   737 
       
   738 #ifdef _DEBUG
       
   739 	RDebug::Print(_L("CMetaDataParserID3v24::ConvertToUnicode :-> Tag Size[%d] Unicode Tag Size[%d]Bytes Unconverted[%d]"),
       
   740 		unicodeData.Length(), aUnicode.Length(), err);
       
   741 #endif
       
   742 
       
   743 	CleanupStack::PopAndDestroy();	// charSetConv
       
   744 	return err;
       
   745 	}
       
   746 
       
   747 
       
   748 // -----------------------------------------------------------------------------
       
   749 // CMetaDataParserWMA::ParseContentDescriptionObject
       
   750 // -----------------------------------------------------------------------------
       
   751 //
       
   752 void CMetaDataParserWMA::ParseContentDescriptionObject()
       
   753 	{
       
   754 		TBuf8<2> data = iHeaderData->Mid(iContentDescriptionOffset + 24, 2);
       
   755 		iTitleLength = ConvertToInt16(data); 
       
   756 		data = iHeaderData->Mid(iContentDescriptionOffset + 26, 2);
       
   757 		iAuthorLength = ConvertToInt16(data); 
       
   758 		data = iHeaderData->Mid(iContentDescriptionOffset + 28, 2);
       
   759 		iCopyrightLength = ConvertToInt16(data); 
       
   760 		data = iHeaderData->Mid(iContentDescriptionOffset + 30, 2);
       
   761 		iDescriptionLength = ConvertToInt16(data); 
       
   762 		data = iHeaderData->Mid(iContentDescriptionOffset + 32, 2);
       
   763 		iRatingLength = ConvertToInt16(data);
       
   764 		return;
       
   765 	}
       
   766 
       
   767 
       
   768 // -----------------------------------------------------------------------------
       
   769 // CMetaDataParserWMA::ParseExtendedContentDescriptionObjectL
       
   770 // -----------------------------------------------------------------------------
       
   771 //
       
   772 void CMetaDataParserWMA::ParseExtendedContentDescriptionObjectL()
       
   773 	{
       
   774 	TBuf8<2> data  =  iHeaderData->Mid(iExtendedContentDescriptionOffset + 24, 2);
       
   775 	iExtendedContentDescriptionCount = ConvertToInt16(data);
       
   776 	TInt offset = iExtendedContentDescriptionOffset + 26;
       
   777 	for(TInt i = 0 ; i < iExtendedContentDescriptionCount; i ++)
       
   778 		{
       
   779 		TBuf8<2> data1  =  iHeaderData->Mid(offset, 2);
       
   780 		offset += 2;
       
   781 		TInt nameLength = ConvertToInt16(data1);
       
   782 		if(nameLength > 0 && iHeaderData->Length() >= (offset+nameLength))
       
   783 			{
       
   784 			HBufC8 *name = iHeaderData->Mid(offset, nameLength).AllocLC();
       
   785 			offset += nameLength;
       
   786 			HBufC* data16 = HBufC::NewLC(nameLength/2 == 0 ? 1 : nameLength/2);
       
   787 			TPtr name16( data16->Des() );
       
   788 			ConvertDes8toDes16(*name, name16);
       
   789 			
       
   790 			if(!name16.Compare(KWMAlbumTitle))
       
   791 				{
       
   792 				iAlbumTitleOffset = offset; 
       
   793 				}
       
   794 			else if(!name16.Compare(KWMPicture))
       
   795 				{
       
   796 				iPictureOffset = offset; 
       
   797 				}
       
   798 			else if(!name16.Compare(KWMText))
       
   799 				{
       
   800 				iTextOffset = offset; 
       
   801 				}
       
   802 			else if(!name16.Compare(KWMComposer))
       
   803 				{
       
   804 				iComposerOffset = offset; 
       
   805 				}
       
   806 			else if(!name16.Compare(KWMGenre))
       
   807 				{
       
   808 				iGenreOffset = offset; 
       
   809 				}
       
   810 			else if(!name16.Compare(KWMYear) || !name16.Compare(KWMYear1))
       
   811 				{
       
   812 				iYearOffset = offset; 
       
   813 				}
       
   814 			else if(!name16.Compare(KWMOriginalArtist))
       
   815 				{
       
   816 				iOriginalArtistOffset = offset; 
       
   817 				}
       
   818 			else if(!name16.Compare(KWMTrackNumber))
       
   819 				{
       
   820 				iTrackNumberOffset = offset; 
       
   821 				}
       
   822 			else if(!name16.Compare(KWMUniqueFileIdentifier))
       
   823 				{
       
   824 				iUniqueFileIdentifierOffset = offset; 
       
   825 				}
       
   826 			else if(!name16.Compare(KWMAudioFileURL))
       
   827 				{
       
   828 				iAudioFileURLOffset = offset; 
       
   829 				}
       
   830 			else if(!name16.Compare(KWMSharedUserRating))
       
   831 				{
       
   832 				iSharedUserRatingOffset = offset; 
       
   833 				}
       
   834 			else if(!name16.Compare(KWMDate))
       
   835 				{
       
   836 				iDateOffset = offset; 
       
   837 				}
       
   838 		#ifdef __WINDOWS_MEDIA
       
   839 			else if(!name16.Compare(KWMProvider))
       
   840 				{
       
   841 				iProviderOffset = offset; 
       
   842 				}
       
   843 		#endif
       
   844 
       
   845 			offset += 2;
       
   846 			TBuf8<2> valueLengthData  =  iHeaderData->Mid(offset, 2);
       
   847 			offset += 2;
       
   848 			TInt valueLength = ConvertToInt16(valueLengthData);
       
   849 			offset += valueLength;
       
   850 			CleanupStack::PopAndDestroy(2); //data16, name
       
   851 			if(iHeaderData->Length() < offset)
       
   852 				{
       
   853 #ifdef _DEBUG
       
   854 	RDebug::Print(_L("CMetaDataParserWMA::ParseExtendedContentDescriptionObjectL: offset[%d] > iHeaderData's Length[%d]."),
       
   855 			offset, iHeaderData->Length());
       
   856 #endif
       
   857 				return;
       
   858 				}
       
   859 			}
       
   860 		}
       
   861 	}
       
   862 
       
   863 // -----------------------------------------------------------------------------
       
   864 // CMetaDataParserWMA::ParseMetadataLibraryObjectL
       
   865 // -----------------------------------------------------------------------------
       
   866 //
       
   867 void CMetaDataParserWMA::ParseMetadataLibraryObjectL()
       
   868 	{
       
   869 	TBuf8<8> objectSizedata  =  iHeaderData->Mid(iMetadataLibraryOffset + 16, 8);
       
   870 	iMetadataLibraryObjectSize = ConvertToInt64(objectSizedata);
       
   871 	TBuf8<2> recordsCountdata  =  iHeaderData->Mid(iMetadataLibraryOffset + 24, 2);
       
   872 	iMetadataLibraryDescriptionCount = ConvertToInt16(recordsCountdata);
       
   873 	TInt offset = iMetadataLibraryOffset + 26;
       
   874 	for(TInt i = 0 ; i < iMetadataLibraryDescriptionCount; i ++)
       
   875 		{
       
   876 		offset += 4; // skipping LanguageID (2 Bytes) and StreamID (2 Bytes) fields
       
   877 		//Reading Name Length 
       
   878 		TBuf8<2> nameLengthdata  =  iHeaderData->Mid(offset, 2);
       
   879 		offset += 2;
       
   880 		TInt nameLength = ConvertToInt16(nameLengthdata);
       
   881 		TBuf8<2> dataTypedata  =  iHeaderData->Mid(offset, 2);
       
   882 		offset += 2;
       
   883 		TInt dataType = ConvertToInt16(dataTypedata);
       
   884 		TBuf8<4> dataLengthdata  =  iHeaderData->Mid(offset, 4);
       
   885 		offset += 4;
       
   886 		TInt32 dataLength = ConvertToInt32(dataLengthdata);
       
   887 		
       
   888 		if(nameLength > 0)
       
   889 			{
       
   890 			HBufC8 *name = iHeaderData->Mid(offset, nameLength).AllocLC();
       
   891 			offset += nameLength;
       
   892 			HBufC* data16 = HBufC::NewLC( nameLength/2);
       
   893 			TPtr name16( data16->Des() );
       
   894 			ConvertDes8toDes16(*name, name16);
       
   895 			if(!name16.Compare(KWMPicture))
       
   896 				{
       
   897 				iPictureOffset = offset;
       
   898 				iMetadatLibraryObjectJpegExists = ETrue; 
       
   899 				}
       
   900 			offset += dataLength;
       
   901 			CleanupStack::PopAndDestroy(2); //data16, name
       
   902 			}
       
   903 		}
       
   904 	}
       
   905 	
       
   906 // -----------------------------------------------------------------------------
       
   907 // CMetaDataParserWMA::ParseHeaderExtensionObjectL
       
   908 // -----------------------------------------------------------------------------
       
   909 //
       
   910 void CMetaDataParserWMA::ParseHeaderExtensionObjectL()
       
   911 	{
       
   912 	TInt length = iHeaderData->Length();
       
   913     if ( iHeaderExtensionOffset + 46 > length)
       
   914         {
       
   915         return; 
       
   916         }
       
   917         
       
   918 	TBuf8<8> objectSizedata  =  iHeaderData->Mid(iHeaderExtensionOffset + 16, 8);
       
   919 	iHeaderExtensionObjectSize = ConvertToInt64(objectSizedata);
       
   920 	TBuf8<4> headerExtensiondata  =  iHeaderData->Mid(iHeaderExtensionOffset + 42, 4);
       
   921 	
       
   922 	TInt32 headerExtensionDataSize = ConvertToInt32(headerExtensiondata);
       
   923 	if(headerExtensionDataSize != iHeaderExtensionObjectSize - 46)
       
   924 	{
       
   925 		return;
       
   926 	}
       
   927 	TInt objOffset = iHeaderExtensionOffset + 46;
       
   928 	
       
   929     if ((objOffset < 0) || (objOffset + 16 > length))   // verify objOffset is not negative
       
   930         {
       
   931         return; 
       
   932         }	
       
   933 	TBuf8<32> objGUID = iHeaderData->Mid(objOffset, 16);
       
   934 	FormatGUID(objGUID);
       
   935 	TBool loop = ETrue;
       
   936 	while (loop)
       
   937 		{
       
   938 		if(!iMetadataLibraryObjectExists && objGUID == 
       
   939 			KASFMetadataLibraryObject)
       
   940 			{
       
   941 			iMetadataLibraryObjectExists = ETrue;
       
   942 			iMetadataLibraryOffset = objOffset;
       
   943 			}
       
   944 				
       
   945         if (objOffset + 24 > length)
       
   946             {
       
   947             return; 
       
   948             }	
       
   949 			
       
   950 		TBuf8<8> size = iHeaderData->Mid(objOffset + 16, 8); 
       
   951 		TInt objSize = ConvertToInt64(size); // upper 32 bits?
       
   952 		if(objSize == 0)
       
   953 			{
       
   954 			return;
       
   955 			}
       
   956 		objOffset += objSize;
       
   957 		
       
   958         if ((objOffset < 0) || (objOffset + 16 > length))
       
   959             {
       
   960             return; 
       
   961             }				
       
   962 		objGUID = iHeaderData->Mid(objOffset, 16);
       
   963 		FormatGUID(objGUID);
       
   964 		TInt val = objOffset - iHeaderExtensionOffset; 
       
   965 		if((val > 0) && (val < iHeaderExtensionObjectSize))
       
   966 			{
       
   967 			loop = ETrue;
       
   968 			}
       
   969 		else
       
   970 			{
       
   971 			loop = EFalse;
       
   972 			}
       
   973 		}
       
   974 	}	
       
   975 
       
   976 //  End of File