1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "HidItem.h"
17 #include "HidDefs.h"
18 #include "StreamIoUtil.h"
19 #include <iostream>
20
21 namespace HidUtil {
22
dataAsUnsigned(unsigned int * out) const23 bool HidItem::dataAsUnsigned(unsigned int *out) const {
24 if (data.size() > 4 || data.size() == 0) {
25 return false;
26 }
27
28 *out = 0;
29 int shift = 0;
30
31 for (auto i : data) {
32 *out |= (i << shift);
33 shift += 8;
34 }
35 return true;
36 }
37
dataAsSigned(int * out) const38 bool HidItem::dataAsSigned(int *out) const {
39 unsigned int u;
40 if (!dataAsUnsigned(&u)) {
41 return false;
42 }
43 size_t bitSize_1 = data.size() * 8 - 1;
44 unsigned int sign = u & (1 << bitSize_1);
45 *out = u | ((sign == 0) ? 0 : ( ~0 << bitSize_1));
46 return true;
47 }
48
tokenize(const uint8_t * begin,size_t size)49 std::vector<HidItem> HidItem::tokenize(const uint8_t *begin, size_t size) {
50 // construct a stream
51 charvectorbuf<unsigned char> buf(begin, size);
52 std::istream is(&buf);
53 return tokenize(is);
54 }
55
tokenize(const std::vector<uint8_t> & descriptor)56 std::vector<HidItem> HidItem::tokenize(const std::vector<uint8_t> &descriptor) {
57 // construct a stream
58 charvectorbuf<unsigned char> buf(descriptor);
59 std::istream is(&buf);
60 return tokenize(is);
61 }
62
tokenize(std::istream & is)63 std::vector<HidItem> HidItem::tokenize(std::istream &is) {
64 std::vector<HidItem> hidToken;
65
66 // this is important to avoid skipping characters
67 is.unsetf(std::ios_base::skipws);
68 while (!is.eof()) {
69 HidItem i;
70 is >> i;
71 if (i.valid) {
72 hidToken.push_back(i);
73 } else {
74 break;
75 }
76 }
77 return hidToken;
78 }
79
operator >>(std::istream & is,HidUtil::HidItem & h)80 std::istream& operator>>(std::istream &is, HidUtil::HidItem &h) {
81 using namespace HidUtil::HidDef::MainTag;
82 using namespace HidUtil::HidDef::TagType;
83
84 h.valid = false;
85 h.offset = is.tellg();
86 h.byteSize = 0;
87 unsigned char first;
88 is >> first;
89 if (!is.eof()) {
90 static const size_t lenTable[] = { 0, 1, 2, 4 };
91 size_t len = lenTable[first & 0x3]; // low 2 bits are length descriptor
92 h.tag = (first >> 4);
93 h.type = (first & 0xC) >> 2;
94
95 if (h.tag == LONG_ITEM && h.type == RESERVED) { // long item
96 //long item
97 unsigned char b = 0;
98 is >> b;
99 len = b;
100 is >> b;
101 h.tag = b;
102 }
103
104 h.data.resize(len);
105 for (auto &i : h.data) {
106 if (is.eof()) {
107 break;
108 }
109 is >> i;
110 }
111 h.byteSize = (ssize_t) is.tellg() - h.offset;
112 h.valid = !is.eof();
113 }
114
115 return is;
116 }
117
operator <<(std::ostream & os,const HidUtil::HidItem & h)118 std::ostream& operator<<(std::ostream &os, const HidUtil::HidItem &h) {
119 os << "offset: " << h.offset << ", size: " << h.byteSize
120 << ", tag: " << h.tag << ", type: " << h.type << ", data: ";
121 if (h.data.empty()) {
122 os << "[empty]";
123 } else {
124 os << h.data.size() << " byte(s) {";
125 for (auto i : h.data) {
126 os << (int) i << ", ";
127 }
128 os << "}";
129 }
130 return os;
131 }
132 } // namespace HidUtil
133