--- a/localconnectivityservice/generichid/src/hidparser.cpp Thu Aug 19 10:46:39 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1941 +0,0 @@
-/*
-* Copyright (c) 2004-2007 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: HID parser implementation
-*
-*/
-
-
-// ----------------------------------------------------------------------
-
-// References:
-//
-// [1] USB Device Class Definition for Human Interface Devices (HID),
-// Firmware Specification, Version 1.11, USB Implementers' Forum,
-// June 2001
-//
-// [2] HID Parser Error Codes (HID Parser Error Checking), Revision
-// 1.2, USB Implementers' Forum, February 2000
-//
-// [3] USB HID Usage Tables, Version 1.11, USB Implementers' Forum,
-// June 2001
-//
-// ----------------------------------------------------------------------
-
-#include <e32std.h>
-#include <e32base.h>
-#include <e32des8.h>
-#include <e32svr.h>
-
-#include "hidreportroot.h"
-#include "hiditem.h"
-#include "hidparser.h"
-#include "debug.h"
-
-
-
-
-// ----------------------------------------------------------------------
-/*
-// Define PARSER_DEBUG to activate trace output for WINS debug builds:
-#undef PARSER_DEBUG
-
-#if defined(PARSER_DEBUG) && defined(_DEBUG) && defined(__WINS__)
-#define PDBG(a) a;
-#define PDBG_ACTIVE
-#else
-#define PDBG(a)
-#endif
-*/
-#define PDBG_ACTIVE
-
-const TUint32 CParser::KLocalItemMask =
- EUsageMin | EUsageMax | EUsageId |
- EDesignatorIndex | EDesignatorMin | EDesignatorMax |
- EStringIndex | EStringMin | EStringMax;
-
-
-const TUint32 KMaxStandardType = 0x06;
-const TUint32 KMinVendorType = 0x80;
-const TUint32 KMaxVendorType = 0xFF;
-const TUint32 KMaxUsagePage = 0xffff;
-const TUint32 KUnitData = 0x0f;
-
-const TUint32 CParser::KUnusedLocalItemsMask = KLocalItemMask & ~EUsageId;
-
-const TUint32 KInputReservedBitsMask = 0xffffff00;
-const TUint32 KOutputReservedBitsMask = 0xffffff00;
-const TUint32 KFeatureReservedBitsMask = 0xffffff00;
-const TUint32 KUnitReservedBitsMask = 0xf0000000;
-
-const TInt KConstantFlag = 1<<0; // Constant (1) or Data (0)
-const TInt KVariableFlag = 1<<1; // Array (0) or Variable (1)
-const TInt KNullStateFlag = 1<<6;
-
-const TInt KExtendedDataSize = 4; // 32-bit extended data size
-const TInt KExtendedDataShift = 16; // 16 bit shift if extended usage page is used
-const TInt KMaxReportIDMax = 255;
-const TInt K32Bit = 32;
-
-const TUint K32BitFirstBitOn = 1u<<31;
-const TInt KUnitSystemMin = 5;
-const TInt KUnitSystem15 = 15;
-
-const TUint32 CParser::KMandatoryItemMask = EUsagePage |
- ELogicalMin | ELogicalMax | EReportSize | EReportCount;
-
-const TUint32 CParser::KReportItemMask = EInputReport |
- EOutputReport | EFeatureReport;
-
-
-// Reserved values as per the HUT document 1.11, [3]:
-// This ranges are reserverd in future use.
-
-const TInt KReservedUsage = 0x0e;
-const TInt KReservedUsageRange1Min = 0x11;
-const TInt KReservedUsageRange1Max = 0x13;
-const TInt KReservedUsageRange2Min = 0x15;
-const TInt KReservedUsageRange2Max = 0x3f;
-const TInt KReservedUsageRange3Min = 0x41;
-const TInt KReservedUsageRange3Max = 0x7f;
-const TInt KReservedUsageRange4Min = 0x88;
-const TInt KReservedUsageRange4Max = 0x8b;
-const TInt KReservedUsageRange5Min = 0x92;
-const TInt KReservedUsageRange5Max = 0xfeff;
-
-// ======== MEMBER FUNCTIONS ========
-
-// ---------------------------------------------------------------------------
-// NewLC()
-// ---------------------------------------------------------------------------
-//
-EXPORT_C CParser* CParser::NewLC()
- {
- CParser* self = new (ELeave) CParser;
- CleanupStack::PushL(self);
- self->ConstructL();
- return self;
- }
-
-// ---------------------------------------------------------------------------
-// NewL()
-// ---------------------------------------------------------------------------
-//
-EXPORT_C CParser* CParser::NewL()
- {
- CParser* self = NewLC();
- CleanupStack::Pop();
- return self;
- }
-
-// ---------------------------------------------------------------------------
-// ConstructL()
-// ---------------------------------------------------------------------------
-//
-void CParser::ConstructL()
- {
- TRACE_FUNC_THIS
- iLocal = CField::NewL();
- }
-
-// ---------------------------------------------------------------------------
-// Constructor
-// ---------------------------------------------------------------------------
-//
-CParser::CParser():
- iFieldCount(0)
- {
- TRACE_FUNC_THIS
- }
-
-// ---------------------------------------------------------------------------
-// Destructor
-// ---------------------------------------------------------------------------
-//
-CParser:: ~CParser()
- {
- TRACE_FUNC_THIS
-
- // Free all RArray storage:
- iGlobalStack.Reset();
-
-
- // Although iCollectionStack is an RPointerArray, we aren't doing
- // a ResetAndDestroy() here, as all the collections are owned by
- // the report root object, iReportRoot:
- iCollectionStack.Reset();
-
- delete iReportRoot;
- delete iLocal;
- }
-
-// ---------------------------------------------------------------------------
-// CreateCollectionL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CreateCollectionL(TUint32 aType)
- {
- TInt err = CheckForCollectionErrors(aType);
-
- if (err == KErrNone)
- {
- CCollection* collection = Collection()->AddCollectionL(); // Created collection added
- // Collection's collection array
- collection->SetType(aType);
- collection->SetUsagePage(iGlobal.iUsagePage);
- collection->SetUsage(iLocal->LastUsage());
- PushCollectionL(collection);
- }
- return err;
- }
-
-// ---------------------------------------------------------------------------
-// CheckForMainErrors()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckForMainErrors()
- {
- if ( ( iItemsDefined & ELogicalMin ) && ( iItemsDefined & ELogicalMax ) )
- {
- if ( iGlobal.iLogicalMin > iGlobal.iLogicalMax )
- {
- IssueWarning( ELogicalMinExceedsMax );
- }
- }
- if ( iItemsDefined & (EPhysicalMin | EPhysicalMax ) )
- {
- if ( !( iItemsDefined & EPhysicalMax ) )
- {
- return ELonelyPhysicalMin;
- }
- if (!( iItemsDefined & EPhysicalMin ))
- {
- return ELonelyPhysicalMax;
- }
-
- if ( iGlobal.iPhysicalMin > iGlobal.iPhysicalMax )
- {
- IssueWarning(EPhysicalMinExceedsMax);
- }
- }
- return KErrNone;
- }
-
-// ---------------------------------------------------------------------------
-// CheckForCollectionErrors()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckForCollectionErrors(TUint32 aType)
- {
- if (iCollectionStack.Count() == 0 )
- {
- return ENoCollectionToCheck;
- }
-
- if (aType > KMaxStandardType)
- {
- if ((aType < KMinVendorType) || (aType > KMaxVendorType))
- {
- IssueWarning( ECollectionTypeUnknownReserved );
- }
- }
-
- if ( iItemsDefined & KUnusedLocalItemsMask )
- {
- IssueWarning( ECollectionLocalUnused );
- }
-
- TInt numUsages = iLocal->UsageCount();
-
- if ( numUsages > 1 )
- {
- // Only a single usage value can be associated with a collection:
- IssueWarning( ECollectionLocalUnused );
- }
-
- if ( numUsages == 0 )
- {
- // A usage tag must be associated with a collection (see [1],
- // Section 6.2.2.6):
- IssueWarning( ECollectionHasNoUsage );
- }
-
- if ( !( iItemsDefined & EUsagePage ) )
- {
- // A usage page must be associated with a collection (see [1],
- // Section 6.2.2.6):
- IssueWarning( ECollectionHasNoUsagePage );
- }
-
- if (( aType == CCollection::EApplication ) && ( iItemsDefined & EDelimiter ))
- {
- // Delimiters can't be used when defining usages that apply to
- // Application Collections ([1], Section 6.2.2.8):
- IssueWarning(EApplicationHasDelimiter);
-
- // It is an error to declare a delimiter for a top-level
- // application collection, [2]:
- if (iCollectionStack.Count() == 1)
- {
- return EDelimiterAtTopLevel;
- }
- }
- return CheckForMainErrors();
- }
-
-
-// ---------------------------------------------------------------------------
-// CheckForFieldErrors()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckForFieldErrors(CField::TType aType, TUint32 aAttributes)
- {
- TInt ret = KErrNone;
- ret = CheckMandatoryFieldErrors(aType, aAttributes);
- if ( ret != KErrNone )
- {
- return ret;
- }
-
- const TInt KLimitsError[] =
- { EInputMinExceedsMax, EOutputMinExceedsMax, EFeatureMinExceedsMax };
-
- if ( iGlobal.iLogicalMin > iGlobal.iLogicalMax )
- {
- return KLimitsError[aType];
- }
-
- if ( ( iItemsDefined & ( EPhysicalMin | EPhysicalMax ) )
- && ( iGlobal.iPhysicalMin > iGlobal.iPhysicalMax ))
- {
- return KLimitsError[aType];
- }
- CheckLogicalMinAndMax( aAttributes );
- CheckFieldBitNeeded( aType, aAttributes );
- return CheckForMainErrors();
- }
-
-
-// ---------------------------------------------------------------------------
-// BitsToRepresentRange()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::BitsToRepresentRange(TInt aMin, TInt aMax)
- {
- // The number of bits required to represent all values in the
- // range aMin to aMax inclusive. If the range is all positive
- // then there is no sign bit, otherwise twos complement format is
- // assumed. ([1], Section 6.2.2.7.)
-
- TInt bitsNeeded = 0;
-
- if (aMin != aMax)
- {
- TUint absVal = static_cast<TUint>(Max(Abs(aMin), Abs(aMax)));
-
- bitsNeeded = K32Bit - NumberOfLeadingZeros(absVal);
-
- // If either are negative, we'll need space for the sign bit:
- //
- if ((aMax < 0) || (aMin < 0))
- {
- bitsNeeded++;
-
- // However, 2s complement allows us to represent one extra
- // negative number than positive, and so our calculation
- // may be one bit over. Catch this with a special case:
- //
- if (bitsNeeded > 1)
- {
- TInt n = 1 << (bitsNeeded - 2);
- if ((aMin == -n) && (aMax < n))
- {
- bitsNeeded--;
- }
- }
- }
- }
-
- return bitsNeeded;
- }
-
-// ---------------------------------------------------------------------------
-// NumberOfLeadingZeros()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::NumberOfLeadingZeros(TUint32 aValue)
- {
- TInt count = 0;
-
- TUint32 pos = K32BitFirstBitOn;
- while ((pos != 0) && ((aValue & pos) == 0))
- {
- count++;
- pos >>= 1;
- }
-
- return count;
- }
-
-
-// ---------------------------------------------------------------------------
-// CheckAllReportSizes()
-// ---------------------------------------------------------------------------
-//
-TBool CParser::CheckAllReportSizes() const
- {
- // Final report sizes must be an integral number of bytes, [2]:
-
- TBool sizesOk = ETrue;
-
- for (TInt i=0; sizesOk && (i<iReportRoot->NumberOfReports()); ++i)
- {
- TInt bits = iReportRoot->ReportSize(i);
-
- if ((bits == 0) || ((bits % 8) != 0))
- {
- sizesOk = EFalse;
- }
- }
- return sizesOk;
- }
-
-
-// ---------------------------------------------------------------------------
-// CreateFieldL()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CreateFieldL(CField::TType aType, TUint32 aAttributes)
- {
- TInt err = CheckForFieldErrors( aType, aAttributes );
- //Microsoft Elite 2 keyboard HID bug fix
- if ( err == EInputMissingItems && iGlobal.iUsagePage == 0x07 )
- if ( iLocal->UsageMin( ) == 0xe0 && iLocal->UsageMax( ) == 0xe7 )
- {
- iGlobal.iLogicalMin = 0x0;
- iGlobal.iLogicalMax = 0x1;
- err = KErrNone;
- }
- else
- {
- iGlobal.iLogicalMin = 0x0;
- err = KErrNone;
- }
-
- if (err == KErrNone)
- {
- // Create a new field object:
- CField* field = Collection()->AddFieldL( ); // Created field added
- // to collection's field array
- DumpStateTableL( field );
- field->SetType( aType );
- field->SetAttributes( aAttributes );
-
- // Set the field offset to the current report size, and
- // increase the report size by the size of this field:
- if ( !iReportRoot )
- {
- User::Leave(ENoReportRoot);
- }
- field->SetOffset( iReportRoot->ReportSize( field->ReportId( ), aType) );
- iReportRoot->IncrementReportSizeL( field->ReportId(),
- aType, field->Count() * field->Size() );
- TRACE_INFO(_L("CParser::CreateFieldL Field added"));
- if ( field->UsageCount() )
- {
- iFieldCount++;
- }
- }
- return err;
- }
-
-// ---------------------------------------------------------------------------
-// DumpStateTableL()
-// ---------------------------------------------------------------------------
-//
-void CParser::DumpStateTableL(CField *aField) const
- {
- TRACE_INFO((_L("DumpStateTableL(0x%08x)\n"), aField));
-
- // Copy global state:
- //
- iGlobal.Populate(aField);
-
- // Copy local state:
- //
- aField->SetUsageRange( iLocal->UsageMin(), iLocal->UsageMax() );
- aField->SetDesignatorIndex( iLocal->DesignatorIndex() );
- aField->SetDesignatorRange( iLocal->DesignatorMin(),
- iLocal->DesignatorMax() );
- aField->SetStringIndex( iLocal->StringIndex() );
- aField->SetStringRange( iLocal->StringMin(), iLocal->StringMax() );
-
- // Copy usage list (local state) and calculate the usage range, if
- // it hasn't already been explicitly specified:
- //
- if ( iLocal->UsageCount() > 0 )
- {
- TInt minUsage, maxUsage;
- minUsage = maxUsage = iLocal->Usage( 0 );
-
- for (TInt i=0; i<iLocal->UsageCount(); ++i)
- {
- TInt value = iLocal->Usage( i );
- aField->AddUsageL( value );
- if ( value < minUsage )
- {
- minUsage = value;
- }
- if ( value > maxUsage )
- {
- maxUsage = value;
- }
- }
- if ( (iItemsDefined & (EUsageMin | EUsageMax) ) == 0)
- {
- aField->SetUsageRange( minUsage, maxUsage );
- }
- }
- }
-
-
-// ---------------------------------------------------------------------------
-// Collection()
-// ---------------------------------------------------------------------------
-//
-CCollection* CParser::Collection()
- {
- CCollection* lastcollection = NULL;
- if ( iCollectionStack.Count( ) > 0 )
- {
- lastcollection = iCollectionStack[ iCollectionStack.Count() - 1 ];
- }
- return lastcollection;
- }
-
-// ---------------------------------------------------------------------------
-// PushCollectionL()
-// ---------------------------------------------------------------------------
-//
-void CParser::PushCollectionL(const CCollection* aCollection)
- {
- User::LeaveIfError( iCollectionStack.Append( aCollection ) );
- }
-
-// ---------------------------------------------------------------------------
-// PopCollection()
-// ---------------------------------------------------------------------------
-//
-void CParser::PopCollection()
- {
-
- if ( iCollectionStack.Count() > 0 )
- {
- iCollectionStack.Remove( iCollectionStack.Count() - 1 );
- }
- }
-
-
-// ---------------------------------------------------------------------------
-// IssueWarning()
-// ---------------------------------------------------------------------------
-//
-void CParser::IssueWarning(TInt aHidWarningCode)
- {
- TRACE_ERROR((_L("Item %3d: Warning 0x%04x\n"), iItemNumber, aHidWarningCode));
- (void)aHidWarningCode;
- }
-
-// ---------------------------------------------------------------------------
-// ParseL()
-// ---------------------------------------------------------------------------
-//
-EXPORT_C CReportRoot* CParser::ParseL(const TDesC8& aRawData)
- {
- ResetParserL();
- // Now we can parse the descriptor data:
- const TInt length = aRawData.Length();
- TInt posn = 0;
- TRACE_INFO((_L("CParser::ParseL() Start parsing length %d"), length));
- while ((posn < length) && (iErrorCode == 0))
- {
- iItemNumber++;
- TRACE_INFO((_L("posn is %d"), posn));
-
- TItem item(aRawData.Right(length-posn));
-
-#ifdef PDBG_ACTIVE
- TRACE_INFO((_L("Item: size %d, tag %d, type %d\n"),
- item.DataSize(), item.Tag(), item.Type()));
- for (TInt i=0; i<item.DataSize(); ++i)
- {
- TRACE_INFO((_L(" Data[%d] = 0x%02x (%d)\n"),
- i, item[i], item[i]))
- }
-#endif
-
- HandleItemL( item );
- posn += item.ItemSize();
- if (posn > length)
- {
- iErrorCode = EInvalidItemLength;
- }
- }
-
- PopCollection();
-
- // PUSH without POP:
- CheckParseErrors();
-
- iGlobalStack.Reset();
- iCollectionStack.Reset();
-
- TRACE_INFO((_L("CParser::ParseL() error code is %d"), iErrorCode));
- // Finished, transfer ownership to caller:
- CReportRoot* reportRoot = iReportRoot;
- iReportRoot = 0;
- return reportRoot;
- }
-
-// ---------------------------------------------------------------------------
-// CParser::FieldCount()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::FieldCount()
- {
- return iFieldCount;
- }
-
-// ---------------------------------------------------------------------------
-// CParser::MainItemL()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::MainItemL(const TItem& aItem)
- {
- TInt retVal = 0;
-
- switch (aItem.Tag())
- {
- case EMainInput:
- retVal = HandleMainInputTagL( aItem );
- break;
-
- case EMainOutput:
- retVal = HandleMainOutputTagL( aItem );
- break;
-
- case EMainFeature:
- retVal = HandleMainFeatureL( aItem );
- break;
-
- case EMainCollection:
- retVal = HandleMainCollectionL( aItem );
- break;
-
- case EMainEndCollection:
- retVal = HandleMainEndCollection( aItem );
- break;
- default:
- TRACE_ERROR(_L("Error: unknown main item\n"));
- retVal = EUnknownItem;
- break;
- }
-
- // All main items cause local state to be cleared:
- ClearLocalState();
-
- // For checking if global items declared more than once between
- // main items:
- iGlobalItemsDefined = 0;
-
- return retVal;
- }
-// ---------------------------------------------------------------------------
-// ClearLocalState()
-// ---------------------------------------------------------------------------
-//
-void CParser::ClearLocalState()
- {
- iLocal->ClearUsageList();
- iLocal->SetUsageRange(0, 0);
- iLocal->SetStringIndex(0);
- iLocal->SetStringRange(0, 0);
- iLocal->SetDesignatorIndex(0);
- iLocal->SetDesignatorRange(0, 0);
-
- iItemsDefined &= ~(KLocalItemMask | EDelimiter);
- iLocalMultipleUse = EFalse;
- }
-
-// ---------------------------------------------------------------------------
-// GlobalItemL()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::GlobalItemL(const TItem& aItem)
- {
- TInt retVal = 0;
- switch (aItem.Tag())
- {
- case EGlobalReportId:
- retVal = HandleGlobalReportId( aItem );
- break;
- case EGlobalUsagePage:
- retVal = HandleGlobalUsagePage( aItem );
- break;
- case EGlobalLogicalMinimum:
- retVal = HandleGlobalLogicalMinimum( aItem );
- break;
- case EGlobalLogicalMaximum:
- retVal = HandleGlobalLogicalMaximum( aItem );
- break;
- case EGlobalPhysicalMinimum:
- retVal = HandleGlobalPhysicalMinimum( aItem );
- break;
- case EGlobalPhysicalMaximum:
- retVal = HandleGlobalPhysicalMaximum( aItem );
- break;
- case EGlobalUnit:
- retVal = HandleGlobalUnit( aItem );
- break;
- case EGlobalUnitExponent:
- retVal = HandleGlobalUnitExponent( aItem );
- break;
- case EGlobalReportSize:
- retVal = HandleGlobalReportSize( aItem );
- break;
- case EGlobalReportCount:
- retVal = HandleGlobalReportCount(aItem );
- break;
- case EGlobalPush:
- retVal = HandleGlobalPushL( aItem );
- break;
- case EGlobalPop:
- retVal = HandleGlobalPop( aItem );
- break;
- default:
- TRACE_ERROR(_L("Error: unknown global item\n"));
- retVal = EUnknownItem;
- break;
- }
-
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// LocalItemL()
-// ---------------------------------------------------------------------------
-//
-TInt CParser::LocalItemL(const TItem& aItem)
- {
- TInt retVal = 0;
- switch (aItem.Tag())
- {
- case ELocalUsage:
- retVal = HandleLocalUsageL( aItem );
- break;
- case ELocalUsageMinimum:
- retVal = HandleLocalUsageMinimum( aItem );
- break;
- case ELocalUsageMaximum:
- retVal = HandleLocalUsageMaximum( aItem );
- break;
- case ELocalDesignatorIndex:
- retVal = HandleLocalDesignatorIndex( aItem );
- break;
- case ELocalDesignatorMinimum:
- retVal = HandleLocalDesignatorMinimum( aItem );
- break;
- case ELocalDesignatorMaximum:
- retVal = HandleLocalDesignatorMaximum( aItem );
- break;
- case ELocalStringIndex:
- retVal = HandleLocalStringIndex( aItem );
- break;
- case ELocalStringMinimum:
- retVal = HandleLocalStringMinimum( aItem );
- break;
- case ELocalStringMaximum:
- retVal = HandleLocalStringMaximum( aItem );
- break;
- // "HID parsers must handle Delimiters however, the support
- // for the alternative usages that they define is optional.
- // Usages other than the first (most preferred) usage defined
- // may not be made accessible by system software.", [1],
- // Section 6.2.2.8.
- //
- // This parser only supports the first usage in a delimiter list.
- case ELocalDelimiter:
- retVal = HandleLocalDelimiter( aItem );
- break;
- default:
- TRACE_ERROR(_L("Error: unknown local item\n"));
- retVal = EUnknownItem;
- break;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// IsReservedUsagePage()
-// ---------------------------------------------------------------------------
-//
-TBool CParser::IsReservedUsagePage(TInt aId)
- {
- return (aId == KReservedUsage) ||
- ((aId >= KReservedUsageRange1Min ) && (aId <= KReservedUsageRange1Max)) ||
- ((aId >= KReservedUsageRange2Min ) && (aId <= KReservedUsageRange2Max)) ||
- ((aId >= KReservedUsageRange3Min) && (aId <= KReservedUsageRange3Max)) ||
- ((aId >= KReservedUsageRange4Min ) && (aId <= KReservedUsageRange4Max)) ||
- ((aId >= KReservedUsageRange5Min) && (aId <= KReservedUsageRange5Max));
- }
-
-// ---------------------------------------------------------------------------
-// Populate()
-// ---------------------------------------------------------------------------
-//
-void TParserGlobalState::Populate(CField *aField) const
- {
- aField->SetUsagePage(iUsagePage);
- aField->SetReportId(iReportId);
- aField->SetLogicalRange(iLogicalMin, iLogicalMax);
- aField->SetSize(iSize);
- aField->SetCount(iCount);
- aField->SetUnit(iUnit);
- aField->SetUnitExponent(iUnitExponent);
-
- // If the physical min and max are both zero, then the HID class
- // document specifies that they should be assumed to be equal to
- // the corresponding logical values ([1], Section 6.2.2.7):
- //
- if ((iPhysicalMin == 0) && (iPhysicalMax == 0))
- {
- aField->SetPhysicalRange(iLogicalMin, iLogicalMax);
- }
- else
- {
- aField->SetPhysicalRange(iPhysicalMin, iPhysicalMax);
- }
- }
-
-
-// ---------------------------------------------------------------------------
-// TParserGlobalState()
-// ---------------------------------------------------------------------------
-//
-TParserGlobalState::TParserGlobalState()
- : iUsagePage(0), iLogicalMin(0), iLogicalMax(0),
- iPhysicalMin(0), iPhysicalMax(0), iUnit(0),
- iUnitExponent(0), iReportId(0), iSize(0), iCount(0)
- {
- // Nothing else to do
- }
-
-// ---------------------------------------------------------------------------
-// HandleMainInputTagL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleMainInputTagL(const TItem& aItem)
- {
- // Section 6.2.2.4 of the HID class specification, [1],
- // states that an Input item may have a data size of zero
- // bytes:
- //
- // "In this case the value of each data bit for the item
- // can be assumed to be zero. This is functionally
- // identical to using a item tag that specifies a 4-byte
- // data item followed by four zero bytes."
- //
- // For a data size of zero, TItem::Data() will return zero
- // and so we will get the required behaviour.
- TRACE_INFO((_L("Input %d\n"), aItem.Data()));
- TInt retVal=0;
-
- iItemsDefined |= EInputReport;
-
- if ( aItem.Data() & KInputReservedBitsMask )
- {
- IssueWarning( EInputReservedBitsNonZero );
- }
- if ( iLocalMultipleUse )
- {
- IssueWarning( EInputLocalMultipleUse );
- }
- if ( iWithinDelimiter )
- {
- retVal = EInputItemWithinDelimiter;
- }
- else
- {
- retVal = CreateFieldL( CField::EInput, aItem.Data() );
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleMainOutputTagL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleMainOutputTagL(const TItem& aItem)
- {
- TRACE_INFO((_L("Output %d\n"), aItem.Data()));
- TInt retVal=0;
- iItemsDefined |= EOutputReport;
-
- if ( aItem.Data() & KOutputReservedBitsMask )
- {
- IssueWarning( EOutputReservedBitsNonZero );
- }
-
- if ( iLocalMultipleUse )
- {
- IssueWarning( EOutputLocalMultipleUse );
- }
-
- if ( iWithinDelimiter )
- {
- retVal = EOutputItemWithinDelimiter;
- }
- else
- {
- retVal = CreateFieldL( CField::EOutput, aItem.Data() );
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleMainFeatureL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleMainFeatureL( const TItem& aItem )
- {
- TRACE_INFO((_L("Feature %d\n"), aItem.Data()));
- TInt retVal=0;
- iItemsDefined |= EFeatureReport;
-
- if ( aItem.Data() & KFeatureReservedBitsMask )
- {
- IssueWarning(EFeatureReservedBitsNonZero );
- }
-
- if ( iLocalMultipleUse )
- {
- IssueWarning( EFeatureLocalMultipleUse );
- }
-
- if ( iWithinDelimiter )
- {
- retVal = EFeatureItemWithinDelimiter;
- }
- else
- {
- retVal = CreateFieldL( CField::EFeature, aItem.Data() );
- }
-
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleMainCollectionL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleMainCollectionL( const TItem& aItem )
- {
- TRACE_INFO((_L("Start collection %d\n"), aItem.Data()));
- TInt retVal = 0;
-
- if ( iWithinDelimiter )
- {
- retVal = EBeginCollectionWithinDelimiter;
- }
- else
- {
- // Application collections can only be declared at
- // top-level:
- if ((aItem.Data() == CCollection::EApplication) &&
- (iCollectionStack.Count() != 1))
- {
- retVal = EApplicationCollectionLevel;
- }
- else
- {
- retVal = CreateCollectionL(aItem.Data());
- }
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleMainEndCollection
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleMainEndCollection( const TItem& aItem )
- {
- TRACE_INFO((_L("Start collection %d\n"), aItem.Data()));
- TInt retVal = 0;
-
- if (aItem.DataSize() != 0)
- {
- IssueWarning(EEndCollectionHasData);
- }
-
- if (iItemsDefined & KLocalItemMask)
- {
- IssueWarning(EEndCollectionLocalUnused);
- }
-
- if (iCollectionStack.Count() > 1)
- {
- PopCollection();
- }
- else
- {
- retVal = ENoMatchingBeginCollection;
- }
-
- if (iWithinDelimiter)
- {
- retVal = EEndCollectionWithinDelimiter;
- }
-
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalReportId
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalReportId( const TItem& aItem )
- {
- TRACE_INFO((_L("Global report ID %d\n"), aItem.Data()));
- TInt retVal = 0;
- TUint reportId = aItem.Data();
-
- if (reportId == 0)
- {
- retVal = EZeroReportId;
- }
- if (reportId > KMaxReportIDMax)
- {
- retVal = EReportIdTooBig;
- }
-
- // If there are to be any report IDs specified at all,
- // then a report ID must be defined before the first
- // input, output or feature report:
- //
- if ((iGlobal.iReportId == 0) && (iItemsDefined & KReportItemMask))
- {
- retVal = ELateReportId;
- }
-
- // Report ID defined outside a top level collection (Microsoft
- // restriction)
- //
- if (iCollectionStack.Count() == 1)
- {
- retVal = EReportIdOutsideTopLevel;
- }
-
- // Same item shouldn't have been declared since last main item:
- //
- if (iGlobalItemsDefined & EReportId)
- {
- // This is an error according to [2], but as it isn't
- // a critical problem, and as some real-world devices
- // fail this check, we issue a warning instead:
- IssueWarning(ERedundantGlobalItem);
- }
- iGlobalItemsDefined |= EReportId;
-
- iItemsDefined |= EReportId;
- iGlobal.iReportId = reportId;
-
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalUsagePage
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalUsagePage( const TItem& aItem )
- {
- TRACE_INFO((_L("Global usage page %d\n"), aItem.Data()));
- TInt retVal = 0;
-
- iGlobal.iUsagePage = aItem.Data();
-
- if (aItem.Data() == 0)
- {
- retVal = EZeroUsagePage;
- }
-
- if (aItem.Data() > KMaxUsagePage)
- {
- retVal = EUsagePageOutOfRange;
- }
-
- if (IsReservedUsagePage(aItem.Data()))
- {
- IssueWarning(EReservedUsagePage);
- }
-
- iItemsDefined |= EUsagePage;
-
- if (iGlobalItemsDefined & EUsagePage)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EUsagePage;
-
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalLogicalMinimum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalLogicalMinimum( const TItem& aItem )
- {
- TRACE_INFO((_L("Global logical min %d\n"), aItem.SignedData()));
- TInt retVal = 0;
- iGlobal.iLogicalMin = aItem.SignedData();
- iItemsDefined |= ELogicalMin;
-
- if (iGlobalItemsDefined & ELogicalMin)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= ELogicalMin;
-
- // "Until Physical Minimum and Physical Maximum are
- // declared in a report descriptor they are assumed by the
- // HID parser to be equal to Logical Minimum and Logical
- // Maximum, respectively.", [1], Section 6.2.2.7.
- //
- if (!(iItemsDefined & EPhysicalMin))
- {
- iGlobal.iPhysicalMin = aItem.SignedData();
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalLogicalMaximum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalLogicalMaximum( const TItem& aItem )
- {
- TRACE_INFO((_L("Global logical max %d\n"), aItem.SignedData()));
- TInt retVal = 0;
-
- iGlobal.iLogicalMax = aItem.SignedData();
- if ( !(iItemsDefined & EPhysicalMax) )
- {
- iGlobal.iPhysicalMax = aItem.SignedData();
- }
- iItemsDefined |= ELogicalMax;
-
- if (iGlobalItemsDefined & ELogicalMax)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= ELogicalMax;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalPhysicalMinimum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalPhysicalMinimum( const TItem& aItem )
- {
- TRACE_INFO((_L("Global physical min %d\n"), aItem.SignedData()));
- TInt retVal = 0;
- iGlobal.iPhysicalMin = aItem.SignedData();
- iItemsDefined |= EPhysicalMin;
-
- if (iGlobalItemsDefined & EPhysicalMin)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EPhysicalMin;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalPhysicalMaximum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalPhysicalMaximum( const TItem& aItem )
- {
- TRACE_INFO((_L("Global physical max %d\n"), aItem.SignedData()));
-
- TInt retVal = 0;
- iGlobal.iPhysicalMax = aItem.SignedData();
- iItemsDefined |= EPhysicalMax;
-
- if ( iGlobalItemsDefined & EPhysicalMax )
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EPhysicalMax;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalUnit
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalUnit( const TItem& aItem )
- {
- TRACE_INFO((_L("Global unit %d\n"), aItem.Data()));
- TInt retVal = 0;
- iGlobal.iUnit = aItem.Data();
- iItemsDefined |= EUnit;
-
- if (iGlobalItemsDefined & EUnit)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EUnit;
-
- TInt unitSystem = aItem.Data() & KUnitData;
- if (((unitSystem >= KUnitSystemMin ) && (unitSystem != KUnitSystem15)) ||
- (aItem.Data() & KUnitReservedBitsMask ))
- {
- IssueWarning(EUnitReservedBitsNonZero);
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalUnitExponent
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalUnitExponent( const TItem& aItem )
- {
- TRACE_INFO((_L("Global unit exponent %d\n"), aItem.Data()));
- TInt retVal = 0;
- iGlobal.iUnitExponent = aItem.Data();
- iItemsDefined |= EUnitExponent;
-
- if (iGlobalItemsDefined & EUnitExponent)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EUnitExponent;
- const TUint32 KReservedBits = ~0x0fUL;
- if (aItem.Data() & KReservedBits)
- {
- IssueWarning( EExponentReservedBitsNonZero );
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalReportSize
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalReportSize( const TItem& aItem )
- {
- TRACE_INFO((_L("Global report size %d\n"), aItem.Data()));
- TInt retVal = 0;
- iGlobal.iSize = aItem.Data();
- iItemsDefined |= EReportSize;
-
- if (iGlobalItemsDefined & EReportSize)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EReportSize;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalReportCount
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalReportCount( const TItem& aItem )
- {
- TRACE_INFO((_L("Global report count %d\n"), aItem.Data()));
- TInt retVal = 0;
- iGlobal.iCount = aItem.Data();
- if (aItem.Data() == 0)
- {
- retVal = EZeroReportCount;
- }
- iItemsDefined |= EReportCount;
-
- if (iGlobalItemsDefined & EReportCount)
- {
- retVal = ERedundantGlobalItem;
- }
- iGlobalItemsDefined |= EReportCount;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalPushL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalPushL( const TItem& aItem )
- {
- TRACE_INFO(_L("Global push\n"));
- TInt retVal = 0;
- if (aItem.DataSize() != 0)
- {
- retVal = EPushHasData;
- }
- User::LeaveIfError(iGlobalStack.Append(iGlobal));
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleGlobalPop
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleGlobalPop( const TItem& aItem )
- {
- TRACE_INFO(_L("Global pop\n"));
- TInt retVal = 0;
- if (aItem.DataSize() != 0)
- {
- retVal = EPopHasData;
- }
-
- if (iGlobalStack.Count() > 0)
- {
- iGlobal = iGlobalStack[iGlobalStack.Count()-1];
- iGlobalStack.Remove(iGlobalStack.Count()-1);
- }
- else
- {
- retVal = EPopWithoutPush;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalUsageL
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalUsageL( const TItem& aItem )
- {
- TRACE_INFO((_L("Local usage %d\n"), aItem.Data()));
- TInt retVal = 0;
-
- if (aItem.DataSize() == KExtendedDataSize )
- {
- // Extended (32-bit) usage:
- TInt usagePage = (aItem.Data() >> KExtendedDataShift);
- if (IsReservedUsagePage(usagePage))
- {
- IssueWarning(EReservedUsagePage);
- }
- }
-
- if ((aItem.Data() & 0xffff) == 0)
- {
- IssueWarning(EZeroUsage);
- }
-
- if (!iWithinDelimiter || (iAliasCount++ == 0))
- {
- iLocal->AddUsageL(aItem.Data());
- iItemsDefined |= EUsageId;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalUsageMinimum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalUsageMinimum( const TItem& aItem )
- {
- TRACE_INFO((_L("Local usage min %d\n"), aItem.Data()));
- TInt retVal = 0;
- if (!iWithinDelimiter || (iAliasCountMin++ == 0))
- {
- TInt usagePage = iGlobal.iUsagePage;
-
- if (aItem.DataSize() == KExtendedDataSize )
- {
- // Extended usage specified.
- usagePage = aItem.Data() >> KExtendedDataShift;
- }
-
- if (iItemsDefined & EUsageMax)
- {
- TInt maxPage =
- static_cast<TUint32>(iLocal->UsageMax()) >> KExtendedDataShift;
- if (maxPage == 0)
- {
- maxPage = iGlobal.iUsagePage;
- }
- if (usagePage != maxPage)
- {
- retVal = EUsagePageMismatchMin;
- }
- }
- iLocal->SetUsageMin(aItem.Data());
- }
- if (iItemsDefined & EUsageMin)
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EUsageMin;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalUsageMaximum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalUsageMaximum( const TItem& aItem )
- {
- TRACE_INFO((_L("Local usage max %d\n"), aItem.Data()));
-
- TInt retVal = 0;
-
- if (!iWithinDelimiter || (iAliasCountMax++ == 0))
- {
- TInt usagePage = iGlobal.iUsagePage;
-
- if (aItem.DataSize() == KExtendedDataSize )
- {
- // Extended usage specified.
- usagePage = aItem.Data() >> KExtendedDataShift;
- }
- if (iItemsDefined & EUsageMin)
- {
- TInt minPage =
- static_cast<TUint32>(iLocal->UsageMin()) >> KExtendedDataShift;
- if (minPage == 0)
- {
- minPage = iGlobal.iUsagePage;
- }
- if (usagePage != minPage)
- {
- retVal = EUsagePageMismatchMax;
- }
- }
- iLocal->SetUsageMax(aItem.Data());
- }
- if (iItemsDefined & EUsageMax)
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EUsageMax;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalDesignatorIndex
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalDesignatorIndex( const TItem& aItem )
- {
- TRACE_INFO((_L("Local designator index %d\n"),
- aItem.Data()));
- TInt retVal = 0;
- iLocal->SetDesignatorIndex(aItem.Data());
- if (iWithinDelimiter)
- {
- retVal = EInvalidItemWithinDelimiter;
- }
- if (iItemsDefined & EDesignatorIndex)
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EDesignatorIndex;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalDesignatorMinimum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalDesignatorMinimum( const TItem& aItem )
- {
- TRACE_INFO((_L("Local designator min %d\n"), aItem.Data()));
- TInt retVal = 0;
- iLocal->SetDesignatorMin(aItem.Data());
- if ( iWithinDelimiter )
- {
- retVal = EInvalidItemWithinDelimiter;
- }
- if (iItemsDefined & EDesignatorMin)
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EDesignatorMin;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalDesignatorMaximum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalDesignatorMaximum( const TItem& aItem )
- {
- TRACE_INFO((_L("Local designator max %d\n"), aItem.Data()));
- TInt retVal = 0;
- iLocal->SetDesignatorMax(aItem.Data());
- if ( iWithinDelimiter )
- {
- retVal = EInvalidItemWithinDelimiter;
- }
- if ( iItemsDefined & EDesignatorMax )
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EDesignatorMax;
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalStringIndex
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalStringIndex( const TItem& aItem )
- {
- TRACE_INFO((_L("Local string index %d\n"), aItem.Data()));
- TInt retVal = 0;
- iLocal->SetStringIndex(aItem.Data());
- if ( iItemsDefined & EStringIndex )
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EStringIndex;
- if ( iWithinDelimiter )
- {
- retVal = EInvalidItemWithinDelimiter;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalStringMinimum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalStringMinimum( const TItem& aItem )
- {
- TRACE_INFO((_L("Local string min %d\n"),
- aItem.Data()));
- TInt retVal = 0;
- iLocal->SetStringMin(aItem.Data());
- if ( iItemsDefined & EStringMin)
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EStringMin;
- if (iWithinDelimiter)
- {
- retVal = EInvalidItemWithinDelimiter;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalStringMaximum
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalStringMaximum( const TItem& aItem )
- {
- TRACE_INFO((_L("Local string max %d\n"),
- aItem.Data()));
- TInt retVal = 0;
- iLocal->SetStringMax(aItem.Data());
- if ( iItemsDefined & EStringMax )
- {
- iLocalMultipleUse = ETrue;
- }
- iItemsDefined |= EStringMax;
- if ( iWithinDelimiter )
- {
- retVal = EInvalidItemWithinDelimiter;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// HandleLocalDelimiter
-// ---------------------------------------------------------------------------
-//
-TInt CParser::HandleLocalDelimiter( const TItem& aItem )
- {
- const TInt KBeginDelimiter = 1;
- const TInt KEndDelimiter = 0;
- TInt retVal = 0;
-
- switch ( aItem.Data() )
- {
- case KBeginDelimiter:
- if ( iWithinDelimiter )
- {
- retVal = ENestedDelimiter;
- }
- // Delimiters can't be used when defining usages
- // that apply to array items ([1], Section 6.2.2.8):
- //
- if ( Collection()->Type() == CCollection::ENamedArray )
- {
- IssueWarning( EDelimiterWithinNamedArray );
- }
- iWithinDelimiter = ETrue;
- iAliasCount = 0;
- iAliasCountMin = 0;
- iAliasCountMax = 0;
- break;
-
- case KEndDelimiter:
- if ( !iWithinDelimiter )
- {
- retVal = ELonelyDelimiter;
- }
- iWithinDelimiter = EFalse;
- break;
-
- default:
- retVal = EUnknownDelimiter;
- TRACE_ERROR((_L("Error: Unknown delimiter type %d\n"),
- aItem.Data()));
- break;
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// CheckMandatoryFieldExistence
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckMandatoryFieldExistence( CField::TType aType, TUint32 aAttributes )
- {
- TInt retVal = KErrNone;
-
- if ( ( ( iItemsDefined & KMandatoryItemMask ) != KMandatoryItemMask )
- && (!(aAttributes & KConstantFlag)))
- {
- if ( aType == CField::EInput )
- {
- retVal = EInputMissingItems;
- }
- if ( aType == CField::EOutput )
- {
- retVal = EOutputMissingItems;
- }
- if ( aType == CField::EFeature )
- {
- retVal = EFeatureMissingItems;
- }
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// CheckUsageMinAndMaxErrors
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckUsageMinAndMaxErrors()
- {
- TInt retVal = KErrNone;
-
- if ( iItemsDefined & ( EUsageMin | EUsageMax ))
- {
- if (!( iItemsDefined & EUsageMax ))
- {
- retVal = ELonelyUsageMin;
- }
- if (!( iItemsDefined & EUsageMin ))
- {
- retVal = ELonelyUsageMax;
- }
- if ( iLocal->UsageMin() > iLocal->UsageMax() )
- {
- retVal = EUsageMinExceedsMax;
- }
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// CheckDesignatorMinAndMaxErrors
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckDesignatorMinAndMaxErrors()
- {
- TInt retVal = KErrNone;
-
- if ( iItemsDefined & ( EDesignatorMin | EDesignatorMax ))
- {
- if ( !( iItemsDefined & EDesignatorMax ) )
- {
- retVal = ELonelyDesignatorMin;
- }
- if ( !( iItemsDefined & EDesignatorMin ) )
- {
- retVal = ELonelyDesignatorMax;
- }
- if ( iLocal->DesignatorMin( ) > iLocal->DesignatorMax( ) )
- {
- retVal = EDesignatorMinExceedsMax;
- }
- }
- return retVal;
- }
-
-// ---------------------------------------------------------------------------
-// CheckStringMinAndMaxErrors
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckStringMinAndMaxErrors()
- {
- TInt retVal = KErrNone;
-
- if (iItemsDefined & (EStringMin | EStringMax))
- {
- if ( !( iItemsDefined & EStringMax ) )
- {
- retVal = ELonelyStringMin;
- }
- if ( !( iItemsDefined & EStringMin ) )
- {
- retVal = ELonelyStringMax;
- }
- if ( iLocal->StringMin( ) > iLocal->StringMax( ) )
- {
- retVal = EStringMinExceedsMax;
- }
- }
- return retVal;
- }
-
-
-// ---------------------------------------------------------------------------
-// CheckStringMinAndMaxErrors
-// ---------------------------------------------------------------------------
-//
-TInt CParser::CheckMandatoryFieldErrors( CField::TType aType, TUint32 aAttributes )
- {
- TInt ret = KErrNone;
- // Check for mandatory items:
- ret = CheckMandatoryFieldExistence( aType, aAttributes );
- if ( ret != KErrNone )
- {
- return ret;
- }
- ret = CheckUsageMinAndMaxErrors();
- if ( ret != KErrNone )
- {
- return ret;
- }
- ret = CheckDesignatorMinAndMaxErrors();
- if ( ret != KErrNone )
- {
- return ret;
- }
- ret = CheckStringMinAndMaxErrors();
- if ( ret != KErrNone )
- {
- return ret;
- }
- return KErrNone;
- }
-
-// ---------------------------------------------------------------------------
-// CheckLogicalMinAndMax
-// ---------------------------------------------------------------------------
-//
-void CParser::CheckLogicalMinAndMax( TUint32 aAttributes )
- {
- // Logical minimum and maximum must match the number of usage
- // values defined if the Array flag is set (Var=0). (Ignore this
- // check for constant fields)
- //
- if ( !( aAttributes & KVariableFlag ) && ( ! ( aAttributes & KConstantFlag ) ) )
- {
- // Logical minimum must equal 1:
- //
- if ( iGlobal.iLogicalMin != 1 )
- {
- // This is an error according to [2], but we issue a
- // warning instead, as many devices (including the
- // Logitech diNovo keyboard) fail this check:
- IssueWarning( ELogicalMinInvalidForArray );
- }
-
- // Logical maximum must equal the number of defined usages:
- //
- TInt numUsages = iLocal->UsageCount();
- if ( numUsages == 0 )
- {
- numUsages = iLocal->UsageMax( ) - iLocal->UsageMin( ) + 1;
- }
- if ( iGlobal.iLogicalMax != numUsages )
- {
- // Again, we issue a warning rather than an error:
- IssueWarning( ELogicalMaxInvalidForArray );
- }
- }
-
- }
-
-// ---------------------------------------------------------------------------
-// CheckFieldBitNeeded
-// ---------------------------------------------------------------------------
-//
-void CParser::CheckFieldBitNeeded( CField::TType aType, TUint32 aAttributes )
- {
- // "The bit field declared by Report Size must be large enough to
- // hold all values declared by Logical Minimum and Logical
- // Maximum. This includes a sign bit if either are less than
- // 0. Also if the Null flag is set then the field must be capable
- // of reporting all values declared by Logical Minimum and Logical
- // Maximum, and a null value.", [2] (footnote 5).
-
- TInt bitsNeeded = 0;
-
- if ( !( aAttributes & KConstantFlag ) )
- {
- if ( aAttributes & KNullStateFlag )
- {
- // The null state flag is set, so there needs to be at
- // least one extra "out of range" value. This could be
- // below the lowest value or above the highest, whichever
- // will fit better:
- bitsNeeded = Min(
- BitsToRepresentRange(iGlobal.iLogicalMin - 1,
- iGlobal.iLogicalMax),
- BitsToRepresentRange(iGlobal.iLogicalMin,
- iGlobal.iLogicalMax + 1));
- }
- else
- {
- // No null state declared:
- bitsNeeded = BitsToRepresentRange(iGlobal.iLogicalMin,
- iGlobal.iLogicalMax);
- }
- }
-
- if ( iGlobal.iSize < bitsNeeded )
- {
- // The Logitech diNovo is missing a Logical Min and Logical
- // Max pair and so will trigger a range error here. As a
- // workaround, we will treat this as a warning rather than
- // a critical error:
- const TInt KRangeError[] =
- { EInputReportSize, EOutputReportSize, EFeatureReportSize };
- IssueWarning(KRangeError[aType]);
- }
- }
-
-// ---------------------------------------------------------------------------
-// HandleItem
-// ---------------------------------------------------------------------------
-//
-void CParser::HandleItemL( TItem& aItem )
- {
- iErrorCode = EUnknownItem;
- if (aItem.IsLocal())
- {
- iErrorCode = LocalItemL(aItem);
- }
- else
- {
- // Not allowed non-local items within a delimiter pair:
- //
- if ( iWithinDelimiter )
- {
- iErrorCode = EInvalidItemWithinDelimiter;
- }
- else
- {
- if ( aItem.IsMain() )
- {
- iErrorCode = MainItemL(aItem);
- }
-
- if ( aItem.IsGlobal() )
- {
- iErrorCode = GlobalItemL(aItem);
- }
- if ( aItem.IsLong() )
- {
- IssueWarning(ELongItemDefined);
- iErrorCode = 0;
- }
- }
- }
- }
-
-// ---------------------------------------------------------------------------
-// CheckParseErrors()
-// ---------------------------------------------------------------------------
-//
-void CParser::CheckParseErrors()
- {
- if ( !iErrorCode && ( iGlobalStack.Count() > 0) )
- {
- iErrorCode = EPushWithoutPop;
- }
-
- // COLLECTION without END_COLLECTION:
- if ( !iErrorCode && ( iCollectionStack.Count() != 0 ) )
- {
- iErrorCode = ENoMatchingEndCollection;
- }
-
- // DELIMITER(Open) without DELIMITER(Close):
- if ( !iErrorCode && iWithinDelimiter )
- {
- iErrorCode = ELonelyDelimiter;
- }
-
- // Final size of all reports must be a multiple of eight bits:
- if ( !CheckAllReportSizes() )
- {
- IssueWarning( EReportMustBeEightBitMultiple );
- }
- }
-
-// ---------------------------------------------------------------------------
-// ResetParser
-// ---------------------------------------------------------------------------
-//
-void CParser::ResetParserL()
- {
- // Create the root collection, which is the container for all
- // other collections and fields:
- //
- delete iReportRoot; // may exist if there has been a Leave()
- iReportRoot = 0;
- iReportRoot = CReportRoot::NewL();
- iCollectionStack.Reset();
- PushCollectionL(iReportRoot);
-
- // Clear the error code and the warnings list:
- //
- iErrorCode = 0;
-
- // Reset the parser internal state:
- //
- iGlobal = TParserGlobalState();
- iGlobalStack.Reset();
- iWithinDelimiter = EFalse;
- iItemsDefined = 0;
- iGlobalItemsDefined = 0;
- iItemNumber = 0;
- ClearLocalState();
- }
-