1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "device/hid/hid_report_descriptor_item.h"
6
7#include <stdlib.h>
8
9#include "base/logging.h"
10#include "device/hid/hid_usage_and_page.h"
11
12namespace device {
13
14namespace {
15
16struct Header {
17  uint8_t size : 2;
18  uint8_t type : 2;
19  uint8_t tag : 4;
20};
21
22}  // namespace
23
24HidReportDescriptorItem::HidReportDescriptorItem(
25    const uint8_t* bytes,
26    HidReportDescriptorItem* previous)
27    : previous_(previous), next_(NULL), parent_(NULL), shortData_(0) {
28  Header* header = (Header*)&bytes[0];
29  tag_ = (Tag)(header->tag << 2 | header->type);
30
31  if (IsLong()) {
32    // In a long item, payload size is the second byte.
33    payload_size_ = bytes[1];
34  } else {
35    payload_size_ = header->size;
36    DCHECK(payload_size_ <= sizeof(shortData_));
37    memcpy(&shortData_, &bytes[GetHeaderSize()], payload_size());
38  }
39
40  if (previous) {
41    DCHECK(!previous->next_);
42    previous->next_ = this;
43    switch (previous->tag()) {
44      case kTagCollection:
45        parent_ = previous;
46        break;
47      default:
48        break;
49    }
50    if (!parent_) {
51      switch (tag()) {
52        case kTagEndCollection:
53          if (previous->parent()) {
54            parent_ = previous->parent()->parent();
55          }
56          break;
57        default:
58          parent_ = previous->parent();
59          break;
60      }
61    }
62  }
63}
64
65size_t HidReportDescriptorItem::GetDepth() const {
66  HidReportDescriptorItem* parent_item = parent();
67  if (parent_item)
68    return parent_item->GetDepth() + 1;
69  return 0;
70}
71
72bool HidReportDescriptorItem::IsLong() const { return tag() == kTagLong; }
73
74size_t HidReportDescriptorItem::GetHeaderSize() const {
75  return IsLong() ? 3 : 1;
76}
77
78size_t HidReportDescriptorItem::GetSize() const {
79  return GetHeaderSize() + payload_size();
80}
81
82uint32_t HidReportDescriptorItem::GetShortData() const {
83  DCHECK(!IsLong());
84  return shortData_;
85}
86
87HidReportDescriptorItem::CollectionType
88HidReportDescriptorItem::GetCollectionTypeFromValue(uint32_t value) {
89  switch (value) {
90    case 0x00:
91      return kCollectionTypePhysical;
92    case 0x01:
93      return kCollectionTypeApplication;
94    case 0x02:
95      return kCollectionTypeLogical;
96    case 0x03:
97      return kCollectionTypeReport;
98    case 0x04:
99      return kCollectionTypeNamedArray;
100    case 0x05:
101      return kCollectionTypeUsageSwitch;
102    case 0x06:
103      return kCollectionTypeUsageModifier;
104    default:
105      break;
106  }
107  if (0x80 < value && value < 0xFF)
108    return kCollectionTypeVendor;
109  return kCollectionTypeReserved;
110}
111
112}  // namespace device
113