| // 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. |
| |
| #ifndef SRC_LIB_FIDL_CODEC_WIRE_OBJECT_H_ |
| #define SRC_LIB_FIDL_CODEC_WIRE_OBJECT_H_ |
| |
| #include <lib/fidl/cpp/message.h> |
| |
| #include <map> |
| #include <memory> |
| #include <string_view> |
| #include <vector> |
| |
| #include "src/lib/fidl_codec/library_loader.h" |
| #include "src/lib/fidl_codec/message_decoder.h" |
| #include "src/lib/fxl/logging.h" |
| |
| namespace fidl_codec { |
| |
| class Visitor; |
| |
| // Base class for all the values we can find within a message. |
| class Value { |
| public: |
| Value(const Type* type) : type_(type) {} |
| virtual ~Value() = default; |
| |
| const Type* type() const { return type_; } |
| |
| virtual bool is_null() const { return false; } |
| |
| // Returns the size needed to display the value. If the needed size is |
| // greater than |remaining_size|, the return value can be anything greater |
| // than |remaining_size| and the only useful information is that the value |
| // can't fit in |remaining_size|. |
| // Remaining size is just an optimization parameter. It avoids to compute the |
| // whole display size for an object: the computation is stopped as soon as we |
| // find that the object doesn't fit. |
| virtual int DisplaySize(int remaining_size) const = 0; |
| |
| // Returns the uint8_t value of the value. If the value is not a uint8_t value this returns zero. |
| // This is used to eventually display a vector of uint8_t values as a string. |
| virtual uint8_t GetUint8Value() const { return 0; } |
| |
| // Decode the extra content of the value (in a secondary object). |
| virtual void DecodeContent(MessageDecoder* decoder, uint64_t offset) = 0; |
| |
| // Pretty print of the value. |
| virtual void PrettyPrint(std::ostream& os, const Colors& colors, |
| const fidl_message_header_t* header, std::string_view line_header, |
| int tabs, int remaining_size, int max_line_size) const = 0; |
| |
| // Use a visitor on this value; |
| virtual void Visit(Visitor* visitor) const = 0; |
| |
| private: |
| const Type* const type_; |
| }; |
| |
| // A name-value pair. |
| class Field { |
| public: |
| Field() = default; |
| Field(const std::string& name, std::unique_ptr<Value> value) |
| : name_(name), value_(std::move(value)) {} |
| |
| const std::string& name() const { return name_; } |
| const std::unique_ptr<Value>& value() const { return value_; } |
| |
| private: |
| std::string name_; |
| std::unique_ptr<Value> value_; |
| }; |
| |
| // Base class for values which are nullable. |
| class NullableValue : public Value { |
| public: |
| NullableValue(const Type* type) : Value(type) {} |
| |
| bool is_null() const override { return is_null_; } |
| |
| bool DecodeNullable(MessageDecoder* decoder, uint64_t offset, uint64_t size); |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| bool is_null_ = false; |
| }; |
| |
| // A name-value pair where the value is nullable. |
| class NullableField { |
| public: |
| NullableField() = default; |
| NullableField(const std::string& name, std::unique_ptr<NullableValue> value) |
| : name_(name), value_(std::move(value)) {} |
| |
| const std::string& name() const { return name_; } |
| const std::unique_ptr<NullableValue>& value() const { return value_; } |
| |
| private: |
| std::string name_; |
| std::unique_ptr<NullableValue> value_; |
| }; |
| |
| // Base class for inlined values (the data is not in a secondary object). |
| class InlineValue : public Value { |
| public: |
| InlineValue(const Type* type) : Value(type) {} |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void Visit(Visitor* visitor) const override; |
| }; |
| |
| // A value with no known representation (we only print the raw data). |
| class RawValue : public InlineValue { |
| public: |
| RawValue(const Type* type, std::optional<std::vector<uint8_t>> data) |
| : InlineValue(type), data_(std::move(data)) {} |
| |
| const std::optional<std::vector<uint8_t>>& data() const { return data_; } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| std::optional<std::vector<uint8_t>> data_; |
| }; |
| |
| // All numeric values (integer and floating point numbers). |
| template <typename T> |
| class NumericValue : public InlineValue { |
| public: |
| explicit NumericValue(const Type* type, std::optional<T> value = std::nullopt) |
| : InlineValue(type), value_(std::move(value)) {} |
| explicit NumericValue(const Type* type, const T* value) |
| : NumericValue(type, value ? std::optional(*value) : std::nullopt) {} |
| |
| std::optional<T> value() const { return value_; } |
| |
| int DisplaySize(int remaining_size) const override { |
| if (value_) { |
| return std::to_string(*value_).size(); |
| } else { |
| return 7; // length of "invalid" |
| } |
| } |
| |
| uint8_t GetUint8Value() const override { |
| return (sizeof(T) == 1 && value_) ? static_cast<uint8_t>(*value_) : 0; |
| } |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override { |
| if (value_) { |
| os << colors.blue << std::to_string(*value_) << colors.reset; |
| } else { |
| os << colors.red << "invalid" << colors.reset; |
| } |
| } |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| std::optional<T> value_; |
| }; |
| |
| // A string value. |
| class StringValue : public NullableValue { |
| public: |
| StringValue(const Type* type, std::string str) |
| : NullableValue(type), string_length_(str.size()), string_(str) {} |
| StringValue(const Type* type, size_t string_length) |
| : NullableValue(type), string_length_(string_length), string_(std::nullopt) {} |
| |
| const std::optional<std::string>& string() const { return string_; } |
| size_t size() const { return string_length_; } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| size_t string_length_; |
| std::optional<std::string> string_; |
| }; |
| |
| // A Boolean value. |
| class BoolValue : public InlineValue { |
| public: |
| BoolValue(const Type* type, std::optional<uint8_t> value) |
| : InlineValue(type), value_(std::move(value)) {} |
| BoolValue(const Type* type, const uint8_t* value) |
| : BoolValue(type, value ? std::optional(*value) : std::nullopt) {} |
| |
| const std::optional<uint8_t> value() const { return value_; } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| std::optional<uint8_t> value_; |
| }; |
| |
| // An object. This represents a struct, a request or a response. |
| class Object : public NullableValue { |
| public: |
| Object(const Type* type, const Struct& struct_definition) |
| : NullableValue(type), struct_definition_(struct_definition) {} |
| |
| const std::map<std::string, std::unique_ptr<Value>>& fields() const { return fields_; } |
| const Struct& struct_definition() const { return struct_definition_; } |
| |
| void AddField(const std::string& field_name, std::unique_ptr<Value> value) { |
| fields_.emplace(std::make_pair(field_name, std::move(value))); |
| } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void DecodeAt(MessageDecoder* decoder, uint64_t base_offset); |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| // Extract the JSON for this object. |
| void ExtractJson(rapidjson::Document::AllocatorType& allocator, rapidjson::Value& result) const; |
| |
| private: |
| const Struct& struct_definition_; |
| std::map<std::string, std::unique_ptr<Value>> fields_; |
| }; |
| |
| // An envelope (used by TableValue and XUnion). |
| class EnvelopeValue : public NullableValue { |
| public: |
| EnvelopeValue(const Type* type); |
| |
| uint32_t num_bytes() const { return num_bytes_; } |
| uint32_t num_handles() const { return num_handles_; } |
| const Value* value() const { return value_.get(); } |
| void set_value(std::unique_ptr<Value> value) { value_ = std::move(value); } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void DecodeAt(MessageDecoder* decoder, uint64_t base_offset); |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| uint32_t num_bytes_ = 0; |
| uint32_t num_handles_ = 0; |
| std::unique_ptr<Value> value_ = nullptr; |
| }; |
| |
| // A table. |
| class TableValue : public NullableValue { |
| public: |
| TableValue(const Type* type, const Table& table_definition, uint64_t envelope_count); |
| |
| const std::vector<NullableField>& envelopes() const { return envelopes_; } |
| |
| void AddField(const std::string& field_name, std::unique_ptr<NullableValue> value) { |
| envelopes_.emplace_back(field_name, std::move(value)); |
| } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void DecodeAt(MessageDecoder* decoder, uint64_t base_offset); |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| const Table& table_definition_; |
| const uint64_t envelope_count_; |
| std::vector<NullableField> envelopes_; |
| }; |
| |
| // An union. |
| class UnionValue : public NullableValue { |
| public: |
| UnionValue(const Type* type, const Union& union_definition) |
| : NullableValue(type), union_definition_(union_definition) {} |
| |
| const Union& definition() const { return union_definition_; } |
| |
| const Field& field() const { return field_; } |
| void set_field(Field field) { field_ = std::move(field); } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void DecodeAt(MessageDecoder* decoder, uint64_t base_offset); |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| const Union& union_definition_; |
| Field field_; |
| }; |
| |
| // An xunion. |
| class XUnionValue : public UnionValue { |
| public: |
| XUnionValue(const Type* type, const Union& xunion_definition) |
| : UnionValue(type, xunion_definition) {} |
| |
| void Visit(Visitor* visitor) const override; |
| }; |
| |
| // An array. |
| class ArrayValue : public Value { |
| public: |
| ArrayValue(const Type* type) : Value(type) {} |
| |
| const std::vector<std::unique_ptr<Value>>& values() const { return values_; } |
| |
| void AddValue(std::unique_ptr<Value> value) { values_.push_back(std::move(value)); } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| std::vector<std::unique_ptr<Value>> values_; |
| }; |
| |
| // A vector. |
| class VectorValue : public NullableValue { |
| public: |
| VectorValue(const Type* type, uint64_t size, const Type* component_type) |
| : NullableValue(type), size_(size), component_type_(component_type) {} |
| |
| size_t size() const { return size_; } |
| const std::vector<std::unique_ptr<Value>>& values() const { return values_; } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| const uint64_t size_; |
| const Type* const component_type_; |
| std::vector<std::unique_ptr<Value>> values_; |
| bool is_string_ = false; |
| bool has_new_line_ = false; |
| }; |
| |
| // An enum. |
| class EnumValue : public InlineValue { |
| public: |
| EnumValue(const Type* type, std::optional<std::vector<uint8_t>> data, const Enum& enum_definition) |
| : InlineValue(type), enum_definition_(enum_definition), data_(std::move(data)) {} |
| |
| const std::optional<std::vector<uint8_t>>& data() const { return data_; } |
| |
| const Enum& enum_definition() const { return enum_definition_; }; |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| const Enum& enum_definition_; |
| std::optional<std::vector<uint8_t>> data_; |
| }; |
| |
| // Bits. |
| class BitsValue : public InlineValue { |
| public: |
| BitsValue(const Type* type, std::optional<std::vector<uint8_t>> data, const Bits& bits_definition) |
| : InlineValue(type), bits_definition_(bits_definition), data_(std::move(data)) {} |
| |
| const std::optional<std::vector<uint8_t>>& data() const { return data_; } |
| |
| const Bits& bits_definition() const { return bits_definition_; }; |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| const Bits& bits_definition_; |
| std::optional<std::vector<uint8_t>> data_; |
| }; |
| |
| // A handle. |
| class HandleValue : public Value { |
| public: |
| HandleValue(const Type* type, const zx_handle_info_t& handle) : Value(type), handle_(handle) {} |
| |
| const zx_handle_info_t& handle() const { return handle_; } |
| |
| int DisplaySize(int remaining_size) const override; |
| |
| void DecodeContent(MessageDecoder* decoder, uint64_t offset) override; |
| |
| void PrettyPrint(std::ostream& os, const Colors& colors, const fidl_message_header_t* header, |
| std::string_view line_header, int tabs, int remaining_size, |
| int max_line_size) const override; |
| |
| void Visit(Visitor* visitor) const override; |
| |
| private: |
| const zx_handle_info_t handle_; |
| }; |
| |
| } // namespace fidl_codec |
| |
| #endif // SRC_LIB_FIDL_CODEC_WIRE_OBJECT_H_ |