| // 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_object.h" |
| |
| #include <iomanip> |
| #include <iostream> |
| #include <memory> |
| #include <vector> |
| |
| #include "src/lib/fidl_codec/display_handle.h" |
| #include "src/lib/fidl_codec/json_visitor.h" |
| #include "src/lib/fidl_codec/library_loader.h" |
| #include "src/lib/fidl_codec/printer.h" |
| #include "src/lib/fidl_codec/visitor.h" |
| #include "src/lib/fidl_codec/wire_types.h" |
| #include "src/lib/fxl/logging.h" |
| |
| namespace fidl_codec { |
| |
| void InvalidValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitInvalidValue(this, for_type); |
| } |
| |
| void NullValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitNullValue(this, for_type); |
| } |
| |
| int RawValue::DisplaySize(const Type* /*for_type*/, int /*remaining_size*/) const { |
| return (data_.size() == 0) ? 0 : static_cast<int>(data_.size()) * 3 - 1; |
| } |
| |
| void RawValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| if (data_.size() == 0) { |
| return; |
| } |
| size_t buffer_size = data_.size() * 3; |
| std::vector<char> buffer(buffer_size); |
| for (size_t i = 0; i < data_.size(); ++i) { |
| if (i != 0) { |
| buffer[i * 3 - 1] = ' '; |
| } |
| snprintf(buffer.data() + (i * 3), 4, "%02x", data_[i]); |
| } |
| printer << buffer.data(); |
| } |
| |
| void RawValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitRawValue(this, for_type); |
| } |
| |
| int BoolValue::DisplaySize(const Type* /*for_type*/, int /*remaining_size*/) const { |
| constexpr int kTrueSize = 4; |
| constexpr int kFalseSize = 5; |
| return value_ ? kTrueSize : kFalseSize; |
| } |
| |
| void BoolValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| printer << Blue << (value_ ? "true" : "false") << ResetColor; |
| } |
| |
| void BoolValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitBoolValue(this, for_type); |
| } |
| |
| uint8_t IntegerValue::GetUint8Value() const { |
| return (!negative_ && (absolute_value_ < 0x100)) ? static_cast<uint8_t>(absolute_value_) : 0; |
| } |
| |
| int IntegerValue::DisplaySize(const Type* for_type, int /*remaining_size*/) const { |
| bool sign_size = negative_ ? 1 : 0; |
| return std::to_string(absolute_value_).size() + sign_size; |
| } |
| |
| void IntegerValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| FXL_DCHECK(for_type != nullptr); |
| for_type->PrettyPrint(this, printer); |
| } |
| |
| void IntegerValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitIntegerValue(this, for_type); |
| } |
| |
| int DoubleValue::DisplaySize(const Type* for_type, int /*remaining_size*/) const { |
| return std::to_string(value_).size(); |
| } |
| |
| void DoubleValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| FXL_DCHECK(for_type != nullptr); |
| for_type->PrettyPrint(this, printer); |
| } |
| |
| void DoubleValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitDoubleValue(this, for_type); |
| } |
| |
| int StringValue::DisplaySize(const Type* /*for_type*/, int /*remaining_size*/) const { |
| return static_cast<int>(string_.size()) + 2; // The two quotes. |
| } |
| |
| void StringValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| printer << Red << '"' << string_ << '"' << ResetColor; |
| } |
| |
| void StringValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitStringValue(this, for_type); |
| } |
| |
| int HandleValue::DisplaySize(const Type* /*for_type*/, int /*remaining_size*/) const { |
| return std::to_string(handle_.handle).size(); |
| } |
| |
| void HandleValue::PrettyPrint(const Type* /*for_type*/, PrettyPrinter& printer) const { |
| printer.DisplayHandle(handle_); |
| } |
| |
| void HandleValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitHandleValue(this, for_type); |
| } |
| |
| int UnionValue::DisplaySize(const Type* for_type, int remaining_size) const { |
| // Two characters for the opening brace ("{ ") + three characters for equal |
| // (" = ") and two characters for the closing brace (" }"). |
| constexpr int kExtraSize = 7; |
| int size = static_cast<int>(member_.name().size()) + kExtraSize; |
| // Two characters for ": ". |
| size += static_cast<int>(member_.type()->Name().size()) + 2; |
| size += value_->DisplaySize(member_.type(), remaining_size - size); |
| return size; |
| } |
| |
| void UnionValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| if (DisplaySize(for_type, printer.remaining_size()) <= printer.remaining_size()) { |
| std::string type_name = member_.type()->Name(); |
| printer << "{ " << member_.name() << ": " << Green << type_name << ResetColor << " = "; |
| value_->PrettyPrint(member_.type(), printer); |
| printer << " }"; |
| } else { |
| std::string type_name = member_.type()->Name(); |
| printer << "{\n"; |
| { |
| Indent indent(printer); |
| printer << member_.name() << ": " << Green << type_name << ResetColor << " = "; |
| value_->PrettyPrint(member_.type(), printer); |
| printer << '\n'; |
| } |
| printer << "}"; |
| } |
| } |
| |
| void UnionValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitUnionValue(this, for_type); |
| } |
| |
| int StructValue::DisplaySize(const Type* for_type, int remaining_size) const { |
| int size = 0; |
| for (const auto& member : struct_definition_.members()) { |
| auto it = fields_.find(member.get()); |
| if (it == fields_.end()) |
| continue; |
| // Two characters for the separator ("{ " or ", ") and three characters for |
| // equal (" = "). |
| constexpr int kExtraSize = 5; |
| size += static_cast<int>(member->name().size()) + kExtraSize; |
| // Two characters for ": ". |
| size += static_cast<int>(member->type()->Name().size()) + 2; |
| size += it->second->DisplaySize(member->type(), remaining_size - size); |
| if (size > remaining_size) { |
| return size; |
| } |
| } |
| // Two characters for the closing brace (" }"). |
| size += 2; |
| return size; |
| } |
| |
| void StructValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| if (fields_.empty()) { |
| printer << "{}"; |
| } else if (DisplaySize(for_type, printer.remaining_size()) <= printer.remaining_size()) { |
| const char* separator = "{ "; |
| for (const auto& member : struct_definition_.members()) { |
| auto it = fields_.find(member.get()); |
| if (it == fields_.end()) |
| continue; |
| printer << separator << member->name() << ": " << Green << member->type()->Name() |
| << ResetColor << " = "; |
| it->second->PrettyPrint(member->type(), printer); |
| separator = ", "; |
| } |
| printer << " }"; |
| } else { |
| printer << "{\n"; |
| { |
| Indent indent(printer); |
| for (const auto& member : struct_definition_.members()) { |
| auto it = fields_.find(member.get()); |
| if (it == fields_.end()) |
| continue; |
| std::string type_name = member->type()->Name(); |
| printer << member->name() << ": " << Green << type_name << ResetColor << " = "; |
| it->second->PrettyPrint(member->type(), printer); |
| printer << "\n"; |
| } |
| } |
| printer << '}'; |
| } |
| } |
| |
| void StructValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitStructValue(this, for_type); |
| } |
| |
| void StructValue::ExtractJson(rapidjson::Document::AllocatorType& allocator, |
| rapidjson::Value& result) const { |
| JsonVisitor visitor(&result, &allocator); |
| |
| Visit(&visitor, nullptr); |
| } |
| |
| int VectorValue::DisplaySize(const Type* for_type, int remaining_size) const { |
| FXL_DCHECK(for_type != nullptr); |
| if (values_.empty()) { |
| return 2; // The two brackets. |
| } |
| if (is_string_) { |
| return static_cast<int>(values_.size() + 2); // The string and the two quotes. |
| } |
| const Type* component_type = for_type->GetComponentType(); |
| FXL_DCHECK(component_type != nullptr); |
| int size = 0; |
| for (const auto& value : values_) { |
| // Two characters for the separator ("[ " or ", "). |
| size += value->DisplaySize(component_type, remaining_size - size) + 2; |
| if (size > remaining_size) { |
| return size; |
| } |
| } |
| // Two characters for the closing bracket (" ]"). |
| size += 2; |
| return size; |
| } |
| |
| void VectorValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| FXL_DCHECK(for_type != nullptr); |
| if (values_.empty()) { |
| printer << "[]"; |
| } else if (is_string_) { |
| if (has_new_line_) { |
| printer << "[\n"; |
| { |
| Indent indent(printer); |
| for (const auto& value : values_) { |
| printer << static_cast<char>(value->GetUint8Value()); |
| } |
| } |
| printer << '\n'; |
| printer << ']'; |
| } else { |
| printer << '"'; |
| for (const auto& value : values_) { |
| printer << static_cast<char>(value->GetUint8Value()); |
| } |
| printer << '"'; |
| } |
| } else if (DisplaySize(for_type, printer.remaining_size()) <= printer.remaining_size()) { |
| const Type* component_type = for_type->GetComponentType(); |
| FXL_DCHECK(component_type != nullptr); |
| const char* separator = "[ "; |
| for (const auto& value : values_) { |
| printer << separator; |
| separator = ", "; |
| value->PrettyPrint(component_type, printer); |
| } |
| printer << " ]"; |
| } else { |
| const Type* component_type = for_type->GetComponentType(); |
| FXL_DCHECK(component_type != nullptr); |
| printer << "[\n"; |
| { |
| Indent indent(printer); |
| for (const auto& value : values_) { |
| int value_size = value->DisplaySize(component_type, printer.remaining_size()); |
| if (!printer.LineEmpty()) { |
| if (value_size + 3 > printer.remaining_size()) { |
| printer << "\n"; |
| } else { |
| printer << ", "; |
| } |
| } |
| value->PrettyPrint(component_type, printer); |
| } |
| printer << '\n'; |
| } |
| printer << ']'; |
| } |
| } |
| |
| void VectorValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitVectorValue(this, for_type); |
| } |
| |
| bool TableValue::AddMember(std::string_view name, std::unique_ptr<Value> value) { |
| const TableMember* member = table_definition_.GetMember(name); |
| if (member == nullptr) { |
| return false; |
| } |
| AddMember(member, std::move(value)); |
| return true; |
| } |
| |
| int TableValue::DisplaySize(const Type* for_type, int remaining_size) const { |
| int size = 0; |
| for (const auto& member : table_definition_.members()) { |
| if ((member != nullptr) && !member->reserved()) { |
| auto it = members_.find(member.get()); |
| if ((it == members_.end()) || it->second->IsNull()) |
| continue; |
| // Two characters for the separator ("{ " or ", "), three characters for " = ". |
| size += static_cast<int>(member->name().size()) + 2 + 3; |
| // Two characters for ": ". |
| size += static_cast<int>(member->type()->Name().size()) + 2; |
| size += it->second->DisplaySize(member->type(), remaining_size - size); |
| if (size > remaining_size) { |
| return size; |
| } |
| } |
| } |
| // Two characters for the closing brace (" }"). |
| size += 2; |
| return size; |
| } |
| |
| void TableValue::PrettyPrint(const Type* for_type, PrettyPrinter& printer) const { |
| int display_size = DisplaySize(for_type, printer.remaining_size()); |
| if (display_size == 2) { |
| printer << "{}"; |
| } else if (display_size <= printer.remaining_size()) { |
| const char* separator = "{ "; |
| for (const auto& member : table_definition_.members()) { |
| if ((member != nullptr) && !member->reserved()) { |
| auto it = members_.find(member.get()); |
| if ((it == members_.end()) || it->second->IsNull()) |
| continue; |
| printer << separator << member->name() << ": " << Green << member->type()->Name() |
| << ResetColor << " = "; |
| separator = ", "; |
| it->second->PrettyPrint(member->type(), printer); |
| } |
| } |
| printer << " }"; |
| } else { |
| printer << "{\n"; |
| { |
| Indent indent(printer); |
| for (const auto& member : table_definition_.members()) { |
| if ((member != nullptr) && !member->reserved()) { |
| auto it = members_.find(member.get()); |
| if ((it == members_.end()) || it->second->IsNull()) |
| continue; |
| std::string type_name = member->type()->Name(); |
| printer << member->name() << ": " << Green << type_name << ResetColor << " = "; |
| it->second->PrettyPrint(member->type(), printer); |
| printer << "\n"; |
| } |
| } |
| } |
| printer << '}'; |
| } |
| } |
| |
| void TableValue::Visit(Visitor* visitor, const Type* for_type) const { |
| visitor->VisitTableValue(this, for_type); |
| } |
| |
| } // namespace fidl_codec |