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