/* * 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); DEFINE_PARSE_STREAMIN_FOR_ENUM(XmlSchemaFormat); 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); } } bool parse(const std::string& s, Level* l) { if (s.empty()) { *l = Level::UNSPECIFIED; return true; } if (s == "legacy") { *l = Level::LEGACY; return true; } size_t value; if (!ParseUint(s, &value)) { return false; } *l = static_cast<Level>(value); return true; } std::ostream& operator<<(std::ostream& os, Level l) { if (l == Level::UNSPECIFIED) { return os; } if (l == Level::LEGACY) { return os << "legacy"; } return os << static_cast<size_t>(l); } // 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 parseKernelConfigTypedValue(const std::string& s, KernelConfigTypedValue* kctv) { if (parseKernelConfigInt(s, &kctv->mIntegerValue)) { kctv->mType = KernelConfigType::INTEGER; return true; } if (parse(s, &kctv->mTristateValue)) { kctv->mType = KernelConfigType::TRISTATE; return true; } // Do not test for KernelConfigType::RANGE. kctv->mType = KernelConfigType::STRING; kctv->mStringValue = s; return true; } 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; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" 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; } #pragma clang diagnostic pop 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::string expandInstances(const MatrixHal& req, const VersionRange& vr, bool brace) { std::string s; size_t count = 0; req.forEachInstance(vr, [&](const auto& matrixInstance) { if (count > 0) s += " AND "; s += toFQNameString(vr, matrixInstance.interface(), matrixInstance.isRegex() ? matrixInstance.regexPattern() : matrixInstance.exactInstance()); count++; return true; }); if (count == 0) { s += "@" + to_string(vr); } if (count >= 2 && brace) { s = "(" + s + ")"; } return s; } std::vector<std::string> expandInstances(const MatrixHal& req) { size_t count = req.instancesCount(); if (count == 0) { return {}; } if (count == 1) { return {expandInstances(req, req.versionRanges.front(), false /* brace */)}; } std::vector<std::string> ss; for (const auto& vr : req.versionRanges) { if (!ss.empty()) { ss.back() += " OR"; } ss.push_back(expandInstances(req, vr, true /* brace */)); } return ss; } 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, bool verbose) { std::ostringstream oss; oss << "kernel = " << ki.osName() << "/" << ki.nodeName() << "/" << ki.osRelease() << "/" << ki.osVersion() << "/" << ki.hardwareId() << ";" << ki.mBootAvbVersion << "/" << ki.mBootVbmetaAvbVersion << ";" << "kernelSepolicyVersion = " << ki.kernelSepolicyVersion() << ";"; if (verbose) { oss << "\n\ncpu info:\n" << ki.cpuInfo(); } oss << "\n#CONFIG's loaded = " << ki.mKernelConfigs.size() << ";\n"; if (verbose) { for (const auto& pair : ki.mKernelConfigs) { oss << pair.first << "=" << pair.second << "\n"; } } return oss.str(); } std::string toFQNameString(const std::string& package, const std::string& version, const std::string& interface, const std::string& instance) { std::stringstream ss; ss << package << "@" << version; if (!interface.empty()) { ss << "::" << interface; if (!instance.empty()) { ss << "/" << instance; } } return ss.str(); } std::string toFQNameString(const std::string& package, const Version& version, const std::string& interface, const std::string& instance) { return toFQNameString(package, to_string(version), interface, instance); } std::string toFQNameString(const Version& version, const std::string& interface, const std::string& instance) { return toFQNameString("", version, interface, instance); } // android.hardware.foo@1.0-1::IFoo/default. // Note that the format is extended to support a range of versions. std::string toFQNameString(const std::string& package, const VersionRange& range, const std::string& interface, const std::string& instance) { return toFQNameString(package, to_string(range), interface, instance); } std::string toFQNameString(const VersionRange& range, const std::string& interface, const std::string& instance) { return toFQNameString("", range, interface, instance); } std::ostream& operator<<(std::ostream& os, const FqInstance& fqInstance) { return os << fqInstance.string(); } bool parse(const std::string& s, FqInstance* fqInstance) { return fqInstance->setTo(s); } } // namespace vintf } // namespace android