| // 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 "rapidjson/error/en.h" |
| #include "src/lib/fidl_codec/wire_object.h" |
| #include "src/lib/fidl_codec/wire_types.h" |
| #include "src/lib/fxl/logging.h" |
| |
| // See library_loader.h for details. |
| |
| namespace fidl_codec { |
| |
| Enum::Enum(Library* enclosing_library, const rapidjson::Value& value) |
| : enclosing_library_(enclosing_library), value_(value) {} |
| |
| Enum::~Enum() = default; |
| |
| void Enum::DecodeTypes() { |
| if (decoded_) { |
| return; |
| } |
| decoded_ = true; |
| name_ = enclosing_library_->ExtractString(value_, "enum", "<unknown>", "name"); |
| type_ = enclosing_library_->ExtractScalarType(value_, "enum", name_, "type", 0); |
| |
| if (!value_.HasMember("members")) { |
| enclosing_library_->FieldNotFound("enum", name_, "members"); |
| } |
| |
| size_ = type_->InlineSize(nullptr); |
| } |
| |
| std::string Enum::GetNameFromBytes(const uint8_t* bytes) const { |
| if (value_.HasMember("members")) { |
| for (auto& member : value_["members"].GetArray()) { |
| if (member.HasMember("value") && member["value"].HasMember("literal") && |
| (type_->ValueEquals(bytes, size_, member["value"]["literal"]))) { |
| if (!member.HasMember("name")) { |
| return "<unknown>"; |
| } |
| return member["name"].GetString(); |
| } |
| } |
| } |
| return "<unknown>"; |
| } |
| |
| Bits::Bits(Library* enclosing_library, const rapidjson::Value& value) |
| : enclosing_library_(enclosing_library), value_(value) {} |
| |
| Bits::~Bits() = default; |
| |
| void Bits::DecodeTypes() { |
| if (decoded_) { |
| return; |
| } |
| decoded_ = true; |
| name_ = enclosing_library_->ExtractString(value_, "bits", "<unknown>", "name"); |
| type_ = enclosing_library_->ExtractType(value_, "bits", name_, "type", 0); |
| |
| if (!value_.HasMember("members")) { |
| enclosing_library_->FieldNotFound("bits", name_, "members"); |
| } |
| |
| size_ = type_->InlineSize(nullptr); |
| } |
| |
| std::string Bits::GetNameFromBytes(const uint8_t* bytes) const { |
| std::string returned_value; |
| if (value_.HasMember("members")) { |
| for (auto& member : value_["members"].GetArray()) { |
| if (member.HasMember("value") && member["value"].HasMember("literal") && |
| (type_->ValueHas(bytes, member["value"]["literal"]))) { |
| if (!returned_value.empty()) { |
| returned_value += "|"; |
| } |
| if (!member.HasMember("name")) { |
| returned_value += "<unknown>"; |
| } |
| returned_value += member["name"].GetString(); |
| } |
| } |
| } |
| if (returned_value.empty()) { |
| return "<none>"; |
| } |
| return returned_value; |
| } |
| |
| UnionMember::UnionMember(Library* enclosing_library, const rapidjson::Value& value, bool for_xunion) |
| : reserved_(enclosing_library->ExtractBool(value, "table member", "<unknown>", "reserved")), |
| name_(reserved_ |
| ? "<reserved>" |
| : enclosing_library->ExtractString(value, "union member", "<unknown>", "name")), |
| offset_(reserved_ ? 0 |
| : enclosing_library->ExtractUint64(value, "union member", name_, "offset")), |
| size_(reserved_ ? 0 : enclosing_library->ExtractUint64(value, "union member", name_, "size")), |
| ordinal_(for_xunion |
| ? enclosing_library->ExtractUint32(value, "union member", name_, "ordinal") |
| : (value.HasMember("xunion_ordinal") |
| ? enclosing_library->ExtractUint32(value, "union member", name_, |
| "xunion_ordinal") |
| : 0)), |
| type_(reserved_ |
| ? std::make_unique<RawType>(0) |
| : enclosing_library->ExtractType(value, "union member", name_, "type", size_)) {} |
| |
| UnionMember::~UnionMember() = default; |
| |
| Union::Union(Library* enclosing_library, const rapidjson::Value& value) |
| : enclosing_library_(enclosing_library), value_(value) {} |
| |
| void Union::DecodeTypes(bool for_xunion) { |
| if (decoded_) { |
| return; |
| } |
| decoded_ = true; |
| name_ = enclosing_library_->ExtractString(value_, "union", "<unknown>", "name"); |
| alignment_ = enclosing_library_->ExtractUint64(value_, "union", name_, "alignment"); |
| size_ = enclosing_library_->ExtractUint64(value_, "union", name_, "size"); |
| |
| if (!value_.HasMember("members")) { |
| enclosing_library_->FieldNotFound("union", name_, "members"); |
| } else { |
| 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, for_xunion)); |
| } |
| } |
| } |
| |
| const UnionMember* Union::MemberWithTag(uint32_t tag) const { |
| // Only non reserved members count for the tag. |
| for (const auto& member : members_) { |
| if (!member->reserved()) { |
| if (tag == 0) { |
| return member.get(); |
| } |
| --tag; |
| } |
| } |
| return nullptr; |
| } |
| |
| const UnionMember* Union::MemberWithOrdinal(Ordinal32 ordinal) const { |
| for (const auto& member : members_) { |
| if (member->ordinal() == ordinal) { |
| if (member->reserved()) { |
| return nullptr; |
| } |
| return member.get(); |
| } |
| } |
| return nullptr; |
| } |
| |
| std::unique_ptr<UnionValue> Union::DecodeUnion(MessageDecoder* decoder, const Type* type, |
| uint64_t offset, bool nullable) const { |
| std::unique_ptr<UnionValue> result = std::make_unique<UnionValue>(type, *this); |
| if (nullable) { |
| result->DecodeNullable(decoder, offset, size_); |
| } else { |
| result->DecodeAt(decoder, offset); |
| } |
| return result; |
| } |
| |
| std::unique_ptr<XUnionValue> Union::DecodeXUnion(MessageDecoder* decoder, const Type* type, |
| uint64_t offset, bool nullable) const { |
| uint32_t ordinal = 0; |
| if (decoder->GetValueAt(offset, &ordinal)) { |
| if ((ordinal == 0) && !nullable) { |
| decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec |
| << ": Null envelope for a non nullable extensible union\n"; |
| return nullptr; |
| } |
| } |
| offset += sizeof(uint64_t); // Skips ordinal + padding. |
| |
| std::unique_ptr<XUnionValue> result = std::make_unique<XUnionValue>(type, *this); |
| |
| std::unique_ptr<EnvelopeValue> envelope; |
| const UnionMember* member = MemberWithOrdinal(ordinal); |
| std::string key_name; |
| if (member == nullptr) { |
| key_name = std::string("unknown$") + std::to_string(ordinal); |
| envelope = std::make_unique<EnvelopeValue>(nullptr); |
| } else { |
| key_name = member->name(); |
| envelope = std::make_unique<EnvelopeValue>(member->type()); |
| } |
| envelope->DecodeAt(decoder, offset); |
| result->set_field(Field(key_name, std::move(envelope))); |
| return result; |
| } |
| |
| StructMember::StructMember(Library* enclosing_library, const rapidjson::Value& value) |
| : name_(enclosing_library->ExtractString(value, "struct member", "<unknown>", "name")), |
| size_(enclosing_library->ExtractUint64(value, "struct member", name_, "size")), |
| type_(enclosing_library->ExtractType(value, "struct member", name_, "type", size_)) { |
| if (!value.HasMember("field_shape_old")) { |
| enclosing_library->FieldNotFound("struct member", name_, "field_shape_old"); |
| } else { |
| const rapidjson::Value& v0 = value["field_shape_old"]; |
| v0_offset_ = enclosing_library->ExtractUint64(v0, "struct member", name_, "offset"); |
| } |
| if (!value.HasMember("field_shape_v1")) { |
| enclosing_library->FieldNotFound("struct member", name_, "field_shape_v1"); |
| } else { |
| const rapidjson::Value& v1 = value["field_shape_v1"]; |
| v1_offset_ = enclosing_library->ExtractUint64(v1, "struct member", name_, "offset"); |
| } |
| } |
| |
| StructMember::~StructMember() = default; |
| |
| uint64_t StructMember::Offset(MessageDecoder* decoder) const { |
| return decoder->unions_are_xunions() ? v1_offset_ : v0_offset_; |
| } |
| |
| Struct::Struct(Library* enclosing_library, const rapidjson::Value& value) |
| : enclosing_library_(enclosing_library), value_(value) {} |
| |
| void Struct::DecodeStructTypes() { |
| if (decoded_) { |
| return; |
| } |
| DecodeTypes("struct", "size", "members", "type_shape_old", "type_shape_v1"); |
| } |
| |
| void Struct::DecodeRequestTypes() { |
| if (decoded_) { |
| return; |
| } |
| DecodeTypes("request", "maybe_request_size", "maybe_request", "maybe_request_type_shape_old", |
| "maybe_request_type_shape_v1"); |
| } |
| |
| void Struct::DecodeResponseTypes() { |
| if (decoded_) { |
| return; |
| } |
| DecodeTypes("response", "maybe_response_size", "maybe_response", "maybe_response_type_shape_old", |
| "maybe_response_type_shape_v1"); |
| } |
| |
| uint32_t Struct::Size(MessageDecoder* decoder) const { |
| return decoder->unions_are_xunions() ? v1_size_ : v0_size_; |
| } |
| |
| std::unique_ptr<Object> Struct::DecodeObject(MessageDecoder* decoder, const Type* type, |
| uint64_t offset, bool nullable) const { |
| std::unique_ptr<Object> result = std::make_unique<Object>(type, *this); |
| if (nullable) { |
| result->DecodeNullable(decoder, offset, Size(decoder)); |
| } else { |
| result->DecodeAt(decoder, offset); |
| } |
| return result; |
| } |
| |
| void Struct::DecodeTypes(std::string_view container_name, const char* size_name, |
| const char* member_name, const char* v0_name, const char* v1_name) { |
| FXL_DCHECK(!decoded_); |
| decoded_ = true; |
| name_ = enclosing_library_->ExtractString(value_, container_name, "<unknown>", "name"); |
| |
| if (!value_.HasMember(v0_name)) { |
| enclosing_library_->FieldNotFound(container_name, name_, v0_name); |
| } else { |
| const rapidjson::Value& v0 = value_[v0_name]; |
| v0_size_ = enclosing_library_->ExtractUint64(v0, container_name, name_, "inline_size"); |
| } |
| |
| if (!value_.HasMember(v1_name)) { |
| enclosing_library_->FieldNotFound(container_name, name_, v1_name); |
| } else { |
| const rapidjson::Value& v1 = value_[v1_name]; |
| v1_size_ = enclosing_library_->ExtractUint64(v1, container_name, name_, "inline_size"); |
| } |
| |
| if (!value_.HasMember(member_name)) { |
| enclosing_library_->FieldNotFound(container_name, name_, member_name); |
| } else { |
| 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(Library* enclosing_library, const rapidjson::Value& value) |
| : reserved_(enclosing_library->ExtractBool(value, "table member", "<unknown>", "reserved")), |
| name_(reserved_ |
| ? "<reserved>" |
| : enclosing_library->ExtractString(value, "table member", "<unknown>", "name")), |
| ordinal_(enclosing_library->ExtractUint32(value, "table member", name_, "ordinal")), |
| size_(reserved_ ? 0 : enclosing_library->ExtractUint64(value, "table member", name_, "size")), |
| type_(reserved_ |
| ? std::make_unique<RawType>(0) |
| : enclosing_library->ExtractType(value, "table member", name_, "type", size_)) {} |
| |
| TableMember::~TableMember() = default; |
| |
| Table::Table(Library* enclosing_library, const rapidjson::Value& value) |
| : enclosing_library_(enclosing_library), value_(value) {} |
| |
| Table::~Table() = default; |
| |
| void Table::DecodeTypes() { |
| if (decoded_) { |
| return; |
| } |
| decoded_ = true; |
| name_ = enclosing_library_->ExtractString(value_, "table", "<unknown>", "name"); |
| size_ = enclosing_library_->ExtractUint64(value_, "table", name_, "size"); |
| |
| unknown_member_type_ = std::make_unique<RawType>(size_); |
| |
| if (!value_.HasMember("members")) { |
| enclosing_library_->FieldNotFound("table", name_, "members"); |
| } else { |
| auto member_arr = value_["members"].GetArray(); |
| Ordinal32 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), |
| name_(interface.enclosing_library()->ExtractString(value, "method", "<unknown>", "name")), |
| // TODO(FIDL-524): Step 4, i.e. both ord and gen are prepared by fidlc for |
| // direct consumption by the bindings. |
| ordinal_(interface.enclosing_library()->ExtractUint64(value, "method", name_, "ordinal")), |
| old_ordinal_(interface.enclosing_library()->ExtractUint64(value, "method", name_, |
| "generated_ordinal")), |
| is_composed_( |
| interface.enclosing_library()->ExtractBool(value, "method", name_, "is_composed")) { |
| if (interface.enclosing_library()->ExtractBool(value, "method", name_, "has_request")) { |
| request_ = std::unique_ptr<Struct>(new Struct(interface.enclosing_library(), value)); |
| } |
| |
| if (interface.enclosing_library()->ExtractBool(value, "method", name_, "has_response")) { |
| 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<Ordinal64, std::unique_ptr<std::vector<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); |
| } |
| } |
| |
| Library::~Library() { enclosing_loader()->Delete(this); } |
| |
| void Library::DecodeTypes() { |
| if (decoded_) { |
| return; |
| } |
| decoded_ = true; |
| name_ = ExtractString(backing_document_, "library", "<unknown>", "name"); |
| |
| if (!backing_document_.HasMember("enum_declarations")) { |
| FieldNotFound("library", name_, "enum_declarations"); |
| } else { |
| 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(this, enu))); |
| } |
| } |
| |
| if (!backing_document_.HasMember("bits_declarations")) { |
| FieldNotFound("library", name_, "bits_declarations"); |
| } else { |
| for (auto& bits : backing_document_["bits_declarations"].GetArray()) { |
| bits_.emplace(std::piecewise_construct, std::forward_as_tuple(bits["name"].GetString()), |
| std::forward_as_tuple(new Bits(this, bits))); |
| } |
| } |
| |
| if (!backing_document_.HasMember("struct_declarations")) { |
| FieldNotFound("library", name_, "struct_declarations"); |
| } else { |
| 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))); |
| } |
| } |
| |
| if (!backing_document_.HasMember("table_declarations")) { |
| FieldNotFound("library", name_, "table_declarations"); |
| } else { |
| 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))); |
| } |
| } |
| |
| if (!backing_document_.HasMember("union_declarations")) { |
| FieldNotFound("library", name_, "union_declarations"); |
| } else { |
| 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))); |
| } |
| } |
| |
| if (!backing_document_.HasMember("xunion_declarations")) { |
| FieldNotFound("library", name_, "xunion_declarations"); |
| } else { |
| 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))); |
| } |
| } |
| } |
| |
| bool Library::DecodeAll() { |
| DecodeTypes(); |
| for (const auto& tmp : structs_) { |
| tmp.second->DecodeStructTypes(); |
| } |
| for (const auto& tmp : enums_) { |
| tmp.second->DecodeTypes(); |
| } |
| for (const auto& tmp : bits_) { |
| tmp.second->DecodeTypes(); |
| } |
| for (const auto& tmp : tables_) { |
| tmp.second->DecodeTypes(); |
| } |
| for (const auto& tmp : unions_) { |
| tmp.second->DecodeUnionTypes(); |
| } |
| for (const auto& tmp : xunions_) { |
| tmp.second->DecodeXunionTypes(); |
| } |
| for (const auto& interface : interfaces_) { |
| for (const auto& method : interface->methods()) { |
| method->request(); |
| method->response(); |
| } |
| } |
| return !has_errors_; |
| } |
| |
| 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 bits = bits_.find(identifier); |
| if (bits != bits_.end()) { |
| bits->second->DecodeTypes(); |
| return std::make_unique<BitsType>(std::ref(*bits->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->DecodeUnionTypes(); |
| 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->DecodeXunionTypes(); |
| return std::make_unique<XUnionType>(std::ref(*xuni->second), is_nullable); |
| } |
| const Interface* ifc; |
| if (GetInterfaceByName(identifier, &ifc)) { |
| return std::make_unique<HandleType>(); |
| } |
| 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; |
| } |
| |
| bool Library::ExtractBool(const rapidjson::Value& value, std::string_view container_type, |
| std::string_view container_name, const char* field_name) { |
| if (!value.HasMember(field_name)) { |
| FieldNotFound(container_type, container_name, field_name); |
| return false; |
| } |
| return value[field_name].GetBool(); |
| } |
| |
| std::string Library::ExtractString(const rapidjson::Value& value, std::string_view container_type, |
| std::string_view container_name, const char* field_name) { |
| if (!value.HasMember(field_name)) { |
| FieldNotFound(container_type, container_name, field_name); |
| return "<unknown>"; |
| } |
| return value["name"].GetString(); |
| } |
| |
| uint64_t Library::ExtractUint64(const rapidjson::Value& value, std::string_view container_type, |
| std::string_view container_name, const char* field_name) { |
| if (!value.HasMember(field_name)) { |
| FieldNotFound(container_type, container_name, field_name); |
| return 0; |
| } |
| return std::strtoll(value[field_name].GetString(), nullptr, kDecimalBase); |
| } |
| |
| uint32_t Library::ExtractUint32(const rapidjson::Value& value, std::string_view container_type, |
| std::string_view container_name, const char* field_name) { |
| if (!value.HasMember(field_name)) { |
| FieldNotFound(container_type, container_name, field_name); |
| return 0; |
| } |
| return std::strtoll(value[field_name].GetString(), nullptr, kDecimalBase); |
| } |
| |
| std::unique_ptr<Type> Library::ExtractScalarType(const rapidjson::Value& value, |
| std::string_view container_type, |
| std::string_view container_name, |
| const char* field_name, uint64_t size) { |
| if (!value.HasMember(field_name)) { |
| FieldNotFound(container_type, container_name, field_name); |
| return std::make_unique<RawType>(size); |
| } |
| return Type::ScalarTypeFromName(value[field_name].GetString(), size); |
| } |
| |
| std::unique_ptr<Type> Library::ExtractType(const rapidjson::Value& value, |
| std::string_view container_type, |
| std::string_view container_name, const char* field_name, |
| uint64_t size) { |
| if (!value.HasMember(field_name)) { |
| FieldNotFound(container_type, container_name, field_name); |
| return std::make_unique<RawType>(size); |
| } |
| return Type::GetType(enclosing_loader(), value[field_name], size); |
| } |
| |
| void Library::FieldNotFound(std::string_view container_type, std::string_view container_name, |
| const char* field_name) { |
| has_errors_ = true; |
| FXL_LOG(ERROR) << "File " << name() << " field '" << field_name << "' missing for " |
| << container_type << ' ' << container_name; |
| } |
| |
| LibraryLoader::LibraryLoader(std::vector<std::unique_ptr<std::istream>>* library_streams, |
| LibraryReadError* err) { |
| AddAll(library_streams, err); |
| } |
| |
| bool LibraryLoader::AddAll(std::vector<std::unique_ptr<std::istream>>* library_streams, |
| LibraryReadError* err) { |
| bool ok = true; |
| err->value = LibraryReadError::kOk; |
| // Go backwards through the streams; we refuse to load the same library twice, and the last one |
| // wins. |
| for (auto i = library_streams->rbegin(); i != library_streams->rend(); ++i) { |
| Add(&(*i), err); |
| if (err->value != LibraryReadError::kOk) { |
| ok = false; |
| } |
| } |
| return ok; |
| } |
| |
| bool LibraryLoader::DecodeAll() { |
| bool ok = true; |
| for (const auto& representation : representations_) { |
| Library* library = representation.second.get(); |
| if (!library->DecodeAll()) { |
| ok = false; |
| } |
| } |
| return ok; |
| } |
| |
| void LibraryLoader::Add(std::unique_ptr<std::istream>* library_stream, LibraryReadError* err) { |
| err->value = LibraryReadError::kOk; |
| std::string ir(std::istreambuf_iterator<char>(**library_stream), {}); |
| if ((*library_stream)->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 fidl_codec |