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
22namespace HidUtil {
23
24void HidParser::reset() {
25    mGlobalStack = HidGlobalStack();
26    mLocal = HidLocal();
27    mTree = std::make_shared<HidTreeNode>();
28    mCurrent = mTree;
29}
30
31bool 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
62bool 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
132bool HidParser::parse(const unsigned char *begin, size_t size) {
133    std::vector<HidItem> hidItemVector = HidItem::tokenize(begin, size);
134    return parse(hidItemVector);
135}
136
137void HidParser::filterTree() {
138    if (mTree != nullptr) {
139        filterTree(mTree);
140    }
141}
142
143void 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
158HidParser::DigestVector HidParser::generateDigest(
159        const std::unordered_set<unsigned int> &interestedUsage) {
160    DigestVector digestVector;
161    digest(&digestVector, mTree, interestedUsage);
162    return digestVector;
163}
164
165void 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
221std::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
271static 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
284std::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