/* * 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 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 SplitString(const std::string &s, char c) { std::vector 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 std::ostream &operator<<(std::ostream &os, const std::vector objs) { bool first = true; for (const T &v : objs) { if (!first) { os << ","; } os << v; first = false; } return os; } template bool parse(const std::string &s, std::vector *objs) { std::vector 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 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(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(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); } } // 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 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(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 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 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 v = SplitString(s, '-'); if (v.size() != 1 && v.size() != 2) { return false; } std::vector 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 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(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(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 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 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