| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // This file contains what would normally be standard_codec_serializer.cc, | |
| // standard_message_codec.cc, and standard_method_codec.cc. They are grouped | |
| // together to simplify use of the client wrapper, since the common case is | |
| // that any client that needs one of these files needs all three. | |
| #include <cassert> | |
| #include <cstring> | |
| #include <iostream> | |
| #include <map> | |
| #include <string> | |
| #include <vector> | |
| #include "byte_buffer_streams.h" | |
| #include "include/flutter/standard_codec_serializer.h" | |
| #include "include/flutter/standard_message_codec.h" | |
| #include "include/flutter/standard_method_codec.h" | |
| namespace flutter { | |
| // ===== standard_codec_serializer.h ===== | |
| namespace { | |
| // The order/values here must match the constants in message_codecs.dart. | |
| enum class EncodedType { | |
| kNull = 0, | |
| kTrue, | |
| kFalse, | |
| kInt32, | |
| kInt64, | |
| kLargeInt, // No longer used. If encountered, treat as kString. | |
| kFloat64, | |
| kString, | |
| kUInt8List, | |
| kInt32List, | |
| kInt64List, | |
| kFloat64List, | |
| kList, | |
| kMap, | |
| kFloat32List, | |
| }; | |
| // Returns the encoded type that should be written when serializing |value|. | |
| EncodedType EncodedTypeForValue(const EncodableValue& value) { | |
| switch (value.index()) { | |
| case 0: | |
| return EncodedType::kNull; | |
| case 1: | |
| return std::get<bool>(value) ? EncodedType::kTrue : EncodedType::kFalse; | |
| case 2: | |
| return EncodedType::kInt32; | |
| case 3: | |
| return EncodedType::kInt64; | |
| case 4: | |
| return EncodedType::kFloat64; | |
| case 5: | |
| return EncodedType::kString; | |
| case 6: | |
| return EncodedType::kUInt8List; | |
| case 7: | |
| return EncodedType::kInt32List; | |
| case 8: | |
| return EncodedType::kInt64List; | |
| case 9: | |
| return EncodedType::kFloat64List; | |
| case 10: | |
| return EncodedType::kList; | |
| case 11: | |
| return EncodedType::kMap; | |
| case 13: | |
| return EncodedType::kFloat32List; | |
| } | |
| assert(false); | |
| return EncodedType::kNull; | |
| } | |
| } // namespace | |
| StandardCodecSerializer::StandardCodecSerializer() = default; | |
| StandardCodecSerializer::~StandardCodecSerializer() = default; | |
| const StandardCodecSerializer& StandardCodecSerializer::GetInstance() { | |
| static StandardCodecSerializer sInstance; | |
| return sInstance; | |
| }; | |
| EncodableValue StandardCodecSerializer::ReadValue( | |
| ByteStreamReader* stream) const { | |
| uint8_t type = stream->ReadByte(); | |
| return ReadValueOfType(type, stream); | |
| } | |
| void StandardCodecSerializer::WriteValue(const EncodableValue& value, | |
| ByteStreamWriter* stream) const { | |
| stream->WriteByte(static_cast<uint8_t>(EncodedTypeForValue(value))); | |
| // TODO(cbracken): Consider replacing this with std::visit. | |
| switch (value.index()) { | |
| case 0: | |
| case 1: | |
| // Null and bool are encoded directly in the type. | |
| break; | |
| case 2: | |
| stream->WriteInt32(std::get<int32_t>(value)); | |
| break; | |
| case 3: | |
| stream->WriteInt64(std::get<int64_t>(value)); | |
| break; | |
| case 4: | |
| stream->WriteAlignment(8); | |
| stream->WriteDouble(std::get<double>(value)); | |
| break; | |
| case 5: { | |
| const auto& string_value = std::get<std::string>(value); | |
| size_t size = string_value.size(); | |
| WriteSize(size, stream); | |
| if (size > 0) { | |
| stream->WriteBytes( | |
| reinterpret_cast<const uint8_t*>(string_value.data()), size); | |
| } | |
| break; | |
| } | |
| case 6: | |
| WriteVector(std::get<std::vector<uint8_t>>(value), stream); | |
| break; | |
| case 7: | |
| WriteVector(std::get<std::vector<int32_t>>(value), stream); | |
| break; | |
| case 8: | |
| WriteVector(std::get<std::vector<int64_t>>(value), stream); | |
| break; | |
| case 9: | |
| WriteVector(std::get<std::vector<double>>(value), stream); | |
| break; | |
| case 10: { | |
| const auto& list = std::get<EncodableList>(value); | |
| WriteSize(list.size(), stream); | |
| for (const auto& item : list) { | |
| WriteValue(item, stream); | |
| } | |
| break; | |
| } | |
| case 11: { | |
| const auto& map = std::get<EncodableMap>(value); | |
| WriteSize(map.size(), stream); | |
| for (const auto& pair : map) { | |
| WriteValue(pair.first, stream); | |
| WriteValue(pair.second, stream); | |
| } | |
| break; | |
| } | |
| case 12: | |
| std::cerr | |
| << "Unhandled custom type in StandardCodecSerializer::WriteValue. " | |
| << "Custom types require codec extensions." << std::endl; | |
| break; | |
| case 13: { | |
| WriteVector(std::get<std::vector<float>>(value), stream); | |
| break; | |
| } | |
| } | |
| } | |
| EncodableValue StandardCodecSerializer::ReadValueOfType( | |
| uint8_t type, | |
| ByteStreamReader* stream) const { | |
| switch (static_cast<EncodedType>(type)) { | |
| case EncodedType::kNull: | |
| return EncodableValue(); | |
| case EncodedType::kTrue: | |
| return EncodableValue(true); | |
| case EncodedType::kFalse: | |
| return EncodableValue(false); | |
| case EncodedType::kInt32: | |
| return EncodableValue(stream->ReadInt32()); | |
| case EncodedType::kInt64: | |
| return EncodableValue(stream->ReadInt64()); | |
| case EncodedType::kFloat64: | |
| stream->ReadAlignment(8); | |
| return EncodableValue(stream->ReadDouble()); | |
| case EncodedType::kLargeInt: | |
| case EncodedType::kString: { | |
| size_t size = ReadSize(stream); | |
| std::string string_value; | |
| string_value.resize(size); | |
| stream->ReadBytes(reinterpret_cast<uint8_t*>(&string_value[0]), size); | |
| return EncodableValue(string_value); | |
| } | |
| case EncodedType::kUInt8List: | |
| return ReadVector<uint8_t>(stream); | |
| case EncodedType::kInt32List: | |
| return ReadVector<int32_t>(stream); | |
| case EncodedType::kInt64List: | |
| return ReadVector<int64_t>(stream); | |
| case EncodedType::kFloat64List: | |
| return ReadVector<double>(stream); | |
| case EncodedType::kList: { | |
| size_t length = ReadSize(stream); | |
| EncodableList list_value; | |
| list_value.reserve(length); | |
| for (size_t i = 0; i < length; ++i) { | |
| list_value.push_back(ReadValue(stream)); | |
| } | |
| return EncodableValue(list_value); | |
| } | |
| case EncodedType::kMap: { | |
| size_t length = ReadSize(stream); | |
| EncodableMap map_value; | |
| for (size_t i = 0; i < length; ++i) { | |
| EncodableValue key = ReadValue(stream); | |
| EncodableValue value = ReadValue(stream); | |
| map_value.emplace(std::move(key), std::move(value)); | |
| } | |
| return EncodableValue(map_value); | |
| } | |
| case EncodedType::kFloat32List: { | |
| return ReadVector<float>(stream); | |
| } | |
| } | |
| std::cerr << "Unknown type in StandardCodecSerializer::ReadValueOfType: " | |
| << static_cast<int>(type) << std::endl; | |
| return EncodableValue(); | |
| } | |
| size_t StandardCodecSerializer::ReadSize(ByteStreamReader* stream) const { | |
| uint8_t byte = stream->ReadByte(); | |
| if (byte < 254) { | |
| return byte; | |
| } else if (byte == 254) { | |
| uint16_t value = 0; | |
| stream->ReadBytes(reinterpret_cast<uint8_t*>(&value), 2); | |
| return value; | |
| } else { | |
| uint32_t value = 0; | |
| stream->ReadBytes(reinterpret_cast<uint8_t*>(&value), 4); | |
| return value; | |
| } | |
| } | |
| void StandardCodecSerializer::WriteSize(size_t size, | |
| ByteStreamWriter* stream) const { | |
| if (size < 254) { | |
| stream->WriteByte(static_cast<uint8_t>(size)); | |
| } else if (size <= 0xffff) { | |
| stream->WriteByte(254); | |
| uint16_t value = static_cast<uint16_t>(size); | |
| stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), 2); | |
| } else { | |
| stream->WriteByte(255); | |
| uint32_t value = static_cast<uint32_t>(size); | |
| stream->WriteBytes(reinterpret_cast<uint8_t*>(&value), 4); | |
| } | |
| } | |
| template <typename T> | |
| EncodableValue StandardCodecSerializer::ReadVector( | |
| ByteStreamReader* stream) const { | |
| size_t count = ReadSize(stream); | |
| std::vector<T> vector; | |
| vector.resize(count); | |
| uint8_t type_size = static_cast<uint8_t>(sizeof(T)); | |
| if (type_size > 1) { | |
| stream->ReadAlignment(type_size); | |
| } | |
| stream->ReadBytes(reinterpret_cast<uint8_t*>(vector.data()), | |
| count * type_size); | |
| return EncodableValue(vector); | |
| } | |
| template <typename T> | |
| void StandardCodecSerializer::WriteVector(const std::vector<T> vector, | |
| ByteStreamWriter* stream) const { | |
| size_t count = vector.size(); | |
| WriteSize(count, stream); | |
| if (count == 0) { | |
| return; | |
| } | |
| uint8_t type_size = static_cast<uint8_t>(sizeof(T)); | |
| if (type_size > 1) { | |
| stream->WriteAlignment(type_size); | |
| } | |
| stream->WriteBytes(reinterpret_cast<const uint8_t*>(vector.data()), | |
| count * type_size); | |
| } | |
| // ===== standard_message_codec.h ===== | |
| // static | |
| const StandardMessageCodec& StandardMessageCodec::GetInstance( | |
| const StandardCodecSerializer* serializer) { | |
| if (!serializer) { | |
| serializer = &StandardCodecSerializer::GetInstance(); | |
| } | |
| static auto* sInstances = new std::map<const StandardCodecSerializer*, | |
| std::unique_ptr<StandardMessageCodec>>; | |
| auto it = sInstances->find(serializer); | |
| if (it == sInstances->end()) { | |
| // Uses new due to private constructor (to prevent API clients from | |
| // accidentally passing temporary codec instances to channels). | |
| auto emplace_result = sInstances->emplace( | |
| serializer, std::unique_ptr<StandardMessageCodec>( | |
| new StandardMessageCodec(serializer))); | |
| it = emplace_result.first; | |
| } | |
| return *(it->second); | |
| } | |
| StandardMessageCodec::StandardMessageCodec( | |
| const StandardCodecSerializer* serializer) | |
| : serializer_(serializer) {} | |
| StandardMessageCodec::~StandardMessageCodec() = default; | |
| std::unique_ptr<EncodableValue> StandardMessageCodec::DecodeMessageInternal( | |
| const uint8_t* binary_message, | |
| size_t message_size) const { | |
| if (!binary_message) { | |
| return std::make_unique<EncodableValue>(); | |
| } | |
| ByteBufferStreamReader stream(binary_message, message_size); | |
| return std::make_unique<EncodableValue>(serializer_->ReadValue(&stream)); | |
| } | |
| std::unique_ptr<std::vector<uint8_t>> | |
| StandardMessageCodec::EncodeMessageInternal( | |
| const EncodableValue& message) const { | |
| auto encoded = std::make_unique<std::vector<uint8_t>>(); | |
| ByteBufferStreamWriter stream(encoded.get()); | |
| serializer_->WriteValue(message, &stream); | |
| return encoded; | |
| } | |
| // ===== standard_method_codec.h ===== | |
| // static | |
| const StandardMethodCodec& StandardMethodCodec::GetInstance( | |
| const StandardCodecSerializer* serializer) { | |
| if (!serializer) { | |
| serializer = &StandardCodecSerializer::GetInstance(); | |
| } | |
| static auto* sInstances = new std::map<const StandardCodecSerializer*, | |
| std::unique_ptr<StandardMethodCodec>>; | |
| auto it = sInstances->find(serializer); | |
| if (it == sInstances->end()) { | |
| // Uses new due to private constructor (to prevent API clients from | |
| // accidentally passing temporary codec instances to channels). | |
| auto emplace_result = sInstances->emplace( | |
| serializer, std::unique_ptr<StandardMethodCodec>( | |
| new StandardMethodCodec(serializer))); | |
| it = emplace_result.first; | |
| } | |
| return *(it->second); | |
| } | |
| StandardMethodCodec::StandardMethodCodec( | |
| const StandardCodecSerializer* serializer) | |
| : serializer_(serializer) {} | |
| StandardMethodCodec::~StandardMethodCodec() = default; | |
| std::unique_ptr<MethodCall<EncodableValue>> | |
| StandardMethodCodec::DecodeMethodCallInternal(const uint8_t* message, | |
| size_t message_size) const { | |
| ByteBufferStreamReader stream(message, message_size); | |
| EncodableValue method_name_value = serializer_->ReadValue(&stream); | |
| const auto* method_name = std::get_if<std::string>(&method_name_value); | |
| if (!method_name) { | |
| std::cerr << "Invalid method call; method name is not a string." | |
| << std::endl; | |
| return nullptr; | |
| } | |
| auto arguments = | |
| std::make_unique<EncodableValue>(serializer_->ReadValue(&stream)); | |
| return std::make_unique<MethodCall<EncodableValue>>(*method_name, | |
| std::move(arguments)); | |
| } | |
| std::unique_ptr<std::vector<uint8_t>> | |
| StandardMethodCodec::EncodeMethodCallInternal( | |
| const MethodCall<EncodableValue>& method_call) const { | |
| auto encoded = std::make_unique<std::vector<uint8_t>>(); | |
| ByteBufferStreamWriter stream(encoded.get()); | |
| serializer_->WriteValue(EncodableValue(method_call.method_name()), &stream); | |
| if (method_call.arguments()) { | |
| serializer_->WriteValue(*method_call.arguments(), &stream); | |
| } else { | |
| serializer_->WriteValue(EncodableValue(), &stream); | |
| } | |
| return encoded; | |
| } | |
| std::unique_ptr<std::vector<uint8_t>> | |
| StandardMethodCodec::EncodeSuccessEnvelopeInternal( | |
| const EncodableValue* result) const { | |
| auto encoded = std::make_unique<std::vector<uint8_t>>(); | |
| ByteBufferStreamWriter stream(encoded.get()); | |
| stream.WriteByte(0); | |
| if (result) { | |
| serializer_->WriteValue(*result, &stream); | |
| } else { | |
| serializer_->WriteValue(EncodableValue(), &stream); | |
| } | |
| return encoded; | |
| } | |
| std::unique_ptr<std::vector<uint8_t>> | |
| StandardMethodCodec::EncodeErrorEnvelopeInternal( | |
| const std::string& error_code, | |
| const std::string& error_message, | |
| const EncodableValue* error_details) const { | |
| auto encoded = std::make_unique<std::vector<uint8_t>>(); | |
| ByteBufferStreamWriter stream(encoded.get()); | |
| stream.WriteByte(1); | |
| serializer_->WriteValue(EncodableValue(error_code), &stream); | |
| if (error_message.empty()) { | |
| serializer_->WriteValue(EncodableValue(), &stream); | |
| } else { | |
| serializer_->WriteValue(EncodableValue(error_message), &stream); | |
| } | |
| if (error_details) { | |
| serializer_->WriteValue(*error_details, &stream); | |
| } else { | |
| serializer_->WriteValue(EncodableValue(), &stream); | |
| } | |
| return encoded; | |
| } | |
| bool StandardMethodCodec::DecodeAndProcessResponseEnvelopeInternal( | |
| const uint8_t* response, | |
| size_t response_size, | |
| MethodResult<EncodableValue>* result) const { | |
| ByteBufferStreamReader stream(response, response_size); | |
| uint8_t flag = stream.ReadByte(); | |
| switch (flag) { | |
| case 0: { | |
| EncodableValue value = serializer_->ReadValue(&stream); | |
| if (value.IsNull()) { | |
| result->Success(); | |
| } else { | |
| result->Success(value); | |
| } | |
| return true; | |
| } | |
| case 1: { | |
| EncodableValue code = serializer_->ReadValue(&stream); | |
| EncodableValue message = serializer_->ReadValue(&stream); | |
| EncodableValue details = serializer_->ReadValue(&stream); | |
| const std::string& message_string = | |
| message.IsNull() ? "" : std::get<std::string>(message); | |
| if (details.IsNull()) { | |
| result->Error(std::get<std::string>(code), message_string); | |
| } else { | |
| result->Error(std::get<std::string>(code), message_string, details); | |
| } | |
| return true; | |
| } | |
| default: | |
| return false; | |
| } | |
| } | |
| } // namespace flutter |