Chromium Code Reviews| Index: device/hid/hid_report_descriptor_item.cc |
| diff --git a/device/hid/hid_report_descriptor_item.cc b/device/hid/hid_report_descriptor_item.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f2ce3b7dd5c0371c81c4359ae6437add2268237e |
| --- /dev/null |
| +++ b/device/hid/hid_report_descriptor_item.cc |
| @@ -0,0 +1,340 @@ |
| +// 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_item.h" |
| + |
| +#include <stdlib.h> |
| + |
| +#include "base/logging.h" |
| +#include "device/hid/hid_usage_and_page.h" |
| + |
| +namespace device { |
| + |
| +namespace { |
| + |
| +std::ostream& operator<<(std::ostream& os, |
| + const HidReportDescriptorItem::Tag& tag) { |
| + switch (tag) { |
| + case HidReportDescriptorItem::kTagDefault: |
| + os << "Default"; |
| + break; |
| + case HidReportDescriptorItem::kTagInput: |
| + os << "Input"; |
| + break; |
| + case HidReportDescriptorItem::kTagOutput: |
| + os << "Output"; |
| + break; |
| + case HidReportDescriptorItem::kTagFeature: |
| + os << "Feature"; |
| + break; |
| + case HidReportDescriptorItem::kTagCollection: |
| + os << "Collection"; |
| + break; |
| + case HidReportDescriptorItem::kTagEndCollection: |
| + os << "End Collection"; |
| + break; |
| + case HidReportDescriptorItem::kTagUsagePage: |
| + os << "Usage Page"; |
| + break; |
| + case HidReportDescriptorItem::kTagLogicalMinimum: |
| + os << "Logical Minimum"; |
| + break; |
| + case HidReportDescriptorItem::kTagLogicalMaximum: |
| + os << "Logical Maximum"; |
| + break; |
| + case HidReportDescriptorItem::kTagPhysicalMinimum: |
| + os << "Physical Minimum"; |
| + break; |
| + case HidReportDescriptorItem::kTagPhysicalMaximum: |
| + os << "Physical Maximum"; |
| + break; |
| + case HidReportDescriptorItem::kTagUnitExponent: |
| + os << "Unit Exponent"; |
| + break; |
| + case HidReportDescriptorItem::kTagUnit: |
| + os << "Unit"; |
| + break; |
| + case HidReportDescriptorItem::kTagReportSize: |
| + os << "Report Size"; |
| + break; |
| + case HidReportDescriptorItem::kTagReportId: |
| + os << "Report ID"; |
| + break; |
| + case HidReportDescriptorItem::kTagReportCount: |
| + os << "Report Count"; |
| + break; |
| + case HidReportDescriptorItem::kTagPush: |
| + os << "Push"; |
| + break; |
| + case HidReportDescriptorItem::kTagPop: |
| + os << "Pop"; |
| + break; |
| + case HidReportDescriptorItem::kTagUsage: |
| + os << "Usage"; |
| + break; |
| + case HidReportDescriptorItem::kTagUsageMinimum: |
| + os << "Usage Minimum"; |
| + break; |
| + case HidReportDescriptorItem::kTagUsageMaximum: |
| + os << "Usage Maximum"; |
| + break; |
| + case HidReportDescriptorItem::kTagDesignatorIndex: |
| + os << "Designator Index"; |
| + break; |
| + case HidReportDescriptorItem::kTagDesignatorMinimum: |
| + os << "Designator Minimum"; |
| + break; |
| + case HidReportDescriptorItem::kTagDesignatorMaximum: |
| + os << "Designator Maximum"; |
| + break; |
| + case HidReportDescriptorItem::kTagStringIndex: |
| + os << "String Index"; |
| + break; |
| + case HidReportDescriptorItem::kTagStringMinimum: |
| + os << "String Minimum"; |
| + break; |
| + case HidReportDescriptorItem::kTagStringMaximum: |
| + os << "String Maximum"; |
| + break; |
| + case HidReportDescriptorItem::kTagDelimiter: |
| + os << "Delimeter"; |
| + break; |
| + case HidReportDescriptorItem::kTagLong: |
| + os << "Long"; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + return os; |
| +} |
| + |
| +std::ostream& operator<<(std::ostream& os, |
| + const HidReportDescriptorItem::ReportInfo& data) { |
| + if (data.data_or_constant) |
| + os << "Con"; |
| + else |
| + os << "Dat"; |
| + if (data.array_or_variable) |
| + os << "|Arr"; |
| + else |
| + os << "|Var"; |
| + if (data.absolute_or_relative) |
| + os << "|Abs"; |
| + else |
| + os << "|Rel"; |
| + if (data.wrap) |
| + os << "|Wrp"; |
| + else |
| + os << "|NoWrp"; |
| + if (data.linear) |
| + os << "|NoLin"; |
| + else |
| + os << "|Lin"; |
| + if (data.preferred) |
| + os << "|NoPrf"; |
| + else |
| + os << "|Prf"; |
| + if (data.null) |
| + os << "|Null"; |
| + else |
| + os << "|NoNull"; |
| + if (data.bit_field_or_buffer) |
| + os << "|Buff"; |
| + else |
| + os << "|BitF"; |
| + return os; |
| +} |
| + |
| +std::ostream& operator<<(std::ostream& os, |
| + const HidReportDescriptorItem::CollectionType& type) { |
| + switch (type) { |
| + case HidReportDescriptorItem::kCollectionTypePhysical: |
| + os << "Physical"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeApplication: |
| + os << "Application"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeLogical: |
| + os << "Logical"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeReport: |
| + os << "Report"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeNamedArray: |
| + os << "Named Array"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeUsageSwitch: |
| + os << "Usage Switch"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeUsageModifier: |
| + os << "Usage Modifier"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeReserved: |
| + os << "Reserved"; |
| + break; |
| + case HidReportDescriptorItem::kCollectionTypeVendor: |
| + os << "Vendor"; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + return os; |
| +} |
| + |
| +struct Header { |
| + uint8_t size : 2; |
| + uint8_t type : 2; |
| + uint8_t tag : 4; |
| +}; |
| + |
| +struct LongHeader { |
| + Header short_header; |
| + uint8_t data_size; |
| + uint8_t long_item_tag; |
| +}; |
| + |
| +} // namespace |
| + |
| +HidReportDescriptorItem::HidReportDescriptorItem( |
| + const uint8_t* bytes, |
| + HidReportDescriptorItem* previous) |
| + : previous_(previous), next_(NULL), parent_(NULL), shortData_(0) { |
| + Header* header = (Header*)&bytes[0]; |
| + tag_ = (Tag)(header->tag << 2 | header->type); |
| + |
| + if (IsLong()) { |
| + LongHeader* long_header = (LongHeader*)&bytes[0]; |
|
Ken Rockot(use gerrit already)
2014/04/21 21:53:53
Please do not do this. You already have the short
jracle (use Gerrit)
2014/04/23 07:48:32
Sure, it will be equivalent in terms of clarity if
|
| + payload_size_ = long_header->data_size; |
| + } else { |
| + payload_size_ = header->size; |
|
Ken Rockot(use gerrit already)
2014/04/21 21:53:53
Please verify that payload_size_ <= sizeof(shortDa
jracle (use Gerrit)
2014/04/23 07:48:32
oops, thanks. Don't wanna end-up to another a-la o
|
| + memcpy(&shortData_, &bytes[GetHeaderSize()], payloadSize()); |
| + } |
| + |
| + if (previous) { |
|
Ken Rockot(use gerrit already)
2014/04/21 21:53:53
Please at least DCHECK(!previous->next_) to clarif
jracle (use Gerrit)
2014/04/23 07:48:32
OK
|
| + previous->next_ = this; |
| + switch (previous->tag()) { |
| + case kTagCollection: |
| + parent_ = previous; |
| + break; |
| + default: |
| + break; |
| + } |
| + if (!parent_) { |
| + switch (tag()) { |
| + case kTagEndCollection: |
| + if (previous->parent()) { |
| + parent_ = previous->parent()->parent(); |
| + } |
| + break; |
| + default: |
| + parent_ = previous->parent(); |
| + break; |
| + } |
| + } |
| + } |
| +} |
| + |
| +size_t HidReportDescriptorItem::GetDepth() const { |
| + HidReportDescriptorItem* parent_item = parent(); |
| + if (parent_item) |
| + return parent_item->GetDepth() + 1; |
| + return 0; |
| +} |
| + |
| +bool HidReportDescriptorItem::IsLong() const { return tag() == kTagLong; } |
| + |
| +size_t HidReportDescriptorItem::GetHeaderSize() const { |
| + return IsLong() ? 3 : 1; |
| +} |
| + |
| +size_t HidReportDescriptorItem::GetSize() const { |
| + return GetHeaderSize() + payloadSize(); |
| +} |
| + |
| +uint32_t HidReportDescriptorItem::GetShortData() const { |
| + DCHECK(!IsLong()); |
| + return shortData_; |
| +} |
| + |
| +HidReportDescriptorItem::CollectionType |
| +HidReportDescriptorItem::GetCollectionTypeFromValue(uint32_t value) { |
| + switch (value) { |
| + case 0x00: |
| + return kCollectionTypePhysical; |
| + case 0x01: |
| + return kCollectionTypePhysical; |
| + case 0x02: |
| + return kCollectionTypePhysical; |
| + case 0x03: |
| + return kCollectionTypePhysical; |
| + case 0x04: |
| + return kCollectionTypePhysical; |
| + case 0x05: |
| + return kCollectionTypePhysical; |
| + case 0x06: |
| + return kCollectionTypePhysical; |
| + default: |
| + break; |
| + } |
| + if (0x80 < value && value < 0xFF) |
| + return kCollectionTypeVendor; |
| + return kCollectionTypeReserved; |
| +} |
| + |
| +std::ostream& operator<<(std::ostream& os, |
| + const HidReportDescriptorItem& item) { |
| + HidReportDescriptorItem::Tag item_tag = item.tag(); |
| + uint32_t data = item.GetShortData(); |
| + |
| + std::ostringstream sstr; |
| + sstr << item_tag; |
| + sstr << " ("; |
| + |
| + long pos = sstr.tellp(); |
| + switch (item_tag) { |
| + case HidReportDescriptorItem::kTagDefault: |
| + case HidReportDescriptorItem::kTagEndCollection: |
| + case HidReportDescriptorItem::kTagPush: |
| + case HidReportDescriptorItem::kTagPop: |
| + case HidReportDescriptorItem::kTagLong: |
| + break; |
| + |
| + case HidReportDescriptorItem::kTagCollection: |
| + sstr << HidReportDescriptorItem::GetCollectionTypeFromValue(data); |
| + break; |
| + |
| + case HidReportDescriptorItem::kTagInput: |
| + case HidReportDescriptorItem::kTagOutput: |
| + case HidReportDescriptorItem::kTagFeature: |
| + sstr << (HidReportDescriptorItem::ReportInfo&)data; |
| + break; |
| + |
| + case HidReportDescriptorItem::kTagUsagePage: |
| + sstr << (HidUsageAndPage::Page)data; |
| + break; |
| + |
| + case HidReportDescriptorItem::kTagUsage: |
| + case HidReportDescriptorItem::kTagReportId: |
| + sstr << "0x" << std::hex << std::uppercase << data; |
| + break; |
| + |
| + default: |
| + sstr << data; |
| + break; |
| + } |
| + if (pos == sstr.tellp()) { |
| + std::string str = sstr.str(); |
| + str.erase(str.end() - 2, str.end()); |
| + os << str; |
| + } else { |
| + os << sstr.str() << ")"; |
| + } |
| + |
| + return os; |
| +} |
| + |
| +} // namespace device |