mirror of
https://github.com/reactos/reactos.git
synced 2024-08-06 11:24:58 +00:00
1348 lines
38 KiB
C
1348 lines
38 KiB
C
![]() |
/*
|
||
|
* PROJECT: ReactOS HID Parser Library
|
||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||
|
* FILE: lib/drivers/hidparser/parser.c
|
||
|
* PURPOSE: HID Parser
|
||
|
* PROGRAMMERS:
|
||
|
* Michael Martin (michael.martin@reactos.org)
|
||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "parser.h"
|
||
|
|
||
|
static UCHAR ItemSize[4] = { 0, 1, 2, 4 };
|
||
|
|
||
|
VOID
|
||
|
HidParser_DeleteReport(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_REPORT Report)
|
||
|
{
|
||
|
//
|
||
|
// not implemented
|
||
|
//
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HidParser_FreeCollection(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_COLLECTION Collection)
|
||
|
{
|
||
|
//
|
||
|
// not implemented
|
||
|
//
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_AllocateCollection(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_COLLECTION ParentCollection,
|
||
|
IN UCHAR Type,
|
||
|
IN PLOCAL_ITEM_STATE LocalItemState,
|
||
|
OUT PHID_COLLECTION * OutCollection)
|
||
|
{
|
||
|
PHID_COLLECTION Collection;
|
||
|
USAGE_VALUE UsageValue;
|
||
|
|
||
|
//
|
||
|
// first allocate the collection
|
||
|
//
|
||
|
Collection = (PHID_COLLECTION)Parser->Alloc(sizeof(HID_COLLECTION));
|
||
|
if (!Collection)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// init collection
|
||
|
//
|
||
|
Collection->Root = ParentCollection;
|
||
|
Collection->Type = Type;
|
||
|
Collection->StringID = LocalItemState->StringIndex;
|
||
|
Collection->PhysicalID = LocalItemState->DesignatorIndex;
|
||
|
|
||
|
//
|
||
|
// set Usage
|
||
|
//
|
||
|
ASSERT(LocalItemState);
|
||
|
ASSERT(LocalItemState->UsageStack);
|
||
|
|
||
|
if (LocalItemState->UsageStackUsed > 0)
|
||
|
{
|
||
|
//
|
||
|
// usage value from first local stack item
|
||
|
//
|
||
|
UsageValue.u.Extended = LocalItemState->UsageStack[0].u.Extended;
|
||
|
}
|
||
|
else if (LocalItemState->UsageMinimumSet)
|
||
|
{
|
||
|
//
|
||
|
// use value from minimum
|
||
|
//
|
||
|
UsageValue.u.Extended = LocalItemState->UsageMinimum.u.Extended;
|
||
|
}
|
||
|
else if (LocalItemState->UsageMaximumSet)
|
||
|
{
|
||
|
//
|
||
|
// use value from maximum
|
||
|
//
|
||
|
UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
|
||
|
}
|
||
|
else if (Type == COLLECTION_LOGICAL)
|
||
|
{
|
||
|
//
|
||
|
// root collection
|
||
|
//
|
||
|
UsageValue.u.Extended = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// no usage set
|
||
|
//
|
||
|
Parser->Debug("HIDPARSE] No usage set\n");
|
||
|
UsageValue.u.Extended = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// store usage
|
||
|
//
|
||
|
Collection->Usage = UsageValue.u.Extended;
|
||
|
|
||
|
//
|
||
|
// store result
|
||
|
//
|
||
|
*OutCollection = Collection;
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HidParser_ResetParser(
|
||
|
OUT PHID_PARSER Parser)
|
||
|
{
|
||
|
ULONG Index;
|
||
|
PHID_PARSER_CONTEXT ParserContext;
|
||
|
|
||
|
//
|
||
|
// get parser context
|
||
|
//
|
||
|
ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
|
||
|
|
||
|
|
||
|
//
|
||
|
// delete all reports
|
||
|
//
|
||
|
for(Index = 0; Index < ParserContext->ReportCount; Index++)
|
||
|
{
|
||
|
//
|
||
|
// delete report
|
||
|
//
|
||
|
HidParser_DeleteReport(Parser, ParserContext->Reports[Index]);
|
||
|
}
|
||
|
|
||
|
if (ParserContext->ReportCount && ParserContext->Reports)
|
||
|
{
|
||
|
//
|
||
|
// free report array
|
||
|
//
|
||
|
Parser->Free(ParserContext->Reports);
|
||
|
}
|
||
|
|
||
|
if (ParserContext->RootCollection)
|
||
|
{
|
||
|
//
|
||
|
// delete root collection
|
||
|
//
|
||
|
HidParser_FreeCollection(Parser, ParserContext->RootCollection);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// reinit parser
|
||
|
//
|
||
|
ParserContext->ReportCount = 0;
|
||
|
ParserContext->Reports = NULL;
|
||
|
ParserContext->RootCollection = NULL;
|
||
|
ParserContext->UseReportIDs = FALSE;
|
||
|
|
||
|
//
|
||
|
// zero item states
|
||
|
//
|
||
|
Parser->Zero(&ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE));
|
||
|
Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE));
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_AddCollection(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_COLLECTION CurrentCollection,
|
||
|
IN PHID_COLLECTION NewCollection)
|
||
|
{
|
||
|
PHID_COLLECTION * NewAllocCollection;
|
||
|
ULONG CollectionCount;
|
||
|
|
||
|
//
|
||
|
// increment collection array
|
||
|
//
|
||
|
CollectionCount = CurrentCollection->NodeCount + 1;
|
||
|
|
||
|
//
|
||
|
// allocate new collection
|
||
|
//
|
||
|
NewAllocCollection = (PHID_COLLECTION*)Parser->Alloc(sizeof(PHID_COLLECTION) * CollectionCount);
|
||
|
if (!NewAllocCollection)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if (CurrentCollection->NodeCount)
|
||
|
{
|
||
|
//
|
||
|
// copy old array
|
||
|
//
|
||
|
Parser->Copy(NewAllocCollection, CurrentCollection->Nodes, CurrentCollection->NodeCount * sizeof(PHID_COLLECTION));
|
||
|
|
||
|
//
|
||
|
// delete old array
|
||
|
//
|
||
|
Parser->Free(CurrentCollection->Nodes);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// insert new item
|
||
|
//
|
||
|
NewAllocCollection[CurrentCollection->NodeCount] = (struct __HID_COLLECTION__*)NewCollection;
|
||
|
|
||
|
|
||
|
//
|
||
|
// store new array
|
||
|
//
|
||
|
CurrentCollection->Nodes = NewAllocCollection;
|
||
|
CurrentCollection->NodeCount++;
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_FindReport(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN UCHAR ReportType,
|
||
|
IN UCHAR ReportID,
|
||
|
OUT PHID_REPORT *OutReport)
|
||
|
{
|
||
|
PHID_PARSER_CONTEXT ParserContext;
|
||
|
ULONG Index;
|
||
|
|
||
|
//
|
||
|
// get parser context
|
||
|
//
|
||
|
ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
|
||
|
ASSERT(ParserContext);
|
||
|
|
||
|
for(Index = 0; Index < ParserContext->ReportCount; Index++)
|
||
|
{
|
||
|
if (ParserContext->Reports[Index]->Type == ReportType && ParserContext->Reports[Index]->ReportID == ReportID)
|
||
|
{
|
||
|
//
|
||
|
// found report
|
||
|
//
|
||
|
*OutReport = ParserContext->Reports[Index];
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// no such report found
|
||
|
//
|
||
|
*OutReport = NULL;
|
||
|
return HIDPARSER_STATUS_REPORT_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_AllocateReport(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN UCHAR ReportType,
|
||
|
IN UCHAR ReportID,
|
||
|
OUT PHID_REPORT *OutReport)
|
||
|
{
|
||
|
PHID_REPORT Report;
|
||
|
|
||
|
//
|
||
|
// allocate report
|
||
|
//
|
||
|
Report = (PHID_REPORT)Parser->Alloc(sizeof(HID_REPORT));
|
||
|
if (!Report)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// init report
|
||
|
//
|
||
|
Report->ReportID = ReportID;
|
||
|
Report->Type = ReportType;
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
*OutReport = Report;
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_AddReport(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_REPORT NewReport)
|
||
|
{
|
||
|
PHID_REPORT * NewReportArray;
|
||
|
PHID_PARSER_CONTEXT ParserContext;
|
||
|
|
||
|
//
|
||
|
// get parser context
|
||
|
//
|
||
|
ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext;
|
||
|
ASSERT(ParserContext);
|
||
|
|
||
|
//
|
||
|
// allocate new report array
|
||
|
//
|
||
|
NewReportArray = (PHID_REPORT*)Parser->Alloc(sizeof(PHID_REPORT) * (ParserContext->ReportCount + 1));
|
||
|
if (!NewReportArray)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if (ParserContext->ReportCount)
|
||
|
{
|
||
|
//
|
||
|
// copy old array contents
|
||
|
//
|
||
|
Parser->Copy(NewReportArray, ParserContext->Reports, sizeof(PHID_REPORT) * ParserContext->ReportCount);
|
||
|
|
||
|
//
|
||
|
// free old array
|
||
|
//
|
||
|
Parser->Free(ParserContext->Reports);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// store result
|
||
|
//
|
||
|
NewReportArray[ParserContext->ReportCount] = NewReport;
|
||
|
ParserContext->Reports = NewReportArray;
|
||
|
ParserContext->ReportCount++;
|
||
|
|
||
|
//
|
||
|
// completed successfully
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_GetReport(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN UCHAR ReportType,
|
||
|
IN UCHAR ReportID,
|
||
|
IN UCHAR CreateIfNotExists,
|
||
|
OUT PHID_REPORT *OutReport)
|
||
|
{
|
||
|
HIDPARSER_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// try finding existing report
|
||
|
//
|
||
|
Status = HidParser_FindReport(Parser, ReportType, ReportID, OutReport);
|
||
|
if (Status == HIDPARSER_STATUS_SUCCESS || CreateIfNotExists == FALSE)
|
||
|
{
|
||
|
//
|
||
|
// founed report
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate new report
|
||
|
//
|
||
|
Status = HidParser_AllocateReport(Parser, ReportType, ReportID, OutReport);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate report
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// add report
|
||
|
//
|
||
|
Status = HidParser_AddReport(Parser, *OutReport);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate report
|
||
|
//
|
||
|
Parser->Free(*OutReport);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_ReserveCollectionItems(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_COLLECTION Collection,
|
||
|
IN ULONG ReportCount)
|
||
|
{
|
||
|
PHID_REPORT_ITEM * NewReportArray;
|
||
|
|
||
|
if (Collection->ItemCount + ReportCount <= Collection->ItemCountAllocated)
|
||
|
{
|
||
|
//
|
||
|
// enough space for the next items
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate report array
|
||
|
//
|
||
|
NewReportArray = (PHID_REPORT_ITEM*)Parser->Alloc(sizeof(PHID_REPORT) * (Collection->ItemCountAllocated + ReportCount));
|
||
|
if (!NewReportArray)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// are there any items
|
||
|
//
|
||
|
if (Collection->ItemCount)
|
||
|
{
|
||
|
//
|
||
|
// copy old items
|
||
|
//
|
||
|
Parser->Copy(NewReportArray, Collection->Items, sizeof(PHID_REPORT_ITEM) * Collection->ItemCount);
|
||
|
|
||
|
//
|
||
|
// free old item
|
||
|
//
|
||
|
Parser->Free(Collection->Items);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// replace array
|
||
|
//
|
||
|
Collection->Items = NewReportArray;
|
||
|
Collection->ItemCountAllocated += ReportCount;
|
||
|
|
||
|
//
|
||
|
// completed sucessfully
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_ReserveReportItems(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_REPORT Report,
|
||
|
IN ULONG ReportCount)
|
||
|
{
|
||
|
PHID_REPORT_ITEM * NewReportArray;
|
||
|
|
||
|
if (Report->ItemCount + ReportCount <= Report->ItemAllocated)
|
||
|
{
|
||
|
//
|
||
|
// enough space for the next items
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate report array
|
||
|
//
|
||
|
NewReportArray = (PHID_REPORT_ITEM*)Parser->Alloc(sizeof(PHID_REPORT_ITEM) * (Report->ItemAllocated + ReportCount));
|
||
|
if (!NewReportArray)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// are there any items
|
||
|
//
|
||
|
if (Report->ItemCount)
|
||
|
{
|
||
|
//
|
||
|
// copy old items
|
||
|
//
|
||
|
Parser->Copy(NewReportArray, Report->Items, sizeof(PHID_REPORT_ITEM) * Report->ItemCount);
|
||
|
|
||
|
//
|
||
|
// free old item
|
||
|
//
|
||
|
Parser->Free(Report->Items);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// replace array
|
||
|
//
|
||
|
Report->Items = NewReportArray;
|
||
|
Report->ItemAllocated += ReportCount;
|
||
|
|
||
|
//
|
||
|
// completed sucessfully
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_AllocateReportItem(
|
||
|
IN PHID_PARSER Parser,
|
||
|
OUT PHID_REPORT_ITEM * OutReportItem)
|
||
|
{
|
||
|
PHID_REPORT_ITEM ReportItem;
|
||
|
|
||
|
//
|
||
|
// allocate report item
|
||
|
//
|
||
|
ReportItem = (PHID_REPORT_ITEM)Parser->Alloc(sizeof(HID_REPORT_ITEM));
|
||
|
if (!ReportItem)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// store result
|
||
|
//
|
||
|
*OutReportItem = ReportItem;
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HidParser_AddReportItemToReport(
|
||
|
IN OUT PHID_REPORT Report,
|
||
|
IN PHID_REPORT_ITEM ReportItem)
|
||
|
{
|
||
|
//
|
||
|
// there should be space in item array
|
||
|
//
|
||
|
ASSERT(Report->ItemCount + 1 <= Report->ItemAllocated);
|
||
|
|
||
|
//
|
||
|
// store item
|
||
|
//
|
||
|
Report->Items[Report->ItemCount] = ReportItem;
|
||
|
Report->ItemCount++;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HidParser_AddReportItemToCollection(
|
||
|
IN OUT PHID_COLLECTION Collection,
|
||
|
IN PHID_REPORT_ITEM ReportItem)
|
||
|
{
|
||
|
//
|
||
|
// there should be space in item array
|
||
|
//
|
||
|
ASSERT(Collection->ItemCount + 1 <= Collection->ItemCountAllocated);
|
||
|
|
||
|
//
|
||
|
// store item
|
||
|
//
|
||
|
Collection->Items[Collection->ItemCount] = ReportItem;
|
||
|
Collection->ItemCount++;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HidParser_SignRange(
|
||
|
IN ULONG Minimum,
|
||
|
IN ULONG Maximum,
|
||
|
OUT PULONG NewMinimum,
|
||
|
OUT PULONG NewMaximum)
|
||
|
{
|
||
|
ULONG Mask = 0x80000000;
|
||
|
ULONG Index;
|
||
|
|
||
|
for (Index = 0; Index < 4; Index++)
|
||
|
{
|
||
|
if (Minimum & Mask)
|
||
|
{
|
||
|
Minimum |= Mask;
|
||
|
if (Maximum & Mask)
|
||
|
Maximum |= Mask;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Mask >>= 8;
|
||
|
Mask |= 0xff000000;
|
||
|
}
|
||
|
|
||
|
*NewMinimum = Minimum;
|
||
|
*NewMaximum = Maximum;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_InitReportItem(
|
||
|
IN PHID_REPORT Report,
|
||
|
IN PHID_REPORT_ITEM ReportItem,
|
||
|
IN PGLOBAL_ITEM_STATE GlobalItemState,
|
||
|
IN PLOCAL_ITEM_STATE LocalItemState,
|
||
|
IN PMAIN_ITEM_DATA ItemData,
|
||
|
IN ULONG ReportItemIndex)
|
||
|
{
|
||
|
ULONG LogicalMinimum;
|
||
|
ULONG LogicalMaximum;
|
||
|
ULONG PhysicalMinimum;
|
||
|
ULONG PhysicalMaximum;
|
||
|
ULONG UsageMinimum;
|
||
|
ULONG UsageMaximum;
|
||
|
USAGE_VALUE UsageValue;
|
||
|
|
||
|
//
|
||
|
// get logical bounds
|
||
|
//
|
||
|
LogicalMinimum = GlobalItemState->LogicalMinimum;
|
||
|
LogicalMaximum = GlobalItemState->LogicialMaximum;
|
||
|
if (LogicalMinimum > LogicalMaximum)
|
||
|
{
|
||
|
//
|
||
|
// make them signed
|
||
|
//
|
||
|
HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum);
|
||
|
}
|
||
|
//ASSERT(LogicalMinimum <= LogicalMaximum);
|
||
|
|
||
|
//
|
||
|
// get physical bounds
|
||
|
//
|
||
|
PhysicalMinimum = GlobalItemState->PhysicalMinimum;
|
||
|
PhysicalMaximum = GlobalItemState->PhysicalMaximum;
|
||
|
if (PhysicalMinimum > PhysicalMaximum)
|
||
|
{
|
||
|
//
|
||
|
// make them signed
|
||
|
//
|
||
|
HidParser_SignRange(PhysicalMinimum, PhysicalMaximum, &PhysicalMinimum, &PhysicalMaximum);
|
||
|
}
|
||
|
//ASSERT(PhysicalMinimum <= PhysicalMaximum);
|
||
|
|
||
|
//
|
||
|
// get usage bounds
|
||
|
//
|
||
|
UsageMinimum = 0;
|
||
|
UsageMaximum = 0;
|
||
|
if (ItemData->ArrayVariable == FALSE)
|
||
|
{
|
||
|
//
|
||
|
// get usage bounds
|
||
|
//
|
||
|
UsageMinimum = LocalItemState->UsageMinimum.u.Extended;
|
||
|
UsageMaximum = LocalItemState->UsageMaximum.u.Extended;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// get usage value from stack
|
||
|
//
|
||
|
if (ReportItemIndex < LocalItemState->UsageStackUsed)
|
||
|
{
|
||
|
//
|
||
|
// use stack item
|
||
|
//
|
||
|
UsageValue = LocalItemState->UsageStack[ReportItemIndex];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// get usage minimum from local state
|
||
|
//
|
||
|
UsageValue = LocalItemState->UsageMinimum;
|
||
|
ASSERT(LocalItemState->UsageMinimumSet);
|
||
|
ASSERT(LocalItemState->UsageMaximumSet);
|
||
|
|
||
|
//
|
||
|
// append item index
|
||
|
//
|
||
|
UsageValue.u.Extended += ReportItemIndex;
|
||
|
|
||
|
if (UsageValue.u.Extended > LocalItemState->UsageMaximum.u.Extended)
|
||
|
{
|
||
|
//
|
||
|
// maximum reached
|
||
|
//
|
||
|
UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// usage usage bounds
|
||
|
//
|
||
|
UsageMinimum = UsageMaximum = UsageValue.u.Extended;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now store all values
|
||
|
//
|
||
|
ReportItem->ByteOffset = (Report->ReportSize / 8);
|
||
|
ReportItem->Shift = (Report->ReportSize % 8);
|
||
|
ReportItem->Mask = ~(0xFFFFFFFF << GlobalItemState->ReportSize);
|
||
|
ReportItem->BitCount = GlobalItemState->ReportSize;
|
||
|
ReportItem->HasData = (ItemData->DataConstant == FALSE);
|
||
|
ReportItem->Array = (ItemData->ArrayVariable == 0);
|
||
|
ReportItem->Relative = (ItemData->Relative == TRUE);
|
||
|
ReportItem->Minimum = LogicalMinimum;
|
||
|
ReportItem->Maximum = LogicalMaximum;
|
||
|
ReportItem->UsageMinimum = UsageMinimum;
|
||
|
ReportItem->UsageMaximum = UsageMaximum;
|
||
|
|
||
|
//
|
||
|
// increment report size
|
||
|
//
|
||
|
Report->ReportSize += GlobalItemState->ReportSize;
|
||
|
|
||
|
//
|
||
|
// completed successfully
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_AddMainItem(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PHID_REPORT Report,
|
||
|
IN PGLOBAL_ITEM_STATE GlobalItemState,
|
||
|
IN PLOCAL_ITEM_STATE LocalItemState,
|
||
|
IN PMAIN_ITEM_DATA ItemData,
|
||
|
IN PHID_COLLECTION Collection)
|
||
|
{
|
||
|
PHID_REPORT_ITEM ReportItem;
|
||
|
HIDPARSER_STATUS Status;
|
||
|
ULONG Index;
|
||
|
|
||
|
//
|
||
|
// first grow report item array
|
||
|
//
|
||
|
Status = HidParser_ReserveReportItems(Parser, Report, GlobalItemState->ReportCount);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate memory
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// grow collection item array
|
||
|
//
|
||
|
Status = HidParser_ReserveCollectionItems(Parser, Collection, GlobalItemState->ReportCount);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate memory
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
for(Index = 0; Index < GlobalItemState->ReportCount; Index++)
|
||
|
{
|
||
|
//
|
||
|
// create report item
|
||
|
//
|
||
|
Status = HidParser_AllocateReportItem(Parser, &ReportItem);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate memory
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HidParser_InitReportItem(Report, ReportItem, GlobalItemState, LocalItemState, ItemData, Index);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// failed to init report item
|
||
|
//
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// add report item
|
||
|
//
|
||
|
HidParser_AddReportItemToReport(Report, ReportItem);
|
||
|
HidParser_AddReportItemToCollection(Collection, ReportItem);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
HIDPARSER_STATUS
|
||
|
HidParser_ParseReportDescriptor(
|
||
|
IN PHID_PARSER Parser,
|
||
|
IN PUCHAR ReportDescriptor,
|
||
|
IN ULONG ReportLength)
|
||
|
{
|
||
|
PGLOBAL_ITEM_STATE LinkedGlobalItemState, NextLinkedGlobalItemState;
|
||
|
ULONG Index;
|
||
|
PUSAGE_VALUE NewUsageStack, UsageValue;
|
||
|
HIDPARSER_STATUS Status;
|
||
|
PHID_COLLECTION CurrentCollection, NewCollection;
|
||
|
PUCHAR CurrentOffset, ReportEnd;
|
||
|
PITEM_PREFIX CurrentItem;
|
||
|
ULONG CurrentItemSize;
|
||
|
PLONG_ITEM CurrentLongItem;
|
||
|
PSHORT_ITEM CurrentShortItem;
|
||
|
ULONG Data;
|
||
|
UCHAR ReportType;
|
||
|
PHID_REPORT Report;
|
||
|
PMAIN_ITEM_DATA MainItemData;
|
||
|
PHID_PARSER_CONTEXT ParserContext;
|
||
|
|
||
|
//
|
||
|
// reset parser
|
||
|
//
|
||
|
HidParser_ResetParser(Parser);
|
||
|
|
||
|
//
|
||
|
// get parser context
|
||
|
//
|
||
|
ParserContext =(PHID_PARSER_CONTEXT)Parser->ParserContext;
|
||
|
ASSERT(ParserContext);
|
||
|
|
||
|
//
|
||
|
// allocate usage stack
|
||
|
//
|
||
|
ParserContext->LocalItemState.UsageStackAllocated = 10;
|
||
|
ParserContext->LocalItemState.UsageStack = (PUSAGE_VALUE)Parser->Alloc(ParserContext->LocalItemState.UsageStackAllocated * sizeof(USAGE_VALUE));
|
||
|
if (!ParserContext->LocalItemState.UsageStack)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now allocate root collection
|
||
|
//
|
||
|
Status = HidParser_AllocateCollection(Parser, NULL, COLLECTION_LOGICAL, &ParserContext->LocalItemState, &ParserContext->RootCollection);
|
||
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
Parser->Free(ParserContext->LocalItemState.UsageStack);
|
||
|
ParserContext->LocalItemState.UsageStack = NULL;
|
||
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// start parsing
|
||
|
//
|
||
|
CurrentCollection = ParserContext->RootCollection;
|
||
|
CurrentOffset = ReportDescriptor;
|
||
|
ReportEnd = ReportDescriptor + ReportLength;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// get current item
|
||
|
//
|
||
|
CurrentItem = (PITEM_PREFIX)CurrentOffset;
|
||
|
|
||
|
//
|
||
|
// get item size
|
||
|
//
|
||
|
CurrentItemSize = ItemSize[CurrentItem->Size];
|
||
|
Data = 0;
|
||
|
|
||
|
if (CurrentItem->Type == ITEM_TYPE_LONG)
|
||
|
{
|
||
|
//
|
||
|
// increment item size with size of data item
|
||
|
//
|
||
|
CurrentLongItem = (PLONG_ITEM)CurrentItem;
|
||
|
CurrentItemSize += CurrentLongItem->DataSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// get short item
|
||
|
//
|
||
|
CurrentShortItem = (PSHORT_ITEM)CurrentItem;
|
||
|
|
||
|
//
|
||
|
// get associated data
|
||
|
//
|
||
|
//ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4);
|
||
|
if (CurrentItemSize == 1)
|
||
|
Data = CurrentShortItem->Data.UData8[0];
|
||
|
else if (CurrentItemSize == 2)
|
||
|
Data = CurrentShortItem->Data.UData16[0];
|
||
|
else if (CurrentItemSize == 4)
|
||
|
Data = CurrentShortItem->Data.UData32;
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// invalid item size
|
||
|
//
|
||
|
//Parser->Debug("CurrentItem invalid item size %lu\n", CurrentItemSize);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// handle items
|
||
|
//
|
||
|
ASSERT(CurrentItem->Type >= ITEM_TYPE_MAIN && CurrentItem->Type <= ITEM_TYPE_LONG);
|
||
|
switch(CurrentItem->Type)
|
||
|
{
|
||
|
case ITEM_TYPE_MAIN:
|
||
|
{
|
||
|
// preprocess the local state if relevant (usages for
|
||
|
// collections and report items)
|
||
|
if (CurrentItem->Tag != ITEM_TAG_MAIN_END_COLLECTION)
|
||
|
{
|
||
|
// make all usages extended for easier later processing
|
||
|
for (Index = 0; Index < ParserContext->LocalItemState.UsageStackUsed; Index++)
|
||
|
{
|
||
|
//
|
||
|
// is it already extended
|
||
|
//
|
||
|
if (ParserContext->LocalItemState.UsageStack[Index].IsExtended)
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// extend usage item
|
||
|
//
|
||
|
ParserContext->LocalItemState.UsageStack[Index].u.s.UsagePage = ParserContext->GlobalItemState.UsagePage;
|
||
|
ParserContext->LocalItemState.UsageStack[Index].IsExtended = TRUE;
|
||
|
}
|
||
|
|
||
|
if (!ParserContext->LocalItemState.UsageMinimum.IsExtended) {
|
||
|
// the specs say if one of them is extended they must
|
||
|
// both be extended, so if the minimum isn't, the
|
||
|
// maximum mustn't either.
|
||
|
ParserContext->LocalItemState.UsageMinimum.u.s.UsagePage
|
||
|
= ParserContext->LocalItemState.UsageMaximum.u.s.UsagePage
|
||
|
= ParserContext->GlobalItemState.UsagePage;
|
||
|
ParserContext->LocalItemState.UsageMinimum.IsExtended
|
||
|
= ParserContext->LocalItemState.UsageMaximum.IsExtended = TRUE;
|
||
|
}
|
||
|
|
||
|
//LocalItemState.usage_stack = usageStack;
|
||
|
//ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed;
|
||
|
}
|
||
|
|
||
|
if (CurrentItem->Tag == ITEM_TAG_MAIN_COLLECTION) {
|
||
|
|
||
|
//
|
||
|
// allocate new collection
|
||
|
//
|
||
|
Status = HidParser_AllocateCollection(Parser, CurrentCollection, (UCHAR)Data, &ParserContext->LocalItemState, &NewCollection);
|
||
|
ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
|
||
|
|
||
|
//
|
||
|
// add new collection to current collection
|
||
|
//
|
||
|
Status = HidParser_AddCollection(Parser, CurrentCollection, NewCollection);
|
||
|
ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
|
||
|
|
||
|
//
|
||
|
// make new collection current
|
||
|
//
|
||
|
CurrentCollection = NewCollection;
|
||
|
}
|
||
|
else if (CurrentItem->Tag == ITEM_TAG_MAIN_END_COLLECTION)
|
||
|
{
|
||
|
//
|
||
|
// assert on ending the root collection
|
||
|
//
|
||
|
ASSERT(CurrentCollection != ParserContext->RootCollection);
|
||
|
|
||
|
//
|
||
|
// use parent of current collection
|
||
|
//
|
||
|
CurrentCollection = CurrentCollection->Root;
|
||
|
ASSERT(CurrentCollection);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ReportType = HID_REPORT_TYPE_ANY;
|
||
|
|
||
|
switch (CurrentItem->Tag) {
|
||
|
case ITEM_TAG_MAIN_INPUT:
|
||
|
ReportType = HID_REPORT_TYPE_INPUT;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_MAIN_OUTPUT:
|
||
|
ReportType = HID_REPORT_TYPE_OUTPUT;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_MAIN_FEATURE:
|
||
|
ReportType = HID_REPORT_TYPE_FEATURE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Parser->Debug("[HIDPARSE] Unknown ReportType %x\n", CurrentItem->Tag);
|
||
|
ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (ReportType == HID_REPORT_TYPE_ANY)
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// get report
|
||
|
//
|
||
|
Status = HidParser_GetReport(Parser, ReportType, ParserContext->GlobalItemState.ReportId, TRUE, &Report);
|
||
|
ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
|
||
|
|
||
|
// fill in a sensible default if the index isn't set
|
||
|
if (!ParserContext->LocalItemState.DesignatorIndexSet) {
|
||
|
ParserContext->LocalItemState.DesignatorIndex
|
||
|
= ParserContext->LocalItemState.DesignatorMinimum;
|
||
|
}
|
||
|
|
||
|
if (!ParserContext->LocalItemState.StringIndexSet)
|
||
|
ParserContext->LocalItemState.StringIndex = ParserContext->LocalItemState.StringMinimum;
|
||
|
|
||
|
//
|
||
|
// get main item data
|
||
|
//
|
||
|
MainItemData = (PMAIN_ITEM_DATA)&Data;
|
||
|
|
||
|
//
|
||
|
// add states & data to the report
|
||
|
//
|
||
|
Status = HidParser_AddMainItem(Parser, Report, &ParserContext->GlobalItemState, &ParserContext->LocalItemState, MainItemData, CurrentCollection);
|
||
|
ASSERT(Status == HIDPARSER_STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// backup stack
|
||
|
//
|
||
|
Index = ParserContext->LocalItemState.UsageStackAllocated;
|
||
|
NewUsageStack = ParserContext->LocalItemState.UsageStack;
|
||
|
|
||
|
//
|
||
|
// reset the local item state and clear the usage stack
|
||
|
//
|
||
|
Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE));
|
||
|
|
||
|
//
|
||
|
// restore stack
|
||
|
//
|
||
|
ParserContext->LocalItemState.UsageStack = NewUsageStack;
|
||
|
ParserContext->LocalItemState.UsageStackAllocated = Index;
|
||
|
break;
|
||
|
}
|
||
|
case ITEM_TYPE_GLOBAL:
|
||
|
{
|
||
|
switch (CurrentItem->Tag) {
|
||
|
case ITEM_TAG_GLOBAL_USAGE_PAGE:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data);
|
||
|
ParserContext->GlobalItemState.UsagePage = Data;
|
||
|
break;
|
||
|
case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data);
|
||
|
ParserContext->GlobalItemState.LogicalMinimum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data);
|
||
|
ParserContext->GlobalItemState.LogicialMaximum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data);
|
||
|
ParserContext->GlobalItemState.PhysicalMinimum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data);
|
||
|
ParserContext->GlobalItemState.PhysicalMaximum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_UNIT_EXPONENT:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data);
|
||
|
ParserContext->GlobalItemState.UnitExponent = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_UNIT:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data);
|
||
|
ParserContext->GlobalItemState.Unit = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_REPORT_SIZE:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data);
|
||
|
ParserContext->GlobalItemState.ReportSize = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_REPORT_ID:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data);
|
||
|
ParserContext->GlobalItemState.ReportId = Data;
|
||
|
ParserContext->UseReportIDs = TRUE;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_REPORT_COUNT:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data);
|
||
|
ParserContext->GlobalItemState.ReportCount = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_GLOBAL_PUSH:
|
||
|
{
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n");
|
||
|
//
|
||
|
// allocate global item state
|
||
|
//
|
||
|
LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)Parser->Alloc(sizeof(GLOBAL_ITEM_STATE));
|
||
|
ASSERT(LinkedGlobalItemState);
|
||
|
|
||
|
//
|
||
|
// copy global item state
|
||
|
//
|
||
|
Parser->Copy(LinkedGlobalItemState, &ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE));
|
||
|
|
||
|
//
|
||
|
// store pushed item in link member
|
||
|
//
|
||
|
ParserContext->GlobalItemState.Next = (struct __GLOBAL_ITEM_STATE__*)LinkedGlobalItemState;
|
||
|
break;
|
||
|
}
|
||
|
case ITEM_TAG_GLOBAL_POP:
|
||
|
{
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n");
|
||
|
if (ParserContext->GlobalItemState.Next == NULL)
|
||
|
{
|
||
|
//
|
||
|
// pop without push
|
||
|
//
|
||
|
ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get link
|
||
|
//
|
||
|
LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
|
||
|
|
||
|
//
|
||
|
// replace current item with linked one
|
||
|
//
|
||
|
Parser->Copy(&ParserContext->GlobalItemState, LinkedGlobalItemState, sizeof(GLOBAL_ITEM_STATE));
|
||
|
|
||
|
//
|
||
|
// free item
|
||
|
//
|
||
|
Parser->Free(LinkedGlobalItemState);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
//
|
||
|
// unknown / unsupported tag
|
||
|
//
|
||
|
ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case ITEM_TYPE_LOCAL:
|
||
|
{
|
||
|
switch (CurrentItem->Tag)
|
||
|
{
|
||
|
case ITEM_TAG_LOCAL_USAGE:
|
||
|
{
|
||
|
if (ParserContext->LocalItemState.UsageStackUsed >= ParserContext->LocalItemState.UsageStackAllocated)
|
||
|
{
|
||
|
//
|
||
|
// increment stack size
|
||
|
//
|
||
|
ParserContext->LocalItemState.UsageStackAllocated += 10;
|
||
|
|
||
|
//
|
||
|
// build new usage stack
|
||
|
//
|
||
|
NewUsageStack = (PUSAGE_VALUE)Parser->Alloc(sizeof(USAGE_VALUE) * ParserContext->LocalItemState.UsageStackAllocated);
|
||
|
ASSERT(NewUsageStack);
|
||
|
|
||
|
//
|
||
|
// copy old usage stack
|
||
|
//
|
||
|
Parser->Copy(NewUsageStack, ParserContext->LocalItemState.UsageStack, sizeof(USAGE_VALUE) * (ParserContext->LocalItemState.UsageStackAllocated - 10));
|
||
|
|
||
|
//
|
||
|
// free old usage stack
|
||
|
//
|
||
|
Parser->Free(ParserContext->LocalItemState.UsageStack);
|
||
|
|
||
|
//
|
||
|
// replace with new usage stack
|
||
|
//
|
||
|
ParserContext->LocalItemState.UsageStack = NewUsageStack;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get fresh usage value
|
||
|
//
|
||
|
UsageValue = &ParserContext->LocalItemState.UsageStack[ParserContext->LocalItemState.UsageStackUsed];
|
||
|
|
||
|
//
|
||
|
// init usage stack
|
||
|
//
|
||
|
UsageValue->IsExtended = CurrentItemSize == sizeof(ULONG);
|
||
|
UsageValue->u.Extended = Data;
|
||
|
|
||
|
//
|
||
|
// increment usage stack usage count
|
||
|
//
|
||
|
ParserContext->LocalItemState.UsageStackUsed++;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ITEM_TAG_LOCAL_USAGE_MINIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.UsageMinimum.u.Extended = Data;
|
||
|
ParserContext->LocalItemState.UsageMinimum.IsExtended
|
||
|
= CurrentItemSize == sizeof(ULONG);
|
||
|
ParserContext->LocalItemState.UsageMinimumSet = TRUE;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_USAGE_MAXIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.UsageMaximum.u.Extended = Data;
|
||
|
ParserContext->LocalItemState.UsageMaximum.IsExtended
|
||
|
= CurrentItemSize == sizeof(ULONG);
|
||
|
ParserContext->LocalItemState.UsageMaximumSet = TRUE;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_DESIGNATOR_INDEX:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.DesignatorIndex = Data;
|
||
|
ParserContext->LocalItemState.DesignatorIndexSet = TRUE;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.DesignatorMinimum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.DesignatorMaximum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_STRING_INDEX:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.StringIndex = Data;
|
||
|
ParserContext->LocalItemState.StringIndexSet = TRUE;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_STRING_MINIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.StringMinimum = Data;
|
||
|
break;
|
||
|
|
||
|
case ITEM_TAG_LOCAL_STRING_MAXIMUM:
|
||
|
Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data);
|
||
|
ParserContext->LocalItemState.StringMaximum = Data;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Parser->Debug("Unknown Local Item Tag %x\n", CurrentItem->Tag);
|
||
|
ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ITEM_TYPE_LONG:
|
||
|
{
|
||
|
CurrentLongItem = (PLONG_ITEM)CurrentItem;
|
||
|
Parser->Debug("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem->LongItemTag);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// move to next item
|
||
|
//
|
||
|
CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX);
|
||
|
|
||
|
|
||
|
}while(CurrentOffset < ReportEnd);
|
||
|
|
||
|
|
||
|
//
|
||
|
// cleanup global stack
|
||
|
//
|
||
|
LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next;
|
||
|
while(LinkedGlobalItemState != NULL)
|
||
|
{
|
||
|
Parser->Debug("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState);
|
||
|
//
|
||
|
// free global item state
|
||
|
//
|
||
|
NextLinkedGlobalItemState = (PGLOBAL_ITEM_STATE)LinkedGlobalItemState->Next;
|
||
|
|
||
|
//
|
||
|
// free state
|
||
|
//
|
||
|
Parser->Free(LinkedGlobalItemState);
|
||
|
|
||
|
//
|
||
|
// move to next global state
|
||
|
//
|
||
|
LinkedGlobalItemState = NextLinkedGlobalItemState;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// free usage stack
|
||
|
//
|
||
|
Parser->Free(ParserContext->LocalItemState.UsageStack);
|
||
|
ParserContext->LocalItemState.UsageStack = NULL;
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return HIDPARSER_STATUS_SUCCESS;
|
||
|
}
|
||
|
|