• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "include/flutter/json_method_codec.h"
6 
7 #include "include/flutter/json_message_codec.h"
8 
9 namespace flutter {
10 
11 namespace {
12 // Keys used in MethodCall encoding.
13 constexpr char kMessageMethodKey[] = "method";
14 constexpr char kMessageArgumentsKey[] = "args";
15 }  // namespace
16 
17 // static
GetInstance()18 const JsonMethodCodec& JsonMethodCodec::GetInstance() {
19   static JsonMethodCodec sInstance;
20   return sInstance;
21 }
22 
23 std::unique_ptr<MethodCall<JsonValueType>>
DecodeMethodCallInternal(const uint8_t * message,const size_t message_size) const24 JsonMethodCodec::DecodeMethodCallInternal(const uint8_t* message,
25                                           const size_t message_size) const {
26   std::unique_ptr<JsonValueType> json_message =
27       JsonMessageCodec::GetInstance().DecodeMessage(message, message_size);
28   if (!json_message) {
29     return nullptr;
30   }
31 
32 #if USE_RAPID_JSON
33   auto method_name_iter = json_message->FindMember(kMessageMethodKey);
34   if (method_name_iter == json_message->MemberEnd()) {
35     return nullptr;
36   }
37   if (!method_name_iter->value.IsString()) {
38     return nullptr;
39   }
40   std::string method_name(method_name_iter->value.GetString());
41   auto arguments_iter = json_message->FindMember(kMessageArgumentsKey);
42   std::unique_ptr<rapidjson::Document> arguments;
43   if (arguments_iter != json_message->MemberEnd()) {
44     // Pull the arguments subtree up to the root of json_message. This is
45     // destructive to json_message, but the full value is no longer needed, and
46     // this avoids a subtree copy.
47     // Note: The static_cast is for compatibility with RapidJSON 1.1; master
48     // already allows swapping a Document with a Value directly. Once there is
49     // a new RapidJSON release (at which point clients can be expected to have
50     // that change in the version they depend on) remove the cast.
51     static_cast<rapidjson::Value*>(json_message.get())
52         ->Swap(arguments_iter->value);
53     // Swap it into |arguments|. This moves the allocator ownership, so that
54     // the data won't be deleted when json_message goes out of scope.
55     arguments = std::make_unique<rapidjson::Document>();
56     arguments->Swap(*json_message);
57   }
58   return std::make_unique<MethodCall<rapidjson::Document>>(
59       method_name, std::move(arguments));
60 #else
61   Json::Value method = (*json_message)[kMessageMethodKey];
62   if (method.isNull()) {
63     return nullptr;
64   }
65   return std::make_unique<MethodCall<Json::Value>>(
66       method.asString(),
67       std::make_unique<Json::Value>((*json_message)[kMessageArgumentsKey]));
68 #endif
69 }
70 
EncodeMethodCallInternal(const MethodCall<JsonValueType> & method_call) const71 std::unique_ptr<std::vector<uint8_t>> JsonMethodCodec::EncodeMethodCallInternal(
72     const MethodCall<JsonValueType>& method_call) const {
73 #if USE_RAPID_JSON
74   // TODO: Consider revisiting the codec APIs to avoid the need to copy
75   // everything when doing encoding (e.g., by having a version that takes
76   // owership of the object to encode, so that it can be moved instead).
77   rapidjson::Document message(rapidjson::kObjectType);
78   auto& allocator = message.GetAllocator();
79   rapidjson::Value name(method_call.method_name(), allocator);
80   rapidjson::Value arguments;
81   if (method_call.arguments()) {
82     arguments.CopyFrom(*method_call.arguments(), allocator);
83   }
84   message.AddMember(kMessageMethodKey, name, allocator);
85   message.AddMember(kMessageArgumentsKey, arguments, allocator);
86 #else
87   Json::Value message(Json::objectValue);
88   message[kMessageMethodKey] = method_call.method_name();
89   const Json::Value* arguments = method_call.arguments();
90   message[kMessageArgumentsKey] = arguments ? *arguments : Json::Value();
91 #endif
92 
93   return JsonMessageCodec::GetInstance().EncodeMessage(message);
94 }
95 
96 std::unique_ptr<std::vector<uint8_t>>
EncodeSuccessEnvelopeInternal(const JsonValueType * result) const97 JsonMethodCodec::EncodeSuccessEnvelopeInternal(
98     const JsonValueType* result) const {
99 #if USE_RAPID_JSON
100   rapidjson::Document envelope;
101   envelope.SetArray();
102   rapidjson::Value result_value;
103   if (result) {
104     result_value.CopyFrom(*result, envelope.GetAllocator());
105   }
106   envelope.PushBack(result_value, envelope.GetAllocator());
107 #else
108   Json::Value envelope(Json::arrayValue);
109   envelope.append(result == nullptr ? Json::Value() : *result);
110 #endif
111 
112   return JsonMessageCodec::GetInstance().EncodeMessage(envelope);
113 }
114 
115 std::unique_ptr<std::vector<uint8_t>>
EncodeErrorEnvelopeInternal(const std::string & error_code,const std::string & error_message,const JsonValueType * error_details) const116 JsonMethodCodec::EncodeErrorEnvelopeInternal(
117     const std::string& error_code,
118     const std::string& error_message,
119     const JsonValueType* error_details) const {
120 #if USE_RAPID_JSON
121   rapidjson::Document envelope(rapidjson::kArrayType);
122   auto& allocator = envelope.GetAllocator();
123   envelope.PushBack(rapidjson::Value(error_code, allocator), allocator);
124   envelope.PushBack(rapidjson::Value(error_message, allocator), allocator);
125   rapidjson::Value details_value;
126   if (error_details) {
127     details_value.CopyFrom(*error_details, allocator);
128   }
129   envelope.PushBack(details_value, allocator);
130 #else
131   Json::Value envelope(Json::arrayValue);
132   envelope.append(error_code);
133   envelope.append(error_message.empty() ? Json::Value() : error_message);
134   envelope.append(error_details == nullptr ? Json::Value() : *error_details);
135 #endif
136 
137   return JsonMessageCodec::GetInstance().EncodeMessage(envelope);
138 }
139 
140 }  // namespace flutter
141