diff -r 000000000000 -r 7f656887cf89 commands/btservices/BtServicesEng.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/btservices/BtServicesEng.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,989 @@ +// BtServicesEng.cpp +// +// Copyright (c) 2003 - 2010 Accenture. All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the "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: +// Accenture - Initial contribution +// + +//#include + +#include + +#include +#include "BtData.h" +#include "btserviceseng.h" +#include +//#include + +const TInt KArrayIncrement = 5; +const TInt KMaxServiceNameLength = 256; +const TInt KDefaultLanguage = 0x0100; +const TInt KIndentationFactor = 3; + +_LIT(KTextHexPrefix,"0x"); + +CBtServicesEng::CBtServicesEng() + { + iSdpAgent = NULL; + iSearchPattern = NULL; + iAttributeArray = NULL; + + iView = NULL; + + iAttributeMatchList = NULL; + iAttributeBuilder = NULL; + + iUUIDFilter = (KL2CAP); + } + +CBtServicesEng::~CBtServicesEng() + { + delete iSdpAgent; // no need to Cancel separately + delete iSearchPattern; + if (iAttributeArray) + { + iAttributeArray->Reset(); + delete iAttributeArray; + } + iRecordArray.ResetAndDestroy(); + delete iAttributeMatchList; + delete iAttributeBuilder; + + iSocketServ.Close(); + iUUIDs.Close(); + iUUIDsAsText.ResetAndDestroy(); + iUUIDsAsText.Close(); + + iErrorCodes.Close(); + iErrorMessages.ResetAndDestroy(); + iErrorMessages.Close(); + } + +CBtServicesEng* CBtServicesEng::NewL() + { + CBtServicesEng* self = new(ELeave) CBtServicesEng(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CBtServicesEng::ConstructL() + { + //iEikon = CEikonEnv::Static(); + + iSearchPattern = CSdpSearchPattern::NewL(); + iAttributeArray = new(ELeave) CDesCArrayFlat(KArrayIncrement); + iAttributeBuilder = CBtAttributeBuilder::NewL(*this); + + //read the available filter UUID and corresponding text + TInt arrayCount = sizeof(UuidAsArray) / sizeof(TUUidPair); + RDebug::Printf("CBtServicesEng::ConstructL() arrayCount= %d \r\n", + arrayCount); + + TInt i; + for (i = 0; i < arrayCount; i++) + { + TUint32 uuid = UuidAsArray[i].uuid; + iUUIDs.Append(TUUID(uuid)); + + HBufC* textForm = HBufC::NewL(64); + RDebug::Printf("i=%d HBufC* textForm = 0x%08x \r\n", + i, textForm); + + RDebug::Printf("i=%d HBufC* textForm = 0x%08x \r\n", + i, textForm); + + TPtrC UuidText = UuidAsArray[i].txt; + RDebug::Print(_L("UuidText: %S \r\n"), &UuidText); + + *textForm = UuidText; + + iUUIDsAsText.Append(textForm); + } + + //================================================== + /* + buf = iEikon->AllocReadResourceAsDes8LC(R_BLUETOOTH_ERROR_MESSAGES); + res.SetBuffer(buf); + arrayCount = res.ReadInt16(); + for (i = 0; i < arrayCount; i++) + { + TInt errorCode = res.ReadInt32(); + iErrorCodes.Append(errorCode); + HBufC* message = res.ReadHBufCL(); + iErrorMessages.Append(message); + } + CleanupStack::PopAndDestroy(); // buf + */ + + User::LeaveIfError(iSocketServ.Connect()); + } + +void CBtServicesEng::ReportMessage(TInt aVerboseLevel, TRefByValue aFmt, ...) + { + if (iView) + { + VA_LIST list; + VA_START(list, aFmt); + iTextBuf.FormatList(aFmt, list); + iView->PrintTextMsg(aVerboseLevel, iTextBuf); + } + } + +//generate a text list of UUID value/string +void CBtServicesEng::MakeTextUUIDList() + { + TInt arrayCount = sizeof(UuidAsArray) / sizeof(TUUidPair); + TInt i; + ReportMessage(0, _L("========================\r\n")); + ReportMessage(0, _L("UUID Value | UUID STRING\r\n")); + ReportMessage(0, _L("========================\r\n")); + for (i = 0; i < arrayCount; i++) + { + TUint32 uuid = UuidAsArray[i].uuid; + TPtrC string = UuidAsArray[i].txt; + + ReportMessage(0, _L("0x%08x | %S\r\n"), uuid, &string); + } + } + +//This function should only be called after NewDeviceSelectedL() asynchrnously completes; +//generate a text list of services found (handle and name) +// +void CBtServicesEng::MakeTextServiceList() + { + TInt i; + + TPtrC UuidStr = UUIDToString(iUUIDFilter); + ReportMessage(0, _L("UUID filter 0x%08x %S\r\n"), iUUIDFilter, &UuidStr); + + TInt HandlesCnt = iRecordArray.Count(); + + if (HandlesCnt) + { + ReportMessage(0, _L("============================\r\n")); + ReportMessage(0, _L("ServiceHandle | Service Name\r\n")); + ReportMessage(0, _L("============================\r\n")); + } + + for (i=0; iiHandle; + const TDesC& Name = iRecordArray[i]->iServiceName; + + ReportMessage(0, _L("0x%08x | \"%S\"\r\n"), Handle, &Name); + + } + + } + +// +void CBtServicesEng::NewDeviceSelectedL(const TBTDevAddr& aAddress,const TBTDeviceName& aDeviceName) + { + iDeviceName = aDeviceName; + iDeviceAddress = aAddress; + + GetDeviceServicesL(); + } + +/** +This starts the SDP agent searching for services. +Firstly, the previous (if any) SDP agent is deleted and a +new one constructed with the address of the new device. The +record filter is set based on the UUID filter settings. +The NextRecordRequestL() function begins the search, with the +results being received via the MSdpAgentNotifier functions. +*/ +void CBtServicesEng::GetDeviceServicesL() + { + if (iSdpAgent) + { + DeleteSdpAgent(); + } + iSdpAgent = CSdpAgent::NewL(*this, iDeviceAddress); // create new SDP Agent for given device address + + iSearchPattern->Reset(); + iSearchPattern->AddL(iUUIDFilter); + iSdpAgent->SetRecordFilterL(*iSearchPattern); + + iRecordArray.ResetAndDestroy(); +// MQikListBoxModel& model = *this; +// model.RemoveAllDataL(); + //iView->ListBox().HandleItemRemovalL(); + //iView->ListBox().DrawNow(); + + /* + TGulAlignment position(EHRightVCenter); + _LIT(KMsgFindingServices, "Finding services"); + iView->GetEikonEnv()->BusyMsgL(KMsgFindingServices, position); + iView->DimCancelButton(EFalse); + iView->DimRefreshButton(ETrue); + */ + + iSdpAgent->NextRecordRequestL(); + } + +/** +The Sdp agent initially returns only record handles for each +service - this function then gets the name attribute for +each one. +*/ +void CBtServicesEng::GetServiceNamesL() + { + if (iHandleCounter < iRecordArray.Count()) + { + TSdpAttributeID attributeID = KSdpAttrIdOffsetServiceName + KDefaultLanguage; // only support default language for SDP + iSdpAgent->AttributeRequestL(iRecordArray[iHandleCounter]->iHandle, + attributeID); + + ReportMessage(1, _L("Query service name for handle 0x%X...\r\n"), + iRecordArray[iHandleCounter]->iHandle ); + } + else + { + iCurrentAttributeRequest = ENoOutstandingRequests; +// iView->GetEikonEnv()->BusyMsgCancel(); +// iView->DimCancelButton(ETrue); +// iView->DimRefreshButton(EFalse); + + if (iView) + iView->AsyncCompleted(); + } + } + +/** +Begins getting the full attribute list +for a given service. Because an MSdpElementBuilder +pointer is passed in AttributeRequestL(), the SDP agent +calls the builder functions with each result, rather than +AttributeRequestResult(). +*/ +void CBtServicesEng::GetAttributesL(TInt aIndex) + { + iCurrentAttributeRequest = EGettingAllAttributes; + iServiceName.Set(iRecordArray[aIndex]->iServiceName); + iAttributeArray->Reset(); + iAttributeBuilder->Reset(); + if (iAttributeMatchList) + { + delete iAttributeMatchList; + iAttributeMatchList = NULL; + } + iAttributeMatchList = CSdpAttrIdMatchList::NewL(); + iAttributeMatchList->AddL(TAttrRange(0, KMaxTUint16)); // getting all attributes + iAttributeBuilder->SetHandle(iRecordArray[aIndex]->iHandle); + iSdpAgent->AttributeRequestL(iAttributeBuilder, iRecordArray[aIndex]->iHandle, *iAttributeMatchList); + } + +/** +this function is supposed to be called +WITHOUT calling "NewDeviceSelectedL()" + +Begins getting the full attribute list +for a given service. Because an MSdpElementBuilder +pointer is passed in AttributeRequestL(), the SDP agent +calls the builder functions with each result, rather than +AttributeRequestResult(). +*/ +void CBtServicesEng::GetDeviceAttributesL(const TBTDevAddr& aAddress,const TBTDeviceName& aDeviceName, TSdpServRecordHandle aHandle) + { + iDeviceName = aDeviceName; + iDeviceAddress = aAddress; + if (iSdpAgent) + { + DeleteSdpAgent(); + } + iSdpAgent = CSdpAgent::NewL(*this, iDeviceAddress); // create new SDP Agent for given device address + + iCurrentAttributeRequest = EGettingAllAttributes; + //iServiceName.Set((*iTextArray)[aIndex]); + iAttributeArray->Reset(); + iAttributeBuilder->Reset(); + if (iAttributeMatchList) + { + delete iAttributeMatchList; + iAttributeMatchList = NULL; + } + iAttributeMatchList = CSdpAttrIdMatchList::NewL(); + iAttributeMatchList->AddL(TAttrRange(0, KMaxTUint16)); // getting all attributes + iAttributeBuilder->SetHandle(aHandle); + iSdpAgent->AttributeRequestL(iAttributeBuilder, aHandle, *iAttributeMatchList); + } + + +void CBtServicesEng::CancelSdpAgent() + { + if (iSdpAgent) + { + iSdpAgent->Cancel(); + } + } + +void CBtServicesEng::DeleteSdpAgent() + { + delete iSdpAgent; + iSdpAgent = NULL; + } + +void CBtServicesEng::SetUUIDFilterL(TUint32 aUUID) + { + iUUIDFilter = aUUID; + } + +void CBtServicesEng::AppendUUIDText(TDes& aBuf, TUUID aUUID) const + { + if (aUUID == TUUID(0)) + { + aUUID = TUUID(iUUIDFilter); + } + TInt i = 0; + TInt UuidCount = iUUIDs.Count(); + for (i = 0; i < UuidCount; i++) + { + if (iUUIDs[i] == aUUID) + { + aBuf.Append(*(iUUIDsAsText[i])); + return; + } + } + _LIT(KTextUUIDHex,"UUID: 0x"); + aBuf.Append(KTextUUIDHex); + + const TPtrC8 ptr = aUUID.ShortestForm(); + TInt ShortestLength = ptr.Length(); + for (i = 0; iDisplayDeviceInfoDialogL(iDeviceName,iDeviceAddress,iDeviceClass); + } + +//display local BT address, device name and class info +// +void CBtServicesEng::DisplayLocalInfoL() + { + /* + RSocket l2CapSock; + TInt err = l2CapSock.Open(iSocketServ, KBTAddrFamily, KSockSeqPacket, KL2CAP); + if (err != KErrNone) + { + _LIT(KErrorText,"Not supported"); + TGulAlignment position(EHRightVTop); + iView->GetEikonEnv()->InfoMsgWithAlignmentAndDuration(position,KErrorText,KErrorMsgDuration); + return; + } + CleanupClosePushL(l2CapSock); + TRequestStatus stat; + + TBTDevAddrPckg addrbuf; + l2CapSock.Ioctl(KHCILocalAddressIoctl, stat, &addrbuf, KSolBtHCI); // takes a TBTDevAddrPckg (TPckgBuf) as documented in 7.0 SDK + User::WaitForRequest(stat); + User::LeaveIfError(stat.Int()); + + THCIDeviceClassBuf classbuf; + l2CapSock.Ioctl(KHCIReadDeviceClassIoctl, stat, &classbuf, KSolBtHCI); // takes a THCIDeviceClassBuf (TPckgBuf) as documented in 7.0 SDK + User::WaitForRequest(stat); + User::LeaveIfError(stat.Int()); + CleanupStack::PopAndDestroy(); // l2CapSock + + RHostResolver hr; + User::LeaveIfError(hr.Open(iSocketServ, KBTAddrFamily, KBTLinkManager)); + CleanupClosePushL(hr); + TBTDeviceName deviceName; + User::LeaveIfError(hr.GetHostName(deviceName)); + CleanupStack::PopAndDestroy(); + + TBTDevAddr& deviceAddress = addrbuf(); + TBTDeviceClass deviceClass(classbuf().iMajorServiceClass, classbuf().iMajorDeviceClass,classbuf().iMinorDeviceClass); + */ + + RBTRegServ serv; + RBTLocalDevice me; + User::LeaveIfError(serv.Connect()); + CleanupClosePushL(serv); + User::LeaveIfError(me.Open(serv)); + CleanupClosePushL(me); + TBTLocalDevice dev; + User::LeaveIfError(me.Get(dev)); + + TBTDeviceName deviceName; + deviceName.Copy(dev.DeviceName().Left(deviceName.MaxLength())); + TBTDeviceClass deviceClass(dev.DeviceClass()); + // RBtLocalDevice doesn't seem to return the address + //const TBTDevAddr& deviceAddress = dev.Address(); + TBTDevAddr deviceAddress; + TPtr8 ptr(deviceAddress.Des()); + User::LeaveIfError(RProperty::Get(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetLocalDeviceAddress, ptr)); + + CleanupStack::PopAndDestroy(2, &serv); + + TBuf<64> ReadableAddr; + deviceAddress.GetReadable(ReadableAddr); + ReportMessage(0, _L("BTAddress:0x%S, Name:\"%S\", DeviceClass=0x%08x\r\n"), + &ReadableAddr, &deviceName, deviceClass.DeviceClass()); + + /* +#if 0 //test code, not used + //query further about the services provided by this device + RSdp sdp; + sdp.Connect(); + CleanupClosePushL(sdp); + + RSdpDatabase sdpData; + sdpData.Open(sdp); + CleanupClosePushL(sdpData); + + CleanupStack::PopAndDestroy(); + CleanupStack::PopAndDestroy(); +#endif + */ + } + + +void CBtServicesEng::SetView(CBtServiceView* apView) + { + iView = apView; + } + + +/* +CDesCArrayFlat* CBtServicesEng::GetTextArray() const + { + return iTextArray; + } +*/ + +/** +Checks whether bluetooth is enabled by opening a host +resolver and immediately closing it again. +*/ +TInt CBtServicesEng::BluetoothReady() + { + RHostResolver hr; + TInt err = hr.Open(iSocketServ, KBTAddrFamily, KBTLinkManager); // just to check if bluetooth is enabled + hr.Close(); + return err; + } + +TBool CBtServicesEng::GettingAllAttributes() const + { + return (iCurrentAttributeRequest == EGettingAllAttributes); + } + +void CBtServicesEng::AddAttributeLineL(const TDesC& aDes) + { + iAttributeArray->AppendL(aDes); + } + +void CBtServicesEng::AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError) + { + ReportMessage(1, _L("[AttributeRequestComplete for Handle:0x%X Err:%d]\r\n\r\n"), aHandle, aError); + + if(aError == KErrNone) + { + TRAP(aError, DoAttributeRequestCompleteL()); + } + if(aError != KErrNone) + { + SdpCompletedWithError(aError); + } + } + +void CBtServicesEng::DoAttributeRequestCompleteL() + { + if (iCurrentAttributeRequest == EGettingNamesOnly) + { + //there are a lot of handles that needs the name, so + //need to keep issue requests until all handles are processed, + //so the whole asynchronous process is not finished yet + iHandleCounter++; + GetServiceNamesL(); + } + else if (iCurrentAttributeRequest == EGettingAllAttributes) + { // all attributes have been got + TInt LineCount = iAttributeArray->Count(); + + for (TInt i=0; iDisplayAttributeDialogL(iAttributeArray, iDeviceName, iServiceName); + iCurrentAttributeRequest = ENoOutstandingRequests; + if (iView) + iView->AsyncCompleted(); + } + } + +void CBtServicesEng::AttributeRequestResult(TSdpServRecordHandle aHandle, TSdpAttributeID /*aAttrID*/, CSdpAttrValue* aAttrValue) + { + ReportMessage(1, _L("[AttributeRequestResult for Handle:0x%X ]\r\n"), aHandle ); + + TRAPD(err,DoAttributeRequestResultL(aAttrValue, aHandle)); // passing ownership + if (err != KErrNone) + { + iSdpAgent->Cancel(); + } + } + +void CBtServicesEng::DoAttributeRequestResultL(CSdpAttrValue* aAttrValue, TSdpServRecordHandle aHandle) + { + CleanupStack::PushL(aAttrValue); // taken ownership + if (iCurrentAttributeRequest == EGettingNamesOnly) + { + TBuf16 unicode; + CnvUtfConverter::ConvertToUnicodeFromUtf8(unicode,aAttrValue->Des()); + if (unicode[unicode.Length() - 1] == L'\0') + { + unicode.Delete(unicode.Length() - 1, 1); // remove NULL-termination + } + //iView->ListBox().HandleItemAdditionL(); + TBuf<64> string; + string.Copy(unicode); + + //extra check to make sure Handle and Name are paired correctly + if (iRecordArray[iHandleCounter]->iHandle != aHandle) + User::Panic(_L("Handle not match"), KErrNone); + + iRecordArray[iHandleCounter]->iServiceName = string; + + ReportMessage(1, _L("%S \r\n"), &string); +/* + MQikListBoxModel& model = *this; + model.ModelBeginUpdateLC(); + MQikListBoxData* data = model.NewDataL(EDataNormal); + data->AddTextL(unicode, EQikListBoxSlotText1); + data->Close(); + model.ModelEndUpdateL(); +*/ + } + + CleanupStack::PopAndDestroy(aAttrValue); + } + +void CBtServicesEng::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt /* aTotalRecordsCount */) + { + if ((aError == KErrNone) || (aError == KErrEof)) + { + TRAPD(err, DoNextRecordRequestCompleteL(aHandle, aError)); + if (err != KErrNone) + { + aError = err; + } + } + if (aError != KErrNone && aError != KErrEof) + { +// iView->GetEikonEnv()->BusyMsgCancel(); + SdpCompletedWithError(aError); + } + + //if aError == KErrEof, that means no more records to read + + } + +void CBtServicesEng::DoNextRecordRequestCompleteL(TSdpServRecordHandle aHandle, TInt aError) + { + if (aError == KErrNone) + { + ReportMessage(1, _L("Record Handle found 0x%X \r\n"), aHandle ); + + CServiceRecordItem* pItem = new CServiceRecordItem; + pItem->iHandle = aHandle; + iRecordArray.Append(pItem); + iSdpAgent->NextRecordRequestL(); + } + else if (aError == KErrEof) + //no more records, now query service name for each record found + { + iHandleCounter = 0; + iCurrentAttributeRequest = EGettingNamesOnly; + + //report status + TInt RecordCnt = iRecordArray.Count(); + ReportMessage(1, _L("%d records found, querying service name...\r\n"), RecordCnt); + GetServiceNamesL(); + } + } + +void CBtServicesEng::SdpCompletedWithError(const TInt aError) + { + + HBufC* buf = HBufC::NewLC(KMaxDescriptorLength); + TPtr errorText = buf->Des(); + AppendErrorMessage(aError,errorText); +// TGulAlignment position(EHRightVTop); +// iView->GetEikonEnv()->InfoMsgWithAlignmentAndDuration(position,errorText,KErrorMsgDuration); + ReportMessage(0, *buf); + + CleanupStack::PopAndDestroy(); + iSdpAgent->Cancel(); +// iView->DimRefreshButton(EFalse); +// iView->DimCancelButton(ETrue); + if (iView) + iView->AsyncCompleted(); + + } + +void CBtServicesEng::AppendErrorMessage(const TInt aError, TDes& aBuf) const + { + for (TInt i = 0; i < iErrorCodes.Count(); i++) + { + if (iErrorCodes[i] == aError) + { + aBuf.Append(*(iErrorMessages[i])); + return; + } + } + _LIT(KErrorTextOther, "Error: "); + aBuf.Append(KErrorTextOther); + aBuf.AppendNum(aError); + } + +void CBtServicesEng::Panic(TBtPanicCode aPanicCode) + { + _LIT(KBtPanicText, "BTSU::Panic "); + User::Panic(KBtPanicText, aPanicCode); + } + +void CBtServicesEng::ReleaseModel() + { + // Do nothing, list box does not own us + } + +//static +//search the Uuid value, and return a text string of its name +TPtrC CBtServicesEng::UUIDToString(TUint32 aUuidValue) + { + //read the available filter UUID and corresponding text + TInt arrayCount = sizeof(UuidAsArray) / sizeof(TUUidPair); + TInt i; + for (i = 0; i < arrayCount; i++) + { + TUint32 uuid = UuidAsArray[i].uuid; + if (uuid == aUuidValue) + return (UuidAsArray[i].txt); + } + return _L(""); + } + +//static +//search through the value, and return the UUID value if there is one match +//aUuidValue: [out] the found result +TBool CBtServicesEng::StringToUUID(TDesC& aString, TUint32& aUuidValue) + { + //read the available filter UUID and corresponding text + TInt arrayCount = sizeof(UuidAsArray) / sizeof(TUUidPair); + TInt i; + for (i = 0; i < arrayCount; i++) + { + TUint32 uuid = UuidAsArray[i].uuid; + if (aString == UuidAsArray[i].txt) + { + aUuidValue = uuid; + return ETrue; + } + } + return EFalse; + } + + +/////////////////////////////////////// +// CBtAttributeBuilder functions +/////////////////////////////////////// + +CBtAttributeBuilder* CBtAttributeBuilder::NewL(CBtServicesEng& aEngine) + { + CBtAttributeBuilder* self = new(ELeave) CBtAttributeBuilder(aEngine); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CBtAttributeBuilder::CBtAttributeBuilder(CBtServicesEng& aEngine) +: iEngine(aEngine) + { + } + +void CBtAttributeBuilder::ConstructL() + { +/* + HBufC8* buf = CEikonEnv::Static()->AllocReadResourceAsDes8LC(R_ATTR_ID_MNEMONICS); + + TResourceReader res; + res.SetBuffer(buf); + + TInt arrayCount = res.ReadInt16(); + for (TInt i = 0; i < arrayCount; i++) + { + TUint attrID = res.ReadUint32(); + iAttrIDs.Append(attrID); + HBufC* mnemonic = res.ReadHBufCL(); + iAttrMnemonics.Append(mnemonic); + } + CleanupStack::PopAndDestroy(); // buf +*/ + } + +CBtAttributeBuilder::~CBtAttributeBuilder() + { + iAttrIDs.Close(); + iAttrMnemonics.ResetAndDestroy(); + iAttrMnemonics.Close(); + } + +void CBtAttributeBuilder::Reset() + { + iIndentation = 0; + iCurrentLine.Zero(); + } + +void CBtAttributeBuilder::SetHandle(TSdpServRecordHandle aHandle) + { + iHandle = aHandle; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildUnknownL(TUint8 aType, TUint8 /* aSizeDesc */, const TDesC8& /* aData */) + { + if (iStatus == EExpectingAttrID) + { + _LIT(KErrorText,"**Error: Unexpected UNKNOWN"); + iCurrentLine.Append(KErrorText); + } + else + { + _LIT(KTextUnknown,"UNKNOWN"); + iCurrentLine.Append(KTextUnknown); + iCurrentLine.AppendNum((TInt) aType); + } + LineFinishedL(); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildNilL() + { + if (iStatus == EExpectingAttrID) + { + _LIT(KErrorText,"**Error: Unexpected NIL"); + iCurrentLine.Append(KErrorText); + } + else + { + _LIT(KTextNULL,"NULL"); + iCurrentLine.Append(KTextNULL); + } + LineFinishedL(); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildUintL(const TDesC8& aUint) + { + + if (iStatus == EExpectingAttrValue) + { + iCurrentLine.Append(KTextHexPrefix); + for (TInt i = 0; i < aUint.Length(); i++) + { + iCurrentLine.AppendNumFixedWidth(aUint[i], EHex,2); + } + LineFinishedL(); + } + else if (iStatus == EExpectingAttrID) + { + TUint value = 0; + for (TInt i = 0; i < aUint.Length(); i++) + { + value <<= 8; + value += aUint[i]; + } + AppendAttrMnemonic(iCurrentLine,value); + iStatus = EExpectingAttrValue; + } + + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildIntL(const TDesC8& aInt) + { + if (iStatus == EExpectingAttrID) + { + _LIT(KErrorText,"**Error: Unexpected Int"); + iCurrentLine.Append(KErrorText); + } + else + { + iCurrentLine.Append(KTextHexPrefix); + for (TInt i = 0; i < aInt.Length(); i++) + { + iCurrentLine.AppendNumFixedWidth(aInt[i], EHex,2); + } + } + LineFinishedL(); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildUUIDL(const TUUID& aUUID) + { + if (iStatus == EExpectingAttrID) + { + _LIT(KErrorText,"**Error: Unexpected UUID"); + iCurrentLine.Append(KErrorText); + } + else + { + iEngine.AppendUUIDText(iCurrentLine,aUUID); + } + LineFinishedL(); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildBooleanL(TBool aBool) + { + if (iStatus == EExpectingAttrID) + { + _LIT(KErrorText,"**Error: Unexpected Boolean"); + iCurrentLine.Append(KErrorText); + } + else + { + if (aBool) + { + _LIT(KTextTrue,"TRUE"); + iCurrentLine.Append(KTextTrue); + } + else + { + _LIT(KTextFalse,"FALSE"); + iCurrentLine.Append(KTextFalse); + } + } + LineFinishedL(); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildStringL(const TDesC8& aString) + { + if (iStatus == EExpectingAttrID) + { + _LIT(KErrorText,"**Error: Unexpected String"); + iCurrentLine.Append(KErrorText); + } + else + { + TBuf16 unicode; + CnvUtfConverter::ConvertToUnicodeFromUtf8(unicode,aString); + if (unicode[unicode.Length() - 1] == NULL) + { + unicode.Delete(unicode.Length() - 1, 1); // remove NULL-termination + } + iCurrentLine.Append(unicode); + } + LineFinishedL(); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildDESL() + { + if (iIndentation == 1) + { + iEngine.AddAttributeLineL(iCurrentLine); + } + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildDEAL() + { + _LIT(KTextDEAL,"Data Element Alternate List"); + iCurrentLine.Append(KTextDEAL); + iEngine.AddAttributeLineL(iCurrentLine); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::StartListL() + { + iIndentation++; + iCurrentLine.Zero(); + __ASSERT_ALWAYS(iIndentation > 0, CBtServicesEng::Panic(EBtIndentationZeroInStartList)); + iCurrentLine.AppendFill(' ', (iIndentation - 1) * KIndentationFactor); + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::EndListL() + { + _LIT(KTextEndListDashes,"--------"); + iCurrentLine.Append(KTextEndListDashes); + iEngine.AddAttributeLineL(iCurrentLine); + iIndentation--; + iCurrentLine.Zero(); + if (iIndentation) + { + iCurrentLine.AppendFill(' ', (iIndentation - 1) * KIndentationFactor); // in this case indentation has already been checked to be greater than zero + } + if (iIndentation == 1) + { + iStatus = EExpectingAttrID; + } + return this; + } + +MSdpElementBuilder* CBtAttributeBuilder::BuildURLL(const TDesC8& aURL) + { + TBuf16 unicode; + CnvUtfConverter::ConvertToUnicodeFromUtf8(unicode,aURL); + iCurrentLine.Append(unicode); + LineFinishedL(); + return this; + } + +void CBtAttributeBuilder::AppendAttrMnemonic(TDes& aBuf, TUint aAttrID) const + { + for (TInt i = 0; i < iAttrIDs.Count(); i++) + { + if (iAttrIDs[i] == aAttrID) + { + aBuf.Append(*(iAttrMnemonics[i])); + return; + } + } + if (aAttrID == 0x0200 && iHandle == 0) + { + _LIT(KVersionNoPrefix,"VersionNo.: "); + aBuf.Append(KVersionNoPrefix); + } + else if (aAttrID == 0x0201 && iHandle == 0) + { + _LIT(KDatabaseStatePrefix,"DatabaseState: "); + aBuf.Append(KDatabaseStatePrefix); + } + else + { + _LIT(KTextAttrIDHex,"AttrID 0x"); + aBuf.Append(KTextAttrIDHex); + aBuf.AppendNum(aAttrID,EHex); + _LIT(KTextColonSpace,": "); + aBuf.Append(KTextColonSpace); + } + } + +void CBtAttributeBuilder::LineFinishedL() + { + iEngine.AddAttributeLineL(iCurrentLine); + iCurrentLine.Zero(); + __ASSERT_ALWAYS(iIndentation > 0, CBtServicesEng::Panic(EBtIndentationZeroInLineFinished)); + iCurrentLine.AppendFill(' ', (iIndentation - 1) * KIndentationFactor); + if (iIndentation == 1) + { + iStatus = EExpectingAttrID; + } + }