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 "HidDefs.h"
17 #include "HidParser.h"
18 #include "HidLog.h"
19 #include <iostream>
20 #include <iomanip>
21 
22 namespace HidUtil {
23 
reset()24 void HidParser::reset() {
25     mGlobalStack = HidGlobalStack();
26     mLocal = HidLocal();
27     mTree = std::make_shared<HidTreeNode>();
28     mCurrent = mTree;
29 }
30 
parse(const std::vector<HidItem> & token)31 bool HidParser::parse(const std::vector<HidItem> &token) {
32     // Clean up internal states of the parser for a new stream of descriptor token
33     reset();
34 
35     bool ret = true;
36     using namespace HidDef::TagType;
37 
38     for (auto &i : token) {
39         switch (i.type) {
40             case MAIN:
41                 ret = processMainTag(i);
42                 break;
43             case GLOBAL:
44                 ret = mGlobalStack.append(i);
45                 break;
46             case LOCAL:
47                 ret = mLocal.append(i);
48                 break;
49             default:
50                 LOG_E << "HidParser found illegal HidItem: " << i << LOG_ENDL;
51                 ret = false;
52         }
53 
54         // in case a parse failure, quit prematurely
55         if (!ret) {
56             break;
57         }
58     }
59     return ret;
60 }
61 
processMainTag(const HidItem & i)62 bool HidParser::processMainTag(const HidItem &i) {
63     using namespace HidDef::MainTag;
64     using namespace HidDef::ReportFlag;
65 
66     bool ret = true;
67     switch (i.tag) {
68         case COLLECTION: {
69             unsigned int collectionType;
70             if (!i.dataAsUnsigned(&collectionType)) {
71                 LOG_E << "Cannot get collection type at offset " << i.offset << LOG_ENDL;
72                 ret = false;
73                 break;
74             }
75             unsigned int fullUsage =
76                     mGlobalStack.top().usagePage.get(0) << 16 | mLocal.getUsage(0);
77             mCurrent = mCurrent->addChild(
78                     std::make_shared<HidTreeNode>(mCurrent, collectionType, fullUsage));
79             break;
80         }
81         case END_COLLECTION:
82             mCurrent = mCurrent->getParent();
83             if (!mCurrent) {
84                 // trigger parse failure so that mCurrent will not be accessed
85                 LOG_E << "unmatched END_COLLECTION at " << i.offset << LOG_ENDL;
86                 ret = false;
87             }
88             break;
89         case INPUT:
90         case OUTPUT:
91         case FEATURE: {
92             unsigned int reportType = i.tag;
93             unsigned int flag;
94             if (!i.dataAsUnsigned(&flag)) {
95                 LOG_E << "Cannot get report flag at offset " << i.offset << LOG_ENDL;
96                 ret = false;
97                 break;
98             }
99             const HidGlobal &top = mGlobalStack.top();
100 
101             // usage page, local min/max, report size and count have to be defined at report
102             // definition.
103             if (!(top.usagePage.isSet() && top.logicalMin.isSet() && top.logicalMax.isSet()
104                   && top.reportSize.isSet() && top.reportCount.isSet())) {
105                 LOG_E << "Report defined at " << i.offset
106                       << " does not have all mandatory fields set" << LOG_ENDL;
107                 ret = false;
108                 break;
109             }
110             if (top.reportSize.get(0) > 32) {
111                 LOG_E << "Report defined at " << i.offset
112                       << " has unsupported report size(> 32 bit)" << LOG_ENDL;
113                 ret = false;
114                 break;
115             }
116 
117             HidReport report(reportType, flag, top, mLocal);
118             mReport.push_back(report);
119             std::shared_ptr<HidTreeNode> node(new HidReportNode(mCurrent, report));
120             mCurrent->addChild(node);
121             break;
122         }
123         default:
124             LOG_E << "unknown main tag, " << i << LOG_ENDL;
125             ret = false;
126     }
127     // locals is cleared after any main tag according to HID spec
128     mLocal.clear();
129     return ret;
130 }
131 
parse(const unsigned char * begin,size_t size)132 bool HidParser::parse(const unsigned char *begin, size_t size) {
133     std::vector<HidItem> hidItemVector = HidItem::tokenize(begin, size);
134     return parse(hidItemVector);
135 }
136 
filterTree()137 void HidParser::filterTree() {
138     if (mTree != nullptr) {
139         filterTree(mTree);
140     }
141 }
142 
filterTree(std::shared_ptr<HidTreeNode> & node)143 void HidParser::filterTree(std::shared_ptr<HidTreeNode> &node) {
144     if (node->isReportCollection()) {
145         std::shared_ptr<HidReportNode> reportNode =
146                 std::static_pointer_cast<HidReportNode>(node->getChildren().front());
147         if (reportNode != nullptr) {
148             reportNode->collapse(node->getFullUsage());
149             node = reportNode;
150         }
151     } else {
152         for (auto &i : node->getChildren()) {
153             filterTree(i);
154         }
155     }
156 }
157 
generateDigest(const std::unordered_set<unsigned int> & interestedUsage)158 HidParser::DigestVector HidParser::generateDigest(
159         const std::unordered_set<unsigned int> &interestedUsage) {
160     DigestVector digestVector;
161     digest(&digestVector, mTree, interestedUsage);
162     return digestVector;
163 }
164 
digest(HidParser::DigestVector * digestVector,const std::shared_ptr<HidTreeNode> & node,const std::unordered_set<unsigned int> & interestedUsage)165 void HidParser::digest(HidParser::DigestVector *digestVector,
166                        const std::shared_ptr<HidTreeNode> &node,
167                        const std::unordered_set<unsigned int> &interestedUsage) {
168     if (digestVector == nullptr) {
169         return;
170     }
171 
172     if (node->isUsageCollection()
173             && interestedUsage.find(node->getFullUsage()) != interestedUsage.end()) {
174         // this collection contains the usage interested
175         ReportSetGroup reportSetGroup;
176 
177         // one layer deep search
178         for (auto &i : node->getChildren()) {
179             // skip all nodes that is not a report node
180             if (i->getNodeType() != HidTreeNode::TYPE_REPORT) {
181                 continue;
182             }
183             const HidReport &report =
184                     std::static_pointer_cast<HidReportNode>(i)->getReport();
185 
186             unsigned int id = report.getReportId();;
187             if (reportSetGroup.find(id) == reportSetGroup.end()) {
188                 // create an id group if it is not created
189                 reportSetGroup.emplace(id, ReportSet());
190             }
191 
192             ReportSet &reportGroup = reportSetGroup[id];
193             switch(report.getType()) {
194                 using namespace HidDef::MainTag;
195                 case FEATURE:
196                     reportGroup[REPORT_TYPE_FEATURE].push_back(report);
197                     break;
198                 case INPUT:
199                     reportGroup[REPORT_TYPE_INPUT].push_back(report);
200                     break;
201                 case OUTPUT:
202                     reportGroup[REPORT_TYPE_OUTPUT].push_back(report);
203                     break;
204             }
205         }
206         ReportDigest digest = {
207             .fullUsage = node->getFullUsage(),
208             .packets = convertGroupToPacket(reportSetGroup)
209         };
210         digestVector->emplace_back(digest);
211     } else {
212         for (const auto &child : node->getChildren()) {
213             if (child->getNodeType() == HidTreeNode::TYPE_NORMAL) {
214                 // only follow into collection nodes
215                 digest(digestVector, child, interestedUsage);
216             }
217         }
218     }
219 }
220 
convertGroupToPacket(const HidParser::ReportSetGroup & group)221 std::vector<HidParser::ReportPacket> HidParser::convertGroupToPacket(
222         const HidParser::ReportSetGroup &group) {
223     std::vector<ReportPacket> packets;
224 
225     const std::vector<int> types = {REPORT_TYPE_FEATURE, REPORT_TYPE_INPUT, REPORT_TYPE_OUTPUT};
226 
227     for (const auto &setPair : group) {
228         unsigned int id = setPair.first;
229         for (auto type : types) {
230             const auto &reports = setPair.second[type]; // feature
231 
232             // template
233             ReportPacket packet = {
234                 .type = type,
235                 .id = id,
236                 .bitSize = 0
237             };
238 
239             for (const auto &r : reports) {
240                 auto logical = r.getLogicalRange();
241                 auto physical = r.getPhysicalRange();
242 
243                 int64_t offset = physical.first - logical.first;
244                 double scale = static_cast<double>((physical.second - physical.first))
245                         / (logical.second - logical.first);
246                 scale *= r.getExponentValue();
247 
248                 ReportItem digest = {
249                     .usage = r.getFullUsage(),
250                     .id = id,
251                     .minRaw = logical.first,
252                     .maxRaw = logical.second,
253                     .a = scale,
254                     .b = offset,
255                     .bitOffset = packet.bitSize,
256                     .bitSize = r.getSize(),
257                     .count = r.getCount(),
258                     .unit = r.getUnit(),
259                 };
260                 packet.reports.push_back(digest);
261                 packet.bitSize += digest.bitSize * digest.count;
262             }
263             if (!packet.reports.empty()) {
264                 packets.push_back(std::move(packet));
265             }
266         }
267     }
268     return packets;
269 }
270 
reportTypeToString(int reportType)271 static std::string reportTypeToString(int reportType) {
272     switch (reportType) {
273         case HidParser::REPORT_TYPE_INPUT:
274             return "INPUT";
275         case HidParser::REPORT_TYPE_OUTPUT:
276             return "OUTPUT";
277         case HidParser::REPORT_TYPE_FEATURE:
278             return "FEATURE";
279         default:
280             return "INVALID REPORT";
281     }
282 }
283 
operator <<(std::ostream & os,const HidParser::DigestVector & digests)284 std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digests) {
285     for (const auto &i : digests) {
286         os << "Usage: 0x" << std::hex  << i.fullUsage << std::dec
287            << ", " << i.packets.size() << " report packet:" << LOG_ENDL;
288         for (const auto &packet : i.packets) {
289             os << reportTypeToString(packet.type) << " id: " << packet.id
290                << " size: " << packet.bitSize
291                << "b(" << packet.getByteSize() << "B), "
292                << packet.reports.size() << " entries" << LOG_ENDL;
293 
294             for (const auto &report : packet.reports) {
295                 double min, max;
296                 report.decode(report.mask(report.minRaw), &min);
297                 report.decode(report.mask(report.maxRaw), &max);
298 
299                 os << "  " << report.bitOffset << " size: " << report.bitSize
300                    << ", count: " << report.count
301                    << ", usage: " << std::hex << std::setfill('0') << std::setw(8)
302                    << report.usage << std::dec
303                    << ", min: " << report.minRaw << ", max: " << report.maxRaw
304                    << ", minDecoded: " << min
305                    << ", maxDecoded: " << max
306                    << ", a: " << report.a << ", b: " << report.b
307                    << std::hex
308                    << ", minRawHex: 0x" << report.mask(report.minRaw)
309                    << ", maxRawHex: 0x" << report.mask(report.maxRaw)
310                    << ", rawMasked: 0x" << report.rawMask()
311                    << std::dec << LOG_ENDL;
312             }
313         }
314         os << LOG_ENDL;
315     }
316     os << LOG_ENDL;
317     return os;
318 }
319 } // namespace HidUtil
320