namespace device {
+namespace {
+
+const int kBitsPerByte = 8;
+
+} // namespace
+
HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
size_t header_index = 0;
HidReportDescriptorItem* item = NULL;
HidReportDescriptor::~HidReportDescriptor() {}
-void HidReportDescriptor::GetTopLevelCollections(
- std::vector<HidUsageAndPage>* topLevelCollections) {
- DCHECK(topLevelCollections);
- STLClearObject(topLevelCollections);
+void HidReportDescriptor::GetDetails(
+ std::vector<HidCollectionInfo>* top_level_collections,
+ bool* has_report_id,
+ int* max_input_report_size,
+ int* max_output_report_size,
+ int* max_feature_report_size) {
+ DCHECK(top_level_collections);
+ DCHECK(max_input_report_size);
+ DCHECK(max_output_report_size);
+ DCHECK(max_feature_report_size);
+ STLClearObject(top_level_collections);
+
+ *has_report_id = false;
+ *max_input_report_size = 0;
+ *max_output_report_size = 0;
+ *max_feature_report_size = 0;
+
+ // Global tags data:
+ HidUsageAndPage::Page current_usage_page = HidUsageAndPage::kPageUndefined;
+ int current_report_count = 0;
+ int cached_report_count = 0;
+ int current_report_size = 0;
+ int cached_report_size = 0;
+ int current_input_report_size = 0;
+ int current_output_report_size = 0;
+ int current_feature_report_size = 0;
+
+ // Local tags data:
+ uint16_t current_usage = 0;
for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
items_iter = items().begin();
items_iter != items().end();
++items_iter) {
- linked_ptr<HidReportDescriptorItem> item = *items_iter;
-
- bool isTopLevelCollection =
- item->tag() == HidReportDescriptorItem::kTagCollection &&
- item->parent() == NULL;
-
- if (isTopLevelCollection) {
- uint16_t collection_usage = 0;
- HidUsageAndPage::Page collection_usage_page =
- HidUsageAndPage::kPageUndefined;
-
- HidReportDescriptorItem* usage = item->previous();
- if (usage && usage->tag() == HidReportDescriptorItem::kTagUsage) {
- collection_usage = usage->GetShortData();
- }
-
- HidReportDescriptorItem* usage_page = usage->previous();
- if (usage_page &&
- usage_page->tag() == HidReportDescriptorItem::kTagUsagePage) {
- collection_usage_page =
- (HidUsageAndPage::Page)usage_page->GetShortData();
- }
-
- topLevelCollections->push_back(
- HidUsageAndPage(collection_usage, collection_usage_page));
+ linked_ptr<HidReportDescriptorItem> current_item = *items_iter;
+
+ switch (current_item->tag()) {
+ // Main tags:
+ case HidReportDescriptorItem::kTagCollection:
+ if (!current_item->parent()) {
+ // This is a top-level collection.
+ HidCollectionInfo collection;
+ collection.usage = HidUsageAndPage(current_usage, current_usage_page);
+ top_level_collections->push_back(collection);
+ }
+ break;
+ case HidReportDescriptorItem::kTagInput:
+ current_input_report_size += current_report_count * current_report_size;
+ break;
+ case HidReportDescriptorItem::kTagOutput:
+ current_output_report_size +=
+ current_report_count * current_report_size;
+ break;
+ case HidReportDescriptorItem::kTagFeature:
+ current_feature_report_size +=
+ current_report_count * current_report_size;
+ break;
+
+ // Global tags:
+ case HidReportDescriptorItem::kTagUsagePage:
+ current_usage_page =
+ (HidUsageAndPage::Page)current_item->GetShortData();
+ break;
+ case HidReportDescriptorItem::kTagReportId:
+ if (top_level_collections->size() > 0) {
+ // Store report ID.
+ top_level_collections->back().report_ids.insert(
+ current_item->GetShortData());
+ *has_report_id = true;
+
+ // Update max report sizes.
+ *max_input_report_size =
+ std::max(*max_input_report_size, current_input_report_size);
+ *max_output_report_size =
+ std::max(*max_output_report_size, current_output_report_size);
+ *max_feature_report_size =
+ std::max(*max_feature_report_size, current_feature_report_size);
+
+ // Reset the report sizes for the next report ID.
+ current_input_report_size = 0;
+ current_output_report_size = 0;
+ current_feature_report_size = 0;
+ }
+ break;
+ case HidReportDescriptorItem::kTagReportCount:
+ current_report_count = current_item->GetShortData();
+ break;
+ case HidReportDescriptorItem::kTagReportSize:
+ current_report_size = current_item->GetShortData();
+ break;
+ case HidReportDescriptorItem::kTagPush:
+ // Cache report count and size.
+ cached_report_count = current_report_count;
+ cached_report_size = current_report_size;
+ break;
+ case HidReportDescriptorItem::kTagPop:
+ // Restore cache.
+ current_report_count = cached_report_count;
+ current_report_size = cached_report_size;
+ // Reset cache.
+ cached_report_count = 0;
+ cached_report_size = 0;
+ break;
+
+ // Local tags:
+ case HidReportDescriptorItem::kTagUsage:
+ current_usage = current_item->GetShortData();
+ break;
+
+ default:
+ break;
}
}
+
+ // Update max report sizes
+ *max_input_report_size =
+ std::max(*max_input_report_size, current_input_report_size);
+ *max_output_report_size =
+ std::max(*max_output_report_size, current_output_report_size);
+ *max_feature_report_size =
+ std::max(*max_feature_report_size, current_feature_report_size);
+
+ // Convert bits into bytes
+ *max_input_report_size /= kBitsPerByte;
+ *max_output_report_size /= kBitsPerByte;
+ *max_feature_report_size /= kBitsPerByte;
}
} // namespace device