{#- # 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_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}}); {%- 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 %}