diff -r 5b6f26637ad3 -r f4a778e096c2 phonebookengines/VirtualPhonebook/VPbkSimStoreImpl/src/CVPbkETelCntConverter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookengines/VirtualPhonebook/VPbkSimStoreImpl/src/CVPbkETelCntConverter.cpp Wed Sep 01 12:29:52 2010 +0100 @@ -0,0 +1,619 @@ +/* +* Copyright (c) 2002-2007 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: A class that can convert sim contacts to etel contacts and vice +* versa +* +*/ + + + +// INCLUDE FILES +#include "CVPbkETelCntConverter.h" + +// From Virtual Phonebook +#include "VPbkSimStoreImplError.h" +#include +#include +#include +#include +#include +#include + +// System includes +#include // CPhoneBookBuffer + +namespace { +// CONSTANTS +// An amount of space to add to estimate of the size of the field +// due to ETel padding bytes. +const TInt KExtraFieldDataSpace = 3; +// A buf size for the test buffer used to test CPhoneBookBuffer +const TInt KTestBufSize = 20; +} +// ============================= LOCAL FUNCTIONS =============================== + +namespace { + +// ----------------------------------------------------------------------------- +// FieldConversion +// Converts native sim field type to ETel field type +// ----------------------------------------------------------------------------- +// +TUint8 FieldConversion( TVPbkSimCntFieldType aType ) + { + TUint8 result = 0; + switch ( aType ) + { + case EVPbkSimName: + { + result = RMobilePhoneBookStore::ETagPBText; + break; + } + case EVPbkSimGsmNumber: // FALLTHROUGH + case EVPbkSimAdditionalNumber1: // FALLTHROUGH + case EVPbkSimAdditionalNumber2: // FALLTHROUGH + case EVPbkSimAdditionalNumber3: // FALLTHROUGH + case EVPbkSimAdditionalNumberLast: // same as EVPbkSimAdditionalNumber + { + result = RMobilePhoneBookStore::ETagPBNumber; + break; + } + case EVPbkSimNickName: // FALLTHROUGH + case EVPbkSimReading: + { + result = RMobilePhoneBookStore::ETagPBSecondName; + break; + } + case EVPbkSimEMailAddress: + { + result = RMobilePhoneBookStore::ETagPBEmailAddress; + break; + } + default: + { + // Do nothing + break; + } + } + return result; + } + +// ----------------------------------------------------------------------------- +// FieldConversion +// Converts ETel field type to native field type +// ----------------------------------------------------------------------------- +// +TVPbkSimCntFieldType FieldConversion( TUint8 aType ) + { + TVPbkSimCntFieldType result = EVPbkSimUnknownType; + switch ( aType ) + { + case RMobilePhoneBookStore::ETagPBText: + { + result = EVPbkSimName; + break; + } + case RMobilePhoneBookStore::ETagPBNumber: + { + result = EVPbkSimGsmNumber; + break; + } + case RMobilePhoneBookStore::ETagPBSecondName: + { + result = EVPbkSimNickName; + break; + } + case RMobilePhoneBookStore::ETagPBEmailAddress: + { + result = EVPbkSimEMailAddress; + break; + } + default: + { + // Do nothing + break; + } + } + return result; + } + +// ----------------------------------------------------------------------------- +// GetFieldData +// Gets the first field data of given ETel field type +// ----------------------------------------------------------------------------- +// +template +void GetFieldData( CPhoneBookBuffer& aETelBuffer, T& aData, TUint8 aFieldType ) + { + TUint8 fieldTag; + CPhoneBookBuffer::TPhBkTagType dataType; + while ( aETelBuffer.GetTagAndType( fieldTag, dataType) == KErrNone ) + { + if ( fieldTag == aFieldType ) + { + aETelBuffer.GetValue( aData ); + return; + } + else + { + aETelBuffer.SkipValue( dataType ); + } + } + } + +// ----------------------------------------------------------------------------- +// EstimateDataSize +// Estimates the size that the data will take in ETel buffer +// ----------------------------------------------------------------------------- +// +inline TInt EstimateDataSize( const TArray& aFieldArray ) + { + // Initialize to zero size + TInt size = 0; + TInt count = aFieldArray.Count(); + for ( TInt i = 0; i < count; ++i ) + { + // Add one byte for the field tag, then two bytes for data size + // information, so 3 bytes will be added + size += KExtraFieldDataSpace; + + // Add the size of the data + size += aFieldArray[i]->Data().Size(); + + // ETel buffer uses word aligned data -> 0-3 padding bytes + size += KExtraFieldDataSpace; + } + return size; + } + +// ----------------------------------------------------------------------------- +// Adds a new data field to ETel contact +// ----------------------------------------------------------------------------- +// +inline TInt AddNewETelField( CPhoneBookBuffer& aETelBuffer, + CVPbkSimCntField& aField ) + { + TUint8 etelType = FieldConversion( aField.Type() ); + __ASSERT_DEBUG( etelType != 0, VPbkSimStoreImpl::Panic( + VPbkSimStoreImpl::EInvalidVPbkToETelTypeConversion ) ); + const TDesC& data = aField.Data(); + if ( data.Length() > 0 ) + { + if( aField.Type() == EVPbkSimAdditionalNumber1 + || aField.Type() == EVPbkSimAdditionalNumber2 + || aField.Type() == EVPbkSimAdditionalNumber3 + || aField.Type()== EVPbkSimAdditionalNumberLast ) // all these four types are all additional field types. + { + // Additional number needs own tag that must be added before data + aETelBuffer.AddNewNumberTag(); + } + return aETelBuffer.PutTagAndValue( etelType, data ); + } + return KErrNotFound; + } + +} // unnamed + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::CVPbkETelCntConverter +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CVPbkETelCntConverter::CVPbkETelCntConverter() + { + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CVPbkETelCntConverter::ConstructL() + { + // Create a Symbian utility for the contact data + iETelBuffer = new( ELeave ) CPhoneBookBuffer; + // Check how much space new entry tag takes and how much space + // is needed for the contact that has only sim index + HBufC8* testBuf = HBufC8::NewLC( KTestBufSize ); + TPtr8 ptr( testBuf->Des() ); + iETelBuffer->Set( &ptr ); + iETelBuffer->AddNewEntryTag(); + iNewEntryTagLength = ptr.Length(); + TUint16 exampleIndex = 1; + iETelBuffer->PutTagAndValue( + RMobilePhoneBookStore::ETagPBAdnIndex, exampleIndex ); + // Safe solution -> double the space + iMinContactLength = 2 * ptr.Length(); + CleanupStack::PopAndDestroy( testBuf ); + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C CVPbkETelCntConverter* CVPbkETelCntConverter::NewL() + { + CVPbkETelCntConverter* self = NewLC(); + CleanupStack::Pop(); + return self; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::NewLC +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C CVPbkETelCntConverter* CVPbkETelCntConverter::NewLC() + { + CVPbkETelCntConverter* self = new( ELeave ) CVPbkETelCntConverter; + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// Destructor +CVPbkETelCntConverter::~CVPbkETelCntConverter() + { + delete iETelBuffer; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactsL +// ----------------------------------------------------------------------------- +// +void CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactsL( + RPointerArray& aResultArray, + TDes8& aETelContactData, MVPbkSimCntStore& aSimStore ) const + { + CleanupResetAndDestroyPushL( aResultArray ); + iETelBuffer->Set( &aETelContactData ); + User::LeaveIfError( StartRead() ); + + TInt cntCounter = 0; + TPtrC8 etelCnt( GetNextContactData( aETelContactData ) ); + while ( etelCnt.Length() > 0 ) + { + CVPbkSimContactBuf* cnt = CVPbkSimContactBuf::NewLC( etelCnt, + aSimStore ); + aResultArray.AppendL( cnt ); + CleanupStack::Pop(); + ++cntCounter; + etelCnt.Set( GetNextContactData( aETelContactData ) ); + } + + // Check if there was no contacts in the ETel descriptor + if ( cntCounter == 0 ) + { + User::Leave( KErrBadDescriptor ); + } + CleanupStack::Pop( &aResultArray ); + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactL +// ----------------------------------------------------------------------------- +// +void CVPbkETelCntConverter::ConvertFromETelToVPbkSimContactL( + TDes8& aETelContact, CVPbkSimContact& aEmptyContact ) const + { + CVPbkSimCntField* tmpField = + aEmptyContact.CreateFieldLC( EVPbkSimUnknownType ); + TInt error = KErrNone; + const TInt count = DoFieldCount( aETelContact, error ); + User::LeaveIfError( error ); + + for ( TInt i = 0; i < count; ++i ) + { + FieldAt( aETelContact, i, *tmpField ); + CVPbkSimCntField* newField = + aEmptyContact.CreateFieldLC( tmpField->Type() ); + newField->SetInitialSimDataL( tmpField->Data() ); + aEmptyContact.AddFieldL( newField ); + CleanupStack::Pop( newField ); + } + CleanupStack::PopAndDestroy( tmpField ); + aEmptyContact.SetSimIndex( SimIndex( aETelContact ) ); + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::ConvertFromVPbkSimFieldsToETelCntLC +// ----------------------------------------------------------------------------- +// +HBufC8* CVPbkETelCntConverter::ConvertFromVPbkSimFieldsToETelCntLC( + const TArray& aFieldArray, TInt aSimIndex ) const + { + // Create a buffer for the ETel contact + TInt size = iMinContactLength + EstimateDataSize( aFieldArray ); + HBufC8* buf = HBufC8::NewLC( size ); + TPtr8 ptr( buf->Des() ); + iETelBuffer->Set( &ptr ); + + // Add new entry tag and the SIM index if not a new contact + iETelBuffer->AddNewEntryTag(); + if ( aSimIndex != KVPbkSimStoreFirstFreeIndex ) + { + iETelBuffer->PutTagAndValue( + RMobilePhoneBookStore::ETagPBAdnIndex, (TUint16) aSimIndex ); + } + + const TInt count = aFieldArray.Count(); + for( TInt i = 0; i < count; ++i ) + { + TInt result = AddNewETelField( *iETelBuffer, *aFieldArray[i] ); + while ( result == KErrOverflow ) + { + // If the buffer is too small for some reason -> double the size + HBufC8* newBuf = buf->ReAllocL( 2 * buf->Size() ); + CleanupStack::Pop( buf ); + buf = newBuf; + CleanupStack::PushL( buf ); + + ptr.Set( buf->Des() ); + iETelBuffer->Set( &ptr ); + result = AddNewETelField( *iETelBuffer, *aFieldArray[i] ); + } + } + return buf; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::SimIndex +// ----------------------------------------------------------------------------- +// +TInt CVPbkETelCntConverter::SimIndex( TDes8& aETelContact ) const + { + iETelBuffer->Set( &aETelContact ); + if ( StartRead() == KErrNone ) + { + TUint16 simIndex = 0; + GetFieldData( *iETelBuffer, simIndex, + RMobilePhoneBookStore::ETagPBAdnIndex ); + if ( simIndex > 0 ) + { + return simIndex; + } + else + { + return KVPbkSimStoreFirstFreeIndex; + } + } + return KErrBadDescriptor; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::FieldCount +// ----------------------------------------------------------------------------- +// +TInt CVPbkETelCntConverter::FieldCount( TDes8& aETelContact ) const + { + // If client gives an invalid buffer KErrBadDescriptor is returned + TInt error = KErrNone; + TInt result = DoFieldCount( aETelContact, error ); + if ( error == KErrNone ) + { + return result; + } + return error; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::FieldAt +// ----------------------------------------------------------------------------- +// +void CVPbkETelCntConverter::FieldAt( TDes8& aETelContact, TInt aIndex, + CVPbkSimCntField& aField ) const + { + iETelBuffer->Set( &aETelContact ); + if ( StartRead() == KErrNone ) + { + for ( TInt i = 0; i <= aIndex; ++i ) + { + GetNextField( aField ); + } + } + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::MoveToNextContact +// Moves pointer to the next contact +// ----------------------------------------------------------------------------- +// +TBool CVPbkETelCntConverter::MoveToNextContact() const + { + TUint8 fieldTag; + CPhoneBookBuffer::TPhBkTagType dataType; + while ( iETelBuffer->GetTagAndType( fieldTag, dataType) == KErrNone ) + { + switch ( fieldTag ) + { + case RMobilePhoneBookStore::ETagPBNewEntry: + { + return ETrue; + } + default: + { + iETelBuffer->SkipValue( dataType ); + break; + } + } + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::StartRead +// Sets the pointer in the ETel buffer to the beginning of the first contact +// Returns KErrBadDescriptor if the header was not found +// ----------------------------------------------------------------------------- +// +TInt CVPbkETelCntConverter::StartRead() const + { + iETelBuffer->StartRead(); + + if ( MoveToNextContact() ) + { + return KErrNone; + } + return KErrBadDescriptor; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::GetNextField +// Gets the next field that has native support, returns EFalse if not found +// ----------------------------------------------------------------------------- +// +TBool CVPbkETelCntConverter::GetNextField( CVPbkSimCntField& aField ) const + { + TPtrC16 data; + TUint8 fieldTag; + CPhoneBookBuffer::TPhBkTagType dataType; + TBool readingAnr = EFalse; + while ( iETelBuffer->GetTagAndType( fieldTag, dataType) == KErrNone ) + { + if ( fieldTag == RMobilePhoneBookStore::ETagPBAnrStart ) + { + readingAnr = ETrue; + } + else if ( dataType == CPhoneBookBuffer::EPhBkTypeDes16 ) + { + iETelBuffer->GetValue( data ); + TVPbkSimCntFieldType nativeType = FieldConversion( fieldTag ); + /// Text field of the ANR is not supported. If it's supported + /// then the CVPbkSimCntField must have a label and it should + /// be set here. + if ( readingAnr && nativeType == EVPbkSimGsmNumber ) + { + // VPbk SIM contact has an own type for additional number + nativeType = EVPbkSimAdditionalNumber; + } + + if ( nativeType != EVPbkSimUnknownType ) + { + aField.SetDataPtr( data ); + aField.SetType( nativeType ); + return ETrue; + } + } + else + { + iETelBuffer->SkipValue( dataType ); + } + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CVPbkETelCntConverter::NumberOfFields +// Returns the number of VPbk supported fields in the buffer +// ----------------------------------------------------------------------------- +// +TInt CVPbkETelCntConverter::NumberOfFields() const + { + TUint8 fieldTag; + CPhoneBookBuffer::TPhBkTagType dataType; + TBool readingAnr = EFalse; + TInt count = 0; + while ( iETelBuffer->GetTagAndType( fieldTag, dataType) == KErrNone ) + { + if ( fieldTag == RMobilePhoneBookStore::ETagPBAnrStart ) + { + // Tag type is EPhBkTypeNoData so it's not needed to get value + readingAnr = ETrue; + ++count; + } + else if ( dataType == CPhoneBookBuffer::EPhBkTypeDes16 ) + { + TVPbkSimCntFieldType nativeType = FieldConversion( fieldTag ); + if ( !readingAnr && nativeType != EVPbkSimUnknownType ) + { + ++count; + } + // ANR number field ends the reading of ANR + else if ( nativeType == EVPbkSimGsmNumber ) + { + readingAnr = EFalse; + } + // Data must be always read from the buffer to make it work + iETelBuffer->SkipValue( dataType ); + } + else + { + iETelBuffer->SkipValue( dataType ); + } + } + + return count; + } + +// ----------------------------------------------------------------------------- +// GetNextContactData +// Gets the next contact from the buffer that contains many contacts +// ----------------------------------------------------------------------------- +// +TPtrC8 CVPbkETelCntConverter::GetNextContactData( TDes8& aBuffer ) const + { + TInt newEntryTagLength = 1; + TInt remainBefore = iETelBuffer->RemainingReadLength(); + + if ( MoveToNextContact() ) + { + TInt remainAfter = iETelBuffer->RemainingReadLength(); + TInt contactLength = remainBefore - remainAfter; + TInt startPos = iETelBuffer->BufferLength() - remainBefore - + newEntryTagLength; + return aBuffer.Mid( startPos, contactLength ); + } + + // 1 or 0 contacts left + if ( remainBefore > 0 ) + { + // 1 contact left + TInt startPos = iETelBuffer->BufferLength() - remainBefore - + newEntryTagLength; + return aBuffer.Mid( startPos ); + } + else + { + // 0 contacts left, return zero length pointer + return TPtrC8(); + } + } + +// ----------------------------------------------------------------------------- +// DoFieldCount +// Counts the number of fields of the contact +// ----------------------------------------------------------------------------- +// +TInt CVPbkETelCntConverter::DoFieldCount( + TDes8& aETelContact, TInt& aError ) const + { + TInt count = 0; + iETelBuffer->Set( &aETelContact ); + + TInt result = StartRead(); + if ( result == KErrNone ) + { + count = NumberOfFields(); + } + aError = result; + + return count; + } + +// End of File