diff options
Diffstat (limited to 'tools/aapt2/ResourceValues.cpp')
-rw-r--r-- | tools/aapt2/ResourceValues.cpp | 116 |
1 files changed, 80 insertions, 36 deletions
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index e808984c75f5..947e091e2d48 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -533,75 +533,119 @@ void Attribute::Print(std::ostream* out) const { } } -static void BuildAttributeMismatchMessage(DiagMessage* msg, - const Attribute* attr, - const Item* value) { - *msg << "expected"; - if (attr->type_mask & android::ResTable_map::TYPE_BOOLEAN) { - *msg << " boolean"; +static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& value, + DiagMessage* out_msg) { + *out_msg << "expected"; + if (attr.type_mask & android::ResTable_map::TYPE_BOOLEAN) { + *out_msg << " boolean"; } - if (attr->type_mask & android::ResTable_map::TYPE_COLOR) { - *msg << " color"; + if (attr.type_mask & android::ResTable_map::TYPE_COLOR) { + *out_msg << " color"; } - if (attr->type_mask & android::ResTable_map::TYPE_DIMENSION) { - *msg << " dimension"; + if (attr.type_mask & android::ResTable_map::TYPE_DIMENSION) { + *out_msg << " dimension"; } - if (attr->type_mask & android::ResTable_map::TYPE_ENUM) { - *msg << " enum"; + if (attr.type_mask & android::ResTable_map::TYPE_ENUM) { + *out_msg << " enum"; } - if (attr->type_mask & android::ResTable_map::TYPE_FLAGS) { - *msg << " flags"; + if (attr.type_mask & android::ResTable_map::TYPE_FLAGS) { + *out_msg << " flags"; } - if (attr->type_mask & android::ResTable_map::TYPE_FLOAT) { - *msg << " float"; + if (attr.type_mask & android::ResTable_map::TYPE_FLOAT) { + *out_msg << " float"; } - if (attr->type_mask & android::ResTable_map::TYPE_FRACTION) { - *msg << " fraction"; + if (attr.type_mask & android::ResTable_map::TYPE_FRACTION) { + *out_msg << " fraction"; } - if (attr->type_mask & android::ResTable_map::TYPE_INTEGER) { - *msg << " integer"; + if (attr.type_mask & android::ResTable_map::TYPE_INTEGER) { + *out_msg << " integer"; } - if (attr->type_mask & android::ResTable_map::TYPE_REFERENCE) { - *msg << " reference"; + if (attr.type_mask & android::ResTable_map::TYPE_REFERENCE) { + *out_msg << " reference"; } - if (attr->type_mask & android::ResTable_map::TYPE_STRING) { - *msg << " string"; + if (attr.type_mask & android::ResTable_map::TYPE_STRING) { + *out_msg << " string"; } - *msg << " but got " << *value; + *out_msg << " but got " << value; } -bool Attribute::Matches(const Item* item, DiagMessage* out_msg) const { +bool Attribute::Matches(const Item& item, DiagMessage* out_msg) const { + constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM; + constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS; + constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER; + constexpr const uint32_t TYPE_REFERENCE = android::ResTable_map::TYPE_REFERENCE; + android::Res_value val = {}; - item->Flatten(&val); + item.Flatten(&val); + + const uint32_t flattened_data = util::DeviceToHost32(val.data); // Always allow references. - const uint32_t mask = type_mask | android::ResTable_map::TYPE_REFERENCE; - if (!(mask & ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType))) { + const uint32_t actual_type = ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType); + + // Only one type must match between the actual and expected. + if ((actual_type & (type_mask | TYPE_REFERENCE)) == 0) { if (out_msg) { - BuildAttributeMismatchMessage(out_msg, this, item); + BuildAttributeMismatchMessage(*this, item, out_msg); } return false; + } + + // Enums and flags are encoded as integers, so check them first before doing any range checks. + if ((type_mask & TYPE_ENUM) != 0 && (actual_type & TYPE_ENUM) != 0) { + for (const Symbol& s : symbols) { + if (flattened_data == s.value) { + return true; + } + } + + // If the attribute accepts integers, we can't fail here. + if ((type_mask & TYPE_INTEGER) == 0) { + if (out_msg) { + *out_msg << item << " is not a valid enum"; + } + return false; + } + } + + if ((type_mask & TYPE_FLAGS) != 0 && (actual_type & TYPE_FLAGS) != 0) { + uint32_t mask = 0u; + for (const Symbol& s : symbols) { + mask |= s.value; + } + + // Check if the flattened data is covered by the flag bit mask. + // If the attribute accepts integers, we can't fail here. + if ((mask & flattened_data) == flattened_data) { + return true; + } else if ((type_mask & TYPE_INTEGER) == 0) { + if (out_msg) { + *out_msg << item << " is not a valid flag"; + } + return false; + } + } - } else if (ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType) & - android::ResTable_map::TYPE_INTEGER) { - if (static_cast<int32_t>(util::DeviceToHost32(val.data)) < min_int) { + // Finally check the integer range of the value. + if ((type_mask & TYPE_INTEGER) != 0 && (actual_type & TYPE_INTEGER) != 0) { + if (static_cast<int32_t>(flattened_data) < min_int) { if (out_msg) { - *out_msg << *item << " is less than minimum integer " << min_int; + *out_msg << item << " is less than minimum integer " << min_int; } return false; - } else if (static_cast<int32_t>(util::DeviceToHost32(val.data)) > max_int) { + } else if (static_cast<int32_t>(flattened_data) > max_int) { if (out_msg) { - *out_msg << *item << " is greater than maximum integer " << max_int; + *out_msg << item << " is greater than maximum integer " << max_int; } return false; } |