blob: d412ac48620f34e9d77bd0013e9d21d5b0332093 [file] [log] [blame]
/*
* 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.
*/
// Convert objects from and to strings.
#include "parse_string.h"
#include <android-base/parseint.h>
namespace android {
using base::ParseUint;
namespace vintf {
static const std::string kRequired("required");
static const std::string kOptional("optional");
static const std::string kConfigPrefix("CONFIG_");
std::vector<std::string> SplitString(const std::string &s, char c) {
std::vector<std::string> components;
size_t startPos = 0;
size_t matchPos;
while ((matchPos = s.find(c, startPos)) != std::string::npos) {
components.push_back(s.substr(startPos, matchPos - startPos));
startPos = matchPos + 1;
}
if (startPos <= s.length()) {
components.push_back(s.substr(startPos));
}
return components;
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> objs) {
bool first = true;
for (const T &v : objs) {
if (!first) {
os << ",";
}
os << v;
first = false;
}
return os;
}
template <typename T>
bool parse(const std::string &s, std::vector<T> *objs) {
std::vector<std::string> v = SplitString(s, ',');
objs->resize(v.size());
size_t idx = 0;
for (const auto &item : v) {
T ver;
if (!parse(item, &ver)) {
return false;
}
objs->at(idx++) = ver;
}
return true;
}
template<typename E, typename Array>
bool parseEnum(const std::string &s, E *e, const Array &strings) {
for (size_t i = 0; i < strings.size(); ++i) {
if (s == strings.at(i)) {
*e = static_cast<E>(i);
return true;
}
}
return false;
}
#define DEFINE_PARSE_STREAMIN_FOR_ENUM(ENUM) \
bool parse(const std::string &s, ENUM *hf) { \
return parseEnum(s, hf, g##ENUM##Strings); \
} \
std::ostream &operator<<(std::ostream &os, ENUM hf) { \
return os << g##ENUM##Strings.at(static_cast<size_t>(hf)); \
} \
DEFINE_PARSE_STREAMIN_FOR_ENUM(HalFormat);
DEFINE_PARSE_STREAMIN_FOR_ENUM(Transport);
DEFINE_PARSE_STREAMIN_FOR_ENUM(Arch);
DEFINE_PARSE_STREAMIN_FOR_ENUM(KernelConfigType);
DEFINE_PARSE_STREAMIN_FOR_ENUM(Tristate);
DEFINE_PARSE_STREAMIN_FOR_ENUM(SchemaType);
std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
switch (kctv.mType) {
case KernelConfigType::STRING:
return os << kctv.mStringValue;
case KernelConfigType::INTEGER:
return os << to_string(kctv.mIntegerValue);
case KernelConfigType::RANGE:
return os << to_string(kctv.mRangeValue.first) << "-"
<< to_string(kctv.mRangeValue.second);
case KernelConfigType::TRISTATE:
return os << to_string(kctv.mTristateValue);
}
}
// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
// because strtoull can accept negative values as well.
// Notice that according to man strtoul, strtoull can actually accept
// -2^64 + 1 to 2^64 - 1, with the 65th bit truncated.
// ParseInt / ParseUint are not used because they do not handle signed hex very well.
template <typename T>
bool parseKernelConfigIntHelper(const std::string &s, T *i) {
char *end;
errno = 0;
unsigned long long int ulli = strtoull(s.c_str(), &end, 0 /* base */);
// It is implementation defined that what value will be returned by strtoull
// in the error case, so we are checking errno directly here.
if (errno == 0 && s.c_str() != end && *end == '\0') {
*i = static_cast<T>(ulli);
return true;
}
return false;
}
bool parseKernelConfigInt(const std::string &s, int64_t *i) {
return parseKernelConfigIntHelper(s, i);
}
bool parseKernelConfigInt(const std::string &s, uint64_t *i) {
return parseKernelConfigIntHelper(s, i);
}
bool parseRange(const std::string &s, KernelConfigRangeValue *range) {
auto pos = s.find('-');
if (pos == std::string::npos) {
return false;
}
return parseKernelConfigInt(s.substr(0, pos), &range->first)
&& parseKernelConfigInt(s.substr(pos + 1), &range->second);
}
bool parse(const std::string &s, KernelConfigKey *key) {
*key = s;
return true;
}
bool parseKernelConfigValue(const std::string &s, KernelConfigTypedValue *kctv) {
switch (kctv->mType) {
case KernelConfigType::STRING:
kctv->mStringValue = s;
return true;
case KernelConfigType::INTEGER:
return parseKernelConfigInt(s, &kctv->mIntegerValue);
case KernelConfigType::RANGE:
return parseRange(s, &kctv->mRangeValue);
case KernelConfigType::TRISTATE:
return parse(s, &kctv->mTristateValue);
}
}
bool parse(const std::string &s, Version *ver) {
std::vector<std::string> v = SplitString(s, '.');
if (v.size() != 2) {
return false;
}
size_t major, minor;
if (!ParseUint(v[0], &major)) {
return false;
}
if (!ParseUint(v[1], &minor)) {
return false;
}
*ver = Version(major, minor);
return true;
}
std::ostream &operator<<(std::ostream &os, const Version &ver) {
return os << ver.majorVer << "." << ver.minorVer;
}
bool parse(const std::string &s, VersionRange *vr) {
std::vector<std::string> v = SplitString(s, '-');
if (v.size() != 1 && v.size() != 2) {
return false;
}
Version minVer;
if (!parse(v[0], &minVer)) {
return false;
}
if (v.size() == 1) {
*vr = VersionRange(minVer.majorVer, minVer.minorVer);
} else {
size_t maxMinor;
if (!ParseUint(v[1], &maxMinor)) {
return false;
}
*vr = VersionRange(minVer.majorVer, minVer.minorVer, maxMinor);
}
return true;
}
std::ostream &operator<<(std::ostream &os, const VersionRange &vr) {
if (vr.isSingleVersion()) {
return os << vr.minVer();
}
return os << vr.minVer() << "-" << vr.maxMinor;
}
bool parse(const std::string &s, VndkVersionRange *vr) {
std::vector<std::string> v = SplitString(s, '-');
if (v.size() != 1 && v.size() != 2) {
return false;
}
std::vector<std::string> minVector = SplitString(v[0], '.');
if (minVector.size() != 3) {
return false;
}
if (!ParseUint(minVector[0], &vr->sdk) ||
!ParseUint(minVector[1], &vr->vndk) ||
!ParseUint(minVector[2], &vr->patchMin)) {
return false;
}
if (v.size() == 1) {
vr->patchMax = vr->patchMin;
return true;
} else {
return ParseUint(v[1], &vr->patchMax);
}
}
std::ostream &operator<<(std::ostream &os, const VndkVersionRange &vr) {
os << vr.sdk << "." << vr.vndk << "." << vr.patchMin;
if (!vr.isSingleVersion()) {
os << "-" << vr.patchMax;
}
return os;
}
bool parse(const std::string &s, KernelVersion *kernelVersion) {
std::vector<std::string> v = SplitString(s, '.');
if (v.size() != 3) {
return false;
}
size_t version, major, minor;
if (!ParseUint(v[0], &version)) {
return false;
}
if (!ParseUint(v[1], &major)) {
return false;
}
if (!ParseUint(v[2], &minor)) {
return false;
}
*kernelVersion = KernelVersion(version, major, minor);
return true;
}
std::ostream &operator<<(std::ostream &os, const TransportArch &ta) {
return os << to_string(ta.transport) << to_string(ta.arch);
}
bool parse(const std::string &s, TransportArch *ta) {
bool transportSet = false;
bool archSet = false;
for (size_t i = 0; i < gTransportStrings.size(); ++i) {
if (s.find(gTransportStrings.at(i)) != std::string::npos) {
ta->transport = static_cast<Transport>(i);
transportSet = true;
break;
}
}
if (!transportSet) {
return false;
}
for (size_t i = 0; i < gArchStrings.size(); ++i) {
if (s.find(gArchStrings.at(i)) != std::string::npos) {
ta->arch = static_cast<Arch>(i);
archSet = true;
break;
}
}
if (!archSet) {
return false;
}
return ta->isValid();
}
std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
}
bool parse(const std::string &s, ManifestHal *hal) {
std::vector<std::string> v = SplitString(s, '/');
if (v.size() != 4) {
return false;
}
if (!parse(v[0], &hal->format)) {
return false;
}
hal->name = v[1];
if (!parse(v[2], &hal->transportArch)) {
return false;
}
if (!parse(v[3], &hal->versions)) {
return false;
}
return hal->isValid();
}
std::ostream &operator<<(std::ostream &os, const ManifestHal &hal) {
return os << hal.format << "/"
<< hal.name << "/"
<< hal.transportArch << "/"
<< hal.versions;
}
bool parse(const std::string &s, MatrixHal *req) {
std::vector<std::string> v = SplitString(s, '/');
if (v.size() != 4) {
return false;
}
if (!parse(v[0], &req->format)) {
return false;
}
req->name = v[1];
if (!parse(v[2], &req->versionRanges)) {
return false;
}
if (v[3] != kRequired || v[3] != kOptional) {
return false;
}
req->optional = (v[3] == kOptional);
return true;
}
std::ostream &operator<<(std::ostream &os, const MatrixHal &req) {
return os << req.format << "/"
<< req.name << "/"
<< req.versionRanges << "/"
<< (req.optional ? kOptional : kRequired);
}
std::ostream &operator<<(std::ostream &os, KernelSepolicyVersion ksv){
return os << ksv.value;
}
bool parse(const std::string &s, KernelSepolicyVersion *ksv){
return ParseUint(s, &ksv->value);
}
std::string dump(const HalManifest &vm) {
std::ostringstream oss;
bool first = true;
for (const auto &hal : vm.getHals()) {
if (!first) {
oss << ":";
}
oss << hal;
first = false;
}
return oss.str();
}
std::string dump(const RuntimeInfo &ki) {
std::ostringstream oss;
oss << "kernel = "
<< ki.osName() << "/"
<< ki.nodeName() << "/"
<< ki.osRelease() << "/"
<< ki.osVersion() << "/"
<< ki.hardwareId() << ";"
<< ki.mBootAvbVersion << "/"
<< ki.mBootVbmetaAvbVersion << ";"
<< "kernelSepolicyVersion = " << ki.kernelSepolicyVersion()
<< ";\n\ncpu info:\n"
<< ki.cpuInfo()
<< "\n#CONFIG's loaded = " << ki.mKernelConfigs.size() << ";\n";
for (const auto &pair : ki.mKernelConfigs) {
oss << pair.first << "=" << pair.second << "\n";
}
return oss.str();
}
} // namespace vintf
} // namespace android