diff -r 3dcb815346df -r 4096754ee773 localconnectivityservice/generichid/src/hidparser.cpp --- 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 -#include -#include -#include - -#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(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 && (iNumberOfReports()); ++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; iUsageCount(); ++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 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(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(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(); - } -