Merge "AAPT2: Fix quoted text in res/xml assets" into pi-dev

This commit is contained in:
Ryan Mitchell
2018-05-02 20:23:49 +00:00
committed by Android (Google) Code Review
2 changed files with 174 additions and 7 deletions

View File

@@ -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();
}

View File

@@ -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" />)");