blob: 969bf2c72e90fcafab8c69d88a594300fd31ea1f [file] [log] [blame]
// Copyright 2018 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.
#ifndef LIB_FIDL_CPP_DECODER_H_
#define LIB_FIDL_CPP_DECODER_H_
#include <lib/fidl/cpp/message.h>
#include <zircon/fidl.h>
#ifdef __Fuchsia__
#include <lib/zx/handle.h>
#include <lib/zx/object.h>
#endif
namespace fidl {
class Decoder final {
public:
explicit Decoder(HLCPPIncomingMessage message);
explicit Decoder(HLCPPIncomingBody body);
~Decoder();
template <typename T>
T* GetPtr(size_t offset) {
return reinterpret_cast<T*>((body_.bytes().data() - body_offset_) + offset);
}
size_t GetOffset(const void* ptr) const { return GetOffset(reinterpret_cast<uintptr_t>(ptr)); }
size_t GetOffset(uintptr_t ptr) const {
// The |ptr| value comes from the message buffer, which we've already
// validated. That means it should correspond to a valid offset within the
// message.
return ptr - reinterpret_cast<uintptr_t>(body_.bytes().data() - body_offset_);
}
#ifdef __Fuchsia__
void DecodeHandle(zx::object_base* value, size_t offset) {
zx_handle_t* handle = GetPtr<zx_handle_t>(offset);
value->reset(*handle);
*handle = ZX_HANDLE_INVALID;
if (value->is_valid()) {
++handle_index_;
}
}
zx::handle ClaimUnknownHandle() {
return zx::handle(body_.handles().data()[handle_index_++].handle);
}
void CloseUnknownHandlesInEnvelope(const fidl_envelope_v2_t* envelope) {
EnvelopeUnknownDataInfoResult info = EnvelopeUnknownDataInfo(envelope);
for (uint32_t i = 0; i < info.num_handles; i++) {
ClaimUnknownHandle();
}
}
#endif
size_t EnvelopeValueOffset(const fidl_envelope_v2_t* envelope) const {
if ((envelope->flags & FIDL_ENVELOPE_FLAGS_INLINING_MASK) != 0) {
return GetOffset(&envelope->inline_value);
}
return GetOffset(*reinterpret_cast<const void* const*>(envelope));
}
struct EnvelopeUnknownDataInfoResult {
size_t value_offset;
uint32_t num_bytes;
uint16_t num_handles;
uint16_t flags;
};
EnvelopeUnknownDataInfoResult EnvelopeUnknownDataInfo(const fidl_envelope_v2_t* envelope) const {
const auto* unknown_data_envelope =
reinterpret_cast<const fidl_envelope_v2_unknown_data_t*>(envelope);
EnvelopeUnknownDataInfoResult result;
if ((unknown_data_envelope->flags & FIDL_ENVELOPE_FLAGS_INLINING_MASK) != 0) {
result.value_offset = GetOffset(&envelope->inline_value);
result.num_bytes = 4;
} else {
result.value_offset = unknown_data_envelope->out_of_line.offset;
result.num_bytes = unknown_data_envelope->out_of_line.num_bytes;
}
result.num_handles = unknown_data_envelope->num_handles;
result.flags = unknown_data_envelope->flags;
return result;
}
private:
HLCPPIncomingBody body_;
// The body_offset_ is either 16 (when decoding the body of a transactional message, which is
// itself a concatenation of 2 FIDL messages, the header and body), or 0 (when decoding a
// standalone "at-rest" message body).
uint32_t body_offset_ = 0;
#ifdef __Fuchsia__
uint32_t handle_index_ = 0;
#endif
};
} // namespace fidl
#endif // LIB_FIDL_CPP_DECODER_H_