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