// 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. #include "flutter/shell/platform/common/cpp/json_method_codec.h" #include "flutter/shell/platform/common/cpp/json_message_codec.h" namespace flutter { namespace { // Keys used in MethodCall encoding. constexpr char kMessageMethodKey[] = "method"; constexpr char kMessageArgumentsKey[] = "args"; } // namespace // static const JsonMethodCodec& JsonMethodCodec::GetInstance() { static JsonMethodCodec sInstance; return sInstance; } std::unique_ptr> JsonMethodCodec::DecodeMethodCallInternal(const uint8_t* message, const size_t message_size) const { std::unique_ptr json_message = JsonMessageCodec::GetInstance().DecodeMessage(message, message_size); if (!json_message) { return nullptr; } auto method_name_iter = json_message->FindMember(kMessageMethodKey); if (method_name_iter == json_message->MemberEnd()) { return nullptr; } if (!method_name_iter->value.IsString()) { return nullptr; } std::string method_name(method_name_iter->value.GetString()); auto arguments_iter = json_message->FindMember(kMessageArgumentsKey); std::unique_ptr arguments; if (arguments_iter != json_message->MemberEnd()) { // Pull the arguments subtree up to the root of json_message. This is // destructive to json_message, but the full value is no longer needed, and // this avoids a subtree copy. // Note: The static_cast is for compatibility with RapidJSON 1.1; master // already allows swapping a Document with a Value directly. Once there is // a new RapidJSON release (at which point clients can be expected to have // that change in the version they depend on) remove the cast. static_cast(json_message.get()) ->Swap(arguments_iter->value); // Swap it into |arguments|. This moves the allocator ownership, so that // the data won't be deleted when json_message goes out of scope. arguments = std::make_unique(); arguments->Swap(*json_message); } return std::make_unique>( method_name, std::move(arguments)); } std::unique_ptr> JsonMethodCodec::EncodeMethodCallInternal( const MethodCall& method_call) const { // TODO: Consider revisiting the codec APIs to avoid the need to copy // everything when doing encoding (e.g., by having a version that takes // owership of the object to encode, so that it can be moved instead). rapidjson::Document message(rapidjson::kObjectType); auto& allocator = message.GetAllocator(); rapidjson::Value name(method_call.method_name(), allocator); rapidjson::Value arguments; if (method_call.arguments()) { arguments.CopyFrom(*method_call.arguments(), allocator); } message.AddMember(kMessageMethodKey, name, allocator); message.AddMember(kMessageArgumentsKey, arguments, allocator); return JsonMessageCodec::GetInstance().EncodeMessage(message); } std::unique_ptr> JsonMethodCodec::EncodeSuccessEnvelopeInternal( const rapidjson::Document* result) const { rapidjson::Document envelope; envelope.SetArray(); rapidjson::Value result_value; if (result) { result_value.CopyFrom(*result, envelope.GetAllocator()); } envelope.PushBack(result_value, envelope.GetAllocator()); return JsonMessageCodec::GetInstance().EncodeMessage(envelope); } std::unique_ptr> JsonMethodCodec::EncodeErrorEnvelopeInternal( const std::string& error_code, const std::string& error_message, const rapidjson::Document* error_details) const { rapidjson::Document envelope(rapidjson::kArrayType); auto& allocator = envelope.GetAllocator(); envelope.PushBack(rapidjson::Value(error_code, allocator), allocator); envelope.PushBack(rapidjson::Value(error_message, allocator), allocator); rapidjson::Value details_value; if (error_details) { details_value.CopyFrom(*error_details, allocator); } envelope.PushBack(details_value, allocator); return JsonMessageCodec::GetInstance().EncodeMessage(envelope); } } // namespace flutter