/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HidItem.h"
#include "HidDefs.h"
#include "StreamIoUtil.h"
#include <iostream>
namespace HidUtil {
bool HidItem::dataAsUnsigned(unsigned int *out) const {
if (data.size() > 4 || data.size() == 0) {
return false;
}
*out = 0;
int shift = 0;
for (auto i : data) {
*out |= (i << shift);
shift += 8;
}
return true;
}
bool HidItem::dataAsSigned(int *out) const {
unsigned int u;
if (!dataAsUnsigned(&u)) {
return false;
}
size_t bitSize_1 = data.size() * 8 - 1;
unsigned int sign = u & (1 << bitSize_1);
*out = u | ((sign == 0) ? 0 : ( ~0 << bitSize_1));
return true;
}
std::vector<HidItem> HidItem::tokenize(const uint8_t *begin, size_t size) {
// construct a stream
charvectorbuf<unsigned char> buf(begin, size);
std::istream is(&buf);
return tokenize(is);
}
std::vector<HidItem> HidItem::tokenize(const std::vector<uint8_t> &descriptor) {
// construct a stream
charvectorbuf<unsigned char> buf(descriptor);
std::istream is(&buf);
return tokenize(is);
}
std::vector<HidItem> HidItem::tokenize(std::istream &is) {
std::vector<HidItem> hidToken;
// this is important to avoid skipping characters
is.unsetf(std::ios_base::skipws);
while (!is.eof()) {
HidItem i;
is >> i;
if (i.valid) {
hidToken.push_back(i);
} else {
break;
}
}
return hidToken;
}
std::istream& operator>>(std::istream &is, HidUtil::HidItem &h) {
using namespace HidUtil::HidDef::MainTag;
using namespace HidUtil::HidDef::TagType;
h.valid = false;
h.offset = is.tellg();
h.byteSize = 0;
unsigned char first;
is >> first;
if (!is.eof()) {
static const size_t lenTable[] = { 0, 1, 2, 4 };
size_t len = lenTable[first & 0x3]; // low 2 bits are length descriptor
h.tag = (first >> 4);
h.type = (first & 0xC) >> 2;
if (h.tag == LONG_ITEM && h.type == RESERVED) { // long item
//long item
unsigned char b = 0;
is >> b;
len = b;
is >> b;
h.tag = b;
}
h.data.resize(len);
for (auto &i : h.data) {
if (is.eof()) {
break;
}
is >> i;
}
h.byteSize = (ssize_t) is.tellg() - h.offset;
h.valid = !is.eof();
}
return is;
}
std::ostream& operator<<(std::ostream &os, const HidUtil::HidItem &h) {
os << "offset: " << h.offset << ", size: " << h.byteSize
<< ", tag: " << h.tag << ", type: " << h.type << ", data: ";
if (h.data.empty()) {
os << "[empty]";
} else {
os << h.data.size() << " byte(s) {";
for (auto i : h.data) {
os << (int) i << ", ";
}
os << "}";
}
return os;
}
} // namespace HidUtil