regex-instance: HalInterface stores regex instances.
Parse <regex-instance> regular expression patterns using
Extended Regular Expression syntax, and store it in
HalInterface object.
Bug: 73738616
Test: libvintf_test
Test: vintf_object_test
Test: vts_treble_vintf_test
Change-Id: If0b8e3bc053a6c2ecd9048092071f52f7896bba0
diff --git a/Android.bp b/Android.bp
index 03267a5..83a3586 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,6 +42,7 @@
"MatrixHal.cpp",
"MatrixInstance.cpp",
"MatrixKernel.cpp",
+ "Regex.cpp",
"SystemSdk.cpp",
"TransportArch.cpp",
"VintfObject.cpp",
diff --git a/HalInterface.cpp b/HalInterface.cpp
index cec33af..b5cbd6b 100644
--- a/HalInterface.cpp
+++ b/HalInterface.cpp
@@ -35,6 +35,11 @@
return false;
}
}
+ for (const auto& instance : mRegexes) {
+ if (!func(mName, instance, true /* isRegex */)) {
+ return false;
+ }
+ }
return true;
}
@@ -47,12 +52,20 @@
return found;
}
-bool HalInterface::insertInstance(const std::string& instanceOrPattern, bool /*isRegex*/) {
- return mInstances.insert(instanceOrPattern).second;
+bool HalInterface::insertInstance(const std::string& instanceOrPattern, bool isRegex) {
+ if (isRegex) {
+ return mRegexes.insert(instanceOrPattern).second;
+ } else {
+ return mInstances.insert(instanceOrPattern).second;
+ }
}
-bool HalInterface::removeInstance(const std::string& instanceOrPattern, bool /*isRegex*/) {
- return mInstances.erase(instanceOrPattern) > 0;
+bool HalInterface::removeInstance(const std::string& instanceOrPattern, bool isRegex) {
+ if (isRegex) {
+ return mRegexes.erase(instanceOrPattern) > 0;
+ } else {
+ return mInstances.erase(instanceOrPattern) > 0;
+ }
}
} // namespace vintf
diff --git a/Regex.cpp b/Regex.cpp
new file mode 100644
index 0000000..c343398
--- /dev/null
+++ b/Regex.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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 "Regex.h"
+
+namespace android {
+namespace vintf {
+namespace details {
+
+Regex::~Regex() {
+ clear();
+}
+
+void Regex::clear() {
+ if (mImpl != nullptr) {
+ regfree(mImpl.get());
+ mImpl = nullptr;
+ }
+}
+
+bool Regex::compile(const std::string& pattern) {
+ clear();
+ mImpl = std::make_unique<regex_t>();
+ int status = regcomp(mImpl.get(), pattern.c_str(), REG_EXTENDED | REG_NEWLINE);
+ return status == 0;
+}
+
+bool Regex::matches(const std::string& s) const {
+ regmatch_t match;
+ int status =
+ regexec(mImpl.get(), s.c_str(), 1 /* nmatch */, &match /* pmatch */, 0 /* flags */);
+ return status == 0 && match.rm_so == 0 && match.rm_eo >= 0 &&
+ static_cast<size_t>(match.rm_eo) == s.length();
+}
+
+} // namespace details
+} // namespace vintf
+} // namespace android
diff --git a/include/vintf/HalInterface.h b/include/vintf/HalInterface.h
index b778a28..12bf79a 100644
--- a/include/vintf/HalInterface.h
+++ b/include/vintf/HalInterface.h
@@ -51,6 +51,7 @@
std::string mName;
std::set<std::string> mInstances;
+ std::set<std::string> mRegexes;
};
} // namespace vintf
diff --git a/include/vintf/Regex.h b/include/vintf/Regex.h
new file mode 100644
index 0000000..86c66f2
--- /dev/null
+++ b/include/vintf/Regex.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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 ANDROID_VINTF_REGEX_H_
+#define ANDROID_VINTF_REGEX_H_
+
+#include <regex.h>
+#include <string>
+
+namespace android {
+namespace vintf {
+namespace details {
+
+// A wrapper class around regex.h. This is used instead of C++ <regex> library because
+// C++ regex library throws exceptions when an invalid regular expression is compiled.
+// Use Extended Regular Expression (ERE) syntax.
+class Regex {
+ public:
+ Regex() = default;
+ ~Regex();
+
+ Regex& operator=(const Regex&) = delete;
+ Regex(const Regex&) = delete;
+
+ __attribute__((warn_unused_result)) bool compile(const std::string& pattern);
+
+ bool matches(const std::string& s) const;
+
+ /**
+ * Return nullptr if not a valid regex pattern, else the Regex object.
+ */
+ static const Regex* Get(const std::string& pattern);
+
+ private:
+ std::unique_ptr<regex_t> mImpl;
+
+ void clear();
+};
+
+} // namespace details
+} // namespace vintf
+} // namespace android
+
+#endif // ANDROID_VINTF_REGEX_H_
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 3d67e1c..27f31c9 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -25,6 +25,7 @@
#include <tinyxml2.h>
+#include "Regex.h"
#include "constants.h"
#include "parse_string.h"
@@ -475,11 +476,14 @@
void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override {
appendTextElement(root, "name", intf.name(), d);
appendTextElements(root, "instance", intf.mInstances, d);
+ appendTextElements(root, "regex-instance", intf.mRegexes, d);
}
bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override {
std::vector<std::string> instances;
+ std::vector<std::string> regexes;
if (!parseTextElement(root, "name", &intf->mName, error) ||
- !parseTextElements(root, "instance", &instances, error)) {
+ !parseTextElements(root, "instance", &instances, error) ||
+ !parseTextElements(root, "regex-instance", ®exes, error)) {
return false;
}
bool success = true;
@@ -490,6 +494,19 @@
success = false;
}
}
+ for (const auto& e : regexes) {
+ details::Regex regex;
+ if (!regex.compile(e)) {
+ if (!error->empty()) *error += "\n";
+ *error += "Invalid regular expression '" + e + "' in " + intf->name();
+ success = false;
+ }
+ if (!intf->insertInstance(e, true /* isRegex */)) {
+ if (!error->empty()) *error += "\n";
+ *error += "Duplicated regex-instance '" + e + "' in " + intf->name();
+ success = false;
+ }
+ }
return success;
}
};