bluetooth/btsdp/database/dataparser.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // dataparser.cpp - all the sdp parser code
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <bluetooth/logger.h>
       
    19 #include <btsdp.h>
       
    20 #include "sdpconsts.h"
       
    21 #include "sdputil.h"
       
    22 
       
    23 #ifdef __FLOG_ACTIVE
       
    24 _LIT8(KLogComponent, LOG_COMPONENT_SDPDATABASE);
       
    25 #endif
       
    26 
       
    27 #ifdef _DEBUG
       
    28 PANICCATEGORY("sdpdatap");
       
    29 #endif
       
    30 
       
    31 static const TInt KLinBufSizeLimit = 0x800;	// 2K
       
    32 
       
    33 CElementParser::CLinearBuf* CElementParser::CLinearBuf::NewLC(TInt aExpandSize)
       
    34 /** Element parser constructor. */
       
    35 	{
       
    36 	CLinearBuf* self = new(ELeave) CLinearBuf;
       
    37 	CleanupStack::PushL(self);
       
    38 	self->ConstructL(aExpandSize);
       
    39 	return self;
       
    40 	}
       
    41 
       
    42 CElementParser::CLinearBuf::~CLinearBuf()
       
    43 	{
       
    44 	delete iBuf;
       
    45 	}
       
    46 
       
    47 void CElementParser::CLinearBuf::AppendL(const TDesC8& aData)
       
    48 /** Add aData onto the end of this linear buffer.*/
       
    49 	{
       
    50 	if (iStartOffset && aData.Length() / 4 > Size())
       
    51 		{// Might as well shuffle the buffer up now
       
    52 		iBuf->Delete(0, iStartOffset);
       
    53 		iStartOffset = 0;
       
    54 		}
       
    55 	iBuf->InsertL(iBuf->Size(), aData, aData.Length());
       
    56 	}
       
    57 
       
    58 const TPtrC8 CElementParser::CLinearBuf::Ptr() const
       
    59 /** Get a constant Ptr to the contents of this buffer.*/
       
    60 	{
       
    61 	return iBuf->Ptr(iStartOffset);
       
    62 	}
       
    63 
       
    64 void CElementParser::CLinearBuf::Consume(TInt aLength)
       
    65 /** Consume the first aLength bytes of the buffer.
       
    66 
       
    67 	Optimised to avoid copies and heap operations on
       
    68 	frequent calls to this function.*/
       
    69 	{
       
    70 	ASSERT_DEBUG(aLength <= Size());
       
    71 	iStartOffset += aLength;
       
    72 	if (iStartOffset > iBuf->Capacity() / 2 || Size() == 0)
       
    73 		{// Actaully delete the stuff
       
    74 		iBuf->Delete(0, iStartOffset);
       
    75 		iStartOffset = 0;
       
    76 		if (iBuf->Capacity() > KLinBufSizeLimit)
       
    77 			{// Won't leave as we're reducing the reserve.
       
    78 			TInt err;
       
    79 			TRAP(err,iBuf->SetReserveL(Max(iBuf->Size(), KLinBufSizeLimit)));
       
    80 			ASSERT_DEBUG(err == KErrNone);
       
    81 			}
       
    82 		}
       
    83 	}
       
    84 
       
    85 inline TInt CElementParser::CLinearBuf::Size() const
       
    86 	{
       
    87 	return iBuf->Size() - iStartOffset;
       
    88 	}
       
    89 
       
    90 CElementParser::CLinearBuf::CLinearBuf()
       
    91 	{
       
    92 	}
       
    93 
       
    94 void CElementParser::CLinearBuf::ConstructL(TInt aExpandSize)
       
    95 	{
       
    96 	iBuf = CBufFlat::NewL(aExpandSize);
       
    97 	}
       
    98 
       
    99 
       
   100 
       
   101 CElementParser::CElementParser(MSdpElementBuilder* aBuilder)
       
   102 	: iBuilder(aBuilder)
       
   103 	{
       
   104 	}
       
   105 
       
   106 EXPORT_C CElementParser* CElementParser::NewL(MSdpElementBuilder* aBuilder)
       
   107 /** Allocates and constructs a new CElementParser object.
       
   108 
       
   109 @param aBuilder Object into which to build data element
       
   110 @return New CElementParser object */
       
   111 	{
       
   112 	CElementParser* self = new(ELeave) CElementParser(aBuilder);
       
   113 	CleanupStack::PushL(self);
       
   114 	self->ConstructL();
       
   115 	CleanupStack::Pop();
       
   116 	return self;
       
   117 	}
       
   118 
       
   119 void CElementParser::ConstructL()
       
   120 	{
       
   121 	this->iListStack = new(ELeave) CSdpStackFix<TInt>;
       
   122 	}
       
   123 
       
   124 EXPORT_C CElementParser::~CElementParser()
       
   125 /** Destructor. */
       
   126 	{
       
   127 	delete iListStack;
       
   128 	}
       
   129 
       
   130 
       
   131 TBool CElementParser::IsComposite(TUint8 aType)
       
   132 	{
       
   133 	return aType == ETypeDES || aType == ETypeDEA;
       
   134 	}
       
   135 
       
   136 EXPORT_C TInt CElementParser::ParseElementsL(const TDesC8& aData)
       
   137 /** Parses a data buffer into the currently set MSdpElementBuilder interface.
       
   138 
       
   139 If a whole number of data elements can not be parsed out of aData, the number 
       
   140 of bytes left unparsed is returned. Those bytes should be prepended to the 
       
   141 buffer when the function is next called. 
       
   142 
       
   143 @param aData Buffer to parse
       
   144 @return Number of bytes not consumed */
       
   145 	{
       
   146 	TUint8* ptr = (TUint8*)aData.Ptr();
       
   147 	const TUint8* ptrE = ptr + aData.Length();
       
   148 
       
   149 	CloseListsL();
       
   150 	while ((ptr < ptrE) && (iBuilder != NULL))
       
   151 		{
       
   152 
       
   153 		// Remember start of this data element
       
   154 		TUint8* ptrStart = ptr;
       
   155 
       
   156 		// We know there's at least one byte already..
       
   157 		TUint8 type = (TUint8)(*ptr>>KSdpElemHdrTypeShift);
       
   158 		TUint8 sizedesc  = (TUint8)(*ptr&KSdpElemHdrSizeMask);
       
   159 		++ptr;
       
   160 
       
   161 		if ( type >= sizeof(KSdpElementValidSizes) ||
       
   162 			 !(KSdpElementValidSizes[type]&(1<<sizedesc)) )
       
   163 			{// Invalid size desc for type.
       
   164 			LOG2(_L("SDP: Invalid size descriptor %d for type %d!"), sizedesc, type);
       
   165 			User::Leave(KErrSdpParserInvalidSizeForType);
       
   166 			}
       
   167 
       
   168 		TUint elementLen;
       
   169 		if (type == ETypeNil)
       
   170 			{// we've already checked that sizedesc == 0
       
   171 			elementLen = 0;
       
   172 			}
       
   173 		else if(sizedesc<=ESizeSixteenBytes)
       
   174 			{
       
   175 			elementLen = 1<<sizedesc;
       
   176 			}
       
   177 		else
       
   178 			{
       
   179 			TUint addSzBytes = 1<<(sizedesc-ESizeOneAdditional);
       
   180 			if((addSzBytes)>TUint(ptrE-ptr))
       
   181 				return (ptrE-ptrStart);
       
   182 			elementLen = SdpUtil::GetUint(TPtrC8(ptr, addSzBytes));
       
   183 			ptr += addSzBytes;
       
   184 			}
       
   185 
       
   186 		if (!iListStack->IsEmpty() && 
       
   187 			(TInt)((ptr-ptrStart)+elementLen) > iListStack->Head())
       
   188 			{// Error! This item is longer than the list it is in!!
       
   189 			User::Leave(KErrSdpParserInvalidSizeForParentList);
       
   190 			}
       
   191 
       
   192 		TUint compositeLen = 0;
       
   193 		if (IsComposite(type))
       
   194 			{//Composite node. We'll parse down into it.
       
   195 			compositeLen = elementLen;
       
   196 			elementLen = 0;		// composites have no element length.
       
   197 			}
       
   198 
       
   199 		if((elementLen)>TUint(ptrE-ptr))return (ptrE-ptrStart);
       
   200 
       
   201 		TPtrC8 data(ptr,elementLen);
       
   202 
       
   203 		switch (type)
       
   204 			{
       
   205 		case ETypeNil:
       
   206 			iBuilder=iBuilder->BuildNilL();
       
   207 			break;
       
   208 		case ETypeUint:
       
   209 			iBuilder=iBuilder->BuildUintL(data);
       
   210 			break;
       
   211 		case ETypeInt:
       
   212 			iBuilder=iBuilder->BuildIntL(data);
       
   213 			break;
       
   214 		case ETypeUUID:
       
   215 			{
       
   216 			TUUID uuid;
       
   217 			uuid.SetL(data);
       
   218 			iBuilder=iBuilder->BuildUUIDL(uuid);
       
   219 			}
       
   220 			break;
       
   221 		case ETypeString:
       
   222 			iBuilder=iBuilder->BuildStringL(data);
       
   223 			break;
       
   224 		case ETypeBoolean:
       
   225 			iBuilder=iBuilder->BuildBooleanL(SdpUtil::GetUint(data));
       
   226 			break;		
       
   227 		case ETypeURL:
       
   228 			iBuilder=iBuilder->BuildURLL(data);
       
   229 			break;
       
   230 		case ETypeDES:
       
   231 			iBuilder=iBuilder->BuildDESL();
       
   232 			break;
       
   233 		case ETypeDEA:
       
   234 			iBuilder=iBuilder->BuildDEAL();
       
   235 			break;
       
   236 		default:
       
   237 			iBuilder=iBuilder->BuildUnknownL(type, sizedesc, data);
       
   238 			break;
       
   239 			};
       
   240 
       
   241 		ptr += elementLen;
       
   242 
       
   243 
       
   244 		if (!iListStack->IsEmpty())
       
   245 			{// Adjust size of existing head entry so we know when the DES/DEA is finished
       
   246 			iListStack->Head() -= (ptr-ptrStart)+compositeLen;
       
   247 			}
       
   248 
       
   249 		if (IsComposite(type))
       
   250 			{ // push the length of the DES/DEA on top of the stack and mark the list
       
   251 			iBuilder=iBuilder->StartListL();
       
   252 			iListStack->PushL(compositeLen);
       
   253 			}
       
   254 
       
   255 		CloseListsL();
       
   256 		}
       
   257 
       
   258 	__ASSERT_DEBUG(ptr<=ptrE, ParsePanic(EFrameOverrun));
       
   259 
       
   260 	return ptrE-ptr;
       
   261 	}
       
   262 
       
   263 EXPORT_C TBool CElementParser::BufferedParseL(const TDesC8& aData)
       
   264 /** Parse out some encoded data, with transparent buffering of unparsed data between 
       
   265 calls.
       
   266 
       
   267 The function stores any incompletely parsed data from a previous call, and 
       
   268 automatically prepends to the data buffer when it is next called.
       
   269 
       
   270 If the function leaves, the unparsed data will be deleted. This means it will 
       
   271 not be possible to continue with this data stream; Reset() should be called 
       
   272 before the next call to this function.
       
   273 
       
   274 @param aData Buffer to parse
       
   275 @return True if a whole number of data elements have not been parsed, so more 
       
   276 data is expected. False if a whole number has been parsed. */
       
   277 	{
       
   278 	TPtrC8 data(aData);
       
   279 	CLinearBuf* remBuf = 0;
       
   280 
       
   281 	if(iRemainderBuf)
       
   282 		{//Need to append new bit onto remainder from previous response
       
   283 		remBuf = iRemainderBuf;
       
   284 		iRemainderBuf = 0;
       
   285 		CleanupStack::PushL(remBuf);
       
   286 		remBuf->AppendL(data);
       
   287 		data.Set(remBuf->Ptr());
       
   288 		}
       
   289 
       
   290 	TInt rem = ParseElementsL(data);
       
   291 
       
   292 	if(remBuf || rem > 0)
       
   293 		{
       
   294 		if(remBuf && rem > 0)
       
   295 			{// skip the bit just parsed
       
   296 			remBuf->Consume(remBuf->Size() - rem);
       
   297 			}
       
   298 		else if (remBuf) // && rem == 0
       
   299 			{// no remainder -- remBuf no longer needed
       
   300 			CleanupStack::PopAndDestroy(); // remBuf
       
   301 			remBuf = 0;
       
   302 			}
       
   303 		else // rem > 0 && remBuf == 0
       
   304 			{// Store remainder in a new remainder buf
       
   305 			remBuf = CLinearBuf::NewLC(rem);
       
   306 			remBuf->AppendL(data.Right(rem));
       
   307 			}
       
   308 
       
   309 		if(remBuf)
       
   310 			{
       
   311 			CleanupStack::Pop(); // remBuf
       
   312 			iRemainderBuf = remBuf;
       
   313 			}
       
   314 		}
       
   315 	ASSERT_DEBUG(rem == 0 || rem == ((iRemainderBuf != NULL) ? iRemainderBuf->Size() : 0));
       
   316 	return iRemainderBuf || !iListStack->IsEmpty();
       
   317 	}
       
   318 
       
   319 EXPORT_C void CElementParser::Reset()
       
   320 /** Resets the parser's buffers to be empty. */
       
   321 	{
       
   322 	iListStack->Reset();
       
   323 	delete iRemainderBuf;
       
   324 	iRemainderBuf = 0;
       
   325 	}
       
   326 
       
   327 EXPORT_C void CElementParser::Reset(MSdpElementBuilder* aBuilder)
       
   328 /** Resets the parser's buffers to be empty, and resets the element builder object 
       
   329 used.
       
   330 
       
   331 @param aBuilder Element builder object to use */
       
   332 	{
       
   333 	Reset();
       
   334 	iBuilder=aBuilder;
       
   335 	}
       
   336 
       
   337 void CElementParser::CloseListsL()
       
   338 	{
       
   339 	while (!iListStack->IsEmpty() && iListStack->Head() == 0 && iBuilder)
       
   340 		{// List has ended
       
   341 		iListStack->Pop();
       
   342 		iBuilder=iBuilder->EndListL();
       
   343 		}
       
   344 	}
       
   345 
       
   346 EXPORT_C void CElementParser::SetBuilder(MSdpElementBuilder* aBuilder)
       
   347 	{
       
   348 	iBuilder = aBuilder;
       
   349 	}
       
   350 
       
   351 EXPORT_C MSdpElementBuilder* CElementParser::Builder()
       
   352 	{
       
   353 	return iBuilder;
       
   354 	}
       
   355 	
       
   356 // EOF