320 lines
12 KiB
Cheetah

{#-
# SPDX-License-Identifier: LGPL-2.1-or-later
# Copyright (C) 2020, Google Inc.
-#}
{#
# \brief Verify that there is enough bytes to deserialize
#
# Generate code that verifies that \a size is not greater than \a dataSize.
# Otherwise log an error with \a name and \a typename.
#}
{%- macro check_data_size(size, dataSize, name, typename) %}
if ({{dataSize}} < {{size}}) {
LOG(IPADataSerializer, Error)
<< "Failed to deserialize " << "{{name}}"
<< ": not enough {{typename}}, expected "
<< ({{size}}) << ", got " << ({{dataSize}});
return ret;
}
{%- endmacro %}
{#
# \brief Serialize a field into return vector
#
# Generate code to serialize \a field into retData, including size of the
# field and fds (where appropriate).
# This code is meant to be used by the IPADataSerializer specialization.
#
# \todo Avoid intermediate vectors
#}
{%- macro serializer_field(field, namespace, loop) %}
{%- if field|is_pod or field|is_enum %}
std::vector<uint8_t> {{field.mojom_name}};
std::tie({{field.mojom_name}}, std::ignore) =
{%- if field|is_pod %}
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
{%- elif field|is_flags %}
IPADataSerializer<{{field|name_full}}>::serialize(data.{{field.mojom_name}});
{%- elif field|is_enum_scoped %}
IPADataSerializer<uint{{field|bit_width}}_t>::serialize(static_cast<uint{{field|bit_width}}_t>(data.{{field.mojom_name}}));
{%- elif field|is_enum %}
IPADataSerializer<uint{{field|bit_width}}_t>::serialize(data.{{field.mojom_name}});
{%- endif %}
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
{%- elif field|is_fd %}
std::vector<uint8_t> {{field.mojom_name}};
std::vector<SharedFD> {{field.mojom_name}}Fds;
std::tie({{field.mojom_name}}, {{field.mojom_name}}Fds) =
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
retFds.insert(retFds.end(), {{field.mojom_name}}Fds.begin(), {{field.mojom_name}}Fds.end());
{%- elif field|is_controls %}
if (data.{{field.mojom_name}}.size() > 0) {
std::vector<uint8_t> {{field.mojom_name}};
std::tie({{field.mojom_name}}, std::ignore) =
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}}, cs);
appendPOD<uint32_t>(retData, {{field.mojom_name}}.size());
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
} else {
appendPOD<uint32_t>(retData, 0);
}
{%- elif field|is_plain_struct or field|is_array or field|is_map or field|is_str %}
std::vector<uint8_t> {{field.mojom_name}};
{%- if field|has_fd %}
std::vector<SharedFD> {{field.mojom_name}}Fds;
std::tie({{field.mojom_name}}, {{field.mojom_name}}Fds) =
{%- else %}
std::tie({{field.mojom_name}}, std::ignore) =
{%- endif %}
{%- if field|is_array or field|is_map %}
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}}, cs);
{%- elif field|is_str %}
IPADataSerializer<{{field|name}}>::serialize(data.{{field.mojom_name}});
{%- else %}
IPADataSerializer<{{field|name_full}}>::serialize(data.{{field.mojom_name}}, cs);
{%- endif %}
appendPOD<uint32_t>(retData, {{field.mojom_name}}.size());
{%- if field|has_fd %}
appendPOD<uint32_t>(retData, {{field.mojom_name}}Fds.size());
{%- endif %}
retData.insert(retData.end(), {{field.mojom_name}}.begin(), {{field.mojom_name}}.end());
{%- if field|has_fd %}
retFds.insert(retFds.end(), {{field.mojom_name}}Fds.begin(), {{field.mojom_name}}Fds.end());
{%- endif %}
{%- else %}
/* Unknown serialization for {{field.mojom_name}}. */
{%- endif %}
{%- endmacro %}
{#
# \brief Deserialize a field into return struct
#
# Generate code to deserialize \a field into object ret.
# This code is meant to be used by the IPADataSerializer specialization.
#}
{%- macro deserializer_field(field, namespace, loop) %}
{% if field|is_pod or field|is_enum %}
{%- set field_size = (field|bit_width|int / 8)|int %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
{%- if field|is_pod %}
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field_size}});
{%- elif field|is_flags %}
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field_size}});
{%- else %}
ret.{{field.mojom_name}} = static_cast<{{field|name_full}}>(IPADataSerializer<uint{{field|bit_width}}_t>::deserialize(m, m + {{field_size}}));
{%- endif %}
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
{%- endif %}
{% elif field|is_fd %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
ret.{{field.mojom_name}} = IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field_size}}, n, n + 1, cs);
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
n += ret.{{field.mojom_name}}.isValid() ? 1 : 0;
fdsSize -= ret.{{field.mojom_name}}.isValid() ? 1 : 0;
{%- endif %}
{% elif field|is_controls %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name + 'Size', 'data')}}
const size_t {{field.mojom_name}}Size = readPOD<uint32_t>(m, 0, dataEnd);
m += {{field_size}};
dataSize -= {{field_size}};
{%- set field_size = field.mojom_name + 'Size' -%}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
if ({{field.mojom_name}}Size > 0)
ret.{{field.mojom_name}} =
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size, cs);
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
{%- endif %}
{% elif field|is_plain_struct or field|is_array or field|is_map or field|is_str %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name + 'Size', 'data')}}
const size_t {{field.mojom_name}}Size = readPOD<uint32_t>(m, 0, dataEnd);
m += {{field_size}};
dataSize -= {{field_size}};
{%- if field|has_fd %}
{%- set field_size = 4 %}
{{- check_data_size(field_size, 'dataSize', field.mojom_name + 'FdsSize', 'data')}}
const size_t {{field.mojom_name}}FdsSize = readPOD<uint32_t>(m, 0, dataEnd);
m += {{field_size}};
dataSize -= {{field_size}};
{{- check_data_size(field.mojom_name + 'FdsSize', 'fdsSize', field.mojom_name, 'fds')}}
{%- endif %}
{%- set field_size = field.mojom_name + 'Size' -%}
{{- check_data_size(field_size, 'dataSize', field.mojom_name, 'data')}}
ret.{{field.mojom_name}} =
{%- if field|is_str %}
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size);
{%- elif field|has_fd and (field|is_array or field|is_map) %}
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size, n, n + {{field.mojom_name}}FdsSize, cs);
{%- elif field|has_fd and (not (field|is_array or field|is_map)) %}
IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field.mojom_name}}Size, n, n + {{field.mojom_name}}FdsSize, cs);
{%- elif (not field|has_fd) and (field|is_array or field|is_map) %}
IPADataSerializer<{{field|name}}>::deserialize(m, m + {{field.mojom_name}}Size, cs);
{%- else %}
IPADataSerializer<{{field|name_full}}>::deserialize(m, m + {{field.mojom_name}}Size, cs);
{%- endif %}
{%- if not loop.last %}
m += {{field_size}};
dataSize -= {{field_size}};
{%- if field|has_fd %}
n += {{field.mojom_name}}FdsSize;
fdsSize -= {{field.mojom_name}}FdsSize;
{%- endif %}
{%- endif %}
{% else %}
/* Unknown deserialization for {{field.mojom_name}}. */
{%- endif %}
{%- endmacro %}
{#
# \brief Serialize a struct
#
# Generate code for IPADataSerializer specialization, for serializing
# \a struct.
#}
{%- macro serializer(struct, namespace) %}
static std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
serialize(const {{struct|name_full}} &data,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
[[maybe_unused]] ControlSerializer *cs = nullptr)
{%- endif %}
{
std::vector<uint8_t> retData;
{%- if struct|has_fd %}
std::vector<SharedFD> retFds;
{%- endif %}
{%- for field in struct.fields %}
{{serializer_field(field, namespace, loop)}}
{%- endfor %}
{% if struct|has_fd %}
return {retData, retFds};
{%- else %}
return {retData, {}};
{%- endif %}
}
{%- endmacro %}
{#
# \brief Deserialize a struct that has fds
#
# Generate code for IPADataSerializer specialization, for deserializing
# \a struct, in the case that \a struct has file descriptors.
#}
{%- macro deserializer_fd(struct, namespace) %}
static {{struct|name_full}}
deserialize(std::vector<uint8_t> &data,
std::vector<SharedFD> &fds,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
ControlSerializer *cs = nullptr)
{%- endif %}
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), fds.cbegin(), fds.cend(), cs);
}
{# \todo Don't inline this function #}
static {{struct|name_full}}
deserialize(std::vector<uint8_t>::const_iterator dataBegin,
std::vector<uint8_t>::const_iterator dataEnd,
std::vector<SharedFD>::const_iterator fdsBegin,
std::vector<SharedFD>::const_iterator fdsEnd,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
[[maybe_unused]] ControlSerializer *cs = nullptr)
{%- endif %}
{
{{struct|name_full}} ret;
std::vector<uint8_t>::const_iterator m = dataBegin;
std::vector<SharedFD>::const_iterator n = fdsBegin;
size_t dataSize = std::distance(dataBegin, dataEnd);
[[maybe_unused]] size_t fdsSize = std::distance(fdsBegin, fdsEnd);
{%- for field in struct.fields -%}
{{deserializer_field(field, namespace, loop)}}
{%- endfor %}
return ret;
}
{%- endmacro %}
{#
# \brief Deserialize a struct that has fds, using non-fd
#
# Generate code for IPADataSerializer specialization, for deserializing
# \a struct, in the case that \a struct has no file descriptors but requires
# deserializers with file descriptors.
#}
{%- macro deserializer_fd_simple(struct, namespace) %}
static {{struct|name_full}}
deserialize(std::vector<uint8_t> &data,
[[maybe_unused]] std::vector<SharedFD> &fds,
ControlSerializer *cs = nullptr)
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), cs);
}
static {{struct|name_full}}
deserialize(std::vector<uint8_t>::const_iterator dataBegin,
std::vector<uint8_t>::const_iterator dataEnd,
[[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
[[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
ControlSerializer *cs = nullptr)
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(dataBegin, dataEnd, cs);
}
{%- endmacro %}
{#
# \brief Deserialize a struct that has no fds
#
# Generate code for IPADataSerializer specialization, for deserializing
# \a struct, in the case that \a struct does not have file descriptors.
#}
{%- macro deserializer_no_fd(struct, namespace) %}
static {{struct|name_full}}
deserialize(std::vector<uint8_t> &data,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
ControlSerializer *cs = nullptr)
{%- endif %}
{
return IPADataSerializer<{{struct|name_full}}>::deserialize(data.cbegin(), data.cend(), cs);
}
{# \todo Don't inline this function #}
static {{struct|name_full}}
deserialize(std::vector<uint8_t>::const_iterator dataBegin,
std::vector<uint8_t>::const_iterator dataEnd,
{%- if struct|needs_control_serializer %}
ControlSerializer *cs)
{%- else %}
[[maybe_unused]] ControlSerializer *cs = nullptr)
{%- endif %}
{
{{struct|name_full}} ret;
std::vector<uint8_t>::const_iterator m = dataBegin;
size_t dataSize = std::distance(dataBegin, dataEnd);
{%- for field in struct.fields -%}
{{deserializer_field(field, namespace, loop)}}
{%- endfor %}
return ret;
}
{%- endmacro %}