diff -r 000000000000 -r 95b198f216e5 omadrm/drmengine/dcf/src/Oma2Dcf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmengine/dcf/src/Oma2Dcf.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,1591 @@ +/* +* Copyright (c) 2002 - 2009 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: Implementation of class representeting discrete OMA2 DCF +* +*/ + + + +// INCLUDE FILES +#include // KMaxTUint32 +#include // Max, Min +#include +#include +#include +#include +#include "Oma2Agent.h" +#include "Oma2Dcf.h" +#include "Oma2DcfPartInfo.h" + +// LOCAL CONSTANTS AND MACROS + +#define M4CC( a ) ( ( a[ 0 ] << 24 ) + ( a[ 1 ] << 16 ) + ( a[ 2 ] << 8 ) + a[ 3 ] ) + +const TUint32 KDiscreteMediaHeaders( M4CC( "odhe" ) ); +const TUint32 KContainer( M4CC( "odrm" ) ); +const TUint32 KContentObject( M4CC( "odda" ) ); +const TUint32 KCommonHeaders( M4CC( "ohdr" ) ); +const TUint32 KMutableInfo( M4CC( "mdri" ) ); +const TUint32 KTransactionTracking( M4CC( "odtt" ) ); +const TUint32 KRightsObject( M4CC( "odrb" ) ); +const TUint32 KGroupId( M4CC( "grpi" ) ); +const TUint32 KUserData( M4CC( "udta" ) ); + +// supported user data boxes +_LIT8( KTitle, "titl" ); +_LIT8( KDescription, "dscp" ); +_LIT8( KCopyright, "cprt" ); +_LIT8( KAuthor, "auth" ); +_LIT8( KIconUri, "icnu" ); +_LIT8( KInfoURL, "infu" ); +_LIT8( KPerformer, "perf" ); +_LIT8( KGenre, "gnre" ); +_LIT8( KRating, "rtng" ); +_LIT8( KClassification, "clsf" ); +_LIT8( KKeyword, "kywd" ); +_LIT8( KLocationInformation, "loci" ); +_LIT8( KAlbum, "albm" ); +_LIT8( KRecordingYear, "yrrc" ); +_LIT8( KCoverUri, "cvru" ); +_LIT8( KLyricsURL, "lrcu" ); + + +_LIT8( KMdri, "mdri" ); +_LIT8( KOdtt, "odtt" ); +_LIT8( KOdrb, "odrb" ); + +// textual headers +_LIT8( KSilentHeader, "Silent" ); +_LIT8( KPreviewHeader, "Preview" ); +_LIT8( KContentURLHeader, "ContentURL" ); +_LIT8( KContentVersionHeader, "ContentVersion" ); +_LIT8( KContentLocationHeader, "Content-Location" ); + +// supported custom textual headers +_LIT8( KIconUriHeader, "IconURI" ); +_LIT8( KTitleHeader, "Title" ); +_LIT8( KDescriptionHeader, "Description" ); +_LIT8( KAuthorHeader, "Author" ); +_LIT8( KCopyrightHeader, "Copyright" ); +_LIT8( KInfoURLHeader, "InfoURL" ); + +// textual headers, methods +_LIT8( KSilentMethodOnDemand, "on-demand" ); +_LIT8( KSilentMethodInAdvance, "in-advance" ); +_LIT8( KPreviewMethodInstant, "instant" ); +_LIT8( KPreviewMethodPreviewRights, "preview-rights" ); +_LIT8( KEmptyTransactionId, "0000000000000000" ); + +_LIT8( KTerminator, "\0" ); +_LIT8( KSeparator, ":" ); +_LIT8( KParamSeparator, ";" ); + +const TInt KBrandingSize( 20 ); +const TInt KMaxBoxHeaderSize( 16 ); +const TInt KLengthBoxSize( 4 ); +const TInt KLengthBoxType( 4 ); +const TInt KLengthBoxSize64( 8 ); +const TInt KLengthVersion( 1 ); +const TInt KLengthFlags( 3 ); +const TInt KLengthEncMethod( 1 ); +const TInt KLengthPadType( 1 ); +const TInt KLengthPlainTextSize( 8 ); +const TInt KLengthDataLengthSize( 8 ); +const TInt KLengthContentIdSize( 2 ); +const TInt KLengthRiUrlSize( 2 ); +const TInt KLengthTextHeadersSize( 2 ); +const TInt KLengthTerminator( 1 ); + +// Smallest possible ISO based media box size +// See ISO/IEC 14496-12 and DRM-DCF-CLI-12 in OMA-TS-DRM-DCF-V2_1 +const TUint32 KMinBoxSize( KLengthBoxSize + KLengthBoxType ); +// Largest supported ISO based media box size +const TUint32 KMaxBoxSize( KMaxTUint32 ); + +const TUint KUserDataBoxMask( 0x000001 ); + +// ============================= LOCAL FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// ReadUint32FromBlock +// ----------------------------------------------------------------------------- +// +LOCAL_C TUint32 ReadUint32FromBlock( const TDesC8& aBlock, TInt aOffset ) + { + return ( aBlock[ aOffset ] << 24 ) + + ( aBlock[ aOffset + 1 ] << 16 ) + + ( aBlock[ aOffset + 2 ] << 8 ) + + aBlock[ aOffset + 3 ]; + } + +// ----------------------------------------------------------------------------- +// ReadUint16FromBlock +// ----------------------------------------------------------------------------- +// +LOCAL_C TUint16 ReadUint16FromBlock( const TDesC8& aBlock, TInt aOffset ) + { + return ( ( aBlock[ aOffset ] << 8 ) + aBlock[ aOffset + 1 ] ); + } + +// ----------------------------------------------------------------------------- +// WriteIntToBlock +// ----------------------------------------------------------------------------- +// +LOCAL_C void WriteIntToBlock( TInt aValue, TDes8& aBlock, TInt aOffset ) + { + aBlock.SetLength( 4 ); + aBlock[ aOffset ] = ( aValue & 0xff000000 ) >> 24; + aBlock[ aOffset + 1 ] = ( aValue & 0x00ff0000 ) >> 16; + aBlock[ aOffset + 2 ] = ( aValue & 0x0000ff00 ) >> 8; + aBlock[ aOffset + 3 ] = ( aValue & 0x000000ff ); + } + +// ----------------------------------------------------------------------------- +// ValidateBoxSizeL +// ----------------------------------------------------------------------------- +// +LOCAL_C void ValidateBoxSizeL( + const TUint32 aSize, + const TUint32 aMinSize = KMinBoxSize, + const TUint32 aMaxSize = KMaxBoxSize ) + { + TUint32 minSize( Max( aMinSize, KMinBoxSize) ); + TUint32 maxSize( Min( aMaxSize, KMaxBoxSize ) ); + if ( aSize < minSize ) + { + User::Leave( KErrArgument ); + } + if ( aSize > maxSize ) + { + User::Leave( KErrArgument ); + } + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// COma2Dcf::COma2Dcf +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +COma2Dcf::COma2Dcf(): + iEncrytionPadding( EPaddingNone ), + iSilentRefresh( ENoSilentRefresh ), + iPreview( ENoPreview ), + iPreviewParameter( NULL ), + iSilentParameter( NULL ), + iTextualHeaders( NULL ), + iContentUrl( NULL ), + iContentVersion( NULL ), + iContentLocation( NULL ), + iTransactionTracking( NULL ), + iUserData( NULL ), + iAuthor( NULL ), + iCopyRight( NULL ), + iInfoUri( NULL ), + iGroupId( NULL ), + iGroupKey( NULL ), + iGkEncryptionMethod( EMethodNULL ), + iMutablePart( NULL ), + iPerformer( NULL ), + iGenre( NULL ), + iRatingInfo( NULL ), + iClassificationInfo( NULL ), + iKeyword( NULL ), + iLocInfoName( NULL ), + iLocInfoAstronomicalBody( NULL ), + iLocInfoAdditionalNotes( NULL ), + iAlbumTitle( NULL ), + iCoverUri( NULL ), + iLyricsURL( NULL ), + iRecordingYear( 0 ), + iAlbumTrack( 0 ) + { + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ConstructL( + const RFile& aFile, + TInt aPart ) + { + CDcfCommon::ConstructL( aFile ); + ReadPartsL(); + User::LeaveIfError( OpenPart( aPart ) ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C COma2Dcf* COma2Dcf::NewL( + const RFile& aFile, + TInt aPart ) + { + COma2Dcf* self( new ( ELeave ) COma2Dcf ); + + CleanupStack::PushL( self ); + self->ConstructL( aFile, aPart ); + CleanupStack::Pop( self ); + + return self; + } + +// Destructor +EXPORT_C COma2Dcf::~COma2Dcf() + { + delete iPreviewParameter; + delete iSilentParameter; + delete iTextualHeaders; + delete iContentUrl; + delete iContentVersion; + delete iContentLocation; + delete iTransactionTracking; + delete iUserData; + delete iAuthor; + delete iCopyRight; + delete iInfoUri; + delete iGroupId; + delete iGroupKey; + delete iPerformer; + delete iGenre; + delete iRatingInfo; + delete iClassificationInfo; + delete iKeyword; + delete iLocInfoName; + delete iLocInfoAstronomicalBody; + delete iLocInfoAdditionalNotes; + delete iAlbumTitle; + delete iCoverUri; + delete iLyricsURL; + delete iMutablePart; + + iRightsObjects.ResetAndDestroy(); + iRightsObjects.Close(); + iParts.ResetAndDestroy(); + iParts.Close(); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::IsValidDcf +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool COma2Dcf::IsValidDcf( + const TDesC8& aDcfFragment ) + { + TBool r( EFalse ); + + if ( aDcfFragment.Length() >= KBrandingSize && + aDcfFragment.Left( KBrandingSize ).Compare( KOma2DcfBranding ) == 0 ) + { + r = ETrue; + } + return r; + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadPartsL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadPartsL( void ) + { + TBuf8 buffer; + TInt size; + TUint32 type; + TInt offset; + TInt headerSize; + COma2DcfPartInfo* part; + + User::LeaveIfError( iFile.Read( 0, buffer, KBrandingSize ) ); + if ( !IsValidDcf( buffer ) ) + { + User::Leave( KErrArgument ); + } + iVersion = ReadUint32FromBlock( buffer, 12 ); + offset = KBrandingSize; + iParts.Reset(); + do + { + ReadBoxSizeAndTypeL( offset, size, type, headerSize ); + if ( headerSize > 0 ) + { + part = COma2DcfPartInfo::NewL(); + part->iType = type; + part->iSize = size; + part->iOffset = offset; + CleanupStack::PushL( part ); + if ( type == KContainer ) + { + ReadPartInfoL( part, offset ); + iParts.Append( part ); + CleanupStack::Pop( part ); + } + else if ( type == KMutableInfo ) + { + iMutablePart = part; + CleanupStack::Pop( part ); + ReadMutableInfoL( offset, size ); + } + else + { + CleanupStack::PopAndDestroy( part ); + } + } + offset += size; + } + while ( offset < iLength && headerSize > 0 ); + + delete iContentID; + iContentID = NULL; + delete iMimeType; + iMimeType = NULL; + + if ( iParts.Count() == 0 || + iParts[ 0 ]->iContentId == NULL || + iParts[ 0 ]->iMimeType == NULL ) + { + User::LeaveIfError( KErrArgument ); + } + iContentID = iParts[ 0 ]->iContentId->AllocL(); + iMimeType = iParts[ 0 ]->iMimeType->AllocL(); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::CheckUniqueId +// ----------------------------------------------------------------------------- +// +TInt COma2Dcf::CheckUniqueId( const TDesC& aUniqueId ) + { + TInt r( CDcfCommon::CheckUniqueId( aUniqueId ) ); + + if ( r == KErrNotFound ) + { + HBufC8* id( NULL ); + TRAPD( err, + id = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aUniqueId ) ); + if ( err == KErrNone ) + { + r = KErrNotFound; + for ( TInt i( 0 ); + i < iParts.Count() && r == KErrNotFound; + i++ ) + { + if ( !id->Compare( *iParts[ i ]->iContentId ) ) + { + r = i; + } + } + delete id; + } + else + { + r = err; + } + } + return r; + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::OpenPart +// ----------------------------------------------------------------------------- +// +TInt COma2Dcf::OpenPart( + const TDesC& aUniqueId ) + { + return OpenPart( CheckUniqueId( aUniqueId ) ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::OpenPart +// ----------------------------------------------------------------------------- +// +TInt COma2Dcf::OpenPart( + TInt aPart ) + { + TInt r( KErrNone ); + TInt size( 0 ); + + if ( aPart >= 0 && aPart < iParts.Count() ) + { + TRAP( r, ReadContainerL( iParts[ aPart ]->iOffset, size ) ); + } + else + { + r = KErrNotFound; + } + return r; + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::GetPartIdsL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::GetPartIdsL( RPointerArray& aPartList ) + { + aPartList.ResetAndDestroy(); + for ( TInt i( 0 ); i < iParts.Count(); i++ ) + { + aPartList.Append( iParts[ i ]->iContentId->AllocL() ); + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadContainerL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadContainerL( + TInt aOffset, + TInt& aSize ) + { + TUint32 type( 0 ); + TInt size( 0 ); + + ReadBoxSizeAndTypeL( aOffset, aSize, type, size ); + VerifyTypeL( type, KContainer ); + aOffset += size + KLengthVersion + KLengthFlags; + ReadDiscreteMediaHeaderL( aOffset, size ); + aOffset += size; + ReadContentObjectL( aOffset, size ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadDiscreteMediaHeaderL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadDiscreteMediaHeaderL( + TInt aOffset, + TInt& aSize ) + { + TBuf8<1> valBuf; + TBuf8<4> udtaBuf; + TInt size( 0 ); + TUint32 type( 0 ); + TUint8 length( 0 ); + TPtr8 ptr( 0, 0 ); + + TBuf8< KLengthVersion + KLengthFlags > buffer; + TUint32 version_and_flags( 0 ); + + ReadBoxSizeAndTypeL( aOffset, aSize, type, size ); + VerifyTypeL( type, KDiscreteMediaHeaders ); + + // read flags and version + aOffset += size; + User::LeaveIfError( iFile.Read( aOffset, buffer ) ); + version_and_flags = ReadUint32FromBlock( buffer, 0 ); + aOffset += KLengthVersion + KLengthFlags; + + // read ContentType + delete iMimeType; + iMimeType = NULL; + + // input validation + if ( aOffset < 0 ) + { + // RFile::Read will panic if offset is negative + User::Leave( KErrArgument ); + } + + User::LeaveIfError( iFile.Read( aOffset, valBuf, 1 ) ); + length = valBuf[ 0 ]; + aOffset += 1; + iMimeType = HBufC8::NewMax( length ); + User::LeaveIfNull( iMimeType ); + ptr.Set( iMimeType->Des() ); + User::LeaveIfError( iFile.Read( ptr, length ) ); + aOffset += length; + + // read Common headers + ReadCommonHeadersL( aOffset, size ); + + // user data box would follow here + if ( version_and_flags & KUserDataBoxMask ) + { + aOffset += size; + User::LeaveIfError( iFile.Read( aOffset, udtaBuf, 4 ) ); + size = ReadUint32FromBlock( udtaBuf, 0 ); + ReadUserDataL( aOffset, size ); + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadContentObjectL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadContentObjectL( + TInt aOffset, + TInt& aSize ) + { + TBuf8 valBuf; + TInt size( 0 ); + TUint32 type( 0 ); + + ReadBoxSizeAndTypeL( aOffset, aSize, type, size ); + VerifyTypeL( type, KContentObject ); + aOffset += size + KLengthVersion + KLengthFlags; + + // read data length + + // input validation + if ( aOffset < 0 ) + { + // RFile::Read will panic if offset is negative + User::Leave( KErrArgument ); + } + + User::LeaveIfError( iFile.Read( aOffset, valBuf, KLengthDataLengthSize ) ); + if ( ReadUint32FromBlock( valBuf, 0 ) != 0 ) + { + // the size is larger than 2^32-1, we can't handle this. + User::Leave( KErrOverflow ); + } + else + { + iDataLength = ReadUint32FromBlock( valBuf, KLengthDataLengthSize / 2 ); + if ( iPlainTextLengthValid ) + { + iPadding = iDataLength - iPlainTextLength; + } + } + iOffset = aOffset + KLengthDataLengthSize; + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadCommonHeadersL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadCommonHeadersL( + TInt aOffset, + TInt& aSize ) + { + TBuf8< KMaxBoxHeaderSize > valBuf; + TInt size( 0 ); + TInt boxEnd( 0 ); + TUint32 type( 0 ); + TInt offset( 0 ); + TUint16 riURLLength( 0 ); + TUint16 contentIdLength( 0 ); + TUint16 textualHeadersLength( 0 ); + TUint16 length( 0 ); + HBufC8* buf( NULL ); + TPtr8 ptr( 0, 0 ); + + ReadBoxSizeAndTypeL( aOffset, aSize, type, size ); + VerifyTypeL( type, KCommonHeaders ); + boxEnd = aOffset + aSize; + aOffset += size + KLengthVersion + KLengthFlags; + + length = KLengthEncMethod + KLengthPadType + KLengthPlainTextSize + + KLengthContentIdSize + KLengthRiUrlSize + KLengthTextHeadersSize; + buf = HBufC8::NewLC( length ); + ptr.Set( buf->Des() ); + + // input validation + if ( aOffset < 0 ) + { + // RFile::Read will panic if offset is negative + User::Leave( KErrArgument ); + } + User::LeaveIfError( iFile.Read( aOffset, ptr, length ) ); + + offset = 0; + iEncryptionMethod = static_cast< TEncryptionMethod >( ( *buf )[ 0 ] ); + offset += KLengthEncMethod; + iEncrytionPadding = static_cast< TEncryptionPadding >( ( *buf )[ 1 ] ); + offset += KLengthPadType; + + iPlainTextLength = ReadUint32FromBlock( ptr, offset ); + offset += KLengthPlainTextSize / 2; + if ( iPlainTextLength != 0 ) + { + User::Leave( KErrOverflow ); + } + else + { + iPlainTextLength = ReadUint32FromBlock( ptr, offset ); + if ( iPlainTextLength > 0 ) + { + iPlainTextLengthValid = ETrue; + } + else + { + iPlainTextLengthValid = EFalse; + } + offset += KLengthPlainTextSize / 2; + } + + contentIdLength = ReadUint16FromBlock( ptr, offset ); + offset += KLengthContentIdSize; + riURLLength = ReadUint16FromBlock( ptr, offset ); + offset += KLengthRiUrlSize; + textualHeadersLength = ReadUint16FromBlock( ptr, offset ); + offset += KLengthTextHeadersSize; + CleanupStack::PopAndDestroy( buf ); + buf = NULL; + + aOffset += offset; + delete iContentID; + iContentID = NULL; + iContentID = HBufC8::NewMax( contentIdLength ); + User::LeaveIfNull( iContentID ); + ptr.Set( iContentID->Des() ); + User::LeaveIfError( iFile.Read( aOffset, ptr, contentIdLength ) ); + aOffset += contentIdLength; + + delete iRightsIssuerURL; + iRightsIssuerURL = NULL; + if ( riURLLength > 0 ) + { + iRightsIssuerURL = HBufC8::NewL( riURLLength ); + ptr.Set( iRightsIssuerURL->Des() ); + User::LeaveIfError( iFile.Read( aOffset, ptr, riURLLength ) ); + aOffset += riURLLength; + } + + delete iTextualHeaders; + iTextualHeaders = NULL; + if ( textualHeadersLength > 0 ) + { + iTextualHeaders = HBufC8::NewL( textualHeadersLength ); + ptr.Set( iTextualHeaders->Des() ); + User::LeaveIfError( iFile.Read( aOffset, ptr, textualHeadersLength ) ); + aOffset += textualHeadersLength; + ParseTextualHeadersL( ptr ); + } + + ReadExtendedHeadersL( aOffset, boxEnd ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ParseTextualHeadersL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ParseTextualHeadersL( + const TDesC8& aMemoryBlock ) + { + HBufC8* buf1( NULL ); + HBufC8* method( NULL ); + TInt r( KErrNone ); + TInt silentOffset( 0 ); + TInt previewOffset( 0 ); + + silentOffset = ReadOneTextualHeaderL( + aMemoryBlock, KSilentHeader, buf1, r ); + if ( r != KErrNotFound && buf1 ) + { + CleanupStack::PushL( buf1 ); + SetHeaderWithParameterL( *buf1, method, iSilentParameter ); + CleanupStack::PopAndDestroy( buf1 ); + buf1 = NULL; + if ( method ) + { + if ( !method->Compare( KSilentMethodOnDemand ) ) + { + iSilentRefresh = EOnDemand; + } + else if ( !method->Compare( KSilentMethodInAdvance ) ) + { + iSilentRefresh = EInAdvance; + } + else + { + delete method; + User::Leave( KErrArgument ); + } + delete method; + method = NULL; + } + } + else + { + iSilentRefresh = ENoSilentRefresh; + delete iSilentParameter; + iSilentParameter = 0; + } + + previewOffset = ReadOneTextualHeaderL( + aMemoryBlock, KPreviewHeader, buf1, r ); + if ( r != KErrNotFound && buf1 ) + { + CleanupStack::PushL( buf1 ); + SetHeaderWithParameterL( *buf1, method, iPreviewParameter ); + CleanupStack::PopAndDestroy( buf1 ); + buf1 = NULL; + if ( method ) + { + if ( !method->CompareF( KPreviewMethodInstant ) ) + { + iPreview = EInstantPreview; + } + else if ( !method->CompareF( KPreviewMethodPreviewRights ) ) + { + iPreview = EPreviewRights; + } + else + { + delete method; + User::Leave( KErrArgument ); + } + delete method; + method = NULL; + } + } + else + { + iPreview = ENoPreview; + delete iPreviewParameter; + iPreviewParameter = NULL; + } + + iPreviewOverridesSilentRefresh = EFalse; + if ( iSilentRefresh != ENoSilentRefresh && iPreview != ENoPreview ) + { + if ( previewOffset < silentOffset ) + { + iPreviewOverridesSilentRefresh = ETrue; + } + } + + ReadOneTextualHeaderL( + aMemoryBlock, KContentLocationHeader, iContentLocation, r ); + if ( r == KErrNotFound ) + { + delete iContentLocation; + iContentLocation = NULL; + } + + ReadOneTextualHeaderL( aMemoryBlock, KContentURLHeader, iContentUrl, r ); + if ( r == KErrNotFound ) + { + delete iContentUrl; + iContentUrl = NULL; + } + + ReadOneTextualHeaderL( + aMemoryBlock, KContentVersionHeader, iContentVersion, r ); + if ( r == KErrNotFound ) + { + delete iContentVersion; + iContentVersion = NULL; + } + + // custom headers -> + ReadOneTextualHeaderL( aMemoryBlock, KInfoURLHeader, iInfoUri, r ); + if ( r == KErrNotFound ) + { + delete iInfoUri; + iInfoUri = NULL; + } + + // custom header + ReadOneTextualHeaderL( aMemoryBlock, KTitleHeader, iTitle, r ); + if ( r == KErrNotFound ) + { + delete iTitle; + iTitle = NULL; + } + + ReadOneTextualHeaderL( aMemoryBlock, KIconUriHeader, iIconUri, r ); + if ( r == KErrNotFound ) + { + delete iIconUri; + iIconUri = NULL; + } + + ReadOneTextualHeaderL( aMemoryBlock, KAuthorHeader, iAuthor, r ); + if ( r == KErrNotFound ) + { + delete iAuthor; + iAuthor = NULL; + } + + ReadOneTextualHeaderL( aMemoryBlock, KDescriptionHeader, iDescription, r ); + if ( r == KErrNotFound ) + { + delete iDescription; + iDescription = NULL; + } + + ReadOneTextualHeaderL( aMemoryBlock, KCopyrightHeader, iCopyRight, r ); + if ( r == KErrNotFound ) + { + delete iCopyRight; + iCopyRight = NULL; + } + + + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::SetHeaderWithParameterL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::SetHeaderWithParameterL( + const TDesC8& aValue, + HBufC8*& aMethod, + HBufC8*& aParameter ) + { + TInt offset( 0 ); + + delete aMethod; + aMethod = NULL; + delete aParameter; + aParameter = NULL; + + offset = aValue.Find( KParamSeparator ); + if ( offset == KErrNotFound || offset == 0 ) + { + aMethod = aValue.AllocL(); + } + else + { + aMethod = aValue.Left( offset ).AllocLC(); + aParameter = aValue.Mid( offset + 1 ).AllocL(); + CleanupStack::Pop( aMethod ); + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadOneTextualHeaderL +// ----------------------------------------------------------------------------- +// +TInt COma2Dcf::ReadOneTextualHeaderL( + const TDesC8& aBlock, + const TDesC8& aName, + HBufC8*& aBuf, + TInt& aError ) + { + TInt offset( aBlock.Find( aName ) ); + + delete aBuf; + aBuf = NULL; + if ( offset == KErrNotFound ) + { + aError = KErrNotFound; + return offset; + } + else + { + if ( offset + aName.Length() < aBlock.Length() && + aBlock.Mid( offset + aName.Length(), 1 ) == KSeparator ) + { + TInt length( 0 ); + length = + aBlock.Mid( offset + aName.Length() + 1 ).Find( KTerminator ); + if ( length == KErrNotFound ) + { + User::Leave( KErrArgument ); + } + else + { + aBuf = HBufC8::NewL( length ); + *aBuf = aBlock.Mid( offset + aName.Length() + 1, length ); + } + } + } + aError = KErrNone; + return offset; + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadExtendedHeadersL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadExtendedHeadersL( + TInt aOffset, + TInt aEndOfBox ) + { + TInt size( 1 ); + TInt groupIdSize( 0 ); + TInt groupKeySize( 0 ); + TUint32 type( 0 ); + TInt headerSize( 0 ); + TInt dataSize( 0 ); + TInt offset( 0 ); + TPtr8 ptr( 0, 0 ); + HBufC8* buffer( NULL ); + + delete iGroupId; + iGroupId = NULL; + delete iGroupKey; + iGroupKey = NULL; + + while ( size > 0 && aOffset < aEndOfBox && iGroupId == NULL ) + { + size = 0; + ReadBoxSizeAndTypeL( aOffset, size, type, headerSize ); + if ( type == KGroupId ) + { + dataSize = size - headerSize - KLengthVersion - KLengthFlags; + offset = aOffset + headerSize + KLengthVersion + KLengthFlags; + // input validation + if ( dataSize < 0 || dataSize > KMaxTInt / 2 ) + { + User::Leave( KErrArgument ); + } + buffer = HBufC8::NewLC( dataSize ); + ptr.Set( buffer->Des() ); + User::LeaveIfError( iFile.Read( offset, ptr, dataSize ) ); + // input validation + if ( ptr.Length() == 0 ) + { + User::Leave( KErrArgument ); + } + iGkEncryptionMethod = static_cast< TEncryptionMethod >( ptr[ 2 ] ); + groupIdSize = ReadUint16FromBlock( ptr, 0 ); + if ( 5 + groupIdSize > ptr.Length() ) + { + User::Leave( KErrArgument ); + } + iGroupId = ptr.Mid( 5, groupIdSize ).AllocL(); + groupKeySize = ReadUint16FromBlock( ptr, 3 ); + if ( 5 + groupIdSize + groupKeySize > ptr.Length() ) + { + User::Leave( KErrArgument ); + } + iGroupKey = ptr.Mid( 5 + groupIdSize, groupKeySize ).AllocL(); + + // Set the content ID of this file to the group ID + delete iContentID; + iContentID = NULL; + iContentID = iGroupId->AllocL(); + + CleanupStack::PopAndDestroy( buffer ); + } + aOffset += size; + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadMutableInfoL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadMutableInfoL( + TInt aOffset, + TInt& aSize ) + { + TInt size( 0 ); + TInt dataSize( 0 ); + TUint32 type( 0 ); + TInt headerSize( 0 ); + TPtr8 ptr( 0, 0 ); + HBufC8* buffer1( NULL ); + TInt boxEnd( 0 ); + TInt offset( 0 ); + + delete iTransactionTracking; + iTransactionTracking = NULL; + iRightsObjects.ResetAndDestroy(); + + ReadBoxSizeAndTypeL( aOffset, aSize, type, headerSize ); + VerifyTypeL( type, KMutableInfo ); + + if ( !iMutablePart ) + { + iMutablePart = COma2DcfPartInfo::NewL(); + iMutablePart->iType = type; + iMutablePart->iSize = aSize; + iMutablePart->iOffset = aOffset; + } + + + boxEnd = aOffset + aSize; + aOffset += headerSize; + + do + { + ReadBoxSizeAndTypeL( aOffset, size, type, headerSize ); + if ( headerSize > 0 ) + { + dataSize = size - headerSize - KLengthVersion - KLengthFlags; + offset = aOffset + headerSize + KLengthVersion + KLengthFlags; + // input validation + if ( dataSize < 0 || dataSize > KMaxTInt / 2 ) + { + User::Leave( KErrArgument ); + } + if ( type == KTransactionTracking && !iTransactionTracking ) + { + buffer1 = HBufC8::NewLC( dataSize ); + ptr.Set( buffer1->Des() ); + User::LeaveIfError( iFile.Read( offset, ptr, dataSize ) ); + CleanupStack::Pop( buffer1 ); + iTransactionTracking = buffer1; + } + else if ( type == KRightsObject ) + { + buffer1 = HBufC8::NewLC( dataSize ); + ptr.Set( buffer1->Des() ); + User::LeaveIfError( iFile.Read( offset, ptr, dataSize ) ); + CleanupStack::Pop( buffer1 ); + iRightsObjects.Append( buffer1 ); + } + } + aOffset += size; + + } + while ( headerSize > 0 && aOffset < boxEnd && offset <= iLength ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadBoxSizeAndTypeL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadBoxSizeAndTypeL( + TInt aOffset, + TInt& aSize, + TUint32& aType, + TInt& aHeaderSize ) + { + TBuf8< KLengthBoxSize + KLengthBoxType > buffer; + + aHeaderSize = 0; + // input validation + if ( aOffset < 0 || aOffset > iLength ) + { + // Valid offset can never be negative + // or greater than length of the opened file. + User::Leave( KErrArgument ); + } + User::LeaveIfError( iFile.Read( aOffset, buffer ) ); + if ( buffer.Length() == KLengthBoxSize + KLengthBoxType ) + { + aSize = ReadUint32FromBlock( buffer, 0 ); + aType = ReadUint32FromBlock( buffer, 4 ); + aHeaderSize = KLengthBoxSize + KLengthBoxType; + + if ( aSize == 1 ) + { + buffer.SetLength( 0 ); + User::LeaveIfError( iFile.Read( buffer ) ); + if ( buffer.Length() < KLengthBoxSize + KLengthBoxType ) + { + User::Leave( KErrArgument ); + } + if ( ReadUint32FromBlock( buffer, 0 ) > 0 ) + { + User::Leave( KErrOverflow ); + } + aSize = ReadUint32FromBlock( buffer, 4 ); + aHeaderSize += KLengthBoxSize64; + } + else if ( aSize == 0 ) + { + aSize = iLength - aOffset; + } + else if ( aType == KContainer ) + { + // oma drm container box must always have large length field set + // See DRM-DCF-CLI-15 in OMA-TS-DRM-DCF-V2_1. + User::Leave( KErrArgument ); + } + } + // Valid box size can never be smaller than discovered header size. + // Nor can it be larger than largest supported ISO based media box size. + ValidateBoxSizeL( aSize, aHeaderSize, KMaxBoxSize - aOffset ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::VerifyTypeL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::VerifyTypeL( TUint32 aType, TUint32 aRefType ) + { + if ( aRefType != aType ) + { + User::Leave( KErrArgument ); + }; + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::SetTransactionIdL +// ----------------------------------------------------------------------------- +// +EXPORT_C void COma2Dcf::SetTransactionIdL( + const TDesC8& aTransactionId ) + { + // Overwrite existing ID, otherwise, recreate the whole MDRI box + if ( iTransactionTracking ) + { + TInt size( 0 ); + TUint32 type( 0 ); + TInt headerSize( 0 ); + TInt offset( 0 ); + + offset = iMutablePart->iOffset; + // Read mutable box headers and skip them + ReadBoxSizeAndTypeL( offset, size, type, headerSize ); + offset += headerSize; + do + { + ReadBoxSizeAndTypeL( offset, size, type, headerSize ); + if ( type != KTransactionTracking ) + { + offset += size; + } + } + while ( headerSize > 0 && + type != KTransactionTracking && offset <= iLength ); + + + if ( type == KTransactionTracking ) + { + offset += headerSize + KLengthVersion + KLengthFlags; + User::LeaveIfError( iFile.Write( offset, aTransactionId ) ); + } + } + else + { + RewriteMutableInfoL( aTransactionId, iRightsObjects ); + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::SetRightsObjectsL +// ----------------------------------------------------------------------------- +// +EXPORT_C void COma2Dcf::SetRightsObjectsL( + RPointerArray& aRoList ) + { + // Always recreate the whole MDRI box, it's simpler + if ( iTransactionTracking ) + { + RewriteMutableInfoL( *iTransactionTracking, aRoList ); + } + else + { + RewriteMutableInfoL( KNullDesC8, aRoList ); + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::RewriteMutableInfoL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::RewriteMutableInfoL( + const TDesC8& aTransactionId, + RPointerArray& aRoList ) + { + TInt offset( 0 ); + TBuf8<4> buffer; + TInt sizeOfRoBoxes( 0 ); + TInt roBoxSize( 0 ); + TInt tidBoxSize( 0 ); + TInt mutableBoxSize( 0 ); + + // Remove the existing box + if ( iMutablePart ) + { + User::LeaveIfError( iFile.SetSize( iMutablePart->iOffset ) ); + } + + // Append the box to the end of the file + User::LeaveIfError( iFile.Size( offset ) ); + + for ( TInt i( 0 ); i < aRoList.Count(); i++ ) + { + sizeOfRoBoxes += aRoList[ i ]->Size() + + KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags; + } + tidBoxSize = 16 + + KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags; + mutableBoxSize = + KLengthBoxSize + KLengthBoxType + tidBoxSize + sizeOfRoBoxes; + + // MDRI box + WriteIntToBlock( mutableBoxSize, buffer, 0 ); + User::LeaveIfError( iFile.Write( offset, buffer ) ); + User::LeaveIfError( iFile.Write( KMdri ) ); + + // ODTT box ( always written ) + WriteIntToBlock( tidBoxSize, buffer, 0 ); + User::LeaveIfError( iFile.Write( buffer ) ); + User::LeaveIfError( iFile.Write( KOdtt ) ); + buffer.FillZ(); + User::LeaveIfError( iFile.Write( buffer ) ); + if ( aTransactionId.Size() > 0 ) + { + User::LeaveIfError( iFile.Write( aTransactionId ) ); + } + else + { + User::LeaveIfError( iFile.Write( KEmptyTransactionId ) ); + } + + // ODRB box + if ( sizeOfRoBoxes > 0 ) + { + for ( TInt i( 0 ); i < aRoList.Count(); i++ ) + { + roBoxSize = aRoList[ i ]->Size() + + KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags; + WriteIntToBlock( roBoxSize, buffer, 0 ); + User::LeaveIfError( iFile.Write( buffer ) ); + User::LeaveIfError( iFile.Write( KOdrb ) ); + buffer.FillZ(); + User::LeaveIfError( iFile.Write( buffer ) ); + User::LeaveIfError( iFile.Write( *aRoList[ i ] ) ); + } + } + + // Reread the MDRI box + User::LeaveIfError( iFile.Size( iLength ) ); + ReadMutableInfoL( offset, mutableBoxSize ); + } + + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadPartInfoL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadPartInfoL( + COma2DcfPartInfo* aPart, + TInt aOffset ) + { + TBuf8<4> buffer; + TUint32 size( 0 ); + TPtr8 ptr( NULL, 0 ); + + // ODRM box header + buffer.SetLength( 0 ); + + // input validation + if ( aOffset < 0 ) + { + // RFile::Read will panic if offset is negative + User::Leave( KErrArgument ); + } + + iFile.Read( aOffset, buffer, 4 ); + size = ReadUint32FromBlock( buffer, 0 ); + aOffset += KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags; + if ( size == 1 ) + { + aOffset += KLengthBoxSize64; + } + + // Discrete headers box header + buffer.SetLength( 0 ); + iFile.Read( aOffset, buffer, 4 ); + if ( buffer.Length() < 4 ) + { + User::Leave( KErrArgument ); + } + size = ReadUint32FromBlock( buffer, 0 ); + aOffset += KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags; + if ( size == 1 ) + { + aOffset += KLengthBoxSize64; + } + + // Content type + buffer.SetLength( 0 ); + iFile.Read( aOffset, buffer, 1 ); + if ( buffer.Length() < 1 ) + { + User::Leave( KErrArgument ); + } + aPart->iMimeType = HBufC8::NewL( buffer[ 0 ] ); + ptr.Set( aPart->iMimeType->Des() ); + iFile.Read( ptr, buffer[ 0 ] ); + aOffset += 1 + buffer[ 0 ]; + + // Common headers box header + buffer.SetLength( 0 ); + iFile.Read( aOffset, buffer, 4 ); + if ( buffer.Length() < 4 ) + { + User::Leave( KErrArgument ); + } + size = ReadUint32FromBlock( buffer, 0 ); + aOffset += KLengthBoxSize + KLengthBoxType + KLengthVersion + KLengthFlags; + if ( size == 1 ) + { + aOffset += KLengthBoxSize64; + } + + // Content ID + aOffset += KLengthEncMethod + KLengthPadType + KLengthPlainTextSize; + buffer.SetLength( 0 ); + iFile.Read( aOffset, buffer, 2 ); + if ( buffer.Length() < 2 ) + { + User::Leave( KErrArgument ); + } + aPart->iContentId = HBufC8::NewL( ReadUint16FromBlock( buffer, 0 ) ); + ptr.Set( aPart->iContentId->Des() ); + aOffset += KLengthContentIdSize + KLengthRiUrlSize + KLengthTextHeadersSize; + iFile.Read( aOffset, ptr, ReadUint16FromBlock( buffer, 0 ) ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadUserDataL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadUserDataL( + TInt aOffset, + TInt& aSize ) + { + TInt size( 0 ); + TUint32 type( 0 ); + TPtr8 ptr( 0, 0 ); + + ReadBoxSizeAndTypeL( aOffset, aSize, type, size ); + VerifyTypeL( type, KUserData ); + aOffset += size; + + delete iUserData; + iUserData = NULL; + iUserData = HBufC8::NewL( aSize ); + User::LeaveIfNull( iUserData ); + + ptr.Set( iUserData->Des() ); + User::LeaveIfError( iFile.Read( aOffset, ptr, aSize ) ); + aOffset += aSize; + + ParseUserDataSubBoxesL( ptr ); + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ParseUserDataSubBoxesL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ParseUserDataSubBoxesL( + const TDesC8& aMemoryBlock ) + { + + // there MAY be zero to several boxes + // depending on language definition. + // here only the first boxes are read out. + + iUserDataLanguageDefined = ETrue; + + // if not found from textual custom headers, try to read out from udta + if ( !iTitle ) + { + ReadOneUserDataBoxL( aMemoryBlock, KTitle, iTitle ); + } + + // if not found from textual custom headers, try to read out from udta + if ( !iDescription ) + { + ReadOneUserDataBoxL( aMemoryBlock, KDescription, iDescription ); + } + + // if not found from textual custom headers, try to read out from udta + if ( !iCopyRight ) + { + ReadOneUserDataBoxL( aMemoryBlock, KCopyright, iCopyRight ); + } + + // if not found from textual custom headers, try to read out from udta + if ( !iAuthor ) + { + ReadOneUserDataBoxL( aMemoryBlock, KAuthor, iAuthor ); + } + + ReadOneUserDataBoxL( aMemoryBlock, KPerformer, iPerformer ); + + ReadOneUserDataBoxL( aMemoryBlock, KGenre, iGenre ); + + ReadOneUserDataBoxL( aMemoryBlock, KRating, iRatingInfo ); + + ReadOneUserDataBoxL( aMemoryBlock, KClassification, iClassificationInfo ); + + ReadOneUserDataBoxL( aMemoryBlock, KKeyword, iKeyword ); + + ReadOneUserDataBoxL( aMemoryBlock, KLocationInformation, iLocInfoName ); + + ReadOneUserDataBoxL( aMemoryBlock, KAlbum, iAlbumTitle ); + + + // These boxes do not contain language information -> + + iUserDataLanguageDefined = EFalse; + + // if not found from textual custom headers, try to read out from udta + if ( !iIconUri ) + { + ReadOneUserDataBoxL( aMemoryBlock, KIconUri, iIconUri ); + } + + ReadOneUserDataBoxL( aMemoryBlock, KInfoURL, iInfoUri ); + + ReadOneUserDataBoxL( aMemoryBlock, KCoverUri, iCoverUri ); + + ReadOneUserDataBoxL( aMemoryBlock, KLyricsURL, iLyricsURL ); + + + TInt yearOffset( iUserData->Find( KRecordingYear ) ); + if ( yearOffset != KErrNotFound ) + { + yearOffset += sizeof( tBoxHeaderStr ) - KLengthBoxSize; + iRecordingYear = ReadUint16FromBlock( iUserData->Des(), yearOffset ); + } + } + +// ----------------------------------------------------------------------------- +// COma2Dcf::ReadOneUserDataBoxL +// ----------------------------------------------------------------------------- +// +void COma2Dcf::ReadOneUserDataBoxL( + const TDesC8& aBlock, + const TDesC8& aName, + HBufC8*& aBuffer ) + { + + TInt offset( aBlock.Find( aName ) ); + TUint32 length( 0 ); + HBufC8* subBlock( NULL ); + TInt subOffset( 0 ); + TBuf8<12> buffer; + + delete aBuffer; + aBuffer = NULL; + + if ( offset == KErrNotFound ) + { + return; + } + else + { + + TUint8* pData( const_cast< TUint8* >( aBlock.Ptr() ) ); + offset -= KLengthBoxSize; + pData += offset; + + buffer.SetLength( 0 ); + buffer.Copy( pData, 12 ); + + tBoxHeaderStr* SubBox = ( tBoxHeaderStr* ) buffer.Ptr(); + length = SWAP32( SubBox->size ); + + subBlock = aBlock.Mid( offset, length ).AllocLC(); + + subOffset += sizeof( tBoxHeaderStr ); + + if ( aName == KClassification ) + { + TUint32 classificationEntity( + ReadUint32FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( classificationEntity ); + + TUint16 classificationTable( + ReadUint16FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( classificationTable ); + } + + if ( aName == KRating ) + { + TUint32 ratingEntity( + ReadUint32FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( ratingEntity ); + + TUint32 ratingCriteria( + ReadUint32FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( ratingCriteria ); + } + + if ( iUserDataLanguageDefined ) + { + TUint16 PadAndLanguage( + ReadUint16FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( PadAndLanguage ); + } + + + if ( aName == KKeyword ) + { + // we return all keywords here + aBuffer = HBufC8::NewL( length ); + TUint8 keywordCnt( subBlock->Des()[ subOffset ] ); + TUint8 keywordSize( 0 ); + + subOffset += sizeof( keywordCnt ); + + for ( TInt count( 0 ); count < keywordCnt; count++ ) + { + keywordSize = subBlock->Des()[ subOffset ]; + subOffset += sizeof( keywordSize ); + aBuffer->Des().Append( + subBlock->Des().Mid( subOffset, keywordSize ) ); + subOffset += keywordSize; + keywordSize = 0; + } + } + + else if ( aName == KAlbum ) + { + TInt tracknbrFound( + subBlock->Des().Mid( subOffset ).Find( KTerminator ) ); + + if ( ( tracknbrFound == KErrNotFound ) || + ( tracknbrFound == + ( subBlock->Des().Length()-subOffset ) - 1 ) ) + { + aBuffer = subBlock->Des().Mid( subOffset ).AllocL(); + iAlbumTrack = NULL; + } + else + { + aBuffer = + subBlock->Des().Mid( subOffset, tracknbrFound ).AllocL(); + subOffset += tracknbrFound + KLengthTerminator; + iAlbumTrack = subBlock->Des()[ subOffset ]; + } + } + + else if ( aName == KLocationInformation ) + { + TInt found( subBlock->Des().Mid( subOffset ).Find( KTerminator ) ); + aBuffer = subBlock->Des().Mid( subOffset, found ).AllocL(); + subOffset += found + KLengthTerminator; + + TUint8 role( subBlock->Des()[ subOffset ] ); + subOffset += sizeof( role ); + TUint32 longitude( + ReadUint32FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( longitude ); + TUint32 latitude( + ReadUint32FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( latitude ); + TUint32 altitude( + ReadUint32FromBlock( subBlock->Des(), subOffset ) ); + subOffset += sizeof( altitude ); + + found = subBlock->Des().Mid( subOffset ).Find( KTerminator ); + + // iLocInfoAstronomicalBody = + // subBlock->Des().Mid( subOffset, found ).AllocL(); + subOffset += found + KLengthTerminator; + + found = subBlock->Des().Mid( subOffset ).Find( KTerminator ); + // iLocInfoAdditionalNotes = + // subBlock->Des().Mid( subOffset, found ).AllocL(); + } + else + { + aBuffer = subBlock->Des().Mid( subOffset ).AllocL(); + } + CleanupStack::PopAndDestroy( subBlock ); + } + } + + +// End of File