blob: 5f4a67871cf9c0d0e8d73ec4857a89c0b186d101 [file] [log] [blame]
// Copyright 2019 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 "wire_object.h"
#include <src/lib/fxl/logging.h>
#include <memory>
#include <vector>
#include "tools/fidlcat/lib/library_loader.h"
#include "tools/fidlcat/lib/wire_types.h"
namespace fidlcat {
bool NullableField::DecodeNullable(MessageDecoder* decoder, uint64_t offset) {
uintptr_t data;
if (!decoder->GetValueAt(offset, &data)) {
return false;
}
if (data == FIDL_ALLOC_ABSENT) {
is_null_ = true;
return true;
}
if (data != FIDL_ALLOC_PRESENT) {
FXL_LOG(ERROR) << "invalid value <" << std::hex << data << std::dec
<< "> for nullable";
return false;
}
decoder->AddSecondaryObject(this);
return true;
}
void InlineField::DecodeContent(MessageDecoder* decoder) {
FXL_LOG(FATAL) << "Field is defined inline";
}
void RawField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
size_t buffer_size = size_ * 3;
char buffer[buffer_size];
for (size_t i = 0; i < size_; ++i) {
if (i != 0) {
buffer[i * 3 - 1] = ' ';
}
snprintf(buffer + (i * 3), 4, "%02x", data()[i]);
}
result.SetString(buffer, allocator);
}
void StringField::DecodeContent(MessageDecoder* decoder) {
data_ = decoder->GetAddress(0, string_length_);
decoder->GotoNextObjectOffset(string_length_);
}
void StringField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
if (is_null()) {
result.SetString("(null)", allocator);
} else if (data_ == nullptr) {
result.SetString("(invalid)", allocator);
} else {
result.SetString(reinterpret_cast<const char*>(data_), string_length_,
allocator);
}
}
void Object::DecodeContent(MessageDecoder* decoder) {
DecodeAt(decoder, 0);
decoder->GotoNextObjectOffset(struct_definition_.size());
}
void Object::DecodeAt(MessageDecoder* decoder, uint64_t base_offset) {
for (const auto& member : struct_definition_.members()) {
std::unique_ptr<Field> field = member->type()->Decode(
decoder, member->name(), base_offset + member->offset());
if (field != nullptr) {
fields_.push_back(std::move(field));
}
}
}
void Object::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
if (is_null()) {
result.SetNull();
} else {
result.SetObject();
for (const auto& field : fields_) {
rapidjson::Value key;
key.SetString(field->name().c_str(), allocator);
result.AddMember(key, rapidjson::Value(), allocator);
field->ExtractJson(allocator, result[field->name().c_str()]);
}
}
}
EnvelopeField::EnvelopeField(std::string_view name, const Type* type)
: NullableField(name), type_(type) {}
void EnvelopeField::DecodeContent(MessageDecoder* decoder) {
MessageDecoder envelope_decoder(decoder, num_bytes_, num_handles_);
field_ = envelope_decoder.DecodeField(name(), type_);
decoder->GotoNextObjectOffset(num_bytes_);
decoder->SkipHandles(num_handles_);
}
void EnvelopeField::DecodeAt(MessageDecoder* decoder, uint64_t base_offset) {
decoder->GetValueAt(base_offset, &num_bytes_);
base_offset += sizeof(num_bytes_);
decoder->GetValueAt(base_offset, &num_handles_);
base_offset += sizeof(num_handles_);
if (DecodeNullable(decoder, base_offset)) {
if (type_ == nullptr) {
FXL_DCHECK(is_null());
}
if (is_null()) {
FXL_DCHECK(num_bytes_ == 0);
FXL_DCHECK(num_handles_ == 0);
return;
}
}
}
void EnvelopeField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
field_->ExtractJson(allocator, result);
}
TableField::TableField(std::string_view name, const Table& table_definition,
uint64_t envelope_count)
: NullableField(name),
table_definition_(table_definition),
envelope_count_(envelope_count) {}
void TableField::DecodeContent(MessageDecoder* decoder) {
uint64_t offset = 0;
for (uint64_t envelope_id = 0; envelope_id < envelope_count_; ++envelope_id) {
const TableMember* member =
(envelope_id < table_definition_.members().size() - 1)
? table_definition_.members()[envelope_id + 1]
: nullptr;
std::unique_ptr<EnvelopeField> envelope;
if (member == nullptr) {
std::string key_name =
std::string("unknown$") + std::to_string(envelope_id + 1);
envelope = std::make_unique<EnvelopeField>(
key_name, table_definition_.unknown_member_type());
} else {
envelope =
std::make_unique<EnvelopeField>(member->name(), member->type());
}
envelope->DecodeAt(decoder, offset);
envelopes_.push_back(std::move(envelope));
offset += 2 * sizeof(uint64_t);
}
decoder->GotoNextObjectOffset(offset);
}
void TableField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
result.SetObject();
for (const auto& envelope : envelopes_) {
if (!envelope->is_null()) {
rapidjson::Value key;
key.SetString(envelope->name().c_str(), allocator);
result.AddMember(key, rapidjson::Value(), allocator);
envelope->ExtractJson(allocator, result[envelope->name().c_str()]);
}
}
}
void UnionField::DecodeContent(MessageDecoder* decoder) {
DecodeAt(decoder, 0);
decoder->GotoNextObjectOffset(union_definition_.size());
}
void UnionField::DecodeAt(MessageDecoder* decoder, uint64_t base_offset) {
uint32_t tag = 0;
decoder->GetValueAt(base_offset, &tag);
const UnionMember* member = union_definition_.MemberWithTag(tag);
if (member == nullptr) {
field_ = std::make_unique<RawField>(
std::string("unknown$") + std::to_string(tag), nullptr, 0);
} else {
field_ = member->type()->Decode(decoder, member->name(),
base_offset + member->offset());
}
}
void UnionField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
if (is_null()) {
result.SetNull();
} else {
result.SetObject();
rapidjson::Value key;
key.SetString(field_->name().c_str(), allocator);
result.AddMember(key, rapidjson::Value(), allocator);
field_->ExtractJson(allocator, result[field_->name().c_str()]);
}
}
void ArrayField::DecodeContent(MessageDecoder* decoder) {
FXL_LOG(FATAL) << "Field is defined inline";
}
void ArrayField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
result.SetArray();
for (const auto& field : fields_) {
rapidjson::Value element;
field->ExtractJson(allocator, element);
result.PushBack(element, allocator);
}
}
void VectorField::DecodeContent(MessageDecoder* decoder) {
uint64_t offset = 0;
for (uint64_t i = 0; i < size_; ++i) {
std::unique_ptr<Field> field = component_type_->Decode(decoder, "", offset);
if (field != nullptr) {
fields_.push_back(std::move(field));
}
offset += component_type_->InlineSize();
}
decoder->GotoNextObjectOffset(offset);
}
void VectorField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
if (is_null()) {
result.SetNull();
} else {
result.SetArray();
for (const auto& field : fields_) {
rapidjson::Value element;
field->ExtractJson(allocator, element);
result.PushBack(element, allocator);
}
}
}
void EnumField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
if (data() == nullptr) {
result.SetString("(invalid)", allocator);
} else {
std::string name = enum_definition_.GetNameFromBytes(data());
result.SetString(name.c_str(), allocator);
}
}
void HandleField::DecodeContent(MessageDecoder* decoder) {
FXL_LOG(FATAL) << "Handle field is defined inline";
}
void HandleField::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
result.SetString(std::to_string(handle_), allocator);
}
} // namespace fidlcat