aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorSteven Moreland <smoreland@google.com>2017-01-18 16:46:01 -0800
committerSteven Moreland <smoreland@google.com>2017-01-18 16:46:43 -0800
commit7ae3d54cb65f1309cb643b83a2040225ad5f3128 (patch)
treebc0737699dceef45b421f4c13328bba5200fe2a3 /utils
parent6a01fb58a5656eb86b2aff69b87cca6c6dc5ccbd (diff)
downloadhidl-7ae3d54cb65f1309cb643b83a2040225ad5f3128.tar.gz
Move FQName to libhidl-gen-util.
This will allow other libraries to process FQNames, namely libhidl. Test: compiles Change-Id: I015a69e016c5cef37f42e02b54c22663315e3676
Diffstat (limited to 'utils')
-rw-r--r--utils/Android.bp1
-rw-r--r--utils/FQName.cpp483
-rw-r--r--utils/include/hidl-util/FQName.h217
3 files changed, 701 insertions, 0 deletions
diff --git a/utils/Android.bp b/utils/Android.bp
index a6c37a62..4f788d66 100644
--- a/utils/Android.bp
+++ b/utils/Android.bp
@@ -22,6 +22,7 @@ cc_library_shared {
srcs: [
"Formatter.cpp",
"StringHelper.cpp",
+ "FQName.cpp"
],
shared_libs: [
"libbase",
diff --git a/utils/FQName.cpp b/utils/FQName.cpp
new file mode 100644
index 00000000..1aad6f0f
--- /dev/null
+++ b/utils/FQName.cpp
@@ -0,0 +1,483 @@
+/*
+ * 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 <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) {
+ mPackage.clear();
+ mMajor.clear();
+ mMinor.clear();
+ mName.clear();
+
+ mValid = true;
+
+ std::smatch match;
+ if (std::regex_match(s, match, kRE1)) {
+ CHECK_EQ(match.size(), 5u);
+
+ mPackage = match.str(1);
+ mMajor = match.str(2);
+ mMinor = match.str(3);
+ mName = match.str(4);
+ } else if (std::regex_match(s, match, kRE2)) {
+ CHECK_EQ(match.size(), 4u);
+
+ mMajor = match.str(1);
+ mMinor = match.str(2);
+ mName = match.str(3);
+ } else if (std::regex_match(s, match, kRE3)) {
+ CHECK_EQ(match.size(), 4u);
+
+ mPackage = match.str(1);
+ mMajor = match.str(2);
+ mMinor = 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);
+ mMajor = match.str(2);
+ mMinor = match.str(3);
+ mName = match.str(4);
+ mValueName = match.str(5);
+ } else if (std::regex_match(s, match, kRE7)) {
+ CHECK_EQ(match.size(), 5u);
+
+ mMajor = match.str(1);
+ mMinor = 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 {
+ CHECK(mMajor.empty() == mMinor.empty());
+ if (mMajor.empty() && mMinor.empty()) {
+ return "";
+ }
+ return mMajor + "." + mMinor;
+}
+
+std::string FQName::sanitizedVersion() const {
+ CHECK(mMajor.empty() == mMinor.empty());
+ if (mMajor.empty() && mMinor.empty()) {
+ return "";
+ }
+ return "V" + mMajor + "_" + mMinor;
+}
+
+std::string FQName::atVersion() const {
+ std::string v = version();
+ return v.empty() ? "" : ("@" + v);
+}
+
+void FQName::setVersion(const std::string &v) {
+ if (v.empty()) {
+ mMajor.clear();
+ mMinor.clear();
+ return;
+ }
+ std::smatch match;
+ if (std::regex_match(v, match, kREVer)) {
+ CHECK_EQ(match.size(), 3u);
+
+ mMajor = match.str(1);
+ mMinor = match.str(2);
+ } else {
+ 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 (!cpp_compatible) {
+ components->push_back(getPackageMajorVersion() +
+ "." + getPackageMinorVersion());
+ return;
+ }
+
+ components->push_back(sanitizedVersion());
+}
+
+std::string FQName::getPackageMajorVersion() const {
+ return mMajor;
+}
+
+std::string FQName::getPackageMinorVersion() const {
+ 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;
+}
+
+} // namespace android
+
diff --git a/utils/include/hidl-util/FQName.h b/utils/include/hidl-util/FQName.h
new file mode 100644
index 00000000..28c14ff2
--- /dev/null
+++ b/utils/include/hidl-util/FQName.h
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#ifndef FQNAME_H_
+
+#define FQNAME_H_
+
+#include <android-base/macros.h>
+#include <string>
+#include <vector>
+
+namespace android {
+
+struct FQName {
+ explicit FQName();
+ explicit FQName(const std::string &s);
+
+ FQName(const std::string &package,
+ const std::string &version,
+ const std::string &name,
+ const std::string &valueName = "");
+
+ // a synonym to FQName(names.join("."))
+ FQName(const std::vector<std::string> &names);
+
+ FQName(const FQName& other);
+
+ bool isValid() const;
+ bool isIdentifier() const;
+ bool setTo(const std::string &s);
+
+ void applyDefaults(
+ const std::string &defaultPackage,
+ const std::string &defaultVersion);
+
+ std::string package() const;
+ // Return version in the form "@1.0" if it is present, otherwise empty string.
+ std::string atVersion() const;
+ // Return version in the form "1.0" if it is present, otherwise empty string.
+ std::string version() const;
+ // Return version in the form "V1_0" if it is present, otherwise empty string.
+ std::string sanitizedVersion() const;
+
+ // The next two methods return the name part of the FQName, that is, the
+ // part after the version field. For example:
+ //
+ // package android.hardware.tests.foo@1.0;
+ // interface IFoo {
+ // struct bar {
+ // struct baz {
+ // ...
+ // };
+ // };
+ // };
+ //
+ // package android.hardware.tests.bar@1.0;
+ // import android.hardware.tests.foo@1.0;
+ // interface {
+ // struct boo {
+ // IFoo.bar.baz base;
+ // };
+ // }
+ //
+ // The FQName for base is android.hardware.tests.foo@1.0::IFoo.bar.baz; so
+ // FQName::name() will return "IFoo.bar.baz". FQName::names() will return
+ // std::vector<std::string>{"IFoo","bar","baz"}
+
+ std::string name() const;
+ std::vector<std::string> names() const;
+
+ // The next two methods returns two parts of the FQName, that is,
+ // the first part package + version + name, the second part valueName.
+ FQName typeName() const;
+ std::string valueName() const;
+
+ bool isFullyQualified() const;
+
+ // true if:
+ // 1. (package)?(version)?(name):(valueName)
+ // 2. (valueName), aka a single identifier
+ bool isValidValueName() const;
+
+ void print() const;
+ std::string string() const;
+
+ bool operator<(const FQName &other) const;
+ bool operator==(const FQName &other) const;
+ bool operator!=(const FQName &other) const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> Bar
+ std::string getInterfaceBaseName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> IBar
+ std::string getInterfaceName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> IHwBar
+ std::string getInterfaceHwName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> BpBar
+ std::string getInterfaceProxyName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> BnBar
+ std::string getInterfaceStubName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> BsBar
+ std::string getInterfacePassthroughName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> android.hardware.foo@1.0::BpBar
+ FQName getInterfaceProxyFqName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> android.hardware.foo@1.0::BnBar
+ FQName getInterfaceStubFqName() const;
+
+ // Must be called on an interface
+ // android.hardware.foo@1.0::IBar
+ // -> android.hardware.foo@1.0::BsBar
+ FQName getInterfacePassthroughFqName() const;
+
+ // Replace whatever after :: with "types"
+ // android.hardware.foo@1.0::Abc.Type:VALUE
+ // -> android.hardware.foo@1.0::types
+ FQName getTypesForPackage() const;
+
+ // android.hardware.foo@1.0::Abc.Type:VALUE
+ // -> android.hardware.foo@1.0
+ FQName getPackageAndVersion() const;
+
+ // the following comments all assume that the FQName
+ // is android.hardware.foo@1.0::IBar.Baz.Bam
+
+ // returns highest type in the hidl namespace, i.e.
+ // android.hardware.foo@1.0::IBar
+ FQName getTopLevelType() const;
+
+ // returns an unambiguous fully qualified name which can be
+ // baked into a token, i.e.
+ // android_hardware_Foo_V1_0_IBar_Baz
+ std::string tokenName() const;
+
+ // Returns an absolute C++ namespace prefix, i.e.
+ // ::android::hardware::Foo::V1_0.
+ std::string cppNamespace() const;
+
+ // Returns a name qualified assuming we are in cppNamespace, i.e.
+ // IBar::Baz.
+ std::string cppLocalName() const;
+
+ // Returns a fully qualified absolute C++ type name, i.e.
+ // ::android::hardware::Foo::V1_0::IBar::Baz.
+ std::string cppName() const;
+
+ // Returns the java package name, i.e. "android.hardware.Foo.V1_0".
+ std::string javaPackage() const;
+
+ // Returns the fully qualified java type name,
+ // i.e. "android.hardware.Foo.V1_0.IBar.Baz"
+ std::string javaName() const;
+
+ bool endsWith(const FQName &other) const;
+
+ void getPackageComponents(std::vector<std::string> *components) const;
+
+ void getPackageAndVersionComponents(
+ std::vector<std::string> *components,
+ bool cpp_compatible) const;
+
+ std::string getPackageMajorVersion() const;
+
+ std::string getPackageMinorVersion() const;
+
+private:
+ bool mValid;
+ bool mIsIdentifier;
+ std::string mPackage;
+ std::string mMajor;
+ std::string mMinor;
+ std::string mName;
+ std::string mValueName;
+
+ void setVersion(const std::string &v);
+};
+
+static const FQName gIBaseFqName = FQName{"android.hidl.base@1.0::IBase"};
+static const FQName gIBasePackageFqName = FQName{"android.hidl.base@1.0"};
+
+} // namespace android
+
+#endif // FQNAME_H_