mirror of
https://github.com/reactos/reactos.git
synced 2025-05-31 15:08:14 +00:00

- Rewrite hidparser so that it support multiple top level collections - Add support for flat collection context meaning all context structures are aligned in after each other. The reason this is required is that usermode hid.dll will access the same structure and thus can't use kernel pointers. User mode hid.dll is used to support keyboard with custom keys (for example search key, email key etc) svn path=/branches/usb-bringup-trunk/; revision=55353
1399 lines
40 KiB
C
1399 lines
40 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;
|
|
}
|
|
|
|
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_FindReportInCollection(
|
|
IN PHID_COLLECTION Collection,
|
|
IN UCHAR ReportType,
|
|
IN UCHAR ReportID,
|
|
OUT PHID_REPORT *OutReport)
|
|
{
|
|
ULONG Index;
|
|
HIDPARSER_STATUS Status;
|
|
|
|
//
|
|
// search in local list
|
|
//
|
|
for(Index = 0; Index < Collection->ReportCount; Index++)
|
|
{
|
|
if (Collection->Reports[Index]->Type == ReportType && Collection->Reports[Index]->ReportID == ReportID)
|
|
{
|
|
//
|
|
// found report
|
|
//
|
|
*OutReport = Collection->Reports[Index];
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// search in sub collections
|
|
//
|
|
for(Index = 0; Index < Collection->NodeCount; Index++)
|
|
{
|
|
Status = HidParser_FindReportInCollection(Collection->Nodes[Index], ReportType, ReportID, OutReport);
|
|
if (Status == HIDPARSER_STATUS_SUCCESS)
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// no such report found
|
|
//
|
|
*OutReport = NULL;
|
|
return HIDPARSER_STATUS_REPORT_NOT_FOUND;
|
|
}
|
|
|
|
|
|
HIDPARSER_STATUS
|
|
HidParser_FindReport(
|
|
IN PHID_PARSER Parser,
|
|
IN PHID_PARSER_CONTEXT ParserContext,
|
|
IN UCHAR ReportType,
|
|
IN UCHAR ReportID,
|
|
OUT PHID_REPORT *OutReport)
|
|
{
|
|
//
|
|
// search in current top level collection
|
|
//
|
|
return HidParser_FindReportInCollection(ParserContext->RootCollection->Nodes[ParserContext->RootCollection->NodeCount-1], ReportType, ReportID, OutReport);
|
|
}
|
|
|
|
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_AddReportToCollection(
|
|
IN PHID_PARSER Parser,
|
|
IN PHID_PARSER_CONTEXT ParserContext,
|
|
IN PHID_COLLECTION CurrentCollection,
|
|
IN PHID_REPORT NewReport)
|
|
{
|
|
PHID_REPORT * NewReportArray;
|
|
|
|
//
|
|
// allocate new report array
|
|
//
|
|
NewReportArray = (PHID_REPORT*)Parser->Alloc(sizeof(PHID_REPORT) * (CurrentCollection->ReportCount + 1));
|
|
if (!NewReportArray)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (CurrentCollection->ReportCount)
|
|
{
|
|
//
|
|
// copy old array contents
|
|
//
|
|
Parser->Copy(NewReportArray, CurrentCollection->Reports, sizeof(PHID_REPORT) * CurrentCollection->ReportCount);
|
|
|
|
//
|
|
// free old array
|
|
//
|
|
Parser->Free(CurrentCollection->Reports);
|
|
}
|
|
|
|
//
|
|
// store result
|
|
//
|
|
NewReportArray[CurrentCollection->ReportCount] = NewReport;
|
|
CurrentCollection->Reports = NewReportArray;
|
|
CurrentCollection->ReportCount++;
|
|
|
|
//
|
|
// completed successfully
|
|
//
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
|
|
HIDPARSER_STATUS
|
|
HidParser_GetReport(
|
|
IN PHID_PARSER Parser,
|
|
IN PHID_PARSER_CONTEXT ParserContext,
|
|
IN PHID_COLLECTION Collection,
|
|
IN UCHAR ReportType,
|
|
IN UCHAR ReportID,
|
|
IN UCHAR CreateIfNotExists,
|
|
OUT PHID_REPORT *OutReport)
|
|
{
|
|
HIDPARSER_STATUS Status;
|
|
|
|
//
|
|
// try finding existing report
|
|
//
|
|
Status = HidParser_FindReport(Parser, ParserContext, 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_AddReportToCollection(Parser, ParserContext, Collection, *OutReport);
|
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// failed to allocate report
|
|
//
|
|
Parser->Free(*OutReport);
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
HIDPARSER_STATUS
|
|
HidParser_ReserveReportItems(
|
|
IN PHID_PARSER Parser,
|
|
IN PHID_REPORT Report,
|
|
IN ULONG ReportCount,
|
|
OUT PHID_REPORT *OutReport)
|
|
{
|
|
PHID_REPORT NewReport;
|
|
ULONG OldSize, Size;
|
|
|
|
if (Report->ItemCount + ReportCount <= Report->ItemAllocated)
|
|
{
|
|
//
|
|
// space is already allocated
|
|
//
|
|
*OutReport = Report;
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
//calculate new size
|
|
//
|
|
OldSize = sizeof(HID_REPORT) + (Report->ItemCount) * sizeof(HID_REPORT_ITEM);
|
|
Size = ReportCount * sizeof(HID_REPORT_ITEM);
|
|
|
|
//
|
|
// allocate memory
|
|
//
|
|
NewReport = (PHID_REPORT)Parser->Alloc(Size + OldSize);
|
|
if (!NewReport)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
//
|
|
// copy old report
|
|
//
|
|
Parser->Copy(NewReport, Report, OldSize);
|
|
|
|
//
|
|
// increase array size
|
|
//
|
|
NewReport->ItemAllocated += ReportCount;
|
|
|
|
//
|
|
// store result
|
|
//
|
|
*OutReport = NewReport;
|
|
|
|
//
|
|
// completed sucessfully
|
|
//
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
BOOLEAN
|
|
HidParser_UpdateCurrentCollectionReport(
|
|
IN PHID_COLLECTION Collection,
|
|
IN PHID_REPORT Report,
|
|
IN PHID_REPORT NewReport)
|
|
{
|
|
ULONG Index;
|
|
BOOLEAN Found = FALSE, TempFound;
|
|
|
|
//
|
|
// search in local list
|
|
//
|
|
for(Index = 0; Index < Collection->ReportCount; Index++)
|
|
{
|
|
if (Collection->Reports[Index] == Report)
|
|
{
|
|
//
|
|
// update report
|
|
//
|
|
Collection->Reports[Index] = NewReport;
|
|
Found = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// search in sub collections
|
|
//
|
|
for(Index = 0; Index < Collection->NodeCount; Index++)
|
|
{
|
|
//
|
|
// was it found
|
|
//
|
|
TempFound = HidParser_UpdateCurrentCollectionReport(Collection->Nodes[Index], Report, NewReport);
|
|
if (TempFound)
|
|
{
|
|
//
|
|
// the same report should not be found in different collections
|
|
//
|
|
ASSERT(Found == FALSE);
|
|
Found = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Found;
|
|
}
|
|
|
|
BOOLEAN
|
|
HidParser_UpdateCollectionReport(
|
|
IN PHID_PARSER_CONTEXT ParserContext,
|
|
IN PHID_REPORT Report,
|
|
IN PHID_REPORT NewReport)
|
|
{
|
|
//
|
|
// update in current collection
|
|
//
|
|
return HidParser_UpdateCurrentCollectionReport(ParserContext->RootCollection->Nodes[ParserContext->RootCollection->NodeCount-1], Report, NewReport);
|
|
}
|
|
|
|
|
|
HIDPARSER_STATUS
|
|
HidParser_AddMainItem(
|
|
IN PHID_PARSER Parser,
|
|
IN PHID_PARSER_CONTEXT ParserContext,
|
|
IN PHID_REPORT Report,
|
|
IN PGLOBAL_ITEM_STATE GlobalItemState,
|
|
IN PLOCAL_ITEM_STATE LocalItemState,
|
|
IN PMAIN_ITEM_DATA ItemData,
|
|
IN PHID_COLLECTION Collection)
|
|
{
|
|
HIDPARSER_STATUS Status;
|
|
ULONG Index;
|
|
PHID_REPORT NewReport;
|
|
BOOLEAN Found;
|
|
|
|
//
|
|
// first grow report item array
|
|
//
|
|
Status = HidParser_ReserveReportItems(Parser, Report, GlobalItemState->ReportCount, &NewReport);
|
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// failed to allocate memory
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
if (NewReport != Report)
|
|
{
|
|
//
|
|
// update current top level collection
|
|
//
|
|
Found = HidParser_UpdateCollectionReport(ParserContext, Report, NewReport);
|
|
ASSERT(Found);
|
|
}
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(NewReport->ItemCount + GlobalItemState->ReportCount <= NewReport->ItemAllocated);
|
|
|
|
for(Index = 0; Index < GlobalItemState->ReportCount; Index++)
|
|
{
|
|
Status = HidParser_InitReportItem(NewReport, &NewReport->Items[NewReport->ItemCount], GlobalItemState, LocalItemState, ItemData, Index);
|
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// failed to init report item
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// increment report item count
|
|
//
|
|
NewReport->ItemCount++;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
|
|
HIDPARSER_STATUS
|
|
AllocateParserContext(
|
|
IN PHID_PARSER Parser,
|
|
OUT PHID_PARSER_CONTEXT *OutParserContext)
|
|
{
|
|
PHID_PARSER_CONTEXT ParserContext;
|
|
|
|
ParserContext = Parser->Alloc(sizeof(HID_PARSER_CONTEXT));
|
|
if (!ParserContext)
|
|
{
|
|
//
|
|
// failed
|
|
//
|
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// store result
|
|
//
|
|
*OutParserContext = ParserContext;
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
HIDPARSER_STATUS
|
|
HidParser_ParseReportDescriptor(
|
|
IN PHID_PARSER Parser,
|
|
IN PUCHAR ReportDescriptor,
|
|
IN ULONG ReportLength,
|
|
OUT PVOID *OutParser)
|
|
{
|
|
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;
|
|
|
|
//
|
|
// allocate parser
|
|
//
|
|
Status = AllocateParserContext(Parser, &ParserContext);
|
|
if (Status != HIDPARSER_STATUS_SUCCESS)
|
|
return Status;
|
|
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
}
|
|
Parser->Debug("Tag %x Type %x Size %x Offset %lu Length %lu\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, ((ULONG_PTR)CurrentItem - (ULONG_PTR)ReportDescriptor), ReportLength);
|
|
//
|
|
// 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 Tag %x Type %x Size %x CurrentItemSize %x\n", CurrentItem->Tag, CurrentItem->Type, CurrentItem->Size, CurrentItemSize);
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
if (ReportType == HID_REPORT_TYPE_ANY)
|
|
break;
|
|
|
|
//
|
|
// get report
|
|
//
|
|
Status = HidParser_GetReport(Parser, ParserContext, CurrentCollection, 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, ParserContext, 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 ItemSize %x %x\n", Data, CurrentItemSize, CurrentItem->Size);
|
|
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;
|
|
|
|
//
|
|
// store result
|
|
//
|
|
*OutParser = ParserContext;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return HIDPARSER_STATUS_SUCCESS;
|
|
}
|
|
|
|
PHID_COLLECTION
|
|
HidParser_GetCollection(
|
|
IN PHID_PARSER Parser,
|
|
PHID_PARSER_CONTEXT ParserContext,
|
|
IN ULONG CollectionNumber)
|
|
{
|
|
//
|
|
// sanity checks
|
|
//
|
|
ASSERT(ParserContext);
|
|
ASSERT(ParserContext->RootCollection);
|
|
ASSERT(ParserContext->RootCollection->NodeCount);
|
|
|
|
//
|
|
// is collection index out of bounds
|
|
//
|
|
if (CollectionNumber < ParserContext->RootCollection->NodeCount)
|
|
{
|
|
//
|
|
// valid collection
|
|
//
|
|
return ParserContext->RootCollection->Nodes[CollectionNumber];
|
|
}
|
|
|
|
//
|
|
// no such collection
|
|
//
|
|
Parser->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
ULONG
|
|
HidParser_NumberOfTopCollections(
|
|
IN PVOID ParserCtx)
|
|
{
|
|
PHID_PARSER_CONTEXT ParserContext;
|
|
|
|
//
|
|
// get parser context
|
|
//
|
|
ParserContext = (PHID_PARSER_CONTEXT)ParserCtx;
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
ASSERT(ParserContext);
|
|
ASSERT(ParserContext->RootCollection);
|
|
ASSERT(ParserContext->RootCollection->NodeCount);
|
|
|
|
//
|
|
// number of top collections
|
|
//
|
|
return ParserContext->RootCollection->NodeCount;
|
|
}
|
|
|
|
HIDPARSER_STATUS
|
|
HidParser_BuildContext(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID ParserContext,
|
|
IN ULONG CollectionIndex,
|
|
IN ULONG ContextSize,
|
|
OUT PVOID *CollectionContext)
|
|
{
|
|
PHID_COLLECTION Collection;
|
|
PVOID Context;
|
|
HIDPARSER_STATUS Status;
|
|
|
|
//
|
|
// lets get the collection
|
|
//
|
|
Collection = HidParser_GetCollection(Parser, (PHID_PARSER_CONTEXT)ParserContext, CollectionIndex);
|
|
ASSERT(Collection);
|
|
|
|
//
|
|
// lets allocate the context
|
|
//
|
|
Context = Parser->Alloc(ContextSize);
|
|
if (Context == NULL)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// lets build the context
|
|
//
|
|
Status = HidParser_BuildCollectionContext(Parser, Collection, Context, ContextSize);
|
|
if (Status == HIDPARSER_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// store context
|
|
//
|
|
*CollectionContext = Context;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
HidParser_GetContextSize(
|
|
IN PHID_PARSER Parser,
|
|
IN PVOID ParserContext,
|
|
IN ULONG CollectionIndex)
|
|
{
|
|
PHID_COLLECTION Collection;
|
|
ULONG Size;
|
|
|
|
//
|
|
// lets get the collection
|
|
//
|
|
Collection = HidParser_GetCollection(Parser, (PHID_PARSER_CONTEXT)ParserContext, CollectionIndex);
|
|
|
|
//
|
|
// calculate size
|
|
//
|
|
Size = HidParser_CalculateContextSize(Collection);
|
|
return Size;
|
|
}
|
|
|