diff -r 000000000000 -r 71ca22bcf22a mmserv/metadatautility/Src/MetaDataParserID3v23.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmserv/metadatautility/Src/MetaDataParserID3v23.cpp Tue Feb 02 01:08:46 2010 +0200 @@ -0,0 +1,809 @@ +/* +* 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 parsing of ID3v2.3 according to the +* specification found in www.id3.org. Note that only a selected +* frames are supported at this time. +* +*/ + + + +// INCLUDE FILES +#include +#include "MetaDataParserID3v23.h" + +// CONSTANTS +// (ID3v2.3 specification found in www.id3.org) +const TInt KID3v2HeaderLength = 10; +const TInt KID3v2ExtendedHeaderLength = 10; +const TInt KID3v2FrameHeaderLength = 10; +const TInt KID3v2FrameIdLength = 4; + +_LIT8( KID3v2FrameIdTitle, "TIT2" ); +_LIT8( KID3v2FrameIdArtist, "TPE1" ); +_LIT8( KID3v2FrameIdAlbum, "TALB" ); +_LIT8( KID3v2FrameIdYear, "TYER" ); +_LIT8( KID3v2FrameIdComment, "COMM" ); +_LIT8( KID3v2FrameIdTrack, "TRCK" ); +_LIT8( KID3v2FrameIdGenre, "TCON" ); +_LIT8( KID3v2FrameIdComposer, "TCOM" ); +_LIT8( KID3v2FrameIdCopyright, "TCOP" ); +_LIT8( KID3v2FrameIdOriginalArtist, "TOPE" ); +_LIT8( KID3v2FrameIdUrl, "WOAF" ); +_LIT8( KID3v2FrameIdUserUrl, "WXXX" ); +_LIT8( KID3v2FrameIdJpeg, "APIC" ); +_LIT8( KID3v2FrameIdDuration, "TLEN" ); +_LIT8( KID3v2FrameIdDate, "TDAT" ); +_LIT8( KID3v2FrameIdRating, "POPM" ); + +_LIT8( KID3v2ImageFormatPngMime, "image/png" ); +_LIT8( KID3v2ImageFormatPng, "png" ); +_LIT8( KID3v2ImageFormatJpegMime, "image/jpeg" ); +_LIT8( KID3v2ImageFormatJpgMime, "image/jpg" ); +_LIT8( KID3v2ImageFormatJpeg, "jpeg" ); + +const TInt KID3v2GenreNameLength = 24; + +// ----------------------------------------------------------------------------- +// (ID3v2.3 specification found in www.id3.org) +// +// $00 ISO-8859-1 [ISO-8859-1]. Terminated with $00. +// $01 UCS-2 encoded Unicode [UNICODE] with BOM. All +// strings in the same frame SHALL have the same byteorder. +// Terminated with $00 00. +// ----------------------------------------------------------------------------- +const TInt KMetaDataParserAsciiEncoding = 0; +const TInt KMetaDataParserUnicodeEncoding = 1; + + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::CMetaDataParserID3v23 +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CMetaDataParserID3v23::CMetaDataParserID3v23( + CMetaDataSource& aSource ) + : CMetaDataParserID3v2(aSource) + { + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::ConstructL() + { + User::LeaveIfError(iFs.Connect()); + iExists = ETrue; +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::ConstructL - Done")); +#endif + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CMetaDataParserID3v23* CMetaDataParserID3v23::NewL( + CMetaDataSource& aSource ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::NewL")); +#endif + CMetaDataParserID3v23* self = new( ELeave ) CMetaDataParserID3v23( aSource ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +// Destructor +CMetaDataParserID3v23::~CMetaDataParserID3v23() + { + iFs.Close(); + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::PrepareToParseL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::PrepareToParseL() + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::PrepareToParseL")); +#endif + // Most of validation was already done by builder. + TBuf8 header; + iSource->ReadL( 0, header ); + // ID3v2.3 header consists of following parts: + // File identifier "ID3" + // Version $03 00 + // Flags %abc00000 + // Size 4 * %0xxxxxxx + + // Read the data length + iFrameDataSize = 0; + for ( TInt i = 6; i < 10; i++ ) + { + iFrameDataSize <<= 7; + iFrameDataSize |= header[i] & 0x7f; + } + + // Check if extended header is present; bit-b in Flags above + if ( header[5] & 0x40 ) + { + TBuf8 extHeader; + iSource->ReadL( KID3v2HeaderLength, extHeader ); + // ID3v2.3 extended header consists of following parts: + // Extended header size $xx xx xx xx + // Extended flags $xx xx + // Size of padding $xx xx xx xx + + // Read the data length + TInt extHeaderSize = 0; + for ( TInt i = 0; i < 4; i++ ) + { + extHeaderSize <<= 8; + extHeaderSize |= extHeader[i]; + } + iFrameOffset = KID3v2HeaderLength + KID3v2ExtendedHeaderLength + extHeaderSize; + } + else + { + iFrameOffset = KID3v2HeaderLength; + } + + // iFrameDataSize is the entire size of ID3 tag including the header + iFrameDataSize += iFrameOffset; + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetNextFieldL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetNextFieldL( + TMetaDataFieldId& aFieldId, + TInt& aFrameHeaderSize, + TInt& aFrameSize ) + { + TBuf8 frameHeader; + iSource->ReadL( iFrameOffset, frameHeader ); + // ID3v2.3 frame header consists of following parts: + // Frame identifier $xx xx xx xx + // Size $xx xx xx xx + // Flags $xx xx + + aFrameSize = 0; + + if(!frameHeader.Length()) + User::Leave(KErrCorrupt); + + for ( TInt i = 4; i < 8; i++ ) + { + aFrameSize <<= 8; + aFrameSize |= frameHeader[i]; + } + + aFrameHeaderSize = KID3v2FrameHeaderLength; + TPtrC8 frameId = frameHeader.Left( KID3v2FrameIdLength ); + _LIT8(KEMPTY, "\0\0\0\0"); + TBuf8<4> empty (KEMPTY); + if ( aFrameSize == 0 && frameId == empty) + { + // We have hit the padding -> no more fields to read + aFieldId = EUnknownMetaDataField; + aFrameHeaderSize = 0; + return; + } + else if (aFrameSize == 0) + { + aFieldId = EUnknownMetaDataField; + return; + } + + if ( frameId.Compare( KID3v2FrameIdTitle ) == 0 ) + { + aFieldId = EMetaDataSongTitle; + } + else if ( frameId.Compare( KID3v2FrameIdArtist ) == 0 ) + { + aFieldId = EMetaDataArtist; + } + else if ( frameId.Compare( KID3v2FrameIdAlbum ) == 0 ) + { + aFieldId = EMetaDataAlbum; + } + else if ( frameId.Compare( KID3v2FrameIdYear ) == 0 ) + { + aFieldId = EMetaDataYear; + } + else if ( frameId.Compare( KID3v2FrameIdComment ) == 0 ) + { + aFieldId = EMetaDataComment; + } + else if ( frameId.Compare( KID3v2FrameIdTrack ) == 0 ) + { + aFieldId = EMetaDataAlbumTrack; + } + else if ( frameId.Compare( KID3v2FrameIdGenre ) == 0 ) + { + aFieldId = EMetaDataGenre; + } + else if ( frameId.Compare( KID3v2FrameIdComposer ) == 0 ) + { + aFieldId = EMetaDataComposer; + } + else if ( frameId.Compare( KID3v2FrameIdCopyright ) == 0 ) + { + aFieldId = EMetaDataCopyright; + } + else if ( frameId.Compare( KID3v2FrameIdOriginalArtist ) == 0 ) + { + aFieldId = EMetaDataOriginalArtist; + } + else if ( frameId.Compare( KID3v2FrameIdUrl ) == 0 ) + { + aFieldId = EMetaDataUrl; + } + else if ( frameId.Compare( KID3v2FrameIdUserUrl ) == 0 ) + { + aFieldId = EMetaDataUserUrl; + } + else if ( frameId.Compare( KID3v2FrameIdJpeg ) == 0 ) + { + aFieldId = EMetaDataJpeg; + } + else if ( frameId.Compare( KID3v2FrameIdDuration ) == 0 ) + { + aFieldId = EMetaDataDuration; + } + else if ( frameId.Compare( KID3v2FrameIdDate ) == 0 ) + { + aFieldId = EMetaDataDate; + } + else if ( frameId.Compare( KID3v2FrameIdRating ) == 0 ) + { + aFieldId = EMetaDataRating; + } + else + { + aFieldId = EUnknownMetaDataField; + } + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetUserUrlL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetUserUrlL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetTextInfoL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + + TInt encoding = (TInt) (des.Left(1))[0]; + + if(encoding == 0x00) + { + _LIT8(KNULL, "\0"); + TInt descOffset = des.Find(KNULL); + if(descOffset + 2 > aSize) + { + CleanupStack::PopAndDestroy(); // frame + return; // empty frame + } + TPtrC8 info = des.Mid(descOffset + 2); + TInt length = info.Length(); + if ( length ) + { + HBufC* data16 = HBufC::NewLC( length ); + TPtr unicode( data16->Des() ); + unicode.Copy( info ); + iContainer->AppendL( EMetaDataUserUrl, unicode ); + CleanupStack::PopAndDestroy(); // data16 + } + } + else + { + _LIT8(KNULL, "\0\0"); + TInt descOffset = des.Find(KNULL); + if(descOffset + 3 > aSize) + { + CleanupStack::PopAndDestroy(); // frame + return; // empty frame + } + TPtrC8 info = des.Mid(descOffset + 3); + TInt length = info.Length(); + if ( length ) + { + HBufC* data16 = HBufC::NewLC( length ); + TPtr unicode( data16->Des() ); + unicode.Copy( info ); + iContainer->AppendL( EMetaDataUserUrl, unicode ); + CleanupStack::PopAndDestroy(); // data16 + } + } + + CleanupStack::PopAndDestroy(); // frame + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetGenreL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetGenreL( + TInt aSize ) + { + #ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v2::GetGenreL")); + #endif + + HandleV2GetGenreL( aSize, KID3v2FrameHeaderLength, KID3v2GenreNameLength ); + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetTextInfoL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetTextInfoL( + TMetaDataFieldId aFieldId, + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetTextInfoL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + + TInt encoding = (TInt) (des.Left(1))[0]; + TPtrC8 info = StripTrailingZeroes( des.Mid(1), encoding); + TInt length = info.Length(); + if ( length ) + { + HBufC* data16 = HBufC::NewLC( length ); + TPtr unicode( data16->Des() ); + if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone ) + { + iContainer->AppendL( aFieldId, unicode ); + } + CleanupStack::PopAndDestroy(); // data16 + } + + CleanupStack::PopAndDestroy(); // frame + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetTextYearL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetTextYearL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetTextYearL")); +#endif + GetTextInfoL( EMetaDataYear, aSize ); + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetCommentL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetCommentL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetCommentL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + + if(aSize <= 4) // emppty frame + { + CleanupStack::PopAndDestroy(); // frame + return; + } + TInt encoding = (TInt) (des.Left(1))[0]; + // Skip over TextEncoding(1 byte) and Language(3 bytes) + TPtr8 text = des.MidTPtr(4); + // Skip over Content description from Comment + TInt contentDesLength; + if(encoding == 0) + { + _LIT8(KNull, "\0"); + contentDesLength = text.Find(KNull); + if(contentDesLength == KErrNotFound) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + text = text.MidTPtr(contentDesLength + 1); + } + else + { + _LIT8(KNull, "\0\0"); + contentDesLength = text.Find(KNull); + if(contentDesLength == KErrNotFound) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + text = text.MidTPtr(contentDesLength + 2); + } + TPtrC8 info = StripTrailingZeroes( text, encoding); + TInt length = info.Length(); + if ( length ) + { + HBufC* data16 = HBufC::NewLC( length ); + TPtr unicode( data16->Des() ); + if ( ConvertToUnicodeL(encoding, info, unicode) == KErrNone ) + { + iContainer->AppendL( EMetaDataComment, unicode ); + } + CleanupStack::PopAndDestroy(); // data16 + } + + CleanupStack::PopAndDestroy(); // frame + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetUrlL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetUrlL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetUrlL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + + // Ignore information followed by termination $00 + TInt trueEnd( des.Locate(0) ); + if ( trueEnd == KErrNotFound ) + { + trueEnd = des.Length(); + } + + TPtrC8 info = des.Left( trueEnd ); + TInt length = info.Length(); + if ( length ) + { + HBufC* data16 = HBufC::NewLC( length ); + TPtr unicode( data16->Des() ); + unicode.Copy( info ); + iContainer->AppendL( EMetaDataUrl, unicode ); + CleanupStack::PopAndDestroy(); // data16 + } + + CleanupStack::PopAndDestroy(); // frame + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetJpegL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetJpegL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetJpegL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + + TInt encoding = (TInt) (des.Left(1))[0]; + + TInt mimeLength = des.Mid(1).Locate(0); + if(mimeLength <= 0 ) + { + User::Leave(KErrCorrupt); + } + TPtrC8 mime = des.Mid(1, mimeLength); + + if ( ( mime.Compare( KID3v2ImageFormatJpeg ) != 0 ) && + ( mime.Compare( KID3v2ImageFormatJpegMime ) != 0 ) && + ( mime.Compare( KID3v2ImageFormatJpgMime ) != 0 ) && + ( mime.Compare( KID3v2ImageFormatPngMime ) != 0 ) && + ( mime.Compare( KID3v2ImageFormatPng ) != 0 ) + ) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + + if(mimeLength+3 > des.Length()) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + + TInt pictureType = (TInt) (des.Mid(mimeLength + 2, 1))[0]; + if ( !NeedRetrieveAlbumArt(pictureType) ) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + + TInt picOffset; + TPtrC8 text8 = des.Mid(mimeLength + 3 ); + if ( encoding == KMetaDataParserAsciiEncoding ) + { + picOffset = text8.Locate(0); + if ( picOffset == KErrNotFound ) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + + picOffset++; // Description termination mark ($00) + } + else if ( encoding == KMetaDataParserUnicodeEncoding ) + { + _LIT8(KNULL, "\0\0"); // 2 bytes of NULL + picOffset = text8.Find(KNULL); + if ( picOffset == KErrNotFound ) + { + CleanupStack::PopAndDestroy(); // frame + return; + } + if (picOffset % 2) // check for offset odd number + { + picOffset++; // add 1 for word boundary + } + picOffset += 2; // Description termination mark ($00 00) + } + else + { + CleanupStack::PopAndDestroy(); // frame + return; + } + // storing it as 8 bit descriptor without conversion to 16 bit + TPtrC8 pic = des.Mid(picOffset + mimeLength + 3); + TInt length = pic.Length(); + if ( length ) + { + // save the offset and the size for retrieving the album art later + iAlbumOffset = picOffset + mimeLength + 3; + iAlbumType = pictureType; + + if (iAlbumPtr) + { + delete iAlbumPtr; // delete the previous buffer + } + CleanupStack::Pop(); // frame - pop from Cleanup stack + iAlbumPtr = frame; // save the buffer + } + else + { + CleanupStack::PopAndDestroy(); // frame + } + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetDurationL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetDurationL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetDurationL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + + TInt encoding = (TInt) (des.Left(1))[0]; + TPtrC8 info = StripTrailingZeroes( des.Mid(1), encoding ); // $00 + TInt length = info.Length(); + if ( length ) + { + TReal sec = ((TReal) atoi((char*)info.Ptr())) / 1000; + TBuf16<10> info1; + info1.Num(sec, TRealFormat (9, 3)); + iContainer->AppendL( EMetaDataDuration, info1 ); + } + + CleanupStack::PopAndDestroy(); // frame + } + + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetTextDateL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetTextDateL( + TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetTextDateL")); +#endif + GetTextInfoL( EMetaDataDate, aSize ); + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::GetRatingL +// ----------------------------------------------------------------------------- +// +void CMetaDataParserID3v23::GetRatingL( TInt aSize ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::GetRatingL")); +#endif + HBufC8* frame = HBufC8::NewLC( aSize ); + TPtr8 des( frame->Des() ); + + iSource->ReadL( iFrameOffset + KID3v2FrameHeaderLength, des, aSize ); + + if ( des.Length() < aSize ) + { + // Partial frame + User::Leave( KErrCorrupt ); + } + _LIT8(KNull, ""); + TInt offset = des.Find(KNull); + if(offset == KErrNotFound) + { + CleanupStack::PopAndDestroy(); + return; + } + TUint8 rating = des[offset]; + if ( rating > 0) + { + TBuf<8> data16; + data16.AppendNum(rating); + iContainer->AppendL( EMetaDataRating, data16 ); + } + CleanupStack::PopAndDestroy(); // frame + } + +// ----------------------------------------------------------------------------- +// CMetaDataParserID3v23::ConvertToUnicodeL +// ----------------------------------------------------------------------------- +// +TInt CMetaDataParserID3v23::ConvertToUnicodeL( + TInt aEncoding, + const TDesC8& aDesc, + TDes16& aUnicode ) + { +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::ConvertToUnicodeL")); +#endif + TPtrC8 unicodeData; + TUint characterSetId = 0; + TInt err; + + CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC(); + TInt state = CCnvCharacterSetConverter::KStateDefault; + + if ( aEncoding == KMetaDataParserAsciiEncoding ) + { + if(iAutoDetectChinese || iAutoDetectRussian || iAutoDetectJapanese) + { + err = AutoDetectL(aDesc, aUnicode); +#ifdef _DEBUG + RDebug::Print(_L("err = AutoDetectL %d"),err); +#endif + CleanupStack::PopAndDestroy(); // charSetConv + return err; + } + else + { + // ISO-8859-1 + characterSetId = KCharacterSetIdentifierIso88591; +#ifdef _DEBUG + RDebug::Print(_L("characterSetId = KCharacterSetIdentifierIso88591")); +#endif + unicodeData.Set( aDesc ); + } + } + else if ( aEncoding == KMetaDataParserUnicodeEncoding ) + { + // USC-2 with BOM + TInt bom = UnicodeBOM(aDesc); + if ( bom == KUnicodeBOMBigEndian ) + { + //characterSetId = KCharacterSetIdentifierUcs2; + characterSetId = KCharacterSetIdentifierUnicodeBig; + // Skip BOM & Terminate marks + unicodeData.Set( aDesc.Mid( 2, aDesc.Length() - 2 ) ); + } + else if ( bom == KUnicodeBOMLittleEndian ) + { + characterSetId = KCharacterSetIdentifierUnicodeLittle; + // Skip BOM & Terminate marks + unicodeData.Set( aDesc.Mid( 2, aDesc.Length() - 2 ) ); + } + else + { + // USC-2 Big Endian without BOM + characterSetId = KCharacterSetIdentifierUnicodeBig; + unicodeData.Set( aDesc ); + } + } + else + { + User::Leave(KErrNotSupported); + } + + charSetConv->PrepareToConvertToOrFromL(characterSetId, *iCharacterSet, iFs); + err = charSetConv->ConvertToUnicode(aUnicode, unicodeData, state); + +#ifdef _DEBUG + RDebug::Print(_L("CMetaDataParserID3v23::ConvertToUnicode :-> Tag Size[%d] Unicode Tag Size[%d]Bytes Unconverted[%d]"), + unicodeData.Length(), aUnicode.Length(), err); +#endif + + CleanupStack::PopAndDestroy(); // charSetConv + return err; + } + +// End of File