blob: d3ede79d273d0b1f77e4211a808741046f68e7ac [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_types.h"
#include <src/lib/fxl/logging.h>
#include <zircon/fidl.h>
#include "rapidjson/error/en.h"
#include "tools/fidlcat/lib/library_loader.h"
#include "tools/fidlcat/lib/wire_object.h"
// See wire_types.h for details.
namespace fidlcat {
bool Type::ValueEquals(const uint8_t* bytes, size_t length,
const rapidjson::Value& value) const {
FXL_LOG(FATAL) << "Equality operator for type not implemented";
return false;
}
size_t Type::InlineSize() const {
FXL_LOG(FATAL) << "Size for type not implemented";
return 0;
}
std::unique_ptr<Field> Type::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
FXL_LOG(ERROR) << "Decode not implemented for field '" << name << "'";
return nullptr;
}
std::unique_ptr<Field> RawType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
return std::make_unique<RawField>(
name, decoder->GetAddress(offset, inline_size_), inline_size_);
}
std::unique_ptr<Field> StringType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
uint64_t string_length = 0;
decoder->GetValueAt(offset, &string_length);
offset += sizeof(string_length);
auto result = std::make_unique<StringField>(name, string_length);
result->DecodeNullable(decoder, offset);
return result;
}
std::unique_ptr<Field> BoolType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
return std::make_unique<BoolField>(
name, decoder->GetAddress(offset, sizeof(uint8_t)));
}
size_t StructType::InlineSize() const { return struct_.size(); }
std::unique_ptr<Field> StructType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
return struct_.DecodeObject(decoder, name, offset, nullable_);
}
size_t TableType::InlineSize() const { return table_.size(); }
std::unique_ptr<Field> TableType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
uint64_t size = 0;
decoder->GetValueAt(offset, &size);
offset += sizeof(size);
auto result = std::make_unique<TableField>(name, table_, size);
if (result->DecodeNullable(decoder, offset)) {
if (result->is_null()) {
FXL_LOG(ERROR) << "invalid null value for table pointer";
}
}
return result;
}
UnionType::UnionType(const Union& uni, bool nullable)
: union_(uni), nullable_(nullable) {}
size_t UnionType::InlineSize() const { return union_.size(); }
std::unique_ptr<Field> UnionType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
return union_.DecodeUnion(decoder, name, offset, nullable_);
}
XUnionType::XUnionType(const XUnion& uni, bool is_nullable)
: xunion_(uni), is_nullable_(is_nullable) {}
size_t XUnionType::InlineSize() const { return xunion_.size(); }
std::unique_ptr<Field> XUnionType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
uint32_t ordinal = 0;
if (decoder->GetValueAt(offset, &ordinal)) {
if ((ordinal == 0) && !is_nullable_) {
FXL_LOG(ERROR) << "null envelope for a non nullable extensible union";
}
}
offset += sizeof(uint64_t); // Skips ordinal + padding.
std::unique_ptr<XUnionField> result =
std::make_unique<XUnionField>(name, xunion_);
std::unique_ptr<EnvelopeField> envelope;
const UnionMember* member = xunion_.MemberWithOrdinal(ordinal);
if (member == nullptr) {
std::string key_name = std::string("unknown$") + std::to_string(ordinal);
envelope = std::make_unique<EnvelopeField>(key_name, nullptr);
} else {
envelope = std::make_unique<EnvelopeField>(member->name(), member->type());
}
envelope->DecodeAt(decoder, offset);
result->set_field(std::move(envelope));
return result;
}
ElementSequenceType::ElementSequenceType(std::unique_ptr<Type>&& component_type)
: component_type_(std::move(component_type)) {
FXL_DCHECK(component_type_.get() != nullptr);
}
ArrayType::ArrayType(std::unique_ptr<Type>&& component_type, uint32_t count)
: ElementSequenceType(std::move(component_type)), count_(count) {}
std::unique_ptr<Field> ArrayType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
auto result = std::make_unique<ArrayField>(name);
for (uint64_t i = 0; i < count_; ++i) {
result->AddField(component_type_->Decode(decoder, "", offset));
offset += component_type_->InlineSize();
}
return result;
}
VectorType::VectorType(std::unique_ptr<Type>&& component_type)
: ElementSequenceType(std::move(component_type)) {}
std::unique_ptr<Field> VectorType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
uint64_t size = 0;
decoder->GetValueAt(offset, &size);
offset += sizeof(size);
auto result =
std::make_unique<VectorField>(name, size, component_type_.get());
result->DecodeNullable(decoder, offset);
return result;
}
EnumType::EnumType(const Enum& e) : enum_(e) {}
std::unique_ptr<Field> EnumType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
return std::make_unique<EnumField>(
name, decoder->GetAddress(offset, enum_.size()), enum_);
}
std::unique_ptr<Field> HandleType::Decode(MessageDecoder* decoder,
std::string_view name,
uint64_t offset) const {
zx_handle_t handle = FIDL_HANDLE_ABSENT;
decoder->GetValueAt(offset, &handle);
if ((handle != FIDL_HANDLE_ABSENT) && (handle != FIDL_HANDLE_PRESENT)) {
FXL_LOG(ERROR) << "invalid value <" << std::hex << handle << std::dec
<< "> for handle";
return std::make_unique<HandleField>(name, FIDL_HANDLE_ABSENT);
}
if (handle != FIDL_HANDLE_ABSENT) {
handle = decoder->GetNextHandle();
}
return std::make_unique<HandleField>(name, handle);
}
std::unique_ptr<Type> Type::ScalarTypeFromName(const std::string& type_name,
size_t inline_size) {
static std::map<std::string, std::function<std::unique_ptr<Type>()>>
scalar_type_map_{
{"bool", []() { return std::make_unique<BoolType>(); }},
{"float32", []() { return std::make_unique<Float32Type>(); }},
{"float64", []() { return std::make_unique<Float64Type>(); }},
{"int8", []() { return std::make_unique<Int8Type>(); }},
{"int16", []() { return std::make_unique<Int16Type>(); }},
{"int32", []() { return std::make_unique<Int32Type>(); }},
{"int64", []() { return std::make_unique<Int64Type>(); }},
{"uint8", []() { return std::make_unique<Uint8Type>(); }},
{"uint16", []() { return std::make_unique<Uint16Type>(); }},
{"uint32", []() { return std::make_unique<Uint32Type>(); }},
{"uint64", []() { return std::make_unique<Uint64Type>(); }},
};
auto it = scalar_type_map_.find(type_name);
if (it != scalar_type_map_.end()) {
return it->second();
}
return std::make_unique<RawType>(inline_size);
}
std::unique_ptr<Type> Type::TypeFromPrimitive(const rapidjson::Value& type,
size_t inline_size) {
if (!type.HasMember("subtype")) {
FXL_LOG(ERROR) << "Invalid type";
return std::make_unique<RawType>(inline_size);
}
std::string subtype = type["subtype"].GetString();
return ScalarTypeFromName(subtype, inline_size);
}
std::unique_ptr<Type> Type::TypeFromIdentifier(LibraryLoader* loader,
const rapidjson::Value& type,
size_t inline_size) {
if (!type.HasMember("identifier")) {
FXL_LOG(ERROR) << "Invalid type";
return std::make_unique<RawType>(inline_size);
}
std::string id = type["identifier"].GetString();
size_t split_index = id.find('/');
std::string library_name = id.substr(0, split_index);
Library* library = loader->GetLibraryFromName(library_name);
if (library == nullptr) {
FXL_LOG(ERROR) << "Unknown type for identifier: " << library_name;
return std::make_unique<RawType>(inline_size);
}
bool is_nullable = false;
if (type.HasMember("nullable")) {
is_nullable = type["nullable"].GetBool();
}
return library->TypeFromIdentifier(is_nullable, id, inline_size);
}
std::unique_ptr<Type> Type::GetType(LibraryLoader* loader,
const rapidjson::Value& type,
size_t inline_size) {
// TODO: This is creating a new type every time we need one. That's pretty
// inefficient. Find a way of caching them if it becomes a problem.
if (!type.HasMember("kind")) {
FXL_LOG(ERROR) << "Invalid type";
return std::make_unique<RawType>(inline_size);
}
std::string kind = type["kind"].GetString();
if (kind == "array") {
const rapidjson::Value& element_type = type["element_type"];
uint32_t element_count =
std::strtol(type["element_count"].GetString(), nullptr, 10);
return std::make_unique<ArrayType>(GetType(loader, element_type, 0),
element_count);
} else if (kind == "vector") {
const rapidjson::Value& element_type = type["element_type"];
return std::make_unique<VectorType>(GetType(loader, element_type, 0));
} else if (kind == "string") {
return std::make_unique<StringType>();
} else if (kind == "handle") {
return std::make_unique<HandleType>();
} else if (kind == "request") {
return std::make_unique<HandleType>();
} else if (kind == "primitive") {
return Type::TypeFromPrimitive(type, inline_size);
} else if (kind == "identifier") {
return Type::TypeFromIdentifier(loader, type, inline_size);
}
FXL_LOG(ERROR) << "Invalid type " << kind;
return std::make_unique<RawType>(inline_size);
}
} // namespace fidlcat