Loading libs/androidfw/include/androidfw/StringPiece.h +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ class BasicStringPiece { public: using const_iterator = const TChar*; using difference_type = size_t; using size_type = size_t; // End of string marker. constexpr static const size_t npos = static_cast<size_t>(-1); Loading tools/aapt2/flatten/XmlFlattener.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -257,9 +257,11 @@ class XmlFlattenerVisitor : public xml::Visitor { // Process plain strings to make sure they get properly escaped. StringPiece raw_value = xml_attr->value; util::StringBuilder str_builder; if (!options_.keep_raw_values) { util::StringBuilder str_builder(true /*preserve_spaces*/); str_builder.Append(xml_attr->value); if (!options_.keep_raw_values) { raw_value = str_builder.ToString(); } Loading tools/aapt2/flatten/XmlFlattener_test.cpp +102 −123 Original line number Diff line number Diff line Loading @@ -23,7 +23,13 @@ #include "util/BigBuffer.h" #include "util/Util.h" using android::StringPiece16; using ::aapt::test::StrEq; using ::android::StringPiece16; using ::testing::Eq; using ::testing::Ge; using ::testing::IsNull; using ::testing::Ne; using ::testing::NotNull; namespace aapt { Loading Loading @@ -72,163 +78,138 @@ class XmlFlattenerTest : public ::testing::Test { }; TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF( <View xmlns:test="http://com.test" attr="hey"> std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( <View xmlns:test="http://com.test" attr="hey"> <Layout test:hello="hi" /> <Layout>Some text\\</Layout> </View>)EOF"); </View>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); ASSERT_EQ(android::ResXMLTree::START_NAMESPACE, tree.next()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE)); size_t len; const char16_t* namespace_prefix = tree.getNamespacePrefix(&len); EXPECT_EQ(StringPiece16(u"test"), StringPiece16(namespace_prefix, len)); const char16_t* namespace_uri = tree.getNamespaceUri(&len); ASSERT_EQ(StringPiece16(u"http://com.test"), StringPiece16(namespace_uri, len)); ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); const char16_t* tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"View"), StringPiece16(tag_name, len)); ASSERT_EQ(1u, tree.getAttributeCount()); ASSERT_EQ(nullptr, tree.getAttributeNamespace(0, &len)); const char16_t* attr_name = tree.getAttributeName(0, &len); EXPECT_EQ(StringPiece16(u"attr"), StringPiece16(attr_name, len)); EXPECT_EQ(0, tree.indexOfAttribute(nullptr, 0, u"attr", StringPiece16(u"attr").size())); EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test")); EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test")); ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"View")); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); EXPECT_THAT(tree.getAttributeNamespace(0, &len), IsNull()); EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"attr")); ASSERT_EQ(1u, tree.getAttributeCount()); const char16_t* attr_namespace = tree.getAttributeNamespace(0, &len); EXPECT_EQ(StringPiece16(u"http://com.test"), StringPiece16(attr_namespace, len)); const StringPiece16 kAttr(u"attr"); EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kAttr.data(), kAttr.size()), Eq(0)); attr_name = tree.getAttributeName(0, &len); EXPECT_EQ(StringPiece16(u"hello"), StringPiece16(attr_name, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); EXPECT_THAT(tree.getAttributeNamespace(0, &len), StrEq(u"http://com.test")); EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"hello")); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); ASSERT_EQ(0u, tree.getAttributeCount()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); ASSERT_EQ(android::ResXMLTree::TEXT, tree.next()); const char16_t* text = tree.getText(&len); EXPECT_EQ(StringPiece16(u"Some text\\"), StringPiece16(text, len)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); ASSERT_THAT(tree.getAttributeCount(), Eq(0u)); ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Some text\\")); ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"View"), StringPiece16(tag_name, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); ASSERT_EQ(android::ResXMLTree::END_NAMESPACE, tree.next()); namespace_prefix = tree.getNamespacePrefix(&len); EXPECT_EQ(StringPiece16(u"test"), StringPiece16(namespace_prefix, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"View")); namespace_uri = tree.getNamespaceUri(&len); ASSERT_EQ(StringPiece16(u"http://com.test"), StringPiece16(namespace_uri, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_NAMESPACE)); EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test")); EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test")); ASSERT_EQ(android::ResXMLTree::END_DOCUMENT, tree.next()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripOnlyTools) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF( std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( <View xmlns:tools="http://schemas.android.com/tools" xmlns:foo="http://schemas.android.com/foo" foo:bar="Foo" tools:ignore="MissingTranslation"/>)EOF"); tools:ignore="MissingTranslation"/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); ASSERT_EQ(tree.next(), android::ResXMLTree::START_NAMESPACE); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE)); size_t len; const char16_t* namespace_prefix = tree.getNamespacePrefix(&len); EXPECT_EQ(StringPiece16(namespace_prefix, len), u"foo"); const char16_t* namespace_uri = tree.getNamespaceUri(&len); ASSERT_EQ(StringPiece16(namespace_uri, len), u"http://schemas.android.com/foo"); ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG); EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"foo")); EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://schemas.android.com/foo")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_EQ(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"), android::NAME_NOT_FOUND); EXPECT_GE(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), 0); EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"), Eq(android::NAME_NOT_FOUND)); EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), Ge(0)); } TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF( std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( <View xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/id" class="str" style="@id/id"/>)EOF"); style="@id/id"/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } EXPECT_EQ(tree.indexOfClass(), 0); EXPECT_EQ(tree.indexOfStyle(), 1); EXPECT_THAT(tree.indexOfClass(), Eq(0)); EXPECT_THAT(tree.indexOfStyle(), Eq(1)); } // The device ResXMLParser in libandroidfw differentiates between empty namespace and null // namespace. TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom("<View package=\"android\"/>"); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<View package="android"/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kPackage = u"package"; EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0); EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), Ge(0)); } TEST_F(XmlFlattenerTest, EmptyStringValueInAttributeIsNotNull) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom("<View package=\"\"/>"); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<View package=""/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kPackage = u"package"; ssize_t idx = tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); ASSERT_GE(idx, 0); ASSERT_THAT(idx, Ge(0)); size_t len; EXPECT_NE(nullptr, tree.getAttributeStringValue(idx, &len)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), NotNull()); } TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { Loading @@ -236,11 +217,11 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { context_->SetPackageId(0x80); context_->SetNameManglerPolicy({"com.app.test.feature"}); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF( std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"( <View xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@id/foo" app:foo="@id/foo" />)EOF"); app:foo="@id/foo" />)"); XmlReferenceLinker linker; ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); Loading @@ -253,59 +234,57 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(android::ResXMLTree::BAD_DOCUMENT, tree.getEventType()); ASSERT_NE(android::ResXMLTree::END_DOCUMENT, tree.getEventType()); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } ssize_t idx; idx = tree.indexOfAttribute(xml::kSchemaAndroid, "id"); ASSERT_GE(idx, 0); EXPECT_EQ(idx, tree.indexOfID()); EXPECT_EQ(ResourceId(0x010100d0), ResourceId(tree.getAttributeNameResID(idx))); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.indexOfID(), Eq(idx)); EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x010100d0u)); idx = tree.indexOfAttribute(xml::kSchemaAuto, "foo"); ASSERT_GE(idx, 0); EXPECT_EQ(ResourceId(0x80010000), ResourceId(tree.getAttributeNameResID(idx))); EXPECT_EQ(android::Res_value::TYPE_REFERENCE, tree.getAttributeDataType(idx)); EXPECT_EQ(ResourceId(0x80020000), tree.getAttributeData(idx)); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x80010000u)); EXPECT_THAT(tree.getAttributeDataType(idx), Eq(android::Res_value::TYPE_REFERENCE)); EXPECT_THAT(tree.getAttributeData(idx), Eq(int32_t(0x80020000))); } TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom( R"EOF(<element value="\?hello" pattern="\\d{5}">\\d{5}</element>)EOF"); R"(<element value="\?hello" pattern="\\d{5}" other=""">\\d{5}</element>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kValue = u"value"; const StringPiece16 kPattern = u"pattern"; const StringPiece16 kOther = u"other"; size_t len; ssize_t idx; const char16_t* str16; idx = tree.indexOfAttribute(nullptr, 0, kValue.data(), kValue.size()); ASSERT_GE(idx, 0); str16 = tree.getAttributeStringValue(idx, &len); ASSERT_NE(nullptr, str16); EXPECT_EQ(StringPiece16(u"?hello"), StringPiece16(str16, len)); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"?hello")); idx = tree.indexOfAttribute(nullptr, 0, kPattern.data(), kPattern.size()); ASSERT_GE(idx, 0); str16 = tree.getAttributeStringValue(idx, &len); ASSERT_NE(nullptr, str16); EXPECT_EQ(StringPiece16(u"\\d{5}"), StringPiece16(str16, len)); ASSERT_EQ(android::ResXMLTree::TEXT, tree.next()); str16 = tree.getText(&len); ASSERT_NE(nullptr, str16); EXPECT_EQ(StringPiece16(u"\\d{5}"), StringPiece16(str16, len)); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\\d{5}")); idx = tree.indexOfAttribute(nullptr, 0, kOther.data(), kOther.size()); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\"")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); } } // namespace aapt tools/aapt2/readme.md +2 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,8 @@ the set of Proguard keep rules. (bug 62216174) - Automatically version XML `<adaptive-icon>` resources to v26. (bug 62316340) - Fixed issue where escaped unicode characters would generate malformed UTF-8. (bug 62839202) - Fixed issue where apostrophes or quotes used in XML attribute values were ignored. (bug 62840406, 62840718) ## Version 2.17 ### `aapt2 ...` Loading tools/aapt2/test/Common.h +6 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,12 @@ void PrintTo(const Maybe<T>& value, std::ostream* out) { namespace test { MATCHER_P(StrEq, a, std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(android::StringPiece16(a))) { return android::StringPiece16(arg) == a; } MATCHER_P(ValueEq, a, std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) { return arg.Equals(&a); Loading Loading
libs/androidfw/include/androidfw/StringPiece.h +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ class BasicStringPiece { public: using const_iterator = const TChar*; using difference_type = size_t; using size_type = size_t; // End of string marker. constexpr static const size_t npos = static_cast<size_t>(-1); Loading
tools/aapt2/flatten/XmlFlattener.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -257,9 +257,11 @@ class XmlFlattenerVisitor : public xml::Visitor { // Process plain strings to make sure they get properly escaped. StringPiece raw_value = xml_attr->value; util::StringBuilder str_builder; if (!options_.keep_raw_values) { util::StringBuilder str_builder(true /*preserve_spaces*/); str_builder.Append(xml_attr->value); if (!options_.keep_raw_values) { raw_value = str_builder.ToString(); } Loading
tools/aapt2/flatten/XmlFlattener_test.cpp +102 −123 Original line number Diff line number Diff line Loading @@ -23,7 +23,13 @@ #include "util/BigBuffer.h" #include "util/Util.h" using android::StringPiece16; using ::aapt::test::StrEq; using ::android::StringPiece16; using ::testing::Eq; using ::testing::Ge; using ::testing::IsNull; using ::testing::Ne; using ::testing::NotNull; namespace aapt { Loading Loading @@ -72,163 +78,138 @@ class XmlFlattenerTest : public ::testing::Test { }; TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF( <View xmlns:test="http://com.test" attr="hey"> std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( <View xmlns:test="http://com.test" attr="hey"> <Layout test:hello="hi" /> <Layout>Some text\\</Layout> </View>)EOF"); </View>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); ASSERT_EQ(android::ResXMLTree::START_NAMESPACE, tree.next()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE)); size_t len; const char16_t* namespace_prefix = tree.getNamespacePrefix(&len); EXPECT_EQ(StringPiece16(u"test"), StringPiece16(namespace_prefix, len)); const char16_t* namespace_uri = tree.getNamespaceUri(&len); ASSERT_EQ(StringPiece16(u"http://com.test"), StringPiece16(namespace_uri, len)); ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); const char16_t* tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"View"), StringPiece16(tag_name, len)); ASSERT_EQ(1u, tree.getAttributeCount()); ASSERT_EQ(nullptr, tree.getAttributeNamespace(0, &len)); const char16_t* attr_name = tree.getAttributeName(0, &len); EXPECT_EQ(StringPiece16(u"attr"), StringPiece16(attr_name, len)); EXPECT_EQ(0, tree.indexOfAttribute(nullptr, 0, u"attr", StringPiece16(u"attr").size())); EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test")); EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test")); ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"View")); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); EXPECT_THAT(tree.getAttributeNamespace(0, &len), IsNull()); EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"attr")); ASSERT_EQ(1u, tree.getAttributeCount()); const char16_t* attr_namespace = tree.getAttributeNamespace(0, &len); EXPECT_EQ(StringPiece16(u"http://com.test"), StringPiece16(attr_namespace, len)); const StringPiece16 kAttr(u"attr"); EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kAttr.data(), kAttr.size()), Eq(0)); attr_name = tree.getAttributeName(0, &len); EXPECT_EQ(StringPiece16(u"hello"), StringPiece16(attr_name, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); EXPECT_THAT(tree.getAttributeNamespace(0, &len), StrEq(u"http://com.test")); EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"hello")); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); ASSERT_EQ(0u, tree.getAttributeCount()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); ASSERT_EQ(android::ResXMLTree::TEXT, tree.next()); const char16_t* text = tree.getText(&len); EXPECT_EQ(StringPiece16(u"Some text\\"), StringPiece16(text, len)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); ASSERT_THAT(tree.getAttributeCount(), Eq(0u)); ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Some text\\")); ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); tag_name = tree.getElementName(&len); EXPECT_EQ(StringPiece16(u"View"), StringPiece16(tag_name, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); ASSERT_EQ(android::ResXMLTree::END_NAMESPACE, tree.next()); namespace_prefix = tree.getNamespacePrefix(&len); EXPECT_EQ(StringPiece16(u"test"), StringPiece16(namespace_prefix, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"View")); namespace_uri = tree.getNamespaceUri(&len); ASSERT_EQ(StringPiece16(u"http://com.test"), StringPiece16(namespace_uri, len)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_NAMESPACE)); EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test")); EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test")); ASSERT_EQ(android::ResXMLTree::END_DOCUMENT, tree.next()); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripOnlyTools) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF( std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( <View xmlns:tools="http://schemas.android.com/tools" xmlns:foo="http://schemas.android.com/foo" foo:bar="Foo" tools:ignore="MissingTranslation"/>)EOF"); tools:ignore="MissingTranslation"/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); ASSERT_EQ(tree.next(), android::ResXMLTree::START_NAMESPACE); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE)); size_t len; const char16_t* namespace_prefix = tree.getNamespacePrefix(&len); EXPECT_EQ(StringPiece16(namespace_prefix, len), u"foo"); const char16_t* namespace_uri = tree.getNamespaceUri(&len); ASSERT_EQ(StringPiece16(namespace_uri, len), u"http://schemas.android.com/foo"); ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG); EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"foo")); EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://schemas.android.com/foo")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_EQ(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"), android::NAME_NOT_FOUND); EXPECT_GE(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), 0); EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"), Eq(android::NAME_NOT_FOUND)); EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), Ge(0)); } TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"EOF( std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"( <View xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/id" class="str" style="@id/id"/>)EOF"); style="@id/id"/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } EXPECT_EQ(tree.indexOfClass(), 0); EXPECT_EQ(tree.indexOfStyle(), 1); EXPECT_THAT(tree.indexOfClass(), Eq(0)); EXPECT_THAT(tree.indexOfStyle(), Eq(1)); } // The device ResXMLParser in libandroidfw differentiates between empty namespace and null // namespace. TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom("<View package=\"android\"/>"); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<View package="android"/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kPackage = u"package"; EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0); EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), Ge(0)); } TEST_F(XmlFlattenerTest, EmptyStringValueInAttributeIsNotNull) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom("<View package=\"\"/>"); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<View package=""/>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kPackage = u"package"; ssize_t idx = tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); ASSERT_GE(idx, 0); ASSERT_THAT(idx, Ge(0)); size_t len; EXPECT_NE(nullptr, tree.getAttributeStringValue(idx, &len)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), NotNull()); } TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { Loading @@ -236,11 +217,11 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { context_->SetPackageId(0x80); context_->SetNameManglerPolicy({"com.app.test.feature"}); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF( std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"( <View xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@id/foo" app:foo="@id/foo" />)EOF"); app:foo="@id/foo" />)"); XmlReferenceLinker linker; ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); Loading @@ -253,59 +234,57 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(android::ResXMLTree::BAD_DOCUMENT, tree.getEventType()); ASSERT_NE(android::ResXMLTree::END_DOCUMENT, tree.getEventType()); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } ssize_t idx; idx = tree.indexOfAttribute(xml::kSchemaAndroid, "id"); ASSERT_GE(idx, 0); EXPECT_EQ(idx, tree.indexOfID()); EXPECT_EQ(ResourceId(0x010100d0), ResourceId(tree.getAttributeNameResID(idx))); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.indexOfID(), Eq(idx)); EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x010100d0u)); idx = tree.indexOfAttribute(xml::kSchemaAuto, "foo"); ASSERT_GE(idx, 0); EXPECT_EQ(ResourceId(0x80010000), ResourceId(tree.getAttributeNameResID(idx))); EXPECT_EQ(android::Res_value::TYPE_REFERENCE, tree.getAttributeDataType(idx)); EXPECT_EQ(ResourceId(0x80020000), tree.getAttributeData(idx)); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x80010000u)); EXPECT_THAT(tree.getAttributeDataType(idx), Eq(android::Res_value::TYPE_REFERENCE)); EXPECT_THAT(tree.getAttributeData(idx), Eq(int32_t(0x80020000))); } TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom( R"EOF(<element value="\?hello" pattern="\\d{5}">\\d{5}</element>)EOF"); R"(<element value="\?hello" pattern="\\d{5}" other=""">\\d{5}</element>)"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kValue = u"value"; const StringPiece16 kPattern = u"pattern"; const StringPiece16 kOther = u"other"; size_t len; ssize_t idx; const char16_t* str16; idx = tree.indexOfAttribute(nullptr, 0, kValue.data(), kValue.size()); ASSERT_GE(idx, 0); str16 = tree.getAttributeStringValue(idx, &len); ASSERT_NE(nullptr, str16); EXPECT_EQ(StringPiece16(u"?hello"), StringPiece16(str16, len)); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"?hello")); idx = tree.indexOfAttribute(nullptr, 0, kPattern.data(), kPattern.size()); ASSERT_GE(idx, 0); str16 = tree.getAttributeStringValue(idx, &len); ASSERT_NE(nullptr, str16); EXPECT_EQ(StringPiece16(u"\\d{5}"), StringPiece16(str16, len)); ASSERT_EQ(android::ResXMLTree::TEXT, tree.next()); str16 = tree.getText(&len); ASSERT_NE(nullptr, str16); EXPECT_EQ(StringPiece16(u"\\d{5}"), StringPiece16(str16, len)); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\\d{5}")); idx = tree.indexOfAttribute(nullptr, 0, kOther.data(), kOther.size()); ASSERT_THAT(idx, Ge(0)); EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\"")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); } } // namespace aapt
tools/aapt2/readme.md +2 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,8 @@ the set of Proguard keep rules. (bug 62216174) - Automatically version XML `<adaptive-icon>` resources to v26. (bug 62316340) - Fixed issue where escaped unicode characters would generate malformed UTF-8. (bug 62839202) - Fixed issue where apostrophes or quotes used in XML attribute values were ignored. (bug 62840406, 62840718) ## Version 2.17 ### `aapt2 ...` Loading
tools/aapt2/test/Common.h +6 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,12 @@ void PrintTo(const Maybe<T>& value, std::ostream* out) { namespace test { MATCHER_P(StrEq, a, std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(android::StringPiece16(a))) { return android::StringPiece16(arg) == a; } MATCHER_P(ValueEq, a, std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) { return arg.Equals(&a); Loading