--- /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 <e32svr.h>
+#endif
+
+#include <s32mem.h>
+
+// 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<TMetaDataFieldId>& 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