Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6ace01c authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Fix unrecognized CDATA"

parents 79e27cd2 cb76d734
Loading
Loading
Loading
Loading
+27 −3
Original line number Diff line number Diff line
@@ -208,6 +208,15 @@ class SegmentNode : public Node {
  }
};

// A chunk of text in the XML string within a CDATA tags.
class CdataSegmentNode : public SegmentNode {
 public:

  void Build(StringBuilder* builder) const override {
    builder->AppendText(data, /* preserve_spaces */ true);
  }
};

// A tag that will be encoded into the final flattened string. Tags like <b> or <i>.
class SpanNode : public Node {
 public:
@@ -244,6 +253,7 @@ bool ResourceParser::FlattenXmlSubtree(
  std::vector<Node*> node_stack;
  node_stack.push_back(&root);

  bool cdata_block = false;
  bool saw_span_node = false;
  SegmentNode* first_segment = nullptr;
  SegmentNode* last_segment = nullptr;
@@ -253,11 +263,15 @@ bool ResourceParser::FlattenXmlSubtree(
    const xml::XmlPullParser::Event event = parser->event();

    // First take care of any SegmentNodes that should be created.
    if (event == xml::XmlPullParser::Event::kStartElement ||
        event == xml::XmlPullParser::Event::kEndElement) {
    if (event == xml::XmlPullParser::Event::kStartElement
        || event == xml::XmlPullParser::Event::kEndElement
        || event == xml::XmlPullParser::Event::kCdataStart
        || event == xml::XmlPullParser::Event::kCdataEnd) {
      if (!current_text.empty()) {
        std::unique_ptr<SegmentNode> segment_node = util::make_unique<SegmentNode>();
        std::unique_ptr<SegmentNode> segment_node = (cdata_block)
            ? util::make_unique<CdataSegmentNode>() : util::make_unique<SegmentNode>();
        segment_node->data = std::move(current_text);

        last_segment = node_stack.back()->AddChild(std::move(segment_node));
        if (first_segment == nullptr) {
          first_segment = last_segment;
@@ -333,6 +347,16 @@ bool ResourceParser::FlattenXmlSubtree(
        }
      } break;

      case xml::XmlPullParser::Event::kCdataStart: {
        cdata_block = true;
        break;
      }

      case xml::XmlPullParser::Event::kCdataEnd: {
        cdata_block = false;
        break;
      }

      default:
        // ignore.
        break;
+36 −0
Original line number Diff line number Diff line
@@ -989,4 +989,40 @@ TEST_F(ResourceParserTest, ParseIdItem) {
  ASSERT_FALSE(TestParse(input));
}

TEST_F(ResourceParserTest, ParseCData) {
  std::string input = R"(
      <string name="foo"><![CDATA[some text and ' apostrophe]]></string>)";

  ASSERT_TRUE(TestParse(input));
  String* output = test::GetValue<String>(&table_, "string/foo");
  ASSERT_THAT(output, NotNull());
  EXPECT_THAT(*output, StrValueEq("some text and ' apostrophe"));

  // Double quotes should not change the state of whitespace processing
  input = R"(<string name="foo2">Hello<![CDATA[ "</string>' ]]>      World</string>)";
  ASSERT_TRUE(TestParse(input));
  output = test::GetValue<String>(&table_, "string/foo2");
  ASSERT_THAT(output, NotNull());
  EXPECT_THAT(*output, StrValueEq(std::string("Hello \"</string>'  World").data()));

  // Cdata blocks should not have their whitespace trimmed
  input = R"(<string name="foo3">     <![CDATA[ text ]]>     </string>)";
  ASSERT_TRUE(TestParse(input));
  output = test::GetValue<String>(&table_, "string/foo3");
  ASSERT_THAT(output, NotNull());
  EXPECT_THAT(*output, StrValueEq(std::string(" text ").data()));

  input = R"(<string name="foo4">     <![CDATA[]]>     </string>)";
  ASSERT_TRUE(TestParse(input));
  output = test::GetValue<String>(&table_, "string/foo4");
  ASSERT_THAT(output, NotNull());
  EXPECT_THAT(*output, StrValueEq(std::string("").data()));

  input = R"(<string name="foo5">     <![CDATA[    ]]>     </string>)";
  ASSERT_TRUE(TestParse(input));
  output = test::GetValue<String>(&table_, "string/foo5");
  ASSERT_THAT(output, NotNull());
  EXPECT_THAT(*output, StrValueEq(std::string("    ").data()));
}

}  // namespace aapt
+9 −6
Original line number Diff line number Diff line
@@ -797,16 +797,20 @@ StringBuilder::StringBuilder(bool preserve_spaces)
    : preserve_spaces_(preserve_spaces), quote_(preserve_spaces) {
}

StringBuilder& StringBuilder::AppendText(const std::string& text) {
StringBuilder& StringBuilder::AppendText(const std::string& text, bool preserve_spaces) {
  if (!error_.empty()) {
    return *this;
  }

  // Enable preserving spaces if it is enabled for this append or the StringBuilder was constructed
  // to preserve spaces
  preserve_spaces = (preserve_spaces) ? preserve_spaces : preserve_spaces_;

  const size_t previous_len = xml_string_.text.size();
  Utf8Iterator iter(text);
  while (iter.HasNext()) {
    char32_t codepoint = iter.Next();
    if (!quote_ && iswspace(codepoint)) {
    if (!preserve_spaces && !quote_ && iswspace(codepoint)) {
      if (!last_codepoint_was_space_) {
        // Emit a space if it's the first.
        xml_string_.text += ' ';
@@ -827,7 +831,6 @@ StringBuilder& StringBuilder::AppendText(const std::string& text) {
          case U't':
            xml_string_.text += '\t';
            break;

          case U'n':
            xml_string_.text += '\n';
            break;
@@ -855,12 +858,12 @@ StringBuilder& StringBuilder::AppendText(const std::string& text) {
            break;
        }
      }
    } else if (!preserve_spaces_ && codepoint == U'"') {
    } else if (!preserve_spaces && codepoint == U'"') {
      // Only toggle the quote state when we are not preserving spaces.
      quote_ = !quote_;

    } else if (!quote_ && codepoint == U'\'') {
      // This should be escaped.
    } else if (!preserve_spaces && !quote_ && codepoint == U'\'') {
      // This should be escaped when we are not preserving spaces
      error_ = StringPrintf("unescaped apostrophe in string\n\"%s\"", text.c_str());
      return *this;

+4 −2
Original line number Diff line number Diff line
@@ -267,8 +267,10 @@ class StringBuilder {
  // single quotations can be used without escaping them.
  explicit StringBuilder(bool preserve_spaces = false);

  // Appends a chunk of text.
  StringBuilder& AppendText(const std::string& text);
  // Appends a chunk of text. If preserve_spaces is true, whitespace removal is not performed, and
  // single quotations can be used without escaping them for this append. Otherwise, the
  // StringBuilder will behave as it was constructed.
  StringBuilder& AppendText(const std::string& text, bool preserve_spaces = false);

  // Starts a Span (tag) with the given name. The name is expected to be of the form:
  //  "tag_name;attr1=value;attr2=value;"
+23 −0
Original line number Diff line number Diff line
@@ -254,6 +254,29 @@ TEST(ResourceUtilsTest, StringBuilderUnicodeCodes) {
TEST(ResourceUtilsTest, StringBuilderPreserveSpaces) {
  EXPECT_THAT(ResourceUtils::StringBuilder(true /*preserve_spaces*/).AppendText("\"").to_string(),
              Eq("\""));

  // Single quotes should be able to be used without escaping them when preserving spaces and the
  // spaces should not be trimmed
  EXPECT_THAT(ResourceUtils::StringBuilder()
                  .AppendText("    hey guys ")
                  .AppendText(" 'this is so cool' ", /* preserve_spaces */ true)
                  .AppendText(" wow    ")
                  .to_string(),
              Eq(" hey guys  'this is so cool'  wow "));

  // Reading a double quote while preserving spaces should not change the quote state
  EXPECT_THAT(ResourceUtils::StringBuilder()
                  .AppendText("    hey guys ")
                  .AppendText(" \"this is so cool' ", /* preserve_spaces */ true)
                  .AppendText(" wow    ")
                  .to_string(),
              Eq(" hey guys  \"this is so cool'  wow "));
  EXPECT_THAT(ResourceUtils::StringBuilder()
                  .AppendText("    hey guys\"  ")
                  .AppendText(" \"this is so cool' ", /* preserve_spaces */ true)
                  .AppendText(" wow  \"  ")
                  .to_string(),
              Eq(" hey guys   \"this is so cool'  wow   "));
}

}  // namespace aapt
Loading