blob: ba8f0834724bc7f0790a1ddb707ac807a3b52808 [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 "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/wire_object.h"
#include "src/lib/fxl/logging.h"
// See wire_types.h for details.
namespace fidl_codec {
bool Type::ValueEquals(const uint8_t* /*bytes*/, size_t /*length*/,
const rapidjson::Value& /*value*/) const {
FXL_LOG(FATAL) << "Equality operator for type not implemented";
return false;
}
bool Type::ValueHas(const uint8_t* /*bytes*/, const rapidjson::Value& /*value*/) const {
FXL_LOG(FATAL) << "ValueHas not implemented";
return false;
}
size_t Type::InlineSize(MessageDecoder* decoder) const {
FXL_LOG(FATAL) << "Size for type not implemented";
return 0;
}
std::unique_ptr<Value> Type::Decode(MessageDecoder* /*decoder*/, uint64_t /*offset*/) const {
FXL_LOG(ERROR) << "Decode not implemented for field";
return nullptr;
}
std::unique_ptr<Value> RawType::Decode(MessageDecoder* decoder, uint64_t offset) const {
return std::make_unique<RawValue>(this, decoder->CopyAddress(offset, inline_size_));
}
std::unique_ptr<Value> StringType::Decode(MessageDecoder* decoder, uint64_t offset) const {
uint64_t string_length = 0;
decoder->GetValueAt(offset, &string_length);
// Here, we test two conditions:
// - the string is a little bit too big and there is not enough data remaining.
// - the string is huge (typically max ulong) and wouldn't fit in the whole buffer.
// In that case, the first condition is not triggered because adding offset to this
// huge number overflows and creates a small number.
if ((offset + string_length > decoder->num_bytes()) || (string_length > decoder->num_bytes())) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec
<< ": Not enough data for string (missing "
<< (offset + string_length - decoder->num_bytes()) << " bytes)\n";
return std::make_unique<StringValue>(this, 0);
}
offset += sizeof(string_length);
auto result = std::make_unique<StringValue>(this, string_length);
// Don't need to check return value because the effects of returning false are
// dealt with in DecodeNullable.
result->DecodeNullable(decoder, offset, string_length);
return result;
}
std::unique_ptr<Value> BoolType::Decode(MessageDecoder* decoder, uint64_t offset) const {
auto byte = decoder->GetAddress(offset, sizeof(uint8_t));
return std::make_unique<BoolValue>(this, byte ? std::optional(*byte) : std::nullopt);
}
size_t StructType::InlineSize(MessageDecoder* decoder) const {
return nullable_ ? sizeof(uintptr_t) : struct_.Size(decoder);
}
std::unique_ptr<Value> StructType::Decode(MessageDecoder* decoder, uint64_t offset) const {
return struct_.DecodeObject(decoder, this, offset, nullable_);
}
size_t TableType::InlineSize(MessageDecoder* decoder) const { return table_.size(); }
std::unique_ptr<Value> TableType::Decode(MessageDecoder* decoder, uint64_t offset) const {
uint64_t size = 0;
decoder->GetValueAt(offset, &size);
offset += sizeof(size);
auto result = std::make_unique<TableValue>(this, table_, size);
if (result->DecodeNullable(decoder, offset, size * 2 * sizeof(uint64_t))) {
if (result->is_null()) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec
<< ": Invalid null value for table pointer\n";
}
}
return result;
}
UnionType::UnionType(const Union& uni, bool nullable) : union_(uni), nullable_(nullable) {}
size_t UnionType::InlineSize(MessageDecoder* decoder) const {
FXL_DCHECK(decoder != nullptr);
if (decoder->unions_are_xunions()) {
// In v1, unions are encoded as xunion. The inline size is the size of an envelope which
// is always 24 bytes.
return 24;
}
return nullable_ ? sizeof(uintptr_t) : union_.size();
}
std::unique_ptr<Value> UnionType::Decode(MessageDecoder* decoder, uint64_t offset) const {
return decoder->unions_are_xunions() ? union_.DecodeXUnion(decoder, this, offset, nullable_)
: union_.DecodeUnion(decoder, this, offset, nullable_);
}
XUnionType::XUnionType(const XUnion& uni, bool nullable) : xunion_(uni), nullable_(nullable) {}
size_t XUnionType::InlineSize(MessageDecoder* decoder) const { return xunion_.size(); }
std::unique_ptr<Value> XUnionType::Decode(MessageDecoder* decoder, uint64_t offset) const {
return xunion_.DecodeXUnion(decoder, this, offset, nullable_);
}
ElementSequenceType::ElementSequenceType(std::unique_ptr<Type>&& component_type)
: component_type_(std::move(component_type)) {
FXL_DCHECK(component_type_.get() != nullptr);
}
ArrayType::ArrayType(std::unique_ptr<Type>&& component_type, uint32_t count)
: ElementSequenceType(std::move(component_type)), count_(count) {}
std::unique_ptr<Value> ArrayType::Decode(MessageDecoder* decoder, uint64_t offset) const {
auto result = std::make_unique<ArrayValue>(this);
for (uint64_t i = 0; i < count_; ++i) {
result->AddValue(component_type_->Decode(decoder, offset));
offset += component_type_->InlineSize(decoder);
}
return result;
}
VectorType::VectorType(std::unique_ptr<Type>&& component_type)
: ElementSequenceType(std::move(component_type)) {}
std::unique_ptr<Value> VectorType::Decode(MessageDecoder* decoder, uint64_t offset) const {
uint64_t size = 0;
decoder->GetValueAt(offset, &size);
offset += sizeof(size);
auto result = std::make_unique<VectorValue>(this, size, component_type_.get());
// Don't need to check return value because the effects of returning false are
// dealt with in DecodeNullable.
result->DecodeNullable(decoder, offset, size * component_type_->InlineSize(decoder));
return result;
}
EnumType::EnumType(const Enum& e) : enum_(e) {}
std::unique_ptr<Value> EnumType::Decode(MessageDecoder* decoder, uint64_t offset) const {
return std::make_unique<EnumValue>(this, decoder->CopyAddress(offset, enum_.size()), enum_);
}
BitsType::BitsType(const Bits& b) : bits_(b) {}
std::unique_ptr<Value> BitsType::Decode(MessageDecoder* decoder, uint64_t offset) const {
return std::make_unique<BitsValue>(this, decoder->CopyAddress(offset, bits_.size()), bits_);
}
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;
}
zx_handle_info_t handle_info;
if (handle == FIDL_HANDLE_ABSENT) {
handle_info.handle = FIDL_HANDLE_ABSENT;
handle_info.type = ZX_OBJ_TYPE_NONE;
handle_info.rights = 0;
} else {
handle_info = decoder->GetNextHandle();
}
return std::make_unique<HandleValue>(this, handle_info);
}
std::unique_ptr<Type> Type::ScalarTypeFromName(const std::string& type_name, size_t inline_size) {
static std::map<std::string, std::function<std::unique_ptr<Type>()>> scalar_type_map_{
{"bool", []() { return std::make_unique<BoolType>(); }},
{"float32", []() { return std::make_unique<Float32Type>(); }},
{"float64", []() { return std::make_unique<Float64Type>(); }},
{"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>(); }},
};
auto it = scalar_type_map_.find(type_name);
if (it != scalar_type_map_.end()) {
return it->second();
}
return std::make_unique<RawType>(inline_size);
}
std::unique_ptr<Type> Type::TypeFromPrimitive(const rapidjson::Value& type, size_t inline_size) {
if (!type.HasMember("subtype")) {
FXL_LOG(ERROR) << "Invalid type";
return std::make_unique<RawType>(inline_size);
}
std::string subtype = type["subtype"].GetString();
return ScalarTypeFromName(subtype, inline_size);
}
std::unique_ptr<Type> Type::TypeFromIdentifier(LibraryLoader* loader, const rapidjson::Value& type,
size_t inline_size) {
if (!type.HasMember("identifier")) {
FXL_LOG(ERROR) << "Invalid type";
return std::make_unique<RawType>(inline_size);
}
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) {
FXL_LOG(ERROR) << "Unknown type for identifier: " << library_name;
return std::make_unique<RawType>(inline_size);
}
bool is_nullable = false;
if (type.HasMember("nullable")) {
is_nullable = type["nullable"].GetBool();
}
return library->TypeFromIdentifier(is_nullable, id, inline_size);
}
std::unique_ptr<Type> Type::GetType(LibraryLoader* loader, const rapidjson::Value& type,
size_t inline_size) {
if (!type.HasMember("kind")) {
FXL_LOG(ERROR) << "Invalid type";
return std::make_unique<RawType>(inline_size);
}
std::string kind = type["kind"].GetString();
if (kind == "array") {
const rapidjson::Value& element_type = type["element_type"];
uint32_t element_count = std::strtol(type["element_count"].GetString(), nullptr, kDecimalBase);
return std::make_unique<ArrayType>(GetType(loader, element_type, 0), element_count);
}
if (kind == "vector") {
const rapidjson::Value& element_type = type["element_type"];
return std::make_unique<VectorType>(GetType(loader, element_type, 0));
}
if (kind == "string") {
return std::make_unique<StringType>();
}
if (kind == "handle") {
return std::make_unique<HandleType>();
}
if (kind == "request") {
return std::make_unique<HandleType>();
}
if (kind == "primitive") {
return Type::TypeFromPrimitive(type, inline_size);
}
if (kind == "identifier") {
return Type::TypeFromIdentifier(loader, type, inline_size);
}
FXL_LOG(ERROR) << "Invalid type " << kind;
return std::make_unique<RawType>(inline_size);
}
} // namespace fidl_codec