diff options
| -rw-r--r-- | tools/aapt2/format/binary/XmlFlattener.cpp | 22 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/XmlFlattener_test.cpp | 159 |
2 files changed, 174 insertions, 7 deletions
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp index d897941da6c4..2fe24245f3d9 100644 --- a/tools/aapt2/format/binary/XmlFlattener.cpp +++ b/tools/aapt2/format/binary/XmlFlattener.cpp @@ -79,23 +79,31 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { } void Visit(const xml::Text* node) override { - if (util::TrimWhitespace(node->text).empty()) { - // Skip whitespace only text nodes. + std::string text = util::TrimWhitespace(node->text).to_string(); + + // Skip whitespace only text nodes. + if (text.empty()) { 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_); ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE); flat_node->lineNumber = util::HostToDevice32(node->line_number); 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. - StringBuilder builder; - builder.AppendText(node->text); - AddString(builder.to_string(), kLowPriority, &flat_text->data); + text = StringBuilder(true /*preserve_spaces*/).AppendText(text).to_string(); + ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>(); + AddString(text, kLowPriority, &flat_text->data); writer.Finish(); } diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp index 08243feb3769..25786b1659e7 100644 --- a/tools/aapt2/format/binary/XmlFlattener_test.cpp +++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp @@ -286,6 +286,165 @@ TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { 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) { std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); |