| // 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 "src/lib/fidl_codec/wire_types.h" |
| |
| #include <zircon/fidl.h> |
| |
| #include <rapidjson/error/en.h> |
| |
| #include "src/lib/fidl_codec/library_loader.h" |
| #include "src/lib/fidl_codec/logger.h" |
| #include "src/lib/fidl_codec/type_visitor.h" |
| #include "src/lib/fidl_codec/wire_object.h" |
| |
| // See wire_types.h for details. |
| |
| namespace fidl_codec { |
| namespace { |
| |
| class ToStringVisitor : public TypeVisitor { |
| public: |
| enum ExpandLevels { |
| kNone, |
| kOne, |
| kAll, |
| }; |
| |
| explicit ToStringVisitor(const std::string& indent, ExpandLevels levels, std::string* result) |
| : indent_(indent), levels_(levels), result_(result) {} |
| ~ToStringVisitor() = default; |
| |
| private: |
| ExpandLevels NextExpandLevels() { |
| if (levels_ == ExpandLevels::kAll) { |
| return ExpandLevels::kAll; |
| } |
| |
| return ExpandLevels::kNone; |
| } |
| |
| template <typename T> |
| void VisitTypeWithMembers(const Type* type, const std::string& name, |
| const std::vector<T>& members, fit::function<bool(const T&)> body) { |
| *result_ += name + " "; |
| VisitType(type); |
| |
| if (levels_ == ExpandLevels::kNone) { |
| return; |
| } |
| |
| *result_ += " {"; |
| |
| if (members.empty()) { |
| *result_ += "}"; |
| return; |
| } |
| |
| *result_ += "\n"; |
| |
| for (const auto& member : members) { |
| if (body(member)) { |
| *result_ += ";\n"; |
| } |
| } |
| |
| *result_ += indent_ + "}"; |
| } |
| |
| void VisitType(const Type* type) override { *result_ += type->Name(); } |
| |
| void VisitEnumType(const EnumType* type) override { |
| VisitTypeWithMembers<EnumOrBitsMember>(type, "enum", type->enum_definition().members(), |
| [this](const EnumOrBitsMember& member) { |
| *result_ += indent_ + " " + member.name() + " = "; |
| if (member.negative()) { |
| *result_ += "-"; |
| } |
| *result_ += std::to_string(member.absolute_value()); |
| return true; |
| }); |
| } |
| |
| void VisitBitsType(const BitsType* type) override { |
| VisitTypeWithMembers<EnumOrBitsMember>( |
| type, "bits", type->bits_definition().members(), [this](const EnumOrBitsMember& member) { |
| *result_ += |
| indent_ + " " + member.name() + " = " + std::to_string(member.absolute_value()); |
| return true; |
| }); |
| } |
| |
| void VisitUnionType(const UnionType* type) override { |
| VisitTypeWithMembers<std::unique_ptr<UnionMember>>( |
| type, "union", type->union_definition().members(), |
| [this](const std::unique_ptr<UnionMember>& member) { |
| *result_ += indent_ + " " + std::to_string(member->ordinal()) + ": "; |
| if (member->reserved()) { |
| *result_ += "reserved"; |
| return true; |
| } |
| |
| ToStringVisitor visitor(indent_ + " ", NextExpandLevels(), result_); |
| member->type()->Visit(&visitor); |
| |
| *result_ += " " + std::string(member->name()); |
| return true; |
| }); |
| } |
| |
| void VisitStructType(const StructType* type) override { |
| VisitTypeWithMembers<std::unique_ptr<StructMember>>( |
| type, "struct", type->struct_definition().members(), |
| [this](const std::unique_ptr<StructMember>& member) { |
| *result_ += indent_ + " "; |
| ToStringVisitor visitor(indent_ + " ", NextExpandLevels(), result_); |
| member->type()->Visit(&visitor); |
| *result_ += " " + std::string(member->name()); |
| return true; |
| }); |
| } |
| |
| void VisitArrayType(const ArrayType* type) override { |
| *result_ += "array<"; |
| type->component_type()->Visit(this); |
| *result_ += ">"; |
| } |
| |
| void VisitVectorType(const VectorType* type) override { |
| *result_ += "vector<"; |
| type->component_type()->Visit(this); |
| *result_ += ">"; |
| } |
| |
| void VisitTableType(const TableType* type) override { |
| VisitTypeWithMembers<std::unique_ptr<TableMember>>( |
| type, "table", type->table_definition().members(), |
| [this](const std::unique_ptr<TableMember>& member) { |
| if (!member) { |
| return false; |
| } |
| *result_ += indent_ + " "; |
| *result_ += std::to_string(member->ordinal()) + ": "; |
| if (member->reserved()) { |
| *result_ += "reserved"; |
| return true; |
| } |
| ToStringVisitor visitor(indent_ + " ", NextExpandLevels(), result_); |
| member->type()->Visit(&visitor); |
| *result_ += " " + std::string(member->name()); |
| return true; |
| }); |
| } |
| |
| std::string indent_; |
| ExpandLevels levels_; |
| std::string* result_; |
| }; |
| |
| } // namespace |
| |
| std::string FidlMethodNameToCpp(std::string_view identifier) { |
| std::string result(identifier); |
| size_t start = 0; |
| while ((start = result.find_first_of("./", start)) != std::string::npos) { |
| result.replace(start, 1, "::"); |
| start += 2; |
| } |
| return result; |
| } |
| |
| std::string Type::ToString(bool expand) const { |
| std::string ret; |
| ToStringVisitor visitor( |
| "", expand ? ToStringVisitor::ExpandLevels::kAll : ToStringVisitor::ExpandLevels::kOne, &ret); |
| Visit(&visitor); |
| return ret; |
| } |
| |
| void Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| printer << Red << "invalid" << ResetColor; |
| } |
| |
| std::string InvalidType::Name() const { return "unknown"; } |
| |
| size_t InvalidType::InlineSize() const { return 0; } |
| |
| std::unique_ptr<Value> InvalidType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| return std::make_unique<InvalidValue>(); |
| } |
| |
| void InvalidType::Visit(TypeVisitor* visitor) const { visitor->VisitInvalidType(this); } |
| |
| size_t BoolType::InlineSize() const { return sizeof(uint8_t); } |
| |
| std::unique_ptr<Value> BoolType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| auto byte = decoder->GetAddress(offset, sizeof(uint8_t)); |
| if (byte == nullptr) { |
| return std::make_unique<InvalidValue>(); |
| } |
| return std::make_unique<BoolValue>(*byte); |
| } |
| |
| void BoolType::Visit(TypeVisitor* visitor) const { visitor->VisitBoolType(this); }; |
| |
| std::string Int8Type::Name() const { |
| switch (kind_) { |
| case Kind::kDecimal: |
| return "int8"; |
| case Kind::kChar: |
| return "char"; |
| } |
| } |
| |
| void Int8Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| switch (kind_) { |
| case Kind::kChar: |
| case Kind::kDecimal: |
| printer << Blue; |
| if (negative) { |
| printer << '-'; |
| } |
| printer << absolute << ResetColor; |
| break; |
| } |
| } |
| } |
| |
| void Int8Type::Visit(TypeVisitor* visitor) const { visitor->VisitInt8Type(this); } |
| |
| std::string Int16Type::Name() const { return "int16"; } |
| |
| void Int16Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| switch (kind_) { |
| case Kind::kDecimal: |
| printer << Blue; |
| if (negative) { |
| printer << '-'; |
| } |
| printer << absolute << ResetColor; |
| break; |
| } |
| } |
| } |
| |
| void Int16Type::Visit(TypeVisitor* visitor) const { visitor->VisitInt16Type(this); } |
| |
| std::string Int32Type::Name() const { return "int32"; } |
| |
| void Int32Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| switch (kind_) { |
| case Kind::kDecimal: |
| printer << Blue; |
| if (negative) { |
| printer << '-'; |
| } |
| printer << absolute << ResetColor; |
| break; |
| } |
| } |
| } |
| |
| void Int32Type::Visit(TypeVisitor* visitor) const { visitor->VisitInt32Type(this); } |
| |
| std::string Int64Type::Name() const { |
| switch (kind_) { |
| case Kind::kDecimal: |
| return "int64"; |
| case Kind::kDuration: |
| return "zx.duration"; |
| case Kind::kTime: |
| return "zx.time"; |
| } |
| } |
| |
| void Int64Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| switch (kind_) { |
| case Kind::kDecimal: |
| printer << Blue; |
| if (negative) { |
| printer << '-'; |
| } |
| printer << absolute << ResetColor; |
| break; |
| case Kind::kDuration: |
| if (negative) { |
| absolute = -absolute; |
| } |
| printer.DisplayDuration(static_cast<zx_duration_t>(absolute)); |
| break; |
| case Kind::kTime: |
| if (negative) { |
| absolute = -absolute; |
| } |
| printer.DisplayTime(static_cast<zx_time_t>(absolute)); |
| break; |
| } |
| } |
| } |
| |
| void Int64Type::Visit(TypeVisitor* visitor) const { visitor->VisitInt64Type(this); } |
| |
| std::string Uint8Type::Name() const { |
| switch (kind_) { |
| case Kind::kDecimal: |
| case Kind::kHexaDecimal: |
| return "uint8"; |
| case Kind::kPacketGuestVcpuType: |
| return "zx.packet_guest_vcpu::type"; |
| } |
| } |
| |
| void Uint8Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| FX_DCHECK(!negative); |
| switch (kind_) { |
| case Kind::kDecimal: |
| printer << Blue << absolute << ResetColor; |
| break; |
| case Kind::kHexaDecimal: |
| printer.DisplayHexa8(static_cast<uint8_t>(absolute)); |
| break; |
| case Kind::kPacketGuestVcpuType: |
| printer.DisplayPacketGuestVcpuType(static_cast<uint8_t>(absolute)); |
| } |
| } |
| } |
| |
| void Uint8Type::Visit(TypeVisitor* visitor) const { visitor->VisitUint8Type(this); } |
| |
| std::string Uint16Type::Name() const { |
| switch (kind_) { |
| case Kind::kDecimal: |
| case Kind::kHexaDecimal: |
| return "uint16"; |
| case Kind::kPacketPageRequestCommand: |
| return "zx.packet_page_request::command"; |
| } |
| } |
| |
| void Uint16Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| FX_DCHECK(!negative); |
| switch (kind_) { |
| case Kind::kDecimal: |
| printer << Blue << absolute << ResetColor; |
| break; |
| case Kind::kHexaDecimal: |
| printer.DisplayHexa16(static_cast<uint16_t>(absolute)); |
| break; |
| case Kind::kPacketPageRequestCommand: |
| printer.DisplayPacketPageRequestCommand(static_cast<uint16_t>(absolute)); |
| break; |
| } |
| } |
| } |
| |
| void Uint16Type::Visit(TypeVisitor* visitor) const { visitor->VisitUint16Type(this); } |
| |
| std::string Uint32Type::Name() const { |
| switch (kind_) { |
| case Kind::kBtiPerm: |
| return "zx.bti_perm"; |
| case Kind::kCachePolicy: |
| return "zx.cache_policy"; |
| case Kind::kClock: |
| return "zx.clock"; |
| case Kind::kDecimal: |
| case Kind::kHexaDecimal: |
| return "uint32"; |
| case Kind::kExceptionState: |
| return "zx.exception_state"; |
| case Kind::kObjectInfoTopic: |
| return "zx.object_info_topic"; |
| case Kind::kPciBarType: |
| return "zx.pci_bar_type"; |
| case Kind::kPortPacketType: |
| return "zx.port_packet::type"; |
| case Kind::kProfileInfoFlags: |
| return "zx.profile_info_flags"; |
| case Kind::kPropType: |
| return "zx.prop_type"; |
| case Kind::kRights: |
| return "zx.rights"; |
| case Kind::kSignals: |
| return "signals"; |
| case Kind::kStatus: |
| return "zx.status"; |
| } |
| } |
| |
| void Uint32Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| FX_DCHECK(!negative); |
| switch (kind_) { |
| case Kind::kBtiPerm: |
| printer.DisplayBtiPerm(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kCachePolicy: |
| printer.DisplayCachePolicy(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kClock: |
| printer.DisplayClock(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kDecimal: |
| printer << Blue << absolute << ResetColor; |
| break; |
| case Kind::kExceptionState: |
| printer.DisplayExceptionState(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kHexaDecimal: |
| printer.DisplayHexa32(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kObjectInfoTopic: |
| printer.DisplayObjectInfoTopic(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kPciBarType: |
| printer.DisplayPciBarType(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kProfileInfoFlags: |
| printer.DisplayProfileInfoFlags(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kPropType: |
| printer.DisplayPropType(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kPortPacketType: |
| printer.DisplayPortPacketType(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kRights: |
| printer.DisplayRights(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kSignals: |
| printer.DisplaySignals(static_cast<uint32_t>(absolute)); |
| break; |
| case Kind::kStatus: |
| printer.DisplayStatus(static_cast<uint32_t>(absolute)); |
| break; |
| } |
| } |
| } |
| |
| void Uint32Type::Visit(TypeVisitor* visitor) const { visitor->VisitUint32Type(this); } |
| |
| std::string Uint64Type::Name() const { |
| switch (kind_) { |
| case Kind::kDecimal: |
| case Kind::kHexaDecimal: |
| return "uint64"; |
| case Kind::kGpAddr: |
| return "zx.gpaddr"; |
| case Kind::kPaddr: |
| return "zx.paddr"; |
| case Kind::kSize: |
| return "size"; |
| case Kind::kUintptr: |
| return "uintptr"; |
| case Kind::kVaddr: |
| return "zx.vaddr"; |
| } |
| } |
| |
| void Uint64Type::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| FX_DCHECK(!negative); |
| switch (kind_) { |
| case Kind::kDecimal: |
| printer << Blue << absolute << ResetColor; |
| break; |
| case Kind::kGpAddr: |
| printer.DisplayGpAddr(absolute); |
| break; |
| case Kind::kHexaDecimal: |
| printer.DisplayHexa64(absolute); |
| break; |
| case Kind::kPaddr: |
| printer.DisplayPaddr(absolute); |
| break; |
| case Kind::kSize: |
| printer << Blue << absolute << ResetColor; |
| break; |
| case Kind::kUintptr: |
| printer.DisplayUintptr(absolute); |
| break; |
| case Kind::kVaddr: |
| printer.DisplayVaddr(absolute); |
| break; |
| } |
| } |
| } |
| |
| void Uint64Type::Visit(TypeVisitor* visitor) const { visitor->VisitUint64Type(this); } |
| |
| std::string Float32Type::Name() const { return "float32"; } |
| |
| std::string Float32Type::CppName() const { return "float"; } |
| |
| void Float32Type::Visit(TypeVisitor* visitor) const { visitor->VisitFloat32Type(this); } |
| |
| std::string Float64Type::Name() const { return "float64"; } |
| |
| std::string Float64Type::CppName() const { return "double"; } |
| |
| void Float64Type::Visit(TypeVisitor* visitor) const { visitor->VisitFloat64Type(this); } |
| |
| std::string StringType::Name() const { return "string"; } |
| |
| std::string StringType::CppName() const { return "std::string"; } |
| |
| size_t StringType::InlineSize() const { return sizeof(uint64_t) + sizeof(uint64_t); } |
| |
| bool StringType::Nullable() const { return true; } |
| |
| std::unique_ptr<Value> StringType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| uint64_t string_length = 0; |
| if (!decoder->GetValueAt(offset, &string_length)) { |
| return std::make_unique<InvalidValue>(); |
| } |
| offset += sizeof(string_length); |
| |
| bool is_null; |
| uint64_t nullable_offset; |
| if (!decoder->DecodeNullableHeader(offset, string_length, &is_null, &nullable_offset)) { |
| return std::make_unique<InvalidValue>(); |
| } |
| if (is_null) { |
| return std::make_unique<NullValue>(); |
| } |
| auto data = reinterpret_cast<const char*>(decoder->GetAddress(nullable_offset, string_length)); |
| if (data == nullptr) { |
| return std::make_unique<InvalidValue>(); |
| } |
| return std::make_unique<StringValue>(std::string_view(data, string_length)); |
| } |
| |
| void StringType::Visit(TypeVisitor* visitor) const { visitor->VisitStringType(this); } |
| |
| std::string HandleType::Name() const { return "handle"; } |
| |
| std::string HandleType::CppName() const { return "zx::handle"; } |
| |
| size_t HandleType::InlineSize() const { return sizeof(zx_handle_t); } |
| |
| std::unique_ptr<Value> HandleType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| zx_handle_t handle = FIDL_HANDLE_ABSENT; |
| decoder->GetValueAt(offset, &handle); |
| if ((handle != FIDL_HANDLE_ABSENT) && (handle != FIDL_HANDLE_PRESENT)) { |
| decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec |
| << ": Invalid value <" << std::hex << handle << std::dec |
| << "> for handle\n"; |
| handle = FIDL_HANDLE_ABSENT; |
| } |
| if (handle == FIDL_HANDLE_ABSENT) { |
| zx_handle_disposition_t handle_disposition; |
| handle_disposition.operation = fidl_codec::kNoHandleDisposition; |
| handle_disposition.handle = FIDL_HANDLE_ABSENT; |
| handle_disposition.type = ZX_OBJ_TYPE_NONE; |
| handle_disposition.rights = 0; |
| handle_disposition.result = ZX_OK; |
| return std::make_unique<HandleValue>(handle_disposition); |
| } else { |
| return std::make_unique<HandleValue>(decoder->GetNextHandle()); |
| } |
| } |
| |
| void HandleType::Visit(TypeVisitor* visitor) const { visitor->VisitHandleType(this); } |
| |
| std::string EnumType::Name() const { return enum_definition_.name(); } |
| |
| std::string EnumType::CppName() const { return FidlMethodNameToCpp(enum_definition_.name()); } |
| |
| size_t EnumType::InlineSize() const { return enum_definition_.size(); } |
| |
| std::unique_ptr<Value> EnumType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| return enum_definition_.type()->Decode(decoder, offset); |
| } |
| |
| void EnumType::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| printer << Blue << enum_definition_.GetName(absolute, negative) << ResetColor; |
| } |
| } |
| |
| void EnumType::Visit(TypeVisitor* visitor) const { visitor->VisitEnumType(this); } |
| |
| std::string BitsType::Name() const { return bits_definition_.name(); } |
| |
| std::string BitsType::CppName() const { return FidlMethodNameToCpp(bits_definition_.name()); } |
| |
| size_t BitsType::InlineSize() const { return bits_definition_.size(); } |
| |
| std::unique_ptr<Value> BitsType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| return bits_definition_.type()->Decode(decoder, offset); |
| } |
| |
| void BitsType::PrettyPrint(const Value* value, PrettyPrinter& printer) const { |
| uint64_t absolute; |
| bool negative; |
| if (!value->GetIntegerValue(&absolute, &negative)) { |
| printer << Red << "invalid" << ResetColor; |
| } else { |
| printer << Blue << bits_definition_.GetName(absolute, negative) << ResetColor; |
| } |
| } |
| |
| void BitsType::Visit(TypeVisitor* visitor) const { visitor->VisitBitsType(this); } |
| |
| std::string UnionType::Name() const { return union_definition_.name(); } |
| |
| std::string UnionType::CppName() const { return FidlMethodNameToCpp(union_definition_.name()); } |
| |
| size_t UnionType::InlineSize() const { |
| // In v1, unions are encoded as xunion. The inline size is the size of an envelope which |
| // is always 24 bytes. |
| return 24; |
| } |
| |
| bool UnionType::Nullable() const { return nullable_; } |
| |
| std::unique_ptr<Value> UnionType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| Ordinal32 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 std::make_unique<InvalidValue>(); |
| } |
| } |
| |
| offset += sizeof(uint64_t); // Skips ordinal + padding. |
| |
| if (ordinal == 0) { |
| if (!decoder->CheckNullEnvelope(offset)) { |
| return std::make_unique<InvalidValue>(); |
| } |
| return std::make_unique<NullValue>(); |
| } |
| |
| const UnionMember* member = union_definition_.MemberWithOrdinal(ordinal); |
| if (member == nullptr) { |
| return std::make_unique<InvalidValue>(); |
| } |
| return std::make_unique<UnionValue>(*member, decoder->DecodeEnvelope(offset, member->type())); |
| } |
| |
| void UnionType::Visit(TypeVisitor* visitor) const { visitor->VisitUnionType(this); } |
| |
| std::string StructType::Name() const { return struct_definition_.name(); } |
| |
| std::string StructType::CppName() const { return FidlMethodNameToCpp(struct_definition_.name()); } |
| |
| size_t StructType::InlineSize() const { |
| return nullable_ ? sizeof(uintptr_t) : struct_definition_.size(); |
| } |
| |
| bool StructType::Nullable() const { return nullable_; } |
| |
| std::unique_ptr<Value> StructType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| if (nullable_) { |
| bool is_null; |
| uint64_t nullable_offset; |
| if (!decoder->DecodeNullableHeader(offset, struct_definition_.size(), &is_null, |
| &nullable_offset)) { |
| return std::make_unique<InvalidValue>(); |
| } |
| if (is_null) { |
| return std::make_unique<NullValue>(); |
| } |
| offset = nullable_offset; |
| } |
| return decoder->DecodeStruct(struct_definition_, offset); |
| } |
| |
| void StructType::Visit(TypeVisitor* visitor) const { visitor->VisitStructType(this); } |
| |
| const Type* ElementSequenceType::GetComponentType() const { return component_type_.get(); } |
| |
| void ElementSequenceType::Visit(TypeVisitor* visitor) const { |
| visitor->VisitElementSequenceType(this); |
| } |
| |
| bool ArrayType::IsArray() const { return true; } |
| |
| std::string ArrayType::Name() const { |
| return std::string("array<") + component_type_->Name() + ">"; |
| } |
| |
| std::string ArrayType::CppName() const { |
| return std::string("std::array<") + component_type_->CppName() + ", " + std::to_string(count()) + |
| ">"; |
| } |
| |
| void ArrayType::PrettyPrint(PrettyPrinter& printer) const { |
| printer << "array<" << Green << component_type_->Name() << ResetColor << ">"; |
| } |
| |
| size_t ArrayType::InlineSize() const { return component_type_->InlineSize() * count_; } |
| |
| std::unique_ptr<Value> ArrayType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| auto result = std::make_unique<VectorValue>(); |
| for (uint64_t i = 0; i < count_; ++i) { |
| result->AddValue(component_type_->Decode(decoder, offset)); |
| offset += component_type_->InlineSize(); |
| } |
| return result; |
| } |
| |
| void ArrayType::Visit(TypeVisitor* visitor) const { visitor->VisitArrayType(this); } |
| |
| std::string VectorType::Name() const { |
| return std::string("vector<") + component_type_->Name() + ">"; |
| } |
| |
| std::string VectorType::CppName() const { |
| return std::string("std::vector<") + component_type_->CppName() + ">"; |
| } |
| |
| void VectorType::PrettyPrint(PrettyPrinter& printer) const { |
| printer << "vector<" << Green << component_type_->Name() << ResetColor << ">"; |
| } |
| |
| size_t VectorType::InlineSize() const { return sizeof(uint64_t) + sizeof(uint64_t); } |
| |
| bool VectorType::Nullable() const { return true; } |
| |
| std::unique_ptr<Value> VectorType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| uint64_t element_count = 0; |
| decoder->GetValueAt(offset, &element_count); |
| offset += sizeof(element_count); |
| bool is_null; |
| uint64_t nullable_offset; |
| if (!decoder->DecodeNullableHeader(offset, element_count * component_type_->InlineSize(), |
| &is_null, &nullable_offset)) { |
| return std::make_unique<InvalidValue>(); |
| } |
| if (is_null) { |
| return std::make_unique<NullValue>(); |
| } |
| |
| size_t component_size = component_type_->InlineSize(); |
| auto result = std::make_unique<VectorValue>(); |
| for (uint64_t i = 0; |
| (i < element_count) && (nullable_offset + component_size <= decoder->num_bytes()); ++i) { |
| result->AddValue(component_type_->Decode(decoder, nullable_offset)); |
| nullable_offset += component_size; |
| } |
| return result; |
| } |
| |
| void VectorType::Visit(TypeVisitor* visitor) const { visitor->VisitVectorType(this); } |
| |
| std::string TableType::Name() const { return table_definition_.name(); } |
| |
| std::string TableType::CppName() const { return FidlMethodNameToCpp(table_definition_.name()); } |
| |
| size_t TableType::InlineSize() const { |
| // A table is always implemented as a size + a pointer. |
| return 2 * sizeof(uint64_t); |
| } |
| |
| std::unique_ptr<Value> TableType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| uint64_t member_count = 0; |
| decoder->GetValueAt(offset, &member_count); |
| offset += sizeof(member_count); |
| |
| bool is_null; |
| uint64_t nullable_offset; |
| constexpr size_t kEnvelopeSize = 2 * sizeof(uint32_t) + sizeof(uint64_t); |
| if (!decoder->DecodeNullableHeader(offset, member_count * kEnvelopeSize, &is_null, |
| &nullable_offset)) { |
| return std::make_unique<InvalidValue>(); |
| } |
| if (is_null) { |
| decoder->AddError() << "Tables are not nullable."; |
| return std::make_unique<InvalidValue>(); |
| } |
| auto result = std::make_unique<TableValue>(table_definition_); |
| for (uint64_t i = 1; i <= member_count; ++i) { |
| const TableMember* member = table_definition_.GetMember(i); |
| if ((member == nullptr) || member->reserved()) { |
| decoder->SkipEnvelope(nullable_offset); |
| } else { |
| std::unique_ptr<Value> value = decoder->DecodeEnvelope(nullable_offset, member->type()); |
| if (!value->IsNull()) { |
| result->AddMember(member, std::move(value)); |
| } |
| } |
| nullable_offset += kEnvelopeSize; |
| } |
| return result; |
| } |
| |
| void TableType::Visit(TypeVisitor* visitor) const { visitor->VisitTableType(this); } |
| |
| std::string FidlMessageType::Name() const { return "fidl-message"; } |
| |
| size_t FidlMessageType::InlineSize() const { return 0; } |
| |
| std::unique_ptr<Value> FidlMessageType::Decode(MessageDecoder* decoder, uint64_t offset) const { |
| return nullptr; |
| } |
| |
| void FidlMessageType::Visit(TypeVisitor* visitor) const { visitor->VisitFidlMessageType(this); } |
| |
| std::unique_ptr<Type> Type::ScalarTypeFromName(const std::string& type_name) { |
| static std::map<std::string, std::function<std::unique_ptr<Type>()>> scalar_type_map_{ |
| {"bool", []() { return std::make_unique<BoolType>(); }}, |
| {"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>(); }}, |
| {"float32", []() { return std::make_unique<Float32Type>(); }}, |
| {"float64", []() { return std::make_unique<Float64Type>(); }}, |
| }; |
| auto it = scalar_type_map_.find(type_name); |
| if (it != scalar_type_map_.end()) { |
| return it->second(); |
| } |
| return std::make_unique<InvalidType>(); |
| } |
| |
| std::unique_ptr<Type> Type::TypeFromPrimitive(const rapidjson::Value& type) { |
| if (!type.HasMember("subtype")) { |
| FX_LOGS_OR_CAPTURE(ERROR) << "Invalid type"; |
| return std::make_unique<InvalidType>(); |
| } |
| |
| std::string subtype = type["subtype"].GetString(); |
| return ScalarTypeFromName(subtype); |
| } |
| |
| std::unique_ptr<Type> Type::TypeFromIdentifier(LibraryLoader* loader, |
| const rapidjson::Value& type) { |
| if (!type.HasMember("identifier")) { |
| FX_LOGS_OR_CAPTURE(ERROR) << "Invalid type"; |
| return std::make_unique<InvalidType>(); |
| } |
| 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) { |
| FX_LOGS_OR_CAPTURE(ERROR) << "Unknown type for identifier: " << library_name; |
| return std::make_unique<InvalidType>(); |
| } |
| |
| bool is_nullable = false; |
| if (type.HasMember("nullable")) { |
| is_nullable = type["nullable"].GetBool(); |
| } |
| return library->TypeFromIdentifier(is_nullable, id); |
| } |
| |
| std::unique_ptr<Type> Type::GetType(LibraryLoader* loader, const rapidjson::Value& type) { |
| if (!type.HasMember("kind")) { |
| FX_LOGS_OR_CAPTURE(ERROR) << "Invalid type"; |
| return std::make_unique<InvalidType>(); |
| } |
| std::string kind = type["kind"].GetString(); |
| if (kind == "string") { |
| return std::make_unique<StringType>(); |
| } |
| if (kind == "handle") { |
| return std::make_unique<HandleType>(); |
| } |
| if (kind == "array") { |
| const rapidjson::Value& element_type = type["element_type"]; |
| uint32_t element_count = static_cast<uint32_t>( |
| std::strtol(type["element_count"].GetString(), nullptr, kDecimalBase)); |
| return std::make_unique<ArrayType>(GetType(loader, element_type), element_count); |
| } |
| if (kind == "vector") { |
| const rapidjson::Value& element_type = type["element_type"]; |
| return std::make_unique<VectorType>(GetType(loader, element_type)); |
| } |
| if (kind == "request") { |
| return std::make_unique<HandleType>(); |
| } |
| if (kind == "primitive") { |
| return Type::TypeFromPrimitive(type); |
| } |
| if (kind == "identifier") { |
| return Type::TypeFromIdentifier(loader, type); |
| } |
| FX_LOGS_OR_CAPTURE(ERROR) << "Invalid type " << kind; |
| return std::make_unique<InvalidType>(); |
| } |
| |
| } // namespace fidl_codec |