bluetooth/btsdp/database/dataparser.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btsdp/database/dataparser.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,356 @@
+// 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:
+// dataparser.cpp - all the sdp parser code
+// 
+//
+
+#include <bluetooth/logger.h>
+#include <btsdp.h>
+#include "sdpconsts.h"
+#include "sdputil.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_SDPDATABASE);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("sdpdatap");
+#endif
+
+static const TInt KLinBufSizeLimit = 0x800;	// 2K
+
+CElementParser::CLinearBuf* CElementParser::CLinearBuf::NewLC(TInt aExpandSize)
+/** Element parser constructor. */
+	{
+	CLinearBuf* self = new(ELeave) CLinearBuf;
+	CleanupStack::PushL(self);
+	self->ConstructL(aExpandSize);
+	return self;
+	}
+
+CElementParser::CLinearBuf::~CLinearBuf()
+	{
+	delete iBuf;
+	}
+
+void CElementParser::CLinearBuf::AppendL(const TDesC8& aData)
+/** Add aData onto the end of this linear buffer.*/
+	{
+	if (iStartOffset && aData.Length() / 4 > Size())
+		{// Might as well shuffle the buffer up now
+		iBuf->Delete(0, iStartOffset);
+		iStartOffset = 0;
+		}
+	iBuf->InsertL(iBuf->Size(), aData, aData.Length());
+	}
+
+const TPtrC8 CElementParser::CLinearBuf::Ptr() const
+/** Get a constant Ptr to the contents of this buffer.*/
+	{
+	return iBuf->Ptr(iStartOffset);
+	}
+
+void CElementParser::CLinearBuf::Consume(TInt aLength)
+/** Consume the first aLength bytes of the buffer.
+
+	Optimised to avoid copies and heap operations on
+	frequent calls to this function.*/
+	{
+	ASSERT_DEBUG(aLength <= Size());
+	iStartOffset += aLength;
+	if (iStartOffset > iBuf->Capacity() / 2 || Size() == 0)
+		{// Actaully delete the stuff
+		iBuf->Delete(0, iStartOffset);
+		iStartOffset = 0;
+		if (iBuf->Capacity() > KLinBufSizeLimit)
+			{// Won't leave as we're reducing the reserve.
+			TInt err;
+			TRAP(err,iBuf->SetReserveL(Max(iBuf->Size(), KLinBufSizeLimit)));
+			ASSERT_DEBUG(err == KErrNone);
+			}
+		}
+	}
+
+inline TInt CElementParser::CLinearBuf::Size() const
+	{
+	return iBuf->Size() - iStartOffset;
+	}
+
+CElementParser::CLinearBuf::CLinearBuf()
+	{
+	}
+
+void CElementParser::CLinearBuf::ConstructL(TInt aExpandSize)
+	{
+	iBuf = CBufFlat::NewL(aExpandSize);
+	}
+
+
+
+CElementParser::CElementParser(MSdpElementBuilder* aBuilder)
+	: iBuilder(aBuilder)
+	{
+	}
+
+EXPORT_C CElementParser* CElementParser::NewL(MSdpElementBuilder* aBuilder)
+/** Allocates and constructs a new CElementParser object.
+
+@param aBuilder Object into which to build data element
+@return New CElementParser object */
+	{
+	CElementParser* self = new(ELeave) CElementParser(aBuilder);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CElementParser::ConstructL()
+	{
+	this->iListStack = new(ELeave) CSdpStackFix<TInt>;
+	}
+
+EXPORT_C CElementParser::~CElementParser()
+/** Destructor. */
+	{
+	delete iListStack;
+	}
+
+
+TBool CElementParser::IsComposite(TUint8 aType)
+	{
+	return aType == ETypeDES || aType == ETypeDEA;
+	}
+
+EXPORT_C TInt CElementParser::ParseElementsL(const TDesC8& aData)
+/** Parses a data buffer into the currently set MSdpElementBuilder interface.
+
+If a whole number of data elements can not be parsed out of aData, the number 
+of bytes left unparsed is returned. Those bytes should be prepended to the 
+buffer when the function is next called. 
+
+@param aData Buffer to parse
+@return Number of bytes not consumed */
+	{
+	TUint8* ptr = (TUint8*)aData.Ptr();
+	const TUint8* ptrE = ptr + aData.Length();
+
+	CloseListsL();
+	while ((ptr < ptrE) && (iBuilder != NULL))
+		{
+
+		// Remember start of this data element
+		TUint8* ptrStart = ptr;
+
+		// We know there's at least one byte already..
+		TUint8 type = (TUint8)(*ptr>>KSdpElemHdrTypeShift);
+		TUint8 sizedesc  = (TUint8)(*ptr&KSdpElemHdrSizeMask);
+		++ptr;
+
+		if ( type >= sizeof(KSdpElementValidSizes) ||
+			 !(KSdpElementValidSizes[type]&(1<<sizedesc)) )
+			{// Invalid size desc for type.
+			LOG2(_L("SDP: Invalid size descriptor %d for type %d!"), sizedesc, type);
+			User::Leave(KErrSdpParserInvalidSizeForType);
+			}
+
+		TUint elementLen;
+		if (type == ETypeNil)
+			{// we've already checked that sizedesc == 0
+			elementLen = 0;
+			}
+		else if(sizedesc<=ESizeSixteenBytes)
+			{
+			elementLen = 1<<sizedesc;
+			}
+		else
+			{
+			TUint addSzBytes = 1<<(sizedesc-ESizeOneAdditional);
+			if((addSzBytes)>TUint(ptrE-ptr))
+				return (ptrE-ptrStart);
+			elementLen = SdpUtil::GetUint(TPtrC8(ptr, addSzBytes));
+			ptr += addSzBytes;
+			}
+
+		if (!iListStack->IsEmpty() && 
+			(TInt)((ptr-ptrStart)+elementLen) > iListStack->Head())
+			{// Error! This item is longer than the list it is in!!
+			User::Leave(KErrSdpParserInvalidSizeForParentList);
+			}
+
+		TUint compositeLen = 0;
+		if (IsComposite(type))
+			{//Composite node. We'll parse down into it.
+			compositeLen = elementLen;
+			elementLen = 0;		// composites have no element length.
+			}
+
+		if((elementLen)>TUint(ptrE-ptr))return (ptrE-ptrStart);
+
+		TPtrC8 data(ptr,elementLen);
+
+		switch (type)
+			{
+		case ETypeNil:
+			iBuilder=iBuilder->BuildNilL();
+			break;
+		case ETypeUint:
+			iBuilder=iBuilder->BuildUintL(data);
+			break;
+		case ETypeInt:
+			iBuilder=iBuilder->BuildIntL(data);
+			break;
+		case ETypeUUID:
+			{
+			TUUID uuid;
+			uuid.SetL(data);
+			iBuilder=iBuilder->BuildUUIDL(uuid);
+			}
+			break;
+		case ETypeString:
+			iBuilder=iBuilder->BuildStringL(data);
+			break;
+		case ETypeBoolean:
+			iBuilder=iBuilder->BuildBooleanL(SdpUtil::GetUint(data));
+			break;		
+		case ETypeURL:
+			iBuilder=iBuilder->BuildURLL(data);
+			break;
+		case ETypeDES:
+			iBuilder=iBuilder->BuildDESL();
+			break;
+		case ETypeDEA:
+			iBuilder=iBuilder->BuildDEAL();
+			break;
+		default:
+			iBuilder=iBuilder->BuildUnknownL(type, sizedesc, data);
+			break;
+			};
+
+		ptr += elementLen;
+
+
+		if (!iListStack->IsEmpty())
+			{// Adjust size of existing head entry so we know when the DES/DEA is finished
+			iListStack->Head() -= (ptr-ptrStart)+compositeLen;
+			}
+
+		if (IsComposite(type))
+			{ // push the length of the DES/DEA on top of the stack and mark the list
+			iBuilder=iBuilder->StartListL();
+			iListStack->PushL(compositeLen);
+			}
+
+		CloseListsL();
+		}
+
+	__ASSERT_DEBUG(ptr<=ptrE, ParsePanic(EFrameOverrun));
+
+	return ptrE-ptr;
+	}
+
+EXPORT_C TBool CElementParser::BufferedParseL(const TDesC8& aData)
+/** Parse out some encoded data, with transparent buffering of unparsed data between 
+calls.
+
+The function stores any incompletely parsed data from a previous call, and 
+automatically prepends to the data buffer when it is next called.
+
+If the function leaves, the unparsed data will be deleted. This means it will 
+not be possible to continue with this data stream; Reset() should be called 
+before the next call to this function.
+
+@param aData Buffer to parse
+@return True if a whole number of data elements have not been parsed, so more 
+data is expected. False if a whole number has been parsed. */
+	{
+	TPtrC8 data(aData);
+	CLinearBuf* remBuf = 0;
+
+	if(iRemainderBuf)
+		{//Need to append new bit onto remainder from previous response
+		remBuf = iRemainderBuf;
+		iRemainderBuf = 0;
+		CleanupStack::PushL(remBuf);
+		remBuf->AppendL(data);
+		data.Set(remBuf->Ptr());
+		}
+
+	TInt rem = ParseElementsL(data);
+
+	if(remBuf || rem > 0)
+		{
+		if(remBuf && rem > 0)
+			{// skip the bit just parsed
+			remBuf->Consume(remBuf->Size() - rem);
+			}
+		else if (remBuf) // && rem == 0
+			{// no remainder -- remBuf no longer needed
+			CleanupStack::PopAndDestroy(); // remBuf
+			remBuf = 0;
+			}
+		else // rem > 0 && remBuf == 0
+			{// Store remainder in a new remainder buf
+			remBuf = CLinearBuf::NewLC(rem);
+			remBuf->AppendL(data.Right(rem));
+			}
+
+		if(remBuf)
+			{
+			CleanupStack::Pop(); // remBuf
+			iRemainderBuf = remBuf;
+			}
+		}
+	ASSERT_DEBUG(rem == 0 || rem == ((iRemainderBuf != NULL) ? iRemainderBuf->Size() : 0));
+	return iRemainderBuf || !iListStack->IsEmpty();
+	}
+
+EXPORT_C void CElementParser::Reset()
+/** Resets the parser's buffers to be empty. */
+	{
+	iListStack->Reset();
+	delete iRemainderBuf;
+	iRemainderBuf = 0;
+	}
+
+EXPORT_C void CElementParser::Reset(MSdpElementBuilder* aBuilder)
+/** Resets the parser's buffers to be empty, and resets the element builder object 
+used.
+
+@param aBuilder Element builder object to use */
+	{
+	Reset();
+	iBuilder=aBuilder;
+	}
+
+void CElementParser::CloseListsL()
+	{
+	while (!iListStack->IsEmpty() && iListStack->Head() == 0 && iBuilder)
+		{// List has ended
+		iListStack->Pop();
+		iBuilder=iBuilder->EndListL();
+		}
+	}
+
+EXPORT_C void CElementParser::SetBuilder(MSdpElementBuilder* aBuilder)
+	{
+	iBuilder = aBuilder;
+	}
+
+EXPORT_C MSdpElementBuilder* CElementParser::Builder()
+	{
+	return iBuilder;
+	}
+	
+// EOF