Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e7a04e8

Browse files
committed
Add FlJsonMessageCodec
1 parent 20f527b commit e7a04e8

File tree

6 files changed

+1170
-0
lines changed

6 files changed

+1170
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
11931193
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
11941194
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
11951195
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
1196+
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc
1197+
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc
11961198
FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc
11971199
FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc
11981200
FILE: ../../../flutter/shell/platform/linux/fl_method_channel.cc
@@ -1219,6 +1221,7 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec
12191221
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
12201222
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
12211223
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
1224+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h
12221225
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h
12231226
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h
12241227
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h

shell/platform/linux/BUILD.gn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ _public_headers = [
4848
"public/flutter_linux/fl_binary_messenger.h",
4949
"public/flutter_linux/fl_dart_project.h",
5050
"public/flutter_linux/fl_engine.h",
51+
"public/flutter_linux/fl_json_message_codec.h",
5152
"public/flutter_linux/fl_message_codec.h",
5253
"public/flutter_linux/fl_method_channel.h",
5354
"public/flutter_linux/fl_method_codec.h",
@@ -72,6 +73,7 @@ source_set("flutter_linux") {
7273
"fl_binary_messenger.cc",
7374
"fl_dart_project.cc",
7475
"fl_engine.cc",
76+
"fl_json_message_codec.cc",
7577
"fl_message_codec.cc",
7678
"fl_method_channel.cc",
7779
"fl_method_codec.cc",
@@ -96,6 +98,7 @@ source_set("flutter_linux") {
9698

9799
deps = [
98100
"//flutter/shell/platform/embedder:embedder_with_symbol_prefix",
101+
"//third_party/rapidjson",
99102
]
100103
}
101104

@@ -109,6 +112,7 @@ executable("flutter_linux_unittests") {
109112
sources = [
110113
"fl_binary_codec_test.cc",
111114
"fl_dart_project_test.cc",
115+
"fl_json_message_codec_test.cc",
112116
"fl_message_codec_test.cc",
113117
"fl_method_codec_test.cc",
114118
"fl_method_response_test.cc",
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
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 "rapidjson/reader.h"
8+
#include "rapidjson/writer.h"
9+
10+
#include <gmodule.h>
11+
12+
G_DEFINE_QUARK(fl_json_message_codec_error_quark, fl_json_message_codec_error)
13+
14+
struct _FlJsonMessageCodec {
15+
FlMessageCodec parent_instance;
16+
};
17+
18+
G_DEFINE_TYPE(FlJsonMessageCodec,
19+
fl_json_message_codec,
20+
fl_message_codec_get_type())
21+
22+
// Recursively writes #FlValue objects using rapidjson
23+
static gboolean write_value(rapidjson::Writer<rapidjson::StringBuffer>& writer,
24+
FlValue* value,
25+
GError** error) {
26+
if (value == nullptr) {
27+
writer.Null();
28+
return TRUE;
29+
}
30+
31+
switch (fl_value_get_type(value)) {
32+
case FL_VALUE_TYPE_NULL:
33+
writer.Null();
34+
break;
35+
case FL_VALUE_TYPE_BOOL:
36+
writer.Bool(fl_value_get_bool(value));
37+
break;
38+
case FL_VALUE_TYPE_INT:
39+
writer.Int64(fl_value_get_int(value));
40+
break;
41+
case FL_VALUE_TYPE_FLOAT:
42+
writer.Double(fl_value_get_float(value));
43+
break;
44+
case FL_VALUE_TYPE_STRING:
45+
writer.String(fl_value_get_string(value));
46+
break;
47+
case FL_VALUE_TYPE_UINT8_LIST: {
48+
writer.StartArray();
49+
const uint8_t* data = fl_value_get_uint8_list(value);
50+
for (size_t i = 0; i < fl_value_get_length(value); i++)
51+
writer.Int(data[i]);
52+
writer.EndArray();
53+
break;
54+
}
55+
case FL_VALUE_TYPE_INT32_LIST: {
56+
writer.StartArray();
57+
const int32_t* data = fl_value_get_int32_list(value);
58+
for (size_t i = 0; i < fl_value_get_length(value); i++)
59+
writer.Int(data[i]);
60+
writer.EndArray();
61+
break;
62+
}
63+
case FL_VALUE_TYPE_INT64_LIST: {
64+
writer.StartArray();
65+
const int64_t* data = fl_value_get_int64_list(value);
66+
for (size_t i = 0; i < fl_value_get_length(value); i++)
67+
writer.Int64(data[i]);
68+
writer.EndArray();
69+
break;
70+
}
71+
case FL_VALUE_TYPE_FLOAT_LIST: {
72+
writer.StartArray();
73+
const double* data = fl_value_get_float_list(value);
74+
for (size_t i = 0; i < fl_value_get_length(value); i++)
75+
writer.Double(data[i]);
76+
writer.EndArray();
77+
break;
78+
}
79+
case FL_VALUE_TYPE_LIST:
80+
writer.StartArray();
81+
for (size_t i = 0; i < fl_value_get_length(value); i++)
82+
if (!write_value(writer, fl_value_get_list_value(value, i), error))
83+
return FALSE;
84+
writer.EndArray();
85+
break;
86+
case FL_VALUE_TYPE_MAP:
87+
writer.StartObject();
88+
for (size_t i = 0; i < fl_value_get_length(value); i++) {
89+
FlValue* key = fl_value_get_map_key(value, i);
90+
if (fl_value_get_type(key) != FL_VALUE_TYPE_STRING) {
91+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
92+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_OBJECT_KEY_TYPE,
93+
"Invalid object key type");
94+
return FALSE;
95+
}
96+
writer.Key(fl_value_get_string(key));
97+
if (!write_value(writer, fl_value_get_map_value(value, i), error))
98+
return FALSE;
99+
}
100+
writer.EndObject();
101+
break;
102+
default:
103+
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
104+
"Encountered unknown FlValue type");
105+
return FALSE;
106+
}
107+
108+
return TRUE;
109+
}
110+
111+
// Handler to parse JSON using rapidjson in SAX mode
112+
struct FlValueHandler {
113+
GPtrArray* stack;
114+
FlValue* key;
115+
116+
FlValueHandler() {
117+
stack = g_ptr_array_new_with_free_func(
118+
reinterpret_cast<GDestroyNotify>(fl_value_unref));
119+
key = nullptr;
120+
}
121+
122+
~FlValueHandler() {
123+
g_ptr_array_unref(stack);
124+
if (key != nullptr)
125+
fl_value_unref(key);
126+
}
127+
128+
// Get the current head of the stack
129+
FlValue* get_head() {
130+
if (stack->len == 0)
131+
return nullptr;
132+
return static_cast<FlValue*>(g_ptr_array_index(stack, stack->len - 1));
133+
}
134+
135+
// Push a value onto the stack
136+
void push(FlValue* value) { g_ptr_array_add(stack, fl_value_ref(value)); }
137+
138+
// Pop the stack
139+
void pop() { g_ptr_array_remove_index(stack, stack->len - 1); }
140+
141+
// Add a new value to the stack
142+
bool add(FlValue* value) {
143+
g_autoptr(FlValue) owned_value = value;
144+
FlValue* head = get_head();
145+
if (head == nullptr)
146+
push(owned_value);
147+
else if (fl_value_get_type(head) == FL_VALUE_TYPE_LIST)
148+
fl_value_append(head, owned_value);
149+
else if (fl_value_get_type(head) == FL_VALUE_TYPE_MAP) {
150+
fl_value_set_take(head, key, fl_value_ref(owned_value));
151+
key = nullptr;
152+
} else
153+
return false;
154+
155+
if (fl_value_get_type(owned_value) == FL_VALUE_TYPE_LIST ||
156+
fl_value_get_type(owned_value) == FL_VALUE_TYPE_MAP)
157+
push(value);
158+
159+
return true;
160+
}
161+
162+
// The following implements the rapidjson SAX API
163+
164+
bool Null() { return add(fl_value_new_null()); }
165+
166+
bool Bool(bool b) { return add(fl_value_new_bool(b)); }
167+
168+
bool Int(int i) { return add(fl_value_new_int(i)); }
169+
170+
bool Uint(unsigned i) { return add(fl_value_new_int(i)); }
171+
172+
bool Int64(int64_t i) { return add(fl_value_new_int(i)); }
173+
174+
bool Uint64(uint64_t i) {
175+
return add(fl_value_new_int(i)); // FIXME: Too big!
176+
}
177+
178+
bool Double(double d) { return add(fl_value_new_float(d)); }
179+
180+
bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
181+
return false;
182+
}
183+
184+
bool String(const char* str, rapidjson::SizeType length, bool copy) {
185+
FlValue* v = fl_value_new_string_sized(str, length);
186+
return add(v);
187+
}
188+
189+
bool StartObject() { return add(fl_value_new_map()); }
190+
191+
bool Key(const char* str, rapidjson::SizeType length, bool copy) {
192+
if (key != nullptr)
193+
fl_value_unref(key);
194+
key = fl_value_new_string_sized(str, length);
195+
return true;
196+
}
197+
198+
bool EndObject(rapidjson::SizeType memberCount) {
199+
pop();
200+
return true;
201+
}
202+
203+
bool StartArray() { return add(fl_value_new_list()); }
204+
205+
bool EndArray(rapidjson::SizeType elementCount) {
206+
pop();
207+
return true;
208+
}
209+
};
210+
211+
// Implements FlMessageCodec:encode_message
212+
static GBytes* fl_json_message_codec_encode_message(FlMessageCodec* codec,
213+
FlValue* message,
214+
GError** error) {
215+
rapidjson::StringBuffer buffer;
216+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
217+
218+
if (!write_value(writer, message, error))
219+
return nullptr;
220+
221+
const gchar* text = buffer.GetString();
222+
return g_bytes_new(text, strlen(text));
223+
}
224+
225+
// Implements FlMessageCodec:decode_message
226+
static FlValue* fl_json_message_codec_decode_message(FlMessageCodec* codec,
227+
GBytes* message,
228+
GError** error) {
229+
gsize data_length;
230+
const gchar* data =
231+
static_cast<const char*>(g_bytes_get_data(message, &data_length));
232+
if (!g_utf8_validate(data, data_length, nullptr)) {
233+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
234+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_UTF8,
235+
"Message is not valid UTF8");
236+
return nullptr;
237+
}
238+
239+
FlValueHandler handler;
240+
rapidjson::Reader reader;
241+
rapidjson::MemoryStream ss(data, data_length);
242+
if (!reader.Parse(ss, handler)) {
243+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
244+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
245+
"Message is not valid JSON");
246+
return nullptr;
247+
}
248+
249+
FlValue* value = handler.get_head();
250+
if (value == nullptr) {
251+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
252+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
253+
"Message is not valid JSON");
254+
return nullptr;
255+
}
256+
257+
return fl_value_ref(value);
258+
}
259+
260+
static void fl_json_message_codec_class_init(FlJsonMessageCodecClass* klass) {
261+
FL_MESSAGE_CODEC_CLASS(klass)->encode_message =
262+
fl_json_message_codec_encode_message;
263+
FL_MESSAGE_CODEC_CLASS(klass)->decode_message =
264+
fl_json_message_codec_decode_message;
265+
}
266+
267+
static void fl_json_message_codec_init(FlJsonMessageCodec* self) {}
268+
269+
G_MODULE_EXPORT FlJsonMessageCodec* fl_json_message_codec_new() {
270+
return static_cast<FlJsonMessageCodec*>(
271+
g_object_new(fl_json_message_codec_get_type(), nullptr));
272+
}
273+
274+
G_MODULE_EXPORT gchar* fl_json_message_codec_encode(FlJsonMessageCodec* codec,
275+
FlValue* value,
276+
GError** error) {
277+
g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);
278+
279+
rapidjson::StringBuffer buffer;
280+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
281+
282+
if (!write_value(writer, value, error))
283+
return nullptr;
284+
285+
return g_strdup(buffer.GetString());
286+
}
287+
288+
G_MODULE_EXPORT FlValue* fl_json_message_codec_decode(FlJsonMessageCodec* codec,
289+
const gchar* text,
290+
GError** error) {
291+
g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);
292+
293+
g_autoptr(GBytes) data = g_bytes_new_static(text, strlen(text));
294+
g_autoptr(FlValue) value = fl_json_message_codec_decode_message(
295+
FL_MESSAGE_CODEC(codec), data, error);
296+
if (value == nullptr)
297+
return nullptr;
298+
299+
return fl_value_ref(value);
300+
}

0 commit comments

Comments
 (0)