Loading tools/aapt2/StringPool_test.cpp +7 −3 Original line number Diff line number Diff line Loading @@ -208,7 +208,8 @@ TEST(StringPoolTest, FlattenUtf8) { StringPool::Ref ref1 = pool.makeRef(u"hello"); StringPool::Ref ref2 = pool.makeRef(u"goodbye"); StringPool::Ref ref3 = pool.makeRef(sLongString); StringPool::StyleRef ref4 = pool.makeRef(StyleString{ StringPool::Ref ref4 = pool.makeRef(u""); StringPool::StyleRef ref5 = pool.makeRef(StyleString{ { u"style" }, { Span{ { u"b" }, 0, 1 }, Span{ { u"i" }, 2, 3 } } }); Loading @@ -217,6 +218,7 @@ TEST(StringPoolTest, FlattenUtf8) { EXPECT_EQ(1u, ref2.getIndex()); EXPECT_EQ(2u, ref3.getIndex()); EXPECT_EQ(3u, ref4.getIndex()); EXPECT_EQ(4u, ref5.getIndex()); BigBuffer buffer(1024); StringPool::flattenUtf8(&buffer, pool); Loading @@ -229,9 +231,11 @@ TEST(StringPoolTest, FlattenUtf8) { EXPECT_EQ(util::getString(test, 0), u"hello"); EXPECT_EQ(util::getString(test, 1), u"goodbye"); EXPECT_EQ(util::getString(test, 2), sLongString); EXPECT_EQ(util::getString(test, 3), u"style"); size_t len; EXPECT_NE(nullptr, test.stringAt(3, &len)); EXPECT_EQ(util::getString(test, 4), u"style"); const ResStringPool_span* span = test.styleAt(3); const ResStringPool_span* span = test.styleAt(4); ASSERT_NE(nullptr, span); EXPECT_EQ(util::getString(test, span->name.index), u"b"); EXPECT_EQ(0u, span->firstChar); Loading tools/aapt2/flatten/XmlFlattener.cpp +20 −10 Original line number Diff line number Diff line Loading @@ -57,14 +57,15 @@ struct XmlFlattenerVisitor : public xml::Visitor { mBuffer(buffer), mOptions(options) { } void addString(const StringPiece16& str, uint32_t priority, android::ResStringPool_ref* dest) { if (!str.empty()) { void addString(const StringPiece16& str, uint32_t priority, android::ResStringPool_ref* dest, bool treatEmptyStringAsNull = false) { if (str.empty() && treatEmptyStringAsNull) { // Some parts of the runtime treat null differently than empty string. dest->index = util::deviceToHost32(-1); } else { mStringRefs.push_back(StringFlattenDest{ mPool.makeRef(str, StringPool::Context{ priority }), dest }); } else { // The device doesn't think a string of size 0 is the same as null. dest->index = util::deviceToHost32(-1); } } Loading Loading @@ -118,8 +119,14 @@ struct XmlFlattenerVisitor : public xml::Visitor { flatNode->comment.index = util::hostToDevice32(-1); ResXMLTree_attrExt* flatElem = startWriter.nextBlock<ResXMLTree_attrExt>(); addString(node->namespaceUri, kLowPriority, &flatElem->ns); addString(node->name, kLowPriority, &flatElem->name); // A missing namespace must be null, not an empty string. Otherwise the runtime // complains. addString(node->namespaceUri, kLowPriority, &flatElem->ns, true /* treatEmptyStringAsNull */); addString(node->name, kLowPriority, &flatElem->name, true /* treatEmptyStringAsNull */); flatElem->attributeStart = util::hostToDevice16(sizeof(*flatElem)); flatElem->attributeSize = util::hostToDevice16(sizeof(ResXMLTree_attribute)); Loading @@ -138,7 +145,8 @@ struct XmlFlattenerVisitor : public xml::Visitor { flatEndNode->comment.index = util::hostToDevice32(-1); ResXMLTree_endElementExt* flatEndElem = endWriter.nextBlock<ResXMLTree_endElementExt>(); addString(node->namespaceUri, kLowPriority, &flatEndElem->ns); addString(node->namespaceUri, kLowPriority, &flatEndElem->ns, true /* treatEmptyStringAsNull */); addString(node->name, kLowPriority, &flatEndElem->name); endWriter.finish(); Loading Loading @@ -205,8 +213,10 @@ struct XmlFlattenerVisitor : public xml::Visitor { } attributeIndex++; // Add the namespaceUri to the list of StringRefs to encode. addString(xmlAttr->namespaceUri, kLowPriority, &flatAttr->ns); // Add the namespaceUri to the list of StringRefs to encode. Use null if the namespace // is empty (doesn't exist). addString(xmlAttr->namespaceUri, kLowPriority, &flatAttr->ns, true /* treatEmptyStringAsNull */); flatAttr->rawValue.index = util::hostToDevice32(-1); Loading tools/aapt2/flatten/XmlFlattener_test.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -207,4 +207,23 @@ TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) { EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0); } TEST_F(XmlFlattenerTest, EmptyStringValueInAttributeIsNotNull) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom("<View package=\"\"/>"); android::ResXMLTree tree; ASSERT_TRUE(flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); } const StringPiece16 kPackage = u"package"; ssize_t idx = tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); ASSERT_GE(idx, 0); size_t len; EXPECT_NE(nullptr, tree.getAttributeStringValue(idx, &len)); } } // namespace aapt Loading
tools/aapt2/StringPool_test.cpp +7 −3 Original line number Diff line number Diff line Loading @@ -208,7 +208,8 @@ TEST(StringPoolTest, FlattenUtf8) { StringPool::Ref ref1 = pool.makeRef(u"hello"); StringPool::Ref ref2 = pool.makeRef(u"goodbye"); StringPool::Ref ref3 = pool.makeRef(sLongString); StringPool::StyleRef ref4 = pool.makeRef(StyleString{ StringPool::Ref ref4 = pool.makeRef(u""); StringPool::StyleRef ref5 = pool.makeRef(StyleString{ { u"style" }, { Span{ { u"b" }, 0, 1 }, Span{ { u"i" }, 2, 3 } } }); Loading @@ -217,6 +218,7 @@ TEST(StringPoolTest, FlattenUtf8) { EXPECT_EQ(1u, ref2.getIndex()); EXPECT_EQ(2u, ref3.getIndex()); EXPECT_EQ(3u, ref4.getIndex()); EXPECT_EQ(4u, ref5.getIndex()); BigBuffer buffer(1024); StringPool::flattenUtf8(&buffer, pool); Loading @@ -229,9 +231,11 @@ TEST(StringPoolTest, FlattenUtf8) { EXPECT_EQ(util::getString(test, 0), u"hello"); EXPECT_EQ(util::getString(test, 1), u"goodbye"); EXPECT_EQ(util::getString(test, 2), sLongString); EXPECT_EQ(util::getString(test, 3), u"style"); size_t len; EXPECT_NE(nullptr, test.stringAt(3, &len)); EXPECT_EQ(util::getString(test, 4), u"style"); const ResStringPool_span* span = test.styleAt(3); const ResStringPool_span* span = test.styleAt(4); ASSERT_NE(nullptr, span); EXPECT_EQ(util::getString(test, span->name.index), u"b"); EXPECT_EQ(0u, span->firstChar); Loading
tools/aapt2/flatten/XmlFlattener.cpp +20 −10 Original line number Diff line number Diff line Loading @@ -57,14 +57,15 @@ struct XmlFlattenerVisitor : public xml::Visitor { mBuffer(buffer), mOptions(options) { } void addString(const StringPiece16& str, uint32_t priority, android::ResStringPool_ref* dest) { if (!str.empty()) { void addString(const StringPiece16& str, uint32_t priority, android::ResStringPool_ref* dest, bool treatEmptyStringAsNull = false) { if (str.empty() && treatEmptyStringAsNull) { // Some parts of the runtime treat null differently than empty string. dest->index = util::deviceToHost32(-1); } else { mStringRefs.push_back(StringFlattenDest{ mPool.makeRef(str, StringPool::Context{ priority }), dest }); } else { // The device doesn't think a string of size 0 is the same as null. dest->index = util::deviceToHost32(-1); } } Loading Loading @@ -118,8 +119,14 @@ struct XmlFlattenerVisitor : public xml::Visitor { flatNode->comment.index = util::hostToDevice32(-1); ResXMLTree_attrExt* flatElem = startWriter.nextBlock<ResXMLTree_attrExt>(); addString(node->namespaceUri, kLowPriority, &flatElem->ns); addString(node->name, kLowPriority, &flatElem->name); // A missing namespace must be null, not an empty string. Otherwise the runtime // complains. addString(node->namespaceUri, kLowPriority, &flatElem->ns, true /* treatEmptyStringAsNull */); addString(node->name, kLowPriority, &flatElem->name, true /* treatEmptyStringAsNull */); flatElem->attributeStart = util::hostToDevice16(sizeof(*flatElem)); flatElem->attributeSize = util::hostToDevice16(sizeof(ResXMLTree_attribute)); Loading @@ -138,7 +145,8 @@ struct XmlFlattenerVisitor : public xml::Visitor { flatEndNode->comment.index = util::hostToDevice32(-1); ResXMLTree_endElementExt* flatEndElem = endWriter.nextBlock<ResXMLTree_endElementExt>(); addString(node->namespaceUri, kLowPriority, &flatEndElem->ns); addString(node->namespaceUri, kLowPriority, &flatEndElem->ns, true /* treatEmptyStringAsNull */); addString(node->name, kLowPriority, &flatEndElem->name); endWriter.finish(); Loading Loading @@ -205,8 +213,10 @@ struct XmlFlattenerVisitor : public xml::Visitor { } attributeIndex++; // Add the namespaceUri to the list of StringRefs to encode. addString(xmlAttr->namespaceUri, kLowPriority, &flatAttr->ns); // Add the namespaceUri to the list of StringRefs to encode. Use null if the namespace // is empty (doesn't exist). addString(xmlAttr->namespaceUri, kLowPriority, &flatAttr->ns, true /* treatEmptyStringAsNull */); flatAttr->rawValue.index = util::hostToDevice32(-1); Loading
tools/aapt2/flatten/XmlFlattener_test.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -207,4 +207,23 @@ TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) { EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0); } TEST_F(XmlFlattenerTest, EmptyStringValueInAttributeIsNotNull) { std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom("<View package=\"\"/>"); android::ResXMLTree tree; ASSERT_TRUE(flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); } const StringPiece16 kPackage = u"package"; ssize_t idx = tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); ASSERT_GE(idx, 0); size_t len; EXPECT_NE(nullptr, tree.getAttributeStringValue(idx, &len)); } } // namespace aapt