AAPT2: Respect format attr in <array> resource
Bug: 38152130
Test: make aapt2_tests
Change-Id: I84f352afb1a8fd2f329354f789aaa36c5ef88e47
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 90f713b..0d1850f 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -34,42 +34,43 @@
namespace aapt {
-constexpr const char* sXliffNamespaceUri =
- "urn:oasis:names:tc:xliff:document:1.2";
+constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
-/**
- * Returns true if the element is <skip> or <eat-comment> and can be safely
- * ignored.
- */
-static bool ShouldIgnoreElement(const StringPiece& ns,
- const StringPiece& name) {
+// Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
+static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) {
return ns.empty() && (name == "skip" || name == "eat-comment");
}
-static uint32_t ParseFormatType(const StringPiece& piece) {
- if (piece == "reference")
+static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) {
+ if (piece == "reference") {
return android::ResTable_map::TYPE_REFERENCE;
- else if (piece == "string")
+ } else if (piece == "string") {
return android::ResTable_map::TYPE_STRING;
- else if (piece == "integer")
+ } else if (piece == "integer") {
return android::ResTable_map::TYPE_INTEGER;
- else if (piece == "boolean")
+ } else if (piece == "boolean") {
return android::ResTable_map::TYPE_BOOLEAN;
- else if (piece == "color")
+ } else if (piece == "color") {
return android::ResTable_map::TYPE_COLOR;
- else if (piece == "float")
+ } else if (piece == "float") {
return android::ResTable_map::TYPE_FLOAT;
- else if (piece == "dimension")
+ } else if (piece == "dimension") {
return android::ResTable_map::TYPE_DIMENSION;
- else if (piece == "fraction")
+ } else if (piece == "fraction") {
return android::ResTable_map::TYPE_FRACTION;
- else if (piece == "enum")
- return android::ResTable_map::TYPE_ENUM;
- else if (piece == "flags")
- return android::ResTable_map::TYPE_FLAGS;
+ }
return 0;
}
+static uint32_t ParseFormatType(const StringPiece& piece) {
+ if (piece == "enum") {
+ return android::ResTable_map::TYPE_ENUM;
+ } else if (piece == "flags") {
+ return android::ResTable_map::TYPE_FLAGS;
+ }
+ return ParseFormatTypeNoEnumsOrFlags(piece);
+}
+
static uint32_t ParseFormatAttribute(const StringPiece& str) {
uint32_t mask = 0;
for (StringPiece part : util::Tokenize(str, '|')) {
@@ -83,9 +84,7 @@
return mask;
}
-/**
- * A parsed resource ready to be added to the ResourceTable.
- */
+// A parsed resource ready to be added to the ResourceTable.
struct ParsedResource {
ResourceName name;
ConfigDescription config;
@@ -416,8 +415,7 @@
can_be_bag = false;
// Items have their type encoded in the type attribute.
- if (Maybe<StringPiece> maybe_type =
- xml::FindNonEmptyAttribute(parser, "type")) {
+ if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
resource_type = maybe_type.value().to_string();
} else {
diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
@@ -425,13 +423,11 @@
return false;
}
- if (Maybe<StringPiece> maybe_format =
- xml::FindNonEmptyAttribute(parser, "format")) {
+ if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) {
// An explicit format for this resource was specified. The resource will
- // retain
- // its type in its name, but the accepted value for this type is
+ // retain its type in its name, but the accepted value for this type is
// overridden.
- resource_format = ParseFormatType(maybe_format.value());
+ resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value());
if (!resource_format) {
diag_->Error(DiagMessage(out_resource->source)
<< "'" << maybe_format.value()
@@ -1157,21 +1153,25 @@
return true;
}
-bool ResourceParser::ParseArray(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_ANY);
+bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ uint32_t resource_format = android::ResTable_map::TYPE_ANY;
+ if (Maybe<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
+ resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value());
+ if (resource_format == 0u) {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ << "'" << format_attr.value() << "' is an invalid format");
+ return false;
+ }
+ }
+ return ParseArrayImpl(parser, out_resource, resource_format);
}
-bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- return ParseArrayImpl(parser, out_resource,
- android::ResTable_map::TYPE_INTEGER);
+bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER);
}
-bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- return ParseArrayImpl(parser, out_resource,
- android::ResTable_map::TYPE_STRING);
+bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING);
}
bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 8062c2e6..faa6607 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -571,14 +571,39 @@
}
TEST_F(ResourceParserTest, ParseStringArray) {
- std::string input =
- "<string-array name=\"foo\">\n"
- " <item>\"Werk\"</item>\n"
- "</string-array>\n";
+ std::string input = R"EOF(
+ <string-array name="foo">
+ <item>"Werk"</item>"
+ </string-array>)EOF";
ASSERT_TRUE(TestParse(input));
EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
}
+TEST_F(ResourceParserTest, ParseArrayWithFormat) {
+ std::string input = R"EOF(
+ <array name="foo" format="string">
+ <item>100</item>
+ </array>)EOF";
+ ASSERT_TRUE(TestParse(input));
+
+ Array* array = test::GetValue<Array>(&table_, "array/foo");
+ ASSERT_NE(nullptr, array);
+
+ ASSERT_EQ(1u, array->items.size());
+
+ String* str = ValueCast<String>(array->items[0].get());
+ ASSERT_NE(nullptr, str);
+ EXPECT_EQ(std::string("100"), *str->value);
+}
+
+TEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
+ std::string input = R"EOF(
+ <array name="foo" format="integer">
+ <item>Hi</item>
+ </array>)EOF";
+ ASSERT_FALSE(TestParse(input));
+}
+
TEST_F(ResourceParserTest, ParsePlural) {
std::string input =
"<plurals name=\"foo\">\n"