--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btsdp/database/ExtractorVisitor.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,510 @@
+// 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 <bluetooth/logger.h>
+#include "ExtractorVisitor.h"
+#include <btsdp.h>
+#include "DataEncoder.h"
+#include "SDPDatabase.h"
+#include "sdputil.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_SDPDATABASE);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("extrvst");
+#endif
+
+CAttrExtractVisitor *CAttrExtractVisitor::NewLC(TElementEncoder aEncoder)
+ {
+ CAttrExtractVisitor *self = new(ELeave) CAttrExtractVisitor(aEncoder);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+CAttrExtractVisitor *CAttrExtractVisitor::NewL(TElementEncoder aEncoder)
+ {
+ CAttrExtractVisitor *self = CAttrExtractVisitor::NewL(aEncoder);
+ CleanupStack::Pop();
+ return self;
+ }
+
+CAttrExtractVisitor::CAttrExtractVisitor(TElementEncoder aEncoder)
+ : iEncoder(aEncoder)
+ {
+ }
+
+void CAttrExtractVisitor::ConstructL()
+ {
+ }
+
+CAttrExtractVisitor::~CAttrExtractVisitor()
+ {
+ }
+
+// the only entry to this class - creates an instance of itself and then calls the FindAttributes
+// method of aList on the record supplied.
+EXPORT_C void CAttrExtractVisitor::EncodeAttributesL(TElementEncoder aEncoder, CSdpServRecord &aRec, CSdpAttrIdMatchList &aList)
+/** Encode attributes in aRec that are in the match list aList, using aEncoder.*/
+ {
+ CAttrExtractVisitor *self = CAttrExtractVisitor::NewLC(aEncoder);
+
+ TRAPD(err, aList.FindAttributesL(aRec, *self));
+
+ // If we ran out of buffer space, a positive leave will have happened in VisitAttributeValueL, below
+ // else, the leave was an error, which should be re-thrown
+ if (err < 0)
+ User::Leave(err);
+
+ CleanupStack::PopAndDestroy(/*self*/);
+ }
+
+void CAttrExtractVisitor::AttributeInMatchListL(CSdpAttr &aAttr)
+ {
+ aAttr.AcceptVisitorL(*this);
+ }
+
+
+
+void CAttrExtractVisitor::VisitAttributeL(CSdpAttr &aAttribute)
+ {
+ //FIXME check rem
+ iEncoder.WriteUint(aAttribute.AttributeID(), sizeof(TSdpAttributeID));
+ }
+
+void CAttrExtractVisitor::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType)
+ {
+ TUint rem=0;
+ switch(aType)
+ {
+ case ETypeNil:
+ rem = iEncoder.WriteNil();
+ break;
+ case ETypeUint:
+ case ETypeInt:
+ case ETypeUUID:
+ case ETypeString:
+ case ETypeURL:
+ rem = iEncoder.WriteElement(aType, aValue.Des());
+ break;
+ case ETypeBoolean:
+ rem = iEncoder.WriteBoolean(aValue.Int());
+ break;
+ case ETypeDES:
+ rem = iEncoder.WriteDES(aValue.DataSize());
+ break;
+ case ETypeDEA:
+ rem = iEncoder.WriteDEA(aValue.DataSize());
+ break;
+ case ETypeEncoded:
+ rem= iEncoder.WriteDesc(aValue.Des());
+ break;
+ }
+ if (rem)
+ User::Leave(rem);
+ }
+
+void CAttrExtractVisitor::StartListL(CSdpAttrValueList &/*aList*/)
+ {
+ }
+
+void CAttrExtractVisitor::EndListL()
+ {
+ }
+
+
+
+
+//
+// CSdpAttrIdMatchList
+//
+
+CSdpAttrIdMatchList::CSdpAttrIdMatchList()
+ {
+ }
+
+EXPORT_C CSdpAttrIdMatchList* CSdpAttrIdMatchList::NewL()
+/** Allocate and construct a new CSdpAttrIdMatchList object.
+
+@return New CSdpAttrIdMatchList object */
+ {
+ CSdpAttrIdMatchList* self = new (ELeave) CSdpAttrIdMatchList;
+ CleanupStack::PushL(self);
+ self->iList = new (ELeave) CArrayFixFlat<TAttrRange> (2);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CSdpAttrIdMatchList* CSdpAttrIdMatchList::NewL(const CSdpAttrIdMatchList& aAttrMatchList)
+/** Allocate and construct a new CSdpAttrIdMatchList object as a copy of another
+CSdpAttrIdMatchList.
+
+@param aAttrMatchList Object to copy
+@return New CSdpAttrIdMatchList object */
+ {
+ CSdpAttrIdMatchList* self = new (ELeave) CSdpAttrIdMatchList;
+ CleanupStack::PushL(self);
+ self->iList = new (ELeave) CArrayFixFlat<TAttrRange> (2);
+ static_cast<CArrayFixFlat<TAttrRange>*>(self->iList)->SetReserveL(aAttrMatchList.Count());
+ for(TInt i = 0; i < aAttrMatchList.Count(); ++i)
+ {
+ self->AddL((aAttrMatchList.iList)->At(i));
+ }
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+EXPORT_C CSdpAttrIdMatchList::~CSdpAttrIdMatchList()
+/** Destructor. */
+ {
+ delete iList;
+ }
+
+EXPORT_C void CSdpAttrIdMatchList::AddL(TAttrRange aRange)
+/** Adds a range of IDs to the list.
+
+@param aRange Range to add */
+ {
+ if (aRange.iStart > aRange.iEnd)
+ {// Bad range
+ User::Leave(KErrArgument);
+ }
+
+
+ // Look for insertion point (pos) in the match list.
+
+ TInt pos = 0; // this new item will start the list unless we find an existing
+ // range for it to overlap or follow
+
+ // If the start of the range 'aRange' is contiguous with one of the existing match list ranges
+ // then the insertion point is the index of that match list range.
+ // If not it is one more than the index of the match list range that
+ // precedes 'aRange'.
+ // N.B. The ranges are stored in ascending order
+
+ TBool bPositionFound = EFalse;
+ TBool bStartInRangeOrContiguous = EFalse;
+
+ // Find the first position in the list in which (or contiguous with) this range lies
+ if (FindInOrContiguousWith(aRange.iStart, pos) == 0)
+ {
+ // the start of this new range overlaps with an existing one (returned in pos) or is contiguous with it
+ bPositionFound = ETrue;
+ bStartInRangeOrContiguous = ETrue;
+ }
+ else
+ {
+ // find which range this new one will be after
+ for (TInt i=iList->Count()-1; i>=0 && !bPositionFound; i-- )
+ {
+ if (aRange.iStart > (iList->At(i).iEnd + 1 ))
+ {
+ pos = i+1;
+ bPositionFound = ETrue;
+ }
+ }
+ }
+
+ TAttrRange *insert;
+
+ if (bStartInRangeOrContiguous)
+ {// Don't actually insert new entry, just grow the existing entry
+ insert = &iList->At(pos);
+
+ // NB If the range to add has a start ID which is one less than the current start of range,
+ // the range may grow "downwards", but will never join up with the preceding range because
+ // the start ID is known not to be contiguous with THAT range.
+ insert->iStart = Min(insert->iStart, aRange.iStart);
+ insert->iEnd = Max(insert->iEnd, aRange.iEnd);
+ }
+ else
+ {// Add a new entry
+ iList->InsertL(pos, aRange);
+ insert = &iList->At(pos);
+ }
+
+ while (pos < iList->Count()-1 && insert->IsContiguousWith(iList->At(pos+1).iStart) )
+ {// There's now overlap with following item
+ insert->iEnd = Max(insert->iEnd, iList->At(pos+1).iEnd);
+ iList->Delete(pos+1); // which leaves a new range to be checked at (pos+1), so no incrementing of pos is required
+ }
+ __TEST_INVARIANT;
+ }
+
+EXPORT_C void CSdpAttrIdMatchList::RemoveL(TAttrRange aRange)
+/** Removes a range of IDs from the list.
+
+@param aRange Range to remove */
+ {
+ if (aRange.iStart > aRange.iEnd)
+ {// Bad range
+ User::Leave(KErrArgument);
+ }
+
+ TInt pos = 0; // the deletion point
+
+ TAttrRange *trim;
+
+ // Find position for the start of the exclude range - is it partway through a current range?
+ if ((Find(aRange.iStart, pos) == 0) && (aRange.iStart > (&iList->At(pos))->iStart))
+ {
+ // Trim a bit off this entry
+ trim = &iList->At(pos);
+
+ if (trim->iEnd > aRange.iEnd)
+ {
+ //It's bigger. Need to split in two
+ // Grow first, in case it fails
+ iList->InsertL(pos+1, TAttrRange(TSdpAttributeID(aRange.iEnd+1), trim->iEnd));
+ trim->iEnd = TSdpAttributeID(aRange.iStart - 1);
+ __TEST_INVARIANT;
+ return; // We know this remove range is fully handled now
+ }
+ trim->iEnd = TSdpAttributeID(aRange.iStart - 1);
+ }
+
+ // whether or not the trimming has already started, now move through the rest of the ranges
+ // removing entire entries which lie within the deletion range.
+ while (pos < iList->Count() && (aRange.iEnd >= iList->At(pos).iEnd))
+ {
+ if (aRange.iStart <= iList->At(pos).iStart)
+ {
+ // This complete item is not needed
+ iList->Delete(pos);
+ }
+ else
+ {
+ // this item is not affected, because we have not yet got to the start of the exclude range
+ pos++;
+ }
+ }
+
+ // Does the end of the deletion range lie within this entry?
+ if ( pos < iList->Count() )
+ {
+ trim = &iList->At(pos);
+ if ((trim->iStart >= aRange.iStart) && (trim->iStart <= aRange.iEnd))
+ {// The following item is too long -- trim it
+ trim->iStart = TSdpAttributeID(aRange.iEnd + 1);
+ }
+ }
+ __TEST_INVARIANT;
+ }
+
+TInt CSdpAttrIdMatchList::Find(TSdpAttributeID aAttrId, TInt &aPos) const
+/** Tests if the specified attribute ID is in the list, and gets its position.
+
+@param aAttrId Attribute ID to test
+@param aPos Position of ID in the list, or unchanged if attribute not found
+@return KErrNone if the attribute is in the list, else KErrNotFound */
+ {
+ __TEST_INVARIANT;
+ TAttrRange searchRange;
+
+ TBool bAttribInRange = EFalse;
+ TInt ret=KErrNotFound;
+
+ for ( TInt i=0; (i<iList->Count()) && !bAttribInRange; i++ )
+ {
+ searchRange = iList->At(i);
+ if (searchRange.IsInRange(aAttrId) )
+ {
+ bAttribInRange = ETrue;
+ aPos = i;
+ ret = KErrNone;
+ }
+ }
+ return ret;
+ }
+
+TInt CSdpAttrIdMatchList::FindInOrContiguousWith(TSdpAttributeID aAttrId, TInt &aPos) const
+/** Tests if the specified attribute ID is in the list (or next to a range in the list), and gets its position.
+
+@param aAttrId Attribute ID to test
+@param aPos Position in the list if the ID is found in a current range, or the lowest range with which the ID is contiguous, or unchanged if neither.
+@return KErrNone if the attribute is in the list, else KErrNotFound */
+ {
+ __TEST_INVARIANT;
+ TAttrRange searchRange;
+
+ TBool bAttribInRange = EFalse;
+ TInt ret=KErrNotFound;
+
+ for ( TInt i=0; (i<iList->Count()) && !bAttribInRange; i++ )
+ {
+ searchRange = iList->At(i);
+ if (searchRange.IsContiguousWith(aAttrId) )
+ {
+ bAttribInRange = ETrue;
+ aPos = i;
+ ret = KErrNone;
+ }
+ }
+ return ret;
+ }
+
+
+EXPORT_C TBool CSdpAttrIdMatchList::InMatchList(TSdpAttributeID aAttrId, TInt &aPos) const
+/** Tests if the specified attribute ID is in the list, and gets its position.
+ Do not use this - it gives an off-by-one error for aPos
+ unless the attribute is the first one in a contiguous range.
+ Use InMatchListRange() instead
+
+@param aAttrId Attribute ID to test
+@param aPos Position of ID in the list with an off-by-one error for IDs not at the start of a range, or 0 if not found
+@return ETrue if the attribute is in the list, else EFalse */
+ {
+ TKeyArrayFix key (_FOFF(TAttrRange, iStart), ECmpTUint16);
+ TAttrRange search(aAttrId);
+ TInt ret = iList->FindIsq(search, key, aPos);
+ return (ret == 0) || (aPos > 0 && iList->At(aPos-1).IsInRange(aAttrId));
+ }
+
+EXPORT_C TBool CSdpAttrIdMatchList::InMatchListRange(TSdpAttributeID aAttrId, TInt &aRange) const
+ {
+/* Tests if the specified attribute ID is in the list, and gets its position.
+
+Param aAttrId: Attribute ID to test
+Param aPos: Position of ID in the list, or 0 if not found
+Returns ETrue if the attribute is in the list, else EFalse */
+
+
+ aRange = 0; // will not be changed unless the attribute has a match in the list
+ TBool bAttribInRange = EFalse;
+ TInt ret = Find(aAttrId, aRange);
+
+ if (ret == KErrNone)
+ {
+ bAttribInRange = ETrue;
+ }
+
+ return bAttribInRange;
+ }
+
+EXPORT_C TUint CSdpAttrIdMatchList::EncodeL(TElementEncoder aEncoder) const
+/** Supplies encoder with attribute Ids in the match list
+
+@param aEncoder The encoder set to encode the attribute Ids in this match list
+@return Number of bytes of this CSdpAttrIdMatchList for which there was NO space in the encoder
+*/
+ {
+ TUint size = 0;
+ TInt i;
+ for (i = 0; i < iList->Count(); ++i)
+ {
+ TAttrRange& range = (*iList)[i];
+ if (range.iStart == range.iEnd)
+ size += 3; // 2 byte uint + header
+ else
+ size += 5; // 4 byte uint + header
+ }
+
+ TInt rem = aEncoder.WriteDES(size);
+ for (i = 0; i < iList->Count(); ++i)
+ {
+ TAttrRange& range = (*iList)[i];
+ if (range.iStart == range.iEnd)
+ {
+ rem += aEncoder.WriteUint(range.iStart, 2);
+ }
+ else
+ {
+ rem += aEncoder.WriteUint((range.iStart << 16) | range.iEnd, 4);
+ }
+ }
+ return rem;
+ }
+
+
+EXPORT_C TBool CSdpAttrIdMatchList::InMatchList(TSdpAttributeID aAttrId) const
+ {
+ TInt pos;
+ return InMatchListRange(aAttrId, pos);
+ }
+
+EXPORT_C TInt CSdpAttrIdMatchList::Count() const
+ {
+ return iList->Count();
+ }
+
+void CSdpAttrIdMatchList::FindAttributesL(CSdpServRecord &aRec, MAttributeMatchHandler &aHandler) const
+ {
+ for(TServAttrIter attrIter(aRec.AttributeIter()); attrIter; attrIter++)
+ {// Iterate thru attributes in record
+ if (InMatchList((*attrIter).AttributeID()))
+ {// this attribute is is the list -- signal it
+ aHandler.AttributeInMatchListL(*attrIter);
+ }
+ }
+ }
+
+MSdpElementBuilder* CSdpAttrIdMatchList::BuildUintL(const TDesC8& aUint)
+/** This should be one or two 16 bit integers, representing an AttrId of range thereof respectively. */
+ {
+ TInt len = aUint.Length();
+ if (len != 2 && len != 4)
+ {// Bad Uint size
+ User::Leave(KErrCorrupt);
+ }
+
+ // Get either the two or four byte version
+ TUint attrId = SdpUtil::GetUint(aUint);
+ TAttrRange range;
+ range.iStart = TUint16(len == 4 ? attrId >> 16 : attrId);
+ range.iEnd = TUint16(attrId);
+
+ // Add in place (optimised for incoming stream ordered -- but we will cope if isn't
+ // Will leave if a bad range is supplied
+ AddL(range);
+ return this;
+ }
+
+
+MSdpElementBuilder* CSdpAttrIdMatchList::BuildDESL()
+ {
+ // Could assert we only get one of these
+ return this;
+ }
+
+MSdpElementBuilder* CSdpAttrIdMatchList::StartListL()
+ {
+ return this;
+ }
+
+MSdpElementBuilder* CSdpAttrIdMatchList::EndListL()
+/** Attribute list now complete. Stop the parser by returning 0. */
+ {
+ return 0;
+ }
+
+EXPORT_C void CSdpAttrIdMatchList::__DbgTestInvariant() const
+ {
+#ifdef _DEBUG
+ TInt count = iList->Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ TAttrRange& range = iList->At(i);
+ ASSERT_DEBUG(range.iStart <= range.iEnd);
+ if (i < count - 1)
+ {
+ ASSERT_DEBUG(range.iEnd + 1 < iList->At(i+1).iStart);
+ }
+ }
+#endif
+ }
+