Loading tools/aapt2/format/binary/XmlFlattener.cpp +15 −7 Original line number Original line Diff line number Diff line Loading @@ -79,23 +79,31 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { } } void Visit(const xml::Text* node) override { void Visit(const xml::Text* node) override { if (util::TrimWhitespace(node->text).empty()) { std::string text = util::TrimWhitespace(node->text).to_string(); // Skip whitespace only text nodes. // Skip whitespace only text nodes. if (text.empty()) { return; return; } } // Compact leading and trailing whitespace into a single space if (isspace(node->text[0])) { text = ' ' + text; } if (isspace(node->text[node->text.length() - 1])) { text = text + ' '; } ChunkWriter writer(buffer_); ChunkWriter writer(buffer_); ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE); ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE); flat_node->lineNumber = util::HostToDevice32(node->line_number); flat_node->lineNumber = util::HostToDevice32(node->line_number); flat_node->comment.index = util::HostToDevice32(-1); flat_node->comment.index = util::HostToDevice32(-1); ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>(); // Process plain strings to make sure they get properly escaped. // Process plain strings to make sure they get properly escaped. StringBuilder builder; text = StringBuilder(true /*preserve_spaces*/).AppendText(text).to_string(); builder.AppendText(node->text); AddString(builder.to_string(), kLowPriority, &flat_text->data); ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>(); AddString(text, kLowPriority, &flat_text->data); writer.Finish(); writer.Finish(); } } Loading tools/aapt2/format/binary/XmlFlattener_test.cpp +159 −0 Original line number Original line Diff line number Diff line Loading @@ -286,6 +286,165 @@ TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); } } TEST_F(XmlFlattenerTest, ProcessQuotes) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom( R"(<root> <item>Regular text</item> <item>"Text in double quotes"</item> <item>'Text in single quotes'</item> <item>Text containing "double quotes"</item> <item>Text containing 'single quotes'</item> </root>)"); size_t len; android::ResXMLTree tree; XmlFlattenerOptions options; ASSERT_TRUE(Flatten(doc.get(), &tree, options)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Regular text")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"\"Text in double quotes\"")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"'Text in single quotes'")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing \"double quotes\"")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing 'single quotes'")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, ProcessWhitepspace) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom( R"(<root> <item> Compact Spaces </item> <item> A </item> <item>B </item> <item>C </item> <item> D </item> <item> E</item> <item> F</item> <item> G </item> <item> H </item> <item> I </item> <item> J </item> <item> </item> </root>)"); size_t len; android::ResXMLTree tree; XmlFlattenerOptions options; ASSERT_TRUE(Flatten(doc.get(), &tree, options)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" Compact Spaces ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" A ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"B ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"C ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" D ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" E")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" F")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" G ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" H ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" I ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" J ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) { TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); Loading Loading
tools/aapt2/format/binary/XmlFlattener.cpp +15 −7 Original line number Original line Diff line number Diff line Loading @@ -79,23 +79,31 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { } } void Visit(const xml::Text* node) override { void Visit(const xml::Text* node) override { if (util::TrimWhitespace(node->text).empty()) { std::string text = util::TrimWhitespace(node->text).to_string(); // Skip whitespace only text nodes. // Skip whitespace only text nodes. if (text.empty()) { return; return; } } // Compact leading and trailing whitespace into a single space if (isspace(node->text[0])) { text = ' ' + text; } if (isspace(node->text[node->text.length() - 1])) { text = text + ' '; } ChunkWriter writer(buffer_); ChunkWriter writer(buffer_); ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE); ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE); flat_node->lineNumber = util::HostToDevice32(node->line_number); flat_node->lineNumber = util::HostToDevice32(node->line_number); flat_node->comment.index = util::HostToDevice32(-1); flat_node->comment.index = util::HostToDevice32(-1); ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>(); // Process plain strings to make sure they get properly escaped. // Process plain strings to make sure they get properly escaped. StringBuilder builder; text = StringBuilder(true /*preserve_spaces*/).AppendText(text).to_string(); builder.AppendText(node->text); AddString(builder.to_string(), kLowPriority, &flat_text->data); ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>(); AddString(text, kLowPriority, &flat_text->data); writer.Finish(); writer.Finish(); } } Loading
tools/aapt2/format/binary/XmlFlattener_test.cpp +159 −0 Original line number Original line Diff line number Diff line Loading @@ -286,6 +286,165 @@ TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); } } TEST_F(XmlFlattenerTest, ProcessQuotes) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom( R"(<root> <item>Regular text</item> <item>"Text in double quotes"</item> <item>'Text in single quotes'</item> <item>Text containing "double quotes"</item> <item>Text containing 'single quotes'</item> </root>)"); size_t len; android::ResXMLTree tree; XmlFlattenerOptions options; ASSERT_TRUE(Flatten(doc.get(), &tree, options)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Regular text")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"\"Text in double quotes\"")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"'Text in single quotes'")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing \"double quotes\"")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing 'single quotes'")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, ProcessWhitepspace) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom( R"(<root> <item> Compact Spaces </item> <item> A </item> <item>B </item> <item>C </item> <item> D </item> <item> E</item> <item> F</item> <item> G </item> <item> H </item> <item> I </item> <item> J </item> <item> </item> </root>)"); size_t len; android::ResXMLTree tree; XmlFlattenerOptions options; ASSERT_TRUE(Flatten(doc.get(), &tree, options)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" Compact Spaces ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" A ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"B ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u"C ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" D ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" E")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" F")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" G ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" H ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" I ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); EXPECT_THAT(tree.getText(&len), StrEq(u" J ")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) { TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); Loading