Loading tools/aapt2/ResourceParser.cpp +41 −41 Original line number Original line Diff line number Diff line Loading @@ -34,40 +34,41 @@ using android::StringPiece; namespace aapt { namespace aapt { constexpr const char* sXliffNamespaceUri = constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2"; "urn:oasis:names:tc:xliff:document:1.2"; /** // Returns true if the element is <skip> or <eat-comment> and can be safely ignored. * Returns true if the element is <skip> or <eat-comment> and can be safely static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) { * ignored. */ static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) { return ns.empty() && (name == "skip" || name == "eat-comment"); return ns.empty() && (name == "skip" || name == "eat-comment"); } } static uint32_t ParseFormatType(const StringPiece& piece) { static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) { if (piece == "reference") if (piece == "reference") { return android::ResTable_map::TYPE_REFERENCE; return android::ResTable_map::TYPE_REFERENCE; else if (piece == "string") } else if (piece == "string") { return android::ResTable_map::TYPE_STRING; return android::ResTable_map::TYPE_STRING; else if (piece == "integer") } else if (piece == "integer") { return android::ResTable_map::TYPE_INTEGER; return android::ResTable_map::TYPE_INTEGER; else if (piece == "boolean") } else if (piece == "boolean") { return android::ResTable_map::TYPE_BOOLEAN; return android::ResTable_map::TYPE_BOOLEAN; else if (piece == "color") } else if (piece == "color") { return android::ResTable_map::TYPE_COLOR; return android::ResTable_map::TYPE_COLOR; else if (piece == "float") } else if (piece == "float") { return android::ResTable_map::TYPE_FLOAT; return android::ResTable_map::TYPE_FLOAT; else if (piece == "dimension") } else if (piece == "dimension") { return android::ResTable_map::TYPE_DIMENSION; return android::ResTable_map::TYPE_DIMENSION; else if (piece == "fraction") } else if (piece == "fraction") { return android::ResTable_map::TYPE_FRACTION; return android::ResTable_map::TYPE_FRACTION; else if (piece == "enum") } return 0; } static uint32_t ParseFormatType(const StringPiece& piece) { if (piece == "enum") { return android::ResTable_map::TYPE_ENUM; return android::ResTable_map::TYPE_ENUM; else if (piece == "flags") } else if (piece == "flags") { return android::ResTable_map::TYPE_FLAGS; return android::ResTable_map::TYPE_FLAGS; return 0; } return ParseFormatTypeNoEnumsOrFlags(piece); } } static uint32_t ParseFormatAttribute(const StringPiece& str) { static uint32_t ParseFormatAttribute(const StringPiece& str) { Loading @@ -83,9 +84,7 @@ static uint32_t ParseFormatAttribute(const StringPiece& str) { return mask; return mask; } } /** // A parsed resource ready to be added to the ResourceTable. * A parsed resource ready to be added to the ResourceTable. */ struct ParsedResource { struct ParsedResource { ResourceName name; ResourceName name; ConfigDescription config; ConfigDescription config; Loading Loading @@ -416,8 +415,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, can_be_bag = false; can_be_bag = false; // Items have their type encoded in the type attribute. // Items have their type encoded in the type attribute. if (Maybe<StringPiece> maybe_type = if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { xml::FindNonEmptyAttribute(parser, "type")) { resource_type = maybe_type.value().to_string(); resource_type = maybe_type.value().to_string(); } else { } else { diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) Loading @@ -425,13 +423,11 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; return false; } } if (Maybe<StringPiece> maybe_format = if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) { xml::FindNonEmptyAttribute(parser, "format")) { // An explicit format for this resource was specified. The resource will // An explicit format for this resource was specified. The resource will // retain // retain its type in its name, but the accepted value for this type is // its type in its name, but the accepted value for this type is // overridden. // overridden. resource_format = ParseFormatType(maybe_format.value()); resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value()); if (!resource_format) { if (!resource_format) { diag_->Error(DiagMessage(out_resource->source) diag_->Error(DiagMessage(out_resource->source) << "'" << maybe_format.value() << "'" << maybe_format.value() Loading Loading @@ -1157,21 +1153,25 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par return true; return true; } } bool ResourceParser::ParseArray(xml::XmlPullParser* parser, bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { ParsedResource* out_resource) { uint32_t resource_format = android::ResTable_map::TYPE_ANY; return ParseArrayImpl(parser, out_resource, 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, bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { ParsedResource* out_resource) { return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER); return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER); } } bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { ParsedResource* out_resource) { return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING); return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING); } } bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, Loading tools/aapt2/ResourceParser_test.cpp +29 −4 Original line number Original line Diff line number Diff line Loading @@ -571,14 +571,39 @@ TEST_F(ResourceParserTest, ParseArray) { } } TEST_F(ResourceParserTest, ParseStringArray) { TEST_F(ResourceParserTest, ParseStringArray) { std::string input = std::string input = R"EOF( "<string-array name=\"foo\">\n" <string-array name="foo"> " <item>\"Werk\"</item>\n" <item>"Werk"</item>" "</string-array>\n"; </string-array>)EOF"; ASSERT_TRUE(TestParse(input)); ASSERT_TRUE(TestParse(input)); EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo")); 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) { TEST_F(ResourceParserTest, ParsePlural) { std::string input = std::string input = "<plurals name=\"foo\">\n" "<plurals name=\"foo\">\n" Loading Loading
tools/aapt2/ResourceParser.cpp +41 −41 Original line number Original line Diff line number Diff line Loading @@ -34,40 +34,41 @@ using android::StringPiece; namespace aapt { namespace aapt { constexpr const char* sXliffNamespaceUri = constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2"; "urn:oasis:names:tc:xliff:document:1.2"; /** // Returns true if the element is <skip> or <eat-comment> and can be safely ignored. * Returns true if the element is <skip> or <eat-comment> and can be safely static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) { * ignored. */ static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) { return ns.empty() && (name == "skip" || name == "eat-comment"); return ns.empty() && (name == "skip" || name == "eat-comment"); } } static uint32_t ParseFormatType(const StringPiece& piece) { static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) { if (piece == "reference") if (piece == "reference") { return android::ResTable_map::TYPE_REFERENCE; return android::ResTable_map::TYPE_REFERENCE; else if (piece == "string") } else if (piece == "string") { return android::ResTable_map::TYPE_STRING; return android::ResTable_map::TYPE_STRING; else if (piece == "integer") } else if (piece == "integer") { return android::ResTable_map::TYPE_INTEGER; return android::ResTable_map::TYPE_INTEGER; else if (piece == "boolean") } else if (piece == "boolean") { return android::ResTable_map::TYPE_BOOLEAN; return android::ResTable_map::TYPE_BOOLEAN; else if (piece == "color") } else if (piece == "color") { return android::ResTable_map::TYPE_COLOR; return android::ResTable_map::TYPE_COLOR; else if (piece == "float") } else if (piece == "float") { return android::ResTable_map::TYPE_FLOAT; return android::ResTable_map::TYPE_FLOAT; else if (piece == "dimension") } else if (piece == "dimension") { return android::ResTable_map::TYPE_DIMENSION; return android::ResTable_map::TYPE_DIMENSION; else if (piece == "fraction") } else if (piece == "fraction") { return android::ResTable_map::TYPE_FRACTION; return android::ResTable_map::TYPE_FRACTION; else if (piece == "enum") } return 0; } static uint32_t ParseFormatType(const StringPiece& piece) { if (piece == "enum") { return android::ResTable_map::TYPE_ENUM; return android::ResTable_map::TYPE_ENUM; else if (piece == "flags") } else if (piece == "flags") { return android::ResTable_map::TYPE_FLAGS; return android::ResTable_map::TYPE_FLAGS; return 0; } return ParseFormatTypeNoEnumsOrFlags(piece); } } static uint32_t ParseFormatAttribute(const StringPiece& str) { static uint32_t ParseFormatAttribute(const StringPiece& str) { Loading @@ -83,9 +84,7 @@ static uint32_t ParseFormatAttribute(const StringPiece& str) { return mask; return mask; } } /** // A parsed resource ready to be added to the ResourceTable. * A parsed resource ready to be added to the ResourceTable. */ struct ParsedResource { struct ParsedResource { ResourceName name; ResourceName name; ConfigDescription config; ConfigDescription config; Loading Loading @@ -416,8 +415,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, can_be_bag = false; can_be_bag = false; // Items have their type encoded in the type attribute. // Items have their type encoded in the type attribute. if (Maybe<StringPiece> maybe_type = if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { xml::FindNonEmptyAttribute(parser, "type")) { resource_type = maybe_type.value().to_string(); resource_type = maybe_type.value().to_string(); } else { } else { diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) Loading @@ -425,13 +423,11 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; return false; } } if (Maybe<StringPiece> maybe_format = if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) { xml::FindNonEmptyAttribute(parser, "format")) { // An explicit format for this resource was specified. The resource will // An explicit format for this resource was specified. The resource will // retain // retain its type in its name, but the accepted value for this type is // its type in its name, but the accepted value for this type is // overridden. // overridden. resource_format = ParseFormatType(maybe_format.value()); resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value()); if (!resource_format) { if (!resource_format) { diag_->Error(DiagMessage(out_resource->source) diag_->Error(DiagMessage(out_resource->source) << "'" << maybe_format.value() << "'" << maybe_format.value() Loading Loading @@ -1157,21 +1153,25 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par return true; return true; } } bool ResourceParser::ParseArray(xml::XmlPullParser* parser, bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { ParsedResource* out_resource) { uint32_t resource_format = android::ResTable_map::TYPE_ANY; return ParseArrayImpl(parser, out_resource, 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, bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { ParsedResource* out_resource) { return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER); return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER); } } bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, ParsedResource* out_resource) { ParsedResource* out_resource) { return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING); return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING); } } bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, Loading
tools/aapt2/ResourceParser_test.cpp +29 −4 Original line number Original line Diff line number Diff line Loading @@ -571,14 +571,39 @@ TEST_F(ResourceParserTest, ParseArray) { } } TEST_F(ResourceParserTest, ParseStringArray) { TEST_F(ResourceParserTest, ParseStringArray) { std::string input = std::string input = R"EOF( "<string-array name=\"foo\">\n" <string-array name="foo"> " <item>\"Werk\"</item>\n" <item>"Werk"</item>" "</string-array>\n"; </string-array>)EOF"; ASSERT_TRUE(TestParse(input)); ASSERT_TRUE(TestParse(input)); EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo")); 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) { TEST_F(ResourceParserTest, ParsePlural) { std::string input = std::string input = "<plurals name=\"foo\">\n" "<plurals name=\"foo\">\n" Loading