Introduce ResourceNamedType that represents pair of name + ResourceType.
This type will be used as part of ResourceName to support types with
custom names inside aapt2.
DD: go/custom-resource-types-in-aapt2
Bug: b/215108200
Test: Resource_test.cpp
Change-Id: Ib09776e6b2f69fefb9724136a345dc25bea42573
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 6364ccd..0bb330e 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -134,6 +134,24 @@
{"xml", ResourceType::kXml},
};
+ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t) {
+ return {to_string(t), t};
+}
+
+std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s) {
+ auto colon = std::find(s.begin(), s.end(), ':');
+ const ResourceType* parsedType;
+ if (colon != s.end() && colon != std::prev(s.end())) {
+ parsedType = ParseResourceType(s.substr(s.begin(), colon));
+ } else {
+ parsedType = ParseResourceType(s);
+ }
+ if (parsedType == nullptr) {
+ return std::nullopt;
+ }
+ return ResourceNamedTypeRef(s, *parsedType);
+}
+
const ResourceType* ParseResourceType(const StringPiece& str) {
auto iter = sResourceTypeMap.find(str);
if (iter == std::end(sResourceTypeMap)) {
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 307c21d..d394b24 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -19,22 +19,21 @@
#include <iomanip>
#include <limits>
+#include <optional>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
+#include "Source.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/StringPiece.h"
#include "utils/JenkinsHash.h"
-#include "Source.h"
-
namespace aapt {
/**
- * The various types of resource types available. Corresponds
- * to the 'type' in package:type/entry.
+ * The various types of resource types available.
*/
enum class ResourceType {
kAnim,
@@ -78,6 +77,52 @@
const ResourceType* ParseResourceType(const android::StringPiece& str);
/**
+ * Pair of type name as in ResourceTable and actual resource type.
+ * Corresponds to the 'type' in package:type/entry.
+ *
+ * This is to support resource types with custom names inside resource tables.
+ */
+struct ResourceNamedType {
+ std::string name;
+ ResourceType type = ResourceType::kRaw;
+
+ ResourceNamedType() = default;
+ ResourceNamedType(const android::StringPiece& n, ResourceType t);
+
+ int compare(const ResourceNamedType& other) const;
+
+ const std::string& to_string() const;
+};
+
+/**
+ * Same as ResourceNamedType, but uses StringPieces instead.
+ * Use this if you need to avoid copying and know that
+ * the lifetime of this object is shorter than that
+ * of the original string.
+ */
+struct ResourceNamedTypeRef {
+ android::StringPiece name;
+ ResourceType type = ResourceType::kRaw;
+
+ ResourceNamedTypeRef() = default;
+ ResourceNamedTypeRef(const ResourceNamedTypeRef&) = default;
+ ResourceNamedTypeRef(ResourceNamedTypeRef&&) = default;
+ ResourceNamedTypeRef(const ResourceNamedType& rhs); // NOLINT(google-explicit-constructor)
+ ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t);
+ ResourceNamedTypeRef& operator=(const ResourceNamedTypeRef& rhs) = default;
+ ResourceNamedTypeRef& operator=(ResourceNamedTypeRef&& rhs) = default;
+ ResourceNamedTypeRef& operator=(const ResourceNamedType& rhs);
+
+ ResourceNamedType ToResourceNamedType() const;
+
+ std::string to_string() const;
+};
+
+ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t);
+
+std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s);
+
+/**
* A resource's name. This can uniquely identify
* a resource in the ResourceTable.
*/
@@ -295,6 +340,81 @@
}
//
+// ResourceNamedType implementation.
+//
+inline ResourceNamedType::ResourceNamedType(const android::StringPiece& n, ResourceType t)
+ : name(n.to_string()), type(t) {
+}
+
+inline int ResourceNamedType::compare(const ResourceNamedType& other) const {
+ int cmp = static_cast<int>(type) - static_cast<int>(other.type);
+ if (cmp != 0) return cmp;
+ cmp = name.compare(other.name);
+ return cmp;
+}
+
+inline const std::string& ResourceNamedType::to_string() const {
+ return name;
+}
+
+inline bool operator<(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool operator==(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
+ return lhs.compare(rhs) == 0;
+}
+
+inline bool operator!=(const ResourceNamedType& lhs, const ResourceNamedType& rhs) {
+ return lhs.compare(rhs) != 0;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedType& val) {
+ return out << val.to_string();
+}
+
+//
+// ResourceNamedTypeRef implementation.
+//
+inline ResourceNamedTypeRef::ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t)
+ : name(n), type(t) {
+}
+
+inline ResourceNamedTypeRef::ResourceNamedTypeRef(const ResourceNamedType& rhs)
+ : name(rhs.name), type(rhs.type) {
+}
+
+inline ResourceNamedTypeRef& ResourceNamedTypeRef::operator=(const ResourceNamedType& rhs) {
+ name = rhs.name;
+ type = rhs.type;
+ return *this;
+}
+
+inline ResourceNamedType ResourceNamedTypeRef::ToResourceNamedType() const {
+ return ResourceNamedType(name, type);
+}
+
+inline std::string ResourceNamedTypeRef::to_string() const {
+ return name.to_string();
+}
+
+inline bool operator<(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
+ return std::tie(lhs.type, lhs.name) < std::tie(rhs.type, rhs.name);
+}
+
+inline bool operator==(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
+ return std::tie(lhs.type, lhs.name) == std::tie(rhs.type, rhs.name);
+}
+
+inline bool operator!=(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
+ return std::tie(lhs.type, lhs.name) != std::tie(rhs.type, rhs.name);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedTypeRef& val) {
+ return out << val.name;
+}
+
+//
// ResourceName implementation.
//
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index c557f3c..2c55d1d 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -18,6 +18,9 @@
#include "test/Test.h"
+using ::testing::Eq;
+using ::testing::Optional;
+
namespace aapt {
TEST(ResourceTypeTest, ParseResourceTypes) {
@@ -125,4 +128,104 @@
EXPECT_EQ(type, nullptr);
}
+TEST(ResourceTypeTest, ParseResourceNamedType) {
+ auto type = ParseResourceNamedType("anim");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("anim", ResourceType::kAnim))));
+
+ type = ParseResourceNamedType("layout");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout", ResourceType::kLayout))));
+
+ type = ParseResourceNamedType("layout:2");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:2", ResourceType::kLayout))));
+
+ type = ParseResourceNamedType("layout:another");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:another", ResourceType::kLayout))));
+
+ type = ParseResourceNamedType("layout:");
+ EXPECT_THAT(type, Eq(std::nullopt));
+
+ type = ParseResourceNamedType("layout2");
+ EXPECT_THAT(type, Eq(std::nullopt));
+
+ type = ParseResourceNamedType("blahaha");
+ EXPECT_THAT(type, Eq(std::nullopt));
+}
+
+TEST(ResourceTypeTest, ResourceNamedTypeWithDefaultName) {
+ auto type = ResourceNamedTypeWithDefaultName(ResourceType::kAnim);
+ EXPECT_THAT(type, Eq(ResourceNamedType("anim", ResourceType::kAnim)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kAnimator);
+ EXPECT_THAT(type, Eq(ResourceNamedType("animator", ResourceType::kAnimator)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kArray);
+ EXPECT_THAT(type, Eq(ResourceNamedType("array", ResourceType::kArray)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kAttr);
+ EXPECT_THAT(type, Eq(ResourceNamedType("attr", ResourceType::kAttr)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kAttrPrivate);
+ EXPECT_THAT(type, Eq(ResourceNamedType("^attr-private", ResourceType::kAttrPrivate)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kBool);
+ EXPECT_THAT(type, Eq(ResourceNamedType("bool", ResourceType::kBool)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kColor);
+ EXPECT_THAT(type, Eq(ResourceNamedType("color", ResourceType::kColor)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kConfigVarying);
+ EXPECT_THAT(type, Eq(ResourceNamedType("configVarying", ResourceType::kConfigVarying)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kDimen);
+ EXPECT_THAT(type, Eq(ResourceNamedType("dimen", ResourceType::kDimen)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kDrawable);
+ EXPECT_THAT(type, Eq(ResourceNamedType("drawable", ResourceType::kDrawable)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kFont);
+ EXPECT_THAT(type, Eq(ResourceNamedType("font", ResourceType::kFont)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kFraction);
+ EXPECT_THAT(type, Eq(ResourceNamedType("fraction", ResourceType::kFraction)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kId);
+ EXPECT_THAT(type, Eq(ResourceNamedType("id", ResourceType::kId)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kInteger);
+ EXPECT_THAT(type, Eq(ResourceNamedType("integer", ResourceType::kInteger)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kInterpolator);
+ EXPECT_THAT(type, Eq(ResourceNamedType("interpolator", ResourceType::kInterpolator)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kLayout);
+ EXPECT_THAT(type, Eq(ResourceNamedType("layout", ResourceType::kLayout)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kMenu);
+ EXPECT_THAT(type, Eq(ResourceNamedType("menu", ResourceType::kMenu)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kMipmap);
+ EXPECT_THAT(type, Eq(ResourceNamedType("mipmap", ResourceType::kMipmap)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kNavigation);
+ EXPECT_THAT(type, Eq(ResourceNamedType("navigation", ResourceType::kNavigation)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kPlurals);
+ EXPECT_THAT(type, Eq(ResourceNamedType("plurals", ResourceType::kPlurals)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kRaw);
+ EXPECT_THAT(type, Eq(ResourceNamedType("raw", ResourceType::kRaw)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kString);
+ EXPECT_THAT(type, Eq(ResourceNamedType("string", ResourceType::kString)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kStyle);
+ EXPECT_THAT(type, Eq(ResourceNamedType("style", ResourceType::kStyle)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kTransition);
+ EXPECT_THAT(type, Eq(ResourceNamedType("transition", ResourceType::kTransition)));
+
+ type = ResourceNamedTypeWithDefaultName(ResourceType::kXml);
+ EXPECT_THAT(type, Eq(ResourceNamedType("xml", ResourceType::kXml)));
+}
+
} // namespace aapt