528 lines
14 KiB
C++
528 lines
14 KiB
C++
/*
|
|
* Copyright (C) 2016 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 "FQName.h"
|
|
|
|
#include "StringHelper.h"
|
|
|
|
#include <android-base/logging.h>
|
|
#include <android-base/parseint.h>
|
|
#include <iostream>
|
|
#include <regex>
|
|
#include <sstream>
|
|
|
|
#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
|
|
#define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
|
|
#define RE_MAJOR "[0-9]+"
|
|
#define RE_MINOR "[0-9]+"
|
|
|
|
// android.hardware.foo@1.0::IFoo.Type
|
|
static const std::regex kRE1("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
|
|
// @1.0::IFoo.Type
|
|
static const std::regex kRE2("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
|
|
// android.hardware.foo@1.0 (for package declaration and whole package import)
|
|
static const std::regex kRE3("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")");
|
|
// IFoo.Type
|
|
static const std::regex kRE4("(" RE_COMPONENT ")([.]" RE_COMPONENT ")+");
|
|
// Type (a plain identifier)
|
|
static const std::regex kRE5("(" RE_COMPONENT ")");
|
|
|
|
// android.hardware.foo@1.0::IFoo.Type:MY_ENUM_VALUE
|
|
static const std::regex kRE6("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT ")");
|
|
// @1.0::IFoo.Type:MY_ENUM_VALUE
|
|
static const std::regex kRE7("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT ")");
|
|
// IFoo.Type:MY_ENUM_VALUE
|
|
static const std::regex kRE8("(" RE_PATH "):(" RE_COMPONENT ")");
|
|
|
|
// 1.0
|
|
static const std::regex kREVer("(" RE_MAJOR ")[.](" RE_MINOR ")");
|
|
|
|
namespace android {
|
|
|
|
FQName::FQName()
|
|
: mValid(false),
|
|
mIsIdentifier(false) {
|
|
}
|
|
|
|
FQName::FQName(const std::string &s)
|
|
: mValid(false),
|
|
mIsIdentifier(false) {
|
|
setTo(s);
|
|
}
|
|
|
|
FQName::FQName(
|
|
const std::string &package,
|
|
const std::string &version,
|
|
const std::string &name,
|
|
const std::string &valueName)
|
|
: mValid(true),
|
|
mIsIdentifier(false),
|
|
mPackage(package),
|
|
mName(name),
|
|
mValueName(valueName) {
|
|
setVersion(version);
|
|
|
|
// Check if this is actually a valid fqName
|
|
FQName other;
|
|
other.setTo(this->string());
|
|
CHECK(other.mValid && (*this) == other);
|
|
}
|
|
|
|
FQName::FQName(const FQName& other)
|
|
: mValid(other.mValid),
|
|
mIsIdentifier(other.mIsIdentifier),
|
|
mPackage(other.mPackage),
|
|
mMajor(other.mMajor),
|
|
mMinor(other.mMinor),
|
|
mName(other.mName),
|
|
mValueName(other.mValueName) {
|
|
}
|
|
|
|
FQName::FQName(const std::vector<std::string> &names)
|
|
: mValid(false),
|
|
mIsIdentifier(false) {
|
|
setTo(StringHelper::JoinStrings(names, "."));
|
|
}
|
|
|
|
bool FQName::isValid() const {
|
|
return mValid;
|
|
}
|
|
|
|
bool FQName::isIdentifier() const {
|
|
return mIsIdentifier;
|
|
}
|
|
|
|
bool FQName::isFullyQualified() const {
|
|
return !mPackage.empty() && !version().empty() && !mName.empty();
|
|
}
|
|
|
|
bool FQName::isValidValueName() const {
|
|
return mIsIdentifier
|
|
|| (!mName.empty() && !mValueName.empty());
|
|
}
|
|
|
|
bool FQName::setTo(const std::string &s) {
|
|
clearVersion();
|
|
mPackage.clear();
|
|
mName.clear();
|
|
|
|
mValid = true;
|
|
|
|
std::smatch match;
|
|
if (std::regex_match(s, match, kRE1)) {
|
|
CHECK_EQ(match.size(), 5u);
|
|
|
|
mPackage = match.str(1);
|
|
parseVersion(match.str(2), match.str(3));
|
|
mName = match.str(4);
|
|
} else if (std::regex_match(s, match, kRE2)) {
|
|
CHECK_EQ(match.size(), 4u);
|
|
|
|
parseVersion(match.str(1), match.str(2));
|
|
mName = match.str(3);
|
|
} else if (std::regex_match(s, match, kRE3)) {
|
|
CHECK_EQ(match.size(), 4u);
|
|
|
|
mPackage = match.str(1);
|
|
parseVersion(match.str(2), match.str(3));
|
|
} else if (std::regex_match(s, match, kRE4)) {
|
|
mName = match.str(0);
|
|
} else if (std::regex_match(s, match, kRE5)) {
|
|
mIsIdentifier = true;
|
|
mName = match.str(0);
|
|
} else if (std::regex_match(s, match, kRE6)) {
|
|
CHECK_EQ(match.size(), 6u);
|
|
|
|
mPackage = match.str(1);
|
|
parseVersion(match.str(2), match.str(3));
|
|
mName = match.str(4);
|
|
mValueName = match.str(5);
|
|
} else if (std::regex_match(s, match, kRE7)) {
|
|
CHECK_EQ(match.size(), 5u);
|
|
|
|
parseVersion(match.str(1), match.str(2));
|
|
mName = match.str(3);
|
|
mValueName = match.str(4);
|
|
} else if (std::regex_match(s, match, kRE8)) {
|
|
CHECK_EQ(match.size(), 3u);
|
|
|
|
mName = match.str(1);
|
|
mValueName = match.str(2);
|
|
} else {
|
|
mValid = false;
|
|
}
|
|
|
|
// mValueName must go with mName.
|
|
CHECK(mValueName.empty() || !mName.empty());
|
|
|
|
// package without version is not allowed.
|
|
CHECK(mPackage.empty() || !version().empty());
|
|
|
|
return isValid();
|
|
}
|
|
|
|
std::string FQName::package() const {
|
|
return mPackage;
|
|
}
|
|
|
|
std::string FQName::version() const {
|
|
if (!hasVersion()) {
|
|
return "";
|
|
}
|
|
return std::to_string(mMajor) + "." + std::to_string(mMinor);
|
|
}
|
|
|
|
std::string FQName::sanitizedVersion() const {
|
|
if (!hasVersion()) {
|
|
return "";
|
|
}
|
|
return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
|
|
}
|
|
|
|
std::string FQName::atVersion() const {
|
|
std::string v = version();
|
|
return v.empty() ? "" : ("@" + v);
|
|
}
|
|
|
|
void FQName::setVersion(const std::string &v) {
|
|
if (v.empty()) {
|
|
clearVersion();
|
|
return;
|
|
}
|
|
std::smatch match;
|
|
if (std::regex_match(v, match, kREVer)) {
|
|
CHECK_EQ(match.size(), 3u);
|
|
|
|
parseVersion(match.str(1), match.str(2));
|
|
} else {
|
|
mValid = false;
|
|
}
|
|
}
|
|
|
|
void FQName::clearVersion() {
|
|
mMajor = mMinor = 0;
|
|
}
|
|
|
|
void FQName::parseVersion(const std::string &majorStr, const std::string &minorStr) {
|
|
bool versionParseSuccess =
|
|
::android::base::ParseUint(majorStr, &mMajor) &&
|
|
::android::base::ParseUint(minorStr, &mMinor);
|
|
if (!versionParseSuccess) {
|
|
LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
|
|
mValid = false;
|
|
}
|
|
}
|
|
|
|
std::string FQName::name() const {
|
|
return mName;
|
|
}
|
|
|
|
std::vector<std::string> FQName::names() const {
|
|
std::vector<std::string> res {};
|
|
std::istringstream ss(name());
|
|
std::string s;
|
|
while (std::getline(ss, s, '.')) {
|
|
res.push_back(s);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
std::string FQName::valueName() const {
|
|
return mValueName;
|
|
}
|
|
|
|
FQName FQName::typeName() const {
|
|
return FQName(mPackage, version(), mName);
|
|
}
|
|
|
|
void FQName::applyDefaults(
|
|
const std::string &defaultPackage,
|
|
const std::string &defaultVersion) {
|
|
|
|
// package without version is not allowed.
|
|
CHECK(mPackage.empty() || !version().empty());
|
|
|
|
if (mPackage.empty()) {
|
|
mPackage = defaultPackage;
|
|
}
|
|
|
|
if (version().empty()) {
|
|
setVersion(defaultVersion);
|
|
}
|
|
}
|
|
|
|
std::string FQName::string() const {
|
|
CHECK(mValid);
|
|
|
|
std::string out;
|
|
out.append(mPackage);
|
|
out.append(atVersion());
|
|
if (!mName.empty()) {
|
|
if (!mPackage.empty() || !version().empty()) {
|
|
out.append("::");
|
|
}
|
|
out.append(mName);
|
|
|
|
if (!mValueName.empty()) {
|
|
out.append(":");
|
|
out.append(mValueName);
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
void FQName::print() const {
|
|
if (!mValid) {
|
|
LOG(INFO) << "INVALID";
|
|
return;
|
|
}
|
|
|
|
LOG(INFO) << string();
|
|
}
|
|
|
|
bool FQName::operator<(const FQName &other) const {
|
|
return string() < other.string();
|
|
}
|
|
|
|
bool FQName::operator==(const FQName &other) const {
|
|
return string() == other.string();
|
|
}
|
|
|
|
bool FQName::operator!=(const FQName &other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
std::string FQName::getInterfaceName() const {
|
|
CHECK(names().size() == 1) << "Must be a top level type";
|
|
CHECK(!mName.empty() && mName[0] == 'I') << mName;
|
|
|
|
return mName;
|
|
}
|
|
|
|
std::string FQName::getInterfaceBaseName() const {
|
|
// cut off the leading 'I'.
|
|
return getInterfaceName().substr(1);
|
|
}
|
|
|
|
std::string FQName::getInterfaceHwName() const {
|
|
return "IHw" + getInterfaceBaseName();
|
|
}
|
|
|
|
std::string FQName::getInterfaceProxyName() const {
|
|
return "BpHw" + getInterfaceBaseName();
|
|
}
|
|
|
|
std::string FQName::getInterfaceStubName() const {
|
|
return "BnHw" + getInterfaceBaseName();
|
|
}
|
|
|
|
std::string FQName::getInterfacePassthroughName() const {
|
|
return "Bs" + getInterfaceBaseName();
|
|
}
|
|
|
|
FQName FQName::getInterfaceProxyFqName() const {
|
|
return FQName(package(), version(), getInterfaceProxyName());
|
|
}
|
|
|
|
FQName FQName::getInterfaceStubFqName() const {
|
|
return FQName(package(), version(), getInterfaceStubName());
|
|
}
|
|
|
|
FQName FQName::getInterfacePassthroughFqName() const {
|
|
return FQName(package(), version(), getInterfacePassthroughName());
|
|
}
|
|
|
|
FQName FQName::getTypesForPackage() const {
|
|
return FQName(package(), version(), "types");
|
|
}
|
|
|
|
FQName FQName::getPackageAndVersion() const {
|
|
return FQName(package(), version(), "");
|
|
}
|
|
|
|
FQName FQName::getTopLevelType() const {
|
|
auto idx = mName.find('.');
|
|
|
|
if (idx == std::string::npos) {
|
|
return *this;
|
|
}
|
|
|
|
return FQName(mPackage, version(), mName.substr(0, idx));
|
|
}
|
|
|
|
std::string FQName::tokenName() const {
|
|
std::vector<std::string> components;
|
|
getPackageAndVersionComponents(&components, true /* cpp_compatible */);
|
|
|
|
if (!mName.empty()) {
|
|
std::vector<std::string> nameComponents;
|
|
StringHelper::SplitString(mName, '.', &nameComponents);
|
|
|
|
components.insert(components.end(), nameComponents.begin(), nameComponents.end());
|
|
}
|
|
|
|
return StringHelper::JoinStrings(components, "_");
|
|
}
|
|
|
|
std::string FQName::cppNamespace() const {
|
|
std::vector<std::string> components;
|
|
getPackageAndVersionComponents(&components, true /* cpp_compatible */);
|
|
|
|
std::string out = "::";
|
|
out += StringHelper::JoinStrings(components, "::");
|
|
|
|
return out;
|
|
}
|
|
|
|
std::string FQName::cppLocalName() const {
|
|
std::vector<std::string> components;
|
|
StringHelper::SplitString(mName, '.', &components);
|
|
|
|
return StringHelper::JoinStrings(components, "::")
|
|
+ (mValueName.empty() ? "" : ("::" + mValueName));
|
|
}
|
|
|
|
std::string FQName::cppName() const {
|
|
std::string out = cppNamespace();
|
|
|
|
std::vector<std::string> components;
|
|
StringHelper::SplitString(name(), '.', &components);
|
|
out += "::";
|
|
out += StringHelper::JoinStrings(components, "::");
|
|
if (!mValueName.empty()) {
|
|
out += "::" + mValueName;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
std::string FQName::javaPackage() const {
|
|
std::vector<std::string> components;
|
|
getPackageAndVersionComponents(&components, true /* cpp_compatible */);
|
|
|
|
return StringHelper::JoinStrings(components, ".");
|
|
}
|
|
|
|
std::string FQName::javaName() const {
|
|
return javaPackage() + "." + name()
|
|
+ (mValueName.empty() ? "" : ("." + mValueName));
|
|
}
|
|
|
|
void FQName::getPackageComponents(std::vector<std::string> *components) const {
|
|
StringHelper::SplitString(package(), '.', components);
|
|
}
|
|
|
|
void FQName::getPackageAndVersionComponents(
|
|
std::vector<std::string> *components,
|
|
bool cpp_compatible) const {
|
|
getPackageComponents(components);
|
|
|
|
if (!hasVersion()) {
|
|
LOG(WARNING) << "FQName: getPackageAndVersionComponents expects version.";
|
|
return;
|
|
}
|
|
|
|
if (!cpp_compatible) {
|
|
components->push_back(std::to_string(getPackageMajorVersion()) +
|
|
"." + std::to_string(getPackageMinorVersion()));
|
|
return;
|
|
}
|
|
|
|
components->push_back(sanitizedVersion());
|
|
}
|
|
|
|
bool FQName::hasVersion() const {
|
|
return mMajor > 0;
|
|
}
|
|
|
|
size_t FQName::getPackageMajorVersion() const {
|
|
CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
|
|
<< "Did you check hasVersion()?";
|
|
return mMajor;
|
|
}
|
|
|
|
size_t FQName::getPackageMinorVersion() const {
|
|
CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
|
|
<< "Did you check hasVersion()?";
|
|
return mMinor;
|
|
}
|
|
|
|
bool FQName::endsWith(const FQName &other) const {
|
|
std::string s1 = string();
|
|
std::string s2 = other.string();
|
|
|
|
size_t pos = s1.rfind(s2);
|
|
if (pos == std::string::npos || pos + s2.size() != s1.size()) {
|
|
return false;
|
|
}
|
|
|
|
// A match is only a match if it is preceded by a "boundary", i.e.
|
|
// we perform a component-wise match from the end.
|
|
// "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
|
|
// "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
|
|
if (pos == 0) {
|
|
// matches "android.hardware.foo@1.0::IFoo.bar.baz"
|
|
return true;
|
|
}
|
|
|
|
if (s1[pos - 1] == '.') {
|
|
// matches "baz" and "bar.baz"
|
|
return true;
|
|
}
|
|
|
|
if (s1[pos - 1] == ':') {
|
|
// matches "IFoo.bar.baz"
|
|
return true;
|
|
}
|
|
|
|
if (s1[pos] == '@') {
|
|
// matches "@1.0::IFoo.bar.baz"
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FQName::inPackage(const std::string &package) const {
|
|
std::vector<std::string> components;
|
|
getPackageComponents(&components);
|
|
|
|
std::vector<std::string> inComponents;
|
|
StringHelper::SplitString(package, '.', &inComponents);
|
|
|
|
if (inComponents.size() > components.size()) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < inComponents.size(); i++) {
|
|
if (inComponents[i] != components[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
FQName FQName::downRev() const {
|
|
FQName ret(*this);
|
|
CHECK(ret.mMinor > 0);
|
|
ret.mMinor--;
|
|
return ret;
|
|
}
|
|
|
|
} // namespace android
|
|
|