| {%- import "validation_macros.tmpl" as validation_macros %} |
| {%- set class_name = struct.name ~ "_Data" %} |
| |
| // static |
| bool {{class_name}}::Validate( |
| const void* data, |
| mojo::internal::ValidationContext* validation_context) { |
| if (!data) |
| return true; |
| |
| if (!ValidateStructHeaderAndClaimMemory(data, validation_context)) |
| return false; |
| |
| // NOTE: The memory backing |object| may be smaller than |sizeof(*object)| if |
| // the message comes from an older version. |
| const {{class_name}}* object = static_cast<const {{class_name}}*>(data); |
| |
| static constexpr struct { |
| uint32_t version; |
| uint32_t num_bytes; |
| } kVersionSizes[] = { |
| {%- for version in struct.versions -%} |
| { {{version.version}}, {{version.num_bytes}} }{% if not loop.last %}, {% endif -%} |
| {%- endfor -%} |
| }; |
| |
| if (object->header_.version <= |
| kVersionSizes[arraysize(kVersionSizes) - 1].version) { |
| // Scan in reverse order to optimize for more recent versions. |
| for (int i = arraysize(kVersionSizes) - 1; i >= 0; --i) { |
| if (object->header_.version >= kVersionSizes[i].version) { |
| if (object->header_.num_bytes == kVersionSizes[i].num_bytes) |
| break; |
| |
| ReportValidationError( |
| validation_context, |
| mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); |
| return false; |
| } |
| } |
| } else if (object->header_.num_bytes < |
| kVersionSizes[arraysize(kVersionSizes) - 1].num_bytes) { |
| ReportValidationError( |
| validation_context, |
| mojo::internal::VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); |
| return false; |
| } |
| |
| {#- Before validating fields introduced at a certain version, we need to add |
| a version check, which makes sure we skip further validation if |object| |
| is from an earlier version. |last_checked_version| records the last |
| version that we have added such version check. #} |
| {%- set last_checked_version = 0 %} |
| {%- for packed_field in struct.packed.packed_fields_in_ordinal_order %} |
| {%- set kind = packed_field.field.kind %} |
| {%- if kind|is_object_kind or kind|is_any_handle_or_interface_kind or |
| kind|is_enum_kind %} |
| {%- if packed_field.min_version > last_checked_version %} |
| {%- set last_checked_version = packed_field.min_version %} |
| if (object->header_.version < {{packed_field.min_version}}) |
| return true; |
| {%- endif %} |
| {%- set field_expr = "object->" ~ packed_field.field.name %} |
| {{validation_macros.validate_field(packed_field.field, field_expr, struct.name, true)}} |
| {%- endif %} |
| {%- endfor %} |
| |
| return true; |
| } |
| |