| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/fidl/cpp/natural_decoder.h> |
| #include <lib/fidl/cpp/wire/message.h> |
| |
| #include <utility> |
| |
| namespace fidl::internal { |
| |
| NaturalDecoder::NaturalDecoder(fidl::EncodedMessage message, |
| fidl::internal::WireFormatVersion wire_format_version) |
| : body_(std::move(message)), wire_format_version_(wire_format_version) {} |
| |
| NaturalDecoder::~NaturalDecoder() = default; |
| |
| void NaturalDecoder::DecodeUnknownEnvelopeOptional(size_t offset) { |
| static_assert(sizeof(fidl_envelope_t) == sizeof(uint64_t)); |
| const fidl_envelope_t* envelope = GetPtr<fidl_envelope_t>(offset); |
| if (FidlIsZeroEnvelope(envelope)) { |
| return; |
| } |
| DecodeUnknownEnvelope(envelope); |
| } |
| |
| void NaturalDecoder::DecodeUnknownEnvelopeRequired(size_t offset) { |
| static_assert(sizeof(fidl_envelope_t) == sizeof(uint64_t)); |
| const fidl_envelope_t* envelope = GetPtr<fidl_envelope_t>(offset); |
| if (unlikely(FidlIsZeroEnvelope(envelope))) { |
| SetError(kCodingErrorInvalidUnionTag); |
| return; |
| } |
| DecodeUnknownEnvelope(envelope); |
| } |
| |
| void NaturalDecoder::DecodeUnknownEnvelope(const fidl_envelope_t* envelope) { |
| if (envelope->flags == 0) { |
| if (envelope->num_bytes % FIDL_ALIGNMENT != 0) { |
| SetError(kCodingErrorInvalidNumBytesSpecifiedInEnvelope); |
| return; |
| } |
| size_t envelope_content_offset; |
| if (!Alloc(envelope->num_bytes, &envelope_content_offset)) { |
| return; |
| } |
| } else if (envelope->flags != FIDL_ENVELOPE_FLAGS_INLINING_MASK) { |
| SetError(kCodingErrorInvalidInlineBit); |
| return; |
| } |
| CloseNextHandles(envelope->num_handles); |
| } |
| |
| void NaturalDecoder::CloseNextHandles(size_t count) { |
| if (unlikely(count > body_.num_handles() - handle_index_)) { |
| SetError(kCodingErrorInvalidNumHandlesSpecifiedInEnvelope); |
| return; |
| } |
| |
| coding_config()->close_many(&body_.handles()[handle_index_], count); |
| const size_t end = handle_index_ + count; |
| for (; handle_index_ < end; handle_index_++) { |
| body_.handles()[handle_index_] = FIDL_HANDLE_INVALID; |
| } |
| } |
| |
| } // namespace fidl::internal |