bluetooth/btsdp/database/SDPDatabase.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btsdp/database/SDPDatabase.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,302 @@
+// Copyright (c) 2000-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:
+//
+
+#include <es_sock.h>
+#include <btsdp.h>
+#include <e32des8.h>
+#include <bluetooth/logger.h>
+
+#include "SDPDatabase.h"
+#include "DataEncoder.h"
+#include "EncoderVisitor.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_SDPDATABASE);
+#endif
+
+void Panic(TSdpDatabasePanics aCode)
+	{
+	User::Panic(KSdpDatabasePanicName, aCode);
+	}
+
+// Class CSdpDatabase 
+
+EXPORT_C CSdpDatabase* CSdpDatabase::NewLC()
+/**
+Creates a CSdpDatabase object, but leaves on the cleanup stack.
+
+@return Pointer to the created CSdpDatabase object
+*/
+	{
+	LOG_STATIC_FUNC
+	CSdpDatabase* self = new(ELeave) CSdpDatabase;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+EXPORT_C CSdpDatabase* CSdpDatabase::NewL()
+/**
+Creates a CSdpDatabase object.(Does NOT leave it on the cleanup stack.)
+
+@return Pointer to the created CSdpDatabase object
+*/
+	{
+	LOG_STATIC_FUNC
+	CSdpDatabase* self = CSdpDatabase::NewLC();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CSdpDatabase::CSdpDatabase()
+: iCanAddRecord(ETrue), 
+  iRecords(CSdpServRecord::LinkOffset()), 
+  iNextFreeHandle(KSdpMinServRecordHandle)
+	{
+	CONNECT_LOGGER
+	}
+
+void CSdpDatabase::ConstructL()
+	{
+	LOG_FUNC
+	}
+
+EXPORT_C CSdpDatabase::~CSdpDatabase()
+/** Destructor
+*/
+	{
+	LOG_FUNC
+	// Delete all records on the record list
+	iRecords.ResetAndDestroy();
+	CLOSE_LOGGER
+	}
+
+/** Adds a service record to this database.
+@param aRecord The record being added
+*/
+EXPORT_C void CSdpDatabase::AddRecord(CSdpServRecord* aRecord)
+	{
+	LOG_FUNC
+	iRecords.AddInOrder(*aRecord); //Panics if aRecord's handle is already bagged.
+	//Must do this AFTER adding latest record...hence need for 'iCanAddRecord'
+	iCanAddRecord = ReviseNextFreeHandle();
+	}
+
+/** Creates a new record on this database
+@leave KErrSdpDatabaseFull implies no more spare handles
+*/
+EXPORT_C CSdpServRecord* CSdpDatabase::NewRecordL()
+	{
+	LOG_FUNC
+	// Add a new record only if we have spare handles...
+	// ...there are 2^32 - 0x10000 to choose from!
+	if(!iCanAddRecord)
+		{
+		User::Leave(KErrSdpDatabaseFull);
+		}
+
+	CSdpServRecord* record = CSdpServRecord::NewL();
+	CleanupStack::PushL(record);
+
+	record
+		->BuildUintL(TSdpIntBuf<TUint16>(0))
+		->BuildUintL(TSdpIntBuf<TSdpServRecordHandle>(NextFreeHandle()));
+
+	AddRecord(record);
+	CleanupStack::Pop(); //record
+	return record;
+	}
+
+/** Encodes complete database. */
+EXPORT_C void CSdpDatabase::EncodeDbL()
+	{
+	LOG_FUNC
+	for(TServRecordIter recIter(RecordIter()); recIter; recIter++)
+		{// Iterate through records in Db
+		for (TServAttrIter attrIter((*recIter).AttributeIter()); attrIter; attrIter++)
+			{// iterate through attributes in record
+			CSdpAttr* theAttr = &(*attrIter);
+			CSdpAttrValue* theAttrValue = &(theAttr->Value());
+			TUint size = TElementEncoder::EncodedSize(theAttrValue->Type(), 
+													  theAttrValue->DataSize());
+
+			HBufC8* outbuf = HBufC8::NewLC(size);
+			TPtr8 writePtr = outbuf->Des();
+			TElementEncoder theEncoder(writePtr);
+			CAttrEncoderVisitor::EncodeAttributeL(theEncoder, (*attrIter).Value());
+			theAttr->BuildEncodedL(writePtr);
+			CleanupStack::PopAndDestroy(); //outbuf
+			}
+		}
+	}
+
+/** Dead function. Space filler for .def file (left in for BC)
+*/
+EXPORT_C void CSdpDatabase::ParseDbL_Obscelete_DoesNothing()
+	{
+	LOG_FUNC
+	return;
+	}
+
+/** Returns the 'TSdpServRecordHandle' iNextFreeHandle.
+@return the next free handle 
+*/
+EXPORT_C TSdpServRecordHandle CSdpDatabase::NextFreeHandle()
+	{
+	LOG_FUNC
+	return iNextFreeHandle;
+	}
+
+/**	Finds a handle not used by any record in database.
+	Starts at current next free handle value, and discovers if
+	it is used by a record in the database. If so cycles it on one in
+	in the allowed range, and checks again. This algorithm continues
+	until an unused handle is found (=>return ETrue) or all handles
+	have been checked and are found to be in use. (=>return EFalse)
+	NB. We start by looking for the next available handle going upwards
+	in value. Only if none are found do we return to the lower limit and
+	search for "holes" below the last claimed handle. This should
+	reduce processing time. We could have gone further and incremented
+	iNextFreeHandle value before doing anything else, because it is likely
+	that the current iNextFreeHandle will have just been used when this
+	function is called
+*/
+TBool CSdpDatabase::ReviseNextFreeHandle()
+	{
+	LOG_FUNC
+	if(iNextFreeHandle>KSdpMaxServRecordHandle||
+		iNextFreeHandle<KSdpMinServRecordHandle)
+		{
+		iNextFreeHandle = KSdpMinServRecordHandle;
+		}
+
+	TSdpServRecordHandle origNextFreeHandle(iNextFreeHandle);
+	for(TServRecordIter recIter(RecordIter()); recIter; recIter++)
+		{// Iterate thru records in iDatabase
+		if((*recIter).Handle()==iNextFreeHandle)
+			{
+			if(++iNextFreeHandle>KSdpMaxServRecordHandle)
+				iNextFreeHandle = KSdpMinServRecordHandle;
+			//We've run out of handles
+			if(iNextFreeHandle==origNextFreeHandle)
+				return EFalse;
+			//Run through all records again to check for new incremented handle.
+			recIter.SetToFirst();
+			}
+		}
+	return ETrue;
+	}
+
+
+EXPORT_C CAttrUuidVisitor* CAttrUuidVisitor::NewL()
+	{
+	LOG_STATIC_FUNC
+	CAttrUuidVisitor* self = new(ELeave)CAttrUuidVisitor();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+	
+EXPORT_C CAttrUuidVisitor::~CAttrUuidVisitor()
+	{
+	LOG_FUNC
+	iUuidContainer.Close();
+	}
+	
+EXPORT_C RUUIDContainer& CAttrUuidVisitor::GetUuids()
+	{
+	LOG_FUNC
+	return iUuidContainer;
+	}
+
+void CAttrUuidVisitor::EncodeAttributeL(CSdpAttrValue& /*aSrcAttr*/)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(ETrue, User::Panic(_L("EncodeAttributeL() erroneously called"), KErrArgument));
+	}
+	
+CAttrUuidVisitor::CAttrUuidVisitor()
+	{
+	LOG_FUNC
+	iUuidContainer.Reset();
+	}
+	
+void CAttrUuidVisitor::ConstructL()
+	{
+	LOG_FUNC
+	}
+
+// Implementation of MAttributeVisitor interface
+void CAttrUuidVisitor::VisitAttributeL(CSdpAttr& /*aAttribute*/)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(ETrue, Panic(ESdpDatabaseVisitAttributeLErroneouslyCalled));
+	}
+	
+void CAttrUuidVisitor::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType)
+	{
+	LOG_FUNC
+	switch (aType)
+		{
+		case ETypeUUID:
+			iUuidContainer.Add(aValue.UUID());
+			break;
+		case ETypeEncoded:
+			{
+			TPtrC8 ptr = aValue.Des();
+			if(ptr.Length() == KSdpElemHdrTypeShift + KSizeOf16BitUUID)
+				{
+				// 16-bit UUID
+				TUUID uuid = TUUID(BigEndian::Get16(&ptr[KSdpElemHdrTypeShift]));
+				iUuidContainer.Add(uuid);
+				}
+			else if(ptr.Length() == KSdpElemHdrTypeShift + KSizeOf32BitUUID)
+				{
+				// 32-bit UUID
+				TUUID uuid = TUUID(BigEndian::Get32(&ptr[KSdpElemHdrTypeShift]));
+				iUuidContainer.Add(uuid);
+				}
+			else if(ptr.Length() == KSdpElemHdrTypeShift + KSizeOf128BitUUID)
+				{
+				// 128-bit UUID
+				TUUID uuid = TUUID(BigEndian::Get32(&ptr[KSdpElemHdrTypeShift]),
+								   BigEndian::Get32(&ptr[KSdpElemHdrTypeShift+sizeof(TUint32)]),
+								   BigEndian::Get32(&ptr[KSdpElemHdrTypeShift+2*sizeof(TUint32)]),
+								   BigEndian::Get32(&ptr[KSdpElemHdrTypeShift+3*sizeof(TUint32)]));
+				iUuidContainer.Add(uuid);
+				}
+			else
+				{
+				// We don't support other UUIDs
+				}
+			}
+			break;
+		default:
+			__ASSERT_DEBUG(ETrue, Panic(ESdpDatabaseUnexpectedAttributeType));
+			break;
+		}
+	}
+
+void CAttrUuidVisitor::StartListL(CSdpAttrValueList& /*aList*/)
+	{
+	LOG_FUNC
+	}
+
+void CAttrUuidVisitor::EndListL()
+	{
+	LOG_FUNC
+	}
+