// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "device/hid/hid_report_descriptor.h" #include "base/stl_util.h" namespace device { namespace { const int kBitsPerByte = 8; } // namespace HidReportDescriptor::HidReportDescriptor(const std::vector& bytes) { size_t header_index = 0; HidReportDescriptorItem* item = NULL; while (header_index < bytes.size()) { item = new HidReportDescriptorItem(&bytes[header_index], item); items_.push_back(linked_ptr(item)); header_index += item->GetSize(); } } HidReportDescriptor::~HidReportDescriptor() {} void HidReportDescriptor::GetDetails( std::vector* top_level_collections, bool* has_report_id, size_t* max_input_report_size, size_t* max_output_report_size, size_t* 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; size_t current_report_count = 0; size_t cached_report_count = 0; size_t current_report_size = 0; size_t cached_report_size = 0; size_t current_input_report_size = 0; size_t current_output_report_size = 0; size_t current_feature_report_size = 0; // Local tags data: uint32_t current_usage = 0; for (std::vector >::const_iterator items_iter = items().begin(); items_iter != items().end(); ++items_iter) { linked_ptr current_item = *items_iter; switch (current_item->tag()) { // Main tags: case HidReportDescriptorItem::kTagCollection: if (!current_item->parent() && (current_usage <= std::numeric_limits::max())) { // This is a top-level collection. HidCollectionInfo collection; collection.usage = HidUsageAndPage( static_cast(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 = static_cast(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