AAPT2: Encode 4-byte strings in Modified UTF-8

Codepoints that are encoded to 4 bytes in UTF-8 are not allowed in
Modified UTF-8. They instead should be encoded as surrogate pairs in the
same way that CESU-8 allows for surrogate pairs. This will also cause 4
byte UTF-8 codes to be represented in 6 bytes.

Bug: 37140916
Test: aapt2_tests
Change-Id: I155dc24f166139d1d36a16bac088dcfcd59eb321
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 4b3afe2..0778564 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -303,6 +303,25 @@
   }
 }
 
+TEST(StringPoolTest, FlattenModifiedUTF8) {
+  using namespace android;  // For NO_ERROR on Windows.
+  StdErrDiagnostics diag;
+  StringPool pool;
+  StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400)
+  StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437)
+  StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7");
+
+  BigBuffer buffer(1024);
+  StringPool::FlattenUtf8(&buffer, pool, &diag);
+  std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+
+  // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs
+  ResStringPool test;
+  ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
+  EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80"));
+  EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+  EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+}
 
 TEST(StringPoolTest, MaxEncodingLength) {
   StdErrDiagnostics diag;