Flutter Engine
fl_json_message_codec.cc
Go to the documentation of this file.
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 "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h"
6 
7 #include <gmodule.h>
8 
9 #include <cstring>
10 
11 #include "rapidjson/reader.h"
12 #include "rapidjson/writer.h"
13 
14 G_DEFINE_QUARK(fl_json_message_codec_error_quark, fl_json_message_codec_error)
15 
17  FlMessageCodec parent_instance;
18 };
19 
20 G_DEFINE_TYPE(FlJsonMessageCodec,
21  fl_json_message_codec,
23 
24 // Recursively writes #FlValue objects using rapidjson.
25 static gboolean write_value(rapidjson::Writer<rapidjson::StringBuffer>& writer,
26  FlValue* value,
27  GError** error) {
28  if (value == nullptr) {
29  writer.Null();
30  return TRUE;
31  }
32 
33  switch (fl_value_get_type(value)) {
34  case FL_VALUE_TYPE_NULL:
35  writer.Null();
36  break;
37  case FL_VALUE_TYPE_BOOL:
38  writer.Bool(fl_value_get_bool(value));
39  break;
40  case FL_VALUE_TYPE_INT:
41  writer.Int64(fl_value_get_int(value));
42  break;
44  writer.Double(fl_value_get_float(value));
45  break;
47  writer.String(fl_value_get_string(value));
48  break;
50  writer.StartArray();
51  const uint8_t* data = fl_value_get_uint8_list(value);
52  for (size_t i = 0; i < fl_value_get_length(value); i++) {
53  writer.Int(data[i]);
54  }
55  writer.EndArray();
56  break;
57  }
59  writer.StartArray();
60  const int32_t* data = fl_value_get_int32_list(value);
61  for (size_t i = 0; i < fl_value_get_length(value); i++) {
62  writer.Int(data[i]);
63  }
64  writer.EndArray();
65  break;
66  }
68  writer.StartArray();
69  const int64_t* data = fl_value_get_int64_list(value);
70  for (size_t i = 0; i < fl_value_get_length(value); i++) {
71  writer.Int64(data[i]);
72  }
73  writer.EndArray();
74  break;
75  }
77  writer.StartArray();
78  const double* data = fl_value_get_float_list(value);
79  for (size_t i = 0; i < fl_value_get_length(value); i++) {
80  writer.Double(data[i]);
81  }
82  writer.EndArray();
83  break;
84  }
85  case FL_VALUE_TYPE_LIST: {
86  writer.StartArray();
87  for (size_t i = 0; i < fl_value_get_length(value); i++) {
88  if (!write_value(writer, fl_value_get_list_value(value, i), error)) {
89  return FALSE;
90  }
91  }
92  writer.EndArray();
93  break;
94  }
95  case FL_VALUE_TYPE_MAP: {
96  writer.StartObject();
97  for (size_t i = 0; i < fl_value_get_length(value); i++) {
98  FlValue* key = fl_value_get_map_key(value, i);
100  g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
102  "Invalid object key type");
103  return FALSE;
104  }
105  writer.Key(fl_value_get_string(key));
106  if (!write_value(writer, fl_value_get_map_value(value, i), error)) {
107  return FALSE;
108  }
109  }
110  writer.EndObject();
111  break;
112  }
113  default:
114  g_set_error(error, FL_MESSAGE_CODEC_ERROR,
116  "Unexpected FlValue type %d", fl_value_get_type(value));
117  return FALSE;
118  }
119 
120  return TRUE;
121 }
122 
123 // Handler to parse JSON using rapidjson in SAX mode.
125  GPtrArray* stack;
127  GError* error;
128 
130  stack = g_ptr_array_new_with_free_func(
131  reinterpret_cast<GDestroyNotify>(fl_value_unref));
132  key = nullptr;
133  error = nullptr;
134  }
135 
137  g_ptr_array_unref(stack);
138  if (key != nullptr) {
139  fl_value_unref(key);
140  }
141  if (error != nullptr) {
142  g_error_free(error);
143  }
144  }
145 
146  // Gets the current head of the stack.
148  if (stack->len == 0) {
149  return nullptr;
150  }
151  return static_cast<FlValue*>(g_ptr_array_index(stack, stack->len - 1));
152  }
153 
154  // Pushes a value onto the stack.
155  void push(FlValue* value) { g_ptr_array_add(stack, fl_value_ref(value)); }
156 
157  // Pops the stack.
158  void pop() { g_ptr_array_remove_index(stack, stack->len - 1); }
159 
160  // Adds a new value to the stack.
161  bool add(FlValue* value) {
162  g_autoptr(FlValue) owned_value = value;
163  FlValue* head = get_head();
164  if (head == nullptr) {
165  push(owned_value);
166  } else if (fl_value_get_type(head) == FL_VALUE_TYPE_LIST) {
167  fl_value_append(head, owned_value);
168  } else if (fl_value_get_type(head) == FL_VALUE_TYPE_MAP) {
169  fl_value_set_take(head, key, fl_value_ref(owned_value));
170  key = nullptr;
171  } else {
173  "Can't add value to non container");
174  return false;
175  }
176 
177  if (fl_value_get_type(owned_value) == FL_VALUE_TYPE_LIST ||
178  fl_value_get_type(owned_value) == FL_VALUE_TYPE_MAP) {
179  push(value);
180  }
181 
182  return true;
183  }
184 
185  // The following implements the rapidjson SAX API.
186 
187  bool Null() { return add(fl_value_new_null()); }
188 
189  bool Bool(bool b) { return add(fl_value_new_bool(b)); }
190 
191  bool Int(int i) { return add(fl_value_new_int(i)); }
192 
193  bool Uint(unsigned i) { return add(fl_value_new_int(i)); }
194 
195  bool Int64(int64_t i) { return add(fl_value_new_int(i)); }
196 
197  bool Uint64(uint64_t i) {
198  // For some reason (bug in rapidjson?) this is not returned in Int64.
199  if (i == G_MAXINT64) {
200  return add(fl_value_new_int(i));
201  } else {
202  return add(fl_value_new_float(i));
203  }
204  }
205 
206  bool Double(double d) { return add(fl_value_new_float(d)); }
207 
208  bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
210  "RawNumber not supported");
211  return false;
212  }
213 
214  bool String(const char* str, rapidjson::SizeType length, bool copy) {
215  FlValue* v = fl_value_new_string_sized(str, length);
216  return add(v);
217  }
218 
219  bool StartObject() { return add(fl_value_new_map()); }
220 
221  bool Key(const char* str, rapidjson::SizeType length, bool copy) {
222  if (key != nullptr) {
223  fl_value_unref(key);
224  }
225  key = fl_value_new_string_sized(str, length);
226  return true;
227  }
228 
229  bool EndObject(rapidjson::SizeType memberCount) {
230  pop();
231  return true;
232  }
233 
234  bool StartArray() { return add(fl_value_new_list()); }
235 
236  bool EndArray(rapidjson::SizeType elementCount) {
237  pop();
238  return true;
239  }
240 };
241 
242 // Implements FlMessageCodec:encode_message.
243 static GBytes* fl_json_message_codec_encode_message(FlMessageCodec* codec,
244  FlValue* message,
245  GError** error) {
246  rapidjson::StringBuffer buffer;
247  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
248 
249  if (!write_value(writer, message, error)) {
250  return nullptr;
251  }
252 
253  const gchar* text = buffer.GetString();
254  return g_bytes_new(text, strlen(text));
255 }
256 
257 // Implements FlMessageCodec:decode_message.
258 static FlValue* fl_json_message_codec_decode_message(FlMessageCodec* codec,
259  GBytes* message,
260  GError** error) {
261  gsize data_length;
262  const gchar* data =
263  static_cast<const char*>(g_bytes_get_data(message, &data_length));
264  if (!g_utf8_validate(data, data_length, nullptr)) {
265  g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
267  "Message is not valid UTF8");
268  return nullptr;
269  }
270 
271  FlValueHandler handler;
272  rapidjson::Reader reader;
273  rapidjson::MemoryStream ss(data, data_length);
274  if (!reader.Parse(ss, handler)) {
275  if (handler.error != nullptr) {
276  g_propagate_error(error, handler.error);
277  handler.error = nullptr;
278  } else {
279  g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
281  "Message is not valid JSON");
282  }
283  return nullptr;
284  }
285 
286  FlValue* value = handler.get_head();
287  if (value == nullptr) {
288  g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
290  "Message is not valid JSON");
291  return nullptr;
292  }
293 
294  return fl_value_ref(value);
295 }
296 
297 static void fl_json_message_codec_class_init(FlJsonMessageCodecClass* klass) {
298  FL_MESSAGE_CODEC_CLASS(klass)->encode_message =
300  FL_MESSAGE_CODEC_CLASS(klass)->decode_message =
302 }
303 
304 static void fl_json_message_codec_init(FlJsonMessageCodec* self) {}
305 
306 G_MODULE_EXPORT FlJsonMessageCodec* fl_json_message_codec_new() {
307  return static_cast<FlJsonMessageCodec*>(
308  g_object_new(fl_json_message_codec_get_type(), nullptr));
309 }
310 
311 G_MODULE_EXPORT gchar* fl_json_message_codec_encode(FlJsonMessageCodec* codec,
312  FlValue* value,
313  GError** error) {
314  g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);
315 
316  rapidjson::StringBuffer buffer;
317  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
318 
319  if (!write_value(writer, value, error)) {
320  return nullptr;
321  }
322 
323  return g_strdup(buffer.GetString());
324 }
325 
326 G_MODULE_EXPORT FlValue* fl_json_message_codec_decode(FlJsonMessageCodec* codec,
327  const gchar* text,
328  GError** error) {
329  g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);
330 
331  g_autoptr(GBytes) data = g_bytes_new_static(text, strlen(text));
333  FL_MESSAGE_CODEC(codec), data, error);
334  if (value == nullptr) {
335  return nullptr;
336  }
337 
338  return fl_value_ref(value);
339 }
G_MODULE_EXPORT FlValue * fl_value_new_list()
Definition: fl_value.cc:310
G_MODULE_EXPORT FlValue * fl_value_new_float(double value)
Definition: fl_value.cc:240
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:395
bool RawNumber(const char *str, rapidjson::SizeType length, bool copy)
G_MODULE_EXPORT void fl_value_unref(FlValue *self)
Definition: fl_value.cc:341
bool Uint64(uint64_t i)
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:39
FlMethodResponse GError ** error
#define FL_JSON_MESSAGE_CODEC_ERROR
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:327
GQuark fl_json_message_codec_error_quark(void) G_GNUC_CONST
G_MODULE_EXPORT const double * fl_value_get_float_list(FlValue *self)
Definition: fl_value.cc:624
G_MODULE_EXPORT int64_t fl_value_get_int(FlValue *self)
Definition: fl_value.cc:582
G_DEFINE_QUARK(fl_binary_messenger_codec_error_quark, fl_binary_messenger_codec_error) struct _FlBinaryMessenger
bool Int64(int64_t i)
#define FL_MESSAGE_CODEC_ERROR
G_MODULE_EXPORT FlJsonMessageCodec * fl_json_message_codec_new()
G_MODULE_EXPORT const int64_t * fl_value_get_int64_list(FlValue *self)
Definition: fl_value.cc:617
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition: fl_value.cc:226
G_MODULE_EXPORT const uint8_t * fl_value_get_uint8_list(FlValue *self)
Definition: fl_value.cc:603
G_DEFINE_TYPE(FlJsonMessageCodec, fl_json_message_codec, fl_message_codec_get_type()) static gboolean write_value(rapidjson
G_MODULE_EXPORT void fl_value_append(FlValue *self, FlValue *value)
Definition: fl_value.cc:506
G_MODULE_EXPORT double fl_value_get_float(FlValue *self)
Definition: fl_value.cc:589
bool Uint(unsigned i)
uint8_t value
G_MODULE_EXPORT void fl_value_set_take(FlValue *self, FlValue *key, FlValue *value)
Definition: fl_value.cc:532
static void fl_json_message_codec_class_init(FlJsonMessageCodecClass *klass)
G_MODULE_EXPORT gchar * fl_json_message_codec_encode(FlJsonMessageCodec *codec, FlValue *value, GError **error)
bool EndArray(rapidjson::SizeType elementCount)
void push(FlValue *value)
size_t length
bool EndObject(rapidjson::SizeType memberCount)
G_MODULE_EXPORT FlValue * fl_value_get_list_value(FlValue *self, size_t index)
Definition: fl_value.cc:677
static FlValue * fl_json_message_codec_decode_message(FlMessageCodec *codec, GBytes *message, GError **error)
bool Key(const char *str, rapidjson::SizeType length, bool copy)
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:233
static GBytes * fl_json_message_codec_encode_message(FlMessageCodec *codec, FlValue *message, GError **error)
G_MODULE_EXPORT GType fl_message_codec_get_type()
G_MODULE_EXPORT FlValue * fl_value_get_map_value(FlValue *self, size_t index)
Definition: fl_value.cc:693
bool add(FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_ref(FlValue *self)
Definition: fl_value.cc:335
G_MODULE_EXPORT FlValue * fl_value_get_map_key(FlValue *self, size_t index)
Definition: fl_value.cc:685
G_MODULE_EXPORT const int32_t * fl_value_get_int32_list(FlValue *self)
Definition: fl_value.cc:610
return TRUE
Definition: fl_view.cc:107
G_MODULE_EXPORT const gchar * fl_value_get_string(FlValue *self)
Definition: fl_value.cc:596
G_MODULE_EXPORT FlValue * fl_json_message_codec_decode(FlJsonMessageCodec *codec, const gchar *text, GError **error)
G_MODULE_EXPORT FlValue * fl_value_new_string_sized(const gchar *value, size_t value_length)
Definition: fl_value.cc:254
FlMessageCodec parent_instance
G_MODULE_EXPORT size_t fl_value_get_length(FlValue *self)
Definition: fl_value.cc:631
bool String(const char *str, rapidjson::SizeType length, bool copy)
G_MODULE_EXPORT FlValue * fl_value_new_null()
Definition: fl_value.cc:222
static void fl_json_message_codec_init(FlJsonMessageCodec *self)
G_MODULE_EXPORT bool fl_value_get_bool(FlValue *self)
Definition: fl_value.cc:575