blob: 3b94c3bdcf061750e2ed28e326648bc03afd282b [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 "library_loader.h"
#include <src/lib/fxl/logging.h>
#include "rapidjson/error/en.h"
#include "tools/fidlcat/lib/wire_object.h"
#include "tools/fidlcat/lib/wire_types.h"
// See library_loader.h for details.
namespace fidlcat {
Enum::Enum(const rapidjson::Value& value) : value_(value) {}
Enum::~Enum() {}
void Enum::DecodeTypes() {
if (decoded_) {
return;
}
decoded_ = true;
name_ = value_["name"].GetString();
type_ = Type::ScalarTypeFromName(value_["type"].GetString(), 0);
size_ = type_->InlineSize();
}
std::string Enum::GetNameFromBytes(const uint8_t* bytes) const {
for (auto& member : value_["members"].GetArray()) {
if (type_->ValueEquals(bytes, size_, member["value"]["literal"])) {
return member["name"].GetString();
}
}
return "(Unknown enum member)";
}
UnionMember::UnionMember(const Library& enclosing_library,
const rapidjson::Value& value)
: name_(value["name"].GetString()),
offset_(std::strtoll(value["offset"].GetString(), nullptr, 10)),
size_(std::strtoll(value["size"].GetString(), nullptr, 10)),
ordinal_(value.HasMember("ordinal")
? std::strtoll(value["ordinal"].GetString(), nullptr, 10)
: 0) {
if (!value.HasMember("type")) {
FXL_LOG(ERROR) << "Type missing";
type_ = std::make_unique<RawType>(size_);
return;
}
type_ =
Type::GetType(enclosing_library.enclosing_loader(), value["type"], size_);
}
UnionMember::~UnionMember() {}
Union::Union(const Library& enclosing_library, const rapidjson::Value& value)
: enclosing_library_(enclosing_library), value_(value) {}
void Union::DecodeTypes() {
if (decoded_) {
return;
}
decoded_ = true;
name_ = value_["name"].GetString();
alignment_ = std::strtoll(value_["alignment"].GetString(), nullptr, 10);
size_ = std::strtoll(value_["size"].GetString(), nullptr, 10);
auto member_arr = value_["members"].GetArray();
members_.reserve(member_arr.Size());
for (auto& member : member_arr) {
members_.push_back(
std::make_unique<UnionMember>(enclosing_library_, member));
}
}
const UnionMember* Union::MemberWithTag(uint32_t tag) const {
if (tag >= members_.size()) {
return nullptr;
}
return members_[tag].get();
}
const UnionMember* Union::MemberWithOrdinal(Ordinal ordinal) const {
for (const auto& member : members_) {
if (member->ordinal() == ordinal) {
return member.get();
}
}
return nullptr;
}
std::unique_ptr<UnionField> Union::DecodeUnion(MessageDecoder* decoder,
std::string_view name,
uint64_t offset,
bool nullable) const {
std::unique_ptr<UnionField> result =
std::make_unique<UnionField>(name, *this);
if (nullable) {
result->DecodeNullable(decoder, offset);
} else {
result->DecodeAt(decoder, offset);
}
return result;
}
StructMember::StructMember(const Library& enclosing_library,
const rapidjson::Value& value)
: name_(value["name"].GetString()),
offset_(std::strtoll(value["offset"].GetString(), nullptr, 10)),
size_(std::strtoll(value["size"].GetString(), nullptr, 10)) {
if (!value.HasMember("type")) {
FXL_LOG(ERROR) << "Type missing";
type_ = std::make_unique<RawType>(size());
return;
}
type_ =
Type::GetType(enclosing_library.enclosing_loader(), value["type"], size_);
}
StructMember::~StructMember() {}
Struct::Struct(const Library& enclosing_library, const rapidjson::Value& value)
: enclosing_library_(enclosing_library), value_(value) {}
void Struct::DecodeStructTypes() {
if (decoded_) {
return;
}
DecodeTypes("size", "members");
}
void Struct::DecodeRequestTypes() {
if (decoded_) {
return;
}
DecodeTypes("maybe_request_size", "maybe_request");
}
void Struct::DecodeResponseTypes() {
if (decoded_) {
return;
}
DecodeTypes("maybe_response_size", "maybe_response");
}
std::unique_ptr<Object> Struct::DecodeObject(MessageDecoder* decoder,
std::string_view name,
uint64_t offset,
bool nullable) const {
std::unique_ptr<Object> result = std::make_unique<Object>(name, *this);
if (nullable) {
result->DecodeNullable(decoder, offset);
} else {
result->DecodeAt(decoder, offset);
}
return result;
}
void Struct::DecodeTypes(std::string size_name, std::string member_name) {
FXL_DCHECK(!decoded_);
decoded_ = true;
name_ = value_["name"].GetString();
size_ = std::strtoll(value_[size_name].GetString(), nullptr, 10);
auto member_arr = value_[member_name].GetArray();
members_.reserve(member_arr.Size());
for (auto& member : member_arr) {
members_.push_back(
std::make_unique<StructMember>(enclosing_library_, member));
}
}
TableMember::TableMember(const Library& enclosing_library,
const rapidjson::Value& value)
: name_(value["name"].GetString()),
ordinal_(std::strtoll(value["ordinal"].GetString(), nullptr, 10)),
size_(std::strtoll(value["size"].GetString(), nullptr, 10)) {
if (!value.HasMember("type")) {
FXL_LOG(ERROR) << "Type missing";
type_ = std::make_unique<RawType>(size_);
return;
}
type_ =
Type::GetType(enclosing_library.enclosing_loader(), value["type"], size_);
}
TableMember::~TableMember() {}
Table::Table(const Library& enclosing_library, const rapidjson::Value& value)
: enclosing_library_(enclosing_library), value_(value) {}
Table::~Table() {}
void Table::DecodeTypes() {
if (decoded_) {
return;
}
decoded_ = true;
name_ = value_["name"].GetString();
size_ = std::strtoll(value_["size"].GetString(), nullptr, 10);
unknown_member_type_ = std::make_unique<RawType>(size_);
auto member_arr = value_["members"].GetArray();
uint32_t max_ordinal = 0;
for (auto& member : member_arr) {
backing_members_.push_back(
std::make_unique<TableMember>(enclosing_library_, member));
max_ordinal = std::max(max_ordinal, backing_members_.back()->ordinal());
}
// There is one element in this array for each possible ordinal value. The
// array is dense, so there are unlikely to be gaps.
members_.resize(max_ordinal + 1, nullptr);
for (const auto& backing_member : backing_members_) {
members_[backing_member->ordinal()] = backing_member.get();
}
}
InterfaceMethod::InterfaceMethod(const Interface& interface,
const rapidjson::Value& value)
: enclosing_interface_(interface),
value_(value),
ordinal_(std::strtoll(value["ordinal"].GetString(), nullptr, 10)),
name_(value["name"].GetString()) {
if (value_["has_request"].GetBool()) {
request_ = std::unique_ptr<Struct>(
new Struct(interface.enclosing_library(), value));
}
if (value_["has_response"].GetBool()) {
response_ = std::unique_ptr<Struct>(
new Struct(interface.enclosing_library(), value));
}
}
std::string InterfaceMethod::fully_qualified_name() const {
std::string fqn(enclosing_interface_.name());
fqn.append(".");
fqn.append(name());
return fqn;
}
bool Interface::GetMethodByFullName(const std::string& name,
const InterfaceMethod** method_ptr) const {
for (const auto& method : methods()) {
if (method->fully_qualified_name() == name) {
*method_ptr = method.get();
return true;
}
}
return false;
}
Library::Library(LibraryLoader* enclosing_loader, rapidjson::Document& document,
std::map<Ordinal, const InterfaceMethod*>& index)
: enclosing_loader_(enclosing_loader),
backing_document_(std::move(document)) {
auto interfaces_array =
backing_document_["interface_declarations"].GetArray();
interfaces_.reserve(interfaces_array.Size());
for (auto& decl : interfaces_array) {
interfaces_.emplace_back(new Interface(*this, decl));
interfaces_.back()->AddMethodsToIndex(index);
}
}
void Library::DecodeTypes() {
if (decoded_) {
return;
}
decoded_ = true;
name_ = backing_document_["name"].GetString();
for (auto& enu : backing_document_["enum_declarations"].GetArray()) {
enums_.emplace(std::piecewise_construct,
std::forward_as_tuple(enu["name"].GetString()),
std::forward_as_tuple(new Enum(enu)));
}
for (auto& str : backing_document_["struct_declarations"].GetArray()) {
structs_.emplace(std::piecewise_construct,
std::forward_as_tuple(str["name"].GetString()),
std::forward_as_tuple(new Struct(*this, str)));
}
for (auto& tab : backing_document_["table_declarations"].GetArray()) {
tables_.emplace(std::piecewise_construct,
std::forward_as_tuple(tab["name"].GetString()),
std::forward_as_tuple(new Table(*this, tab)));
}
for (auto& uni : backing_document_["union_declarations"].GetArray()) {
unions_.emplace(std::piecewise_construct,
std::forward_as_tuple(uni["name"].GetString()),
std::forward_as_tuple(new Union(*this, uni)));
}
for (auto& xuni : backing_document_["xunion_declarations"].GetArray()) {
xunions_.emplace(std::piecewise_construct,
std::forward_as_tuple(xuni["name"].GetString()),
std::forward_as_tuple(new XUnion(*this, xuni)));
}
}
std::unique_ptr<Type> Library::TypeFromIdentifier(bool is_nullable,
std::string& identifier,
size_t inline_size) {
auto str = structs_.find(identifier);
if (str != structs_.end()) {
str->second->DecodeStructTypes();
std::unique_ptr<Type> type(
new StructType(std::ref(*str->second), is_nullable));
return type;
}
auto enu = enums_.find(identifier);
if (enu != enums_.end()) {
enu->second->DecodeTypes();
return std::make_unique<EnumType>(std::ref(*enu->second));
}
auto tab = tables_.find(identifier);
if (tab != tables_.end()) {
tab->second->DecodeTypes();
return std::make_unique<TableType>(std::ref(*tab->second));
}
auto uni = unions_.find(identifier);
if (uni != unions_.end()) {
uni->second->DecodeTypes();
return std::make_unique<UnionType>(std::ref(*uni->second), is_nullable);
}
auto xuni = xunions_.find(identifier);
if (xuni != xunions_.end()) {
// Note: XUnion and nullable XUnion are encoded in the same way
xuni->second->DecodeTypes();
return std::make_unique<XUnionType>(std::ref(*xuni->second), is_nullable);
}
return std::make_unique<RawType>(inline_size);
}
bool Library::GetInterfaceByName(const std::string& name,
const Interface** ptr) const {
for (const auto& interface : interfaces()) {
if (interface->name() == name) {
*ptr = interface.get();
return true;
}
}
return false;
}
LibraryLoader::LibraryLoader(
std::vector<std::unique_ptr<std::istream>>& library_streams,
LibraryReadError* err) {
err->value = LibraryReadError::kOk;
for (size_t i = 0; i < library_streams.size(); i++) {
std::string ir(std::istreambuf_iterator<char>(*library_streams[i]), {});
if (library_streams[i]->fail()) {
err->value = LibraryReadError ::kIoError;
return;
}
Add(ir, err);
if (err->value != LibraryReadError::kOk) {
FXL_LOG(ERROR) << "JSON parse error: "
<< rapidjson::GetParseError_En(err->parse_result.Code())
<< " at offset " << err->parse_result.Offset();
return;
}
}
}
} // namespace fidlcat