Retain parsed attribute type

If the value of an attribute enum is defined as a hexadecimal integer,
flatten uses of the attribute as with the
android::Res_value::TYPE_INT_HEX type.

This change adds a "type" field to pb::Attribute::Symbol, which if left
unset, will have a default value of android::Res_value::TYPE_INT_DEC
when deserialized by aapt2.

Bug: 124474141
Test: aapt2_tests and manual compilation of files and inspection using
`aapt2 dump chunks`
Change-Id: Ibf12394284fdbe3a8047f7ecf4fe68517dfc3abb
This commit is contained in:
Ryan Mitchell
2019-05-20 16:47:08 -07:00
parent e05fdd2f72
commit c1676807f4
11 changed files with 19 additions and 5 deletions

View File

@@ -1387,7 +1387,7 @@ Maybe<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(
return Attribute::Symbol{
Reference(ResourceNameRef({}, ResourceType::kId, maybe_name.value())),
val.data};
val.data, val.dataType};
}
bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {

View File

@@ -401,7 +401,7 @@ TEST_F(ResourceParserTest, ParseEnumAttr) {
std::string input = R"(
<attr name="foo">
<enum name="bar" value="0"/>
<enum name="bat" value="1"/>
<enum name="bat" value="0x1"/>
<enum name="baz" value="2"/>
</attr>)";
ASSERT_TRUE(TestParse(input));
@@ -414,14 +414,17 @@ TEST_F(ResourceParserTest, ParseEnumAttr) {
ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
EXPECT_THAT(enum_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
EXPECT_THAT(enum_attr->symbols[0].value, Eq(0u));
EXPECT_THAT(enum_attr->symbols[0].type, Eq(Res_value::TYPE_INT_DEC));
ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
EXPECT_THAT(enum_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
EXPECT_THAT(enum_attr->symbols[1].value, Eq(1u));
EXPECT_THAT(enum_attr->symbols[1].type, Eq(Res_value::TYPE_INT_HEX));
ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
EXPECT_THAT(enum_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
EXPECT_THAT(enum_attr->symbols[2].value, Eq(2u));
EXPECT_THAT(enum_attr->symbols[2].type, Eq(Res_value::TYPE_INT_DEC));
}
TEST_F(ResourceParserTest, ParseFlagAttr) {

View File

@@ -378,7 +378,7 @@ std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
const ResourceName& enum_symbol_resource_name = symbol.symbol.name.value();
if (trimmed_str == enum_symbol_resource_name.entry) {
android::Res_value value = {};
value.dataType = android::Res_value::TYPE_INT_DEC;
value.dataType = symbol.type;
value.data = symbol.value;
return util::make_unique<BinaryPrimitive>(value);
}

View File

@@ -292,6 +292,7 @@ struct Attribute : public BaseValue<Attribute> {
struct Symbol {
Reference symbol;
uint32_t value;
uint8_t type;
friend std::ostream& operator<<(std::ostream& out, const Symbol& symbol);
};

View File

@@ -388,6 +388,9 @@ message Attribute {
// The value of the enum/flag.
uint32 value = 4;
// The data type of the enum/flag as defined in android::Res_value.
uint32 type = 5;
}
// Bitmask of formats allowed for an attribute.

View File

@@ -614,6 +614,7 @@ std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef
if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Attribute::Symbol symbol;
symbol.value = util::DeviceToHost32(map_entry.value.data);
symbol.type = map_entry.value.dataType;
symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
attr->symbols.push_back(std::move(symbol));
}

View File

@@ -107,7 +107,7 @@ class MapFlattenVisitor : public ValueVisitor {
}
for (Attribute::Symbol& s : attr->symbols) {
BinaryPrimitive val(Res_value::TYPE_INT_DEC, s.value);
BinaryPrimitive val(s.type, s.value);
FlattenEntry(&s.symbol, &val);
}
}

View File

@@ -708,6 +708,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
return {};
}
symbol.value = pb_symbol.value();
symbol.type = pb_symbol.type() != 0U ? pb_symbol.type()
: android::Res_value::TYPE_INT_DEC;
attr->symbols.push_back(std::move(symbol));
}
value = std::move(attr);

View File

@@ -552,6 +552,7 @@ class ValueSerializer : public ConstValueVisitor {
SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
pb_symbol->set_value(symbol.value);
pb_symbol->set_type(symbol.type);
}
}

View File

@@ -80,7 +80,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
ASSERT_TRUE(table->AddResource(
test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
test::BuildPrimitive(android::Res_value::TYPE_INT_HEX, 321u), context->GetDiagnostics()));
// Make a reference with both resource name and resource ID.
// The reference should point to a resource outside of this table to test that both name and id
@@ -133,11 +133,13 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
&new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
ASSERT_THAT(prim, NotNull());
EXPECT_THAT(prim->value.data, Eq(123u));
EXPECT_THAT(prim->value.dataType, Eq(0x10));
prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
&new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
ASSERT_THAT(prim, NotNull());
EXPECT_THAT(prim->value.data, Eq(321u));
EXPECT_THAT(prim->value.dataType, Eq(0x11));
Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
ASSERT_THAT(actual_ref, NotNull());

View File

@@ -313,6 +313,7 @@ static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
symbol.symbol.name = parsed_name.value();
symbol.symbol.id = ResourceId(map_entry.key);
symbol.value = map_entry.value.data;
symbol.type = map_entry.value.dataType;
s->attribute->symbols.push_back(std::move(symbol));
}
}