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

Commit 5ad4f9e

Browse files
Add FlJsonMessageCodec (#18221)
1 parent df2dfac commit 5ad4f9e

File tree

6 files changed

+1204
-0
lines changed

6 files changed

+1204
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
11941194
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
11951195
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
11961196
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
1197+
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc
1198+
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc
11971199
FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc
11981200
FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc
11991201
FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc
@@ -1213,6 +1215,7 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec
12131215
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
12141216
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
12151217
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
1218+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h
12161219
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h
12171220
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
12181221
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h

shell/platform/linux/BUILD.gn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ _public_headers = [
4949
"public/flutter_linux/fl_binary_messenger.h",
5050
"public/flutter_linux/fl_dart_project.h",
5151
"public/flutter_linux/fl_engine.h",
52+
"public/flutter_linux/fl_json_message_codec.h",
5253
"public/flutter_linux/fl_message_codec.h",
5354
"public/flutter_linux/fl_standard_message_codec.h",
5455
"public/flutter_linux/fl_string_codec.h",
@@ -70,6 +71,7 @@ source_set("flutter_linux") {
7071
"fl_binary_messenger.cc",
7172
"fl_dart_project.cc",
7273
"fl_engine.cc",
74+
"fl_json_message_codec.cc",
7375
"fl_message_codec.cc",
7476
"fl_renderer.cc",
7577
"fl_renderer_x11.cc",
@@ -90,6 +92,7 @@ source_set("flutter_linux") {
9092

9193
deps = [
9294
"//flutter/shell/platform/embedder:embedder_with_symbol_prefix",
95+
"//third_party/rapidjson",
9396
]
9497
}
9598

@@ -103,6 +106,7 @@ executable("flutter_linux_unittests") {
103106
sources = [
104107
"fl_binary_codec_test.cc",
105108
"fl_dart_project_test.cc",
109+
"fl_json_message_codec_test.cc",
106110
"fl_message_codec_test.cc",
107111
"fl_standard_message_codec_test.cc",
108112
"fl_string_codec_test.cc",
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
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+
}
87+
case FL_VALUE_TYPE_MAP: {
88+
writer.StartObject();
89+
for (size_t i = 0; i < fl_value_get_length(value); i++) {
90+
FlValue* key = fl_value_get_map_key(value, i);
91+
if (fl_value_get_type(key) != FL_VALUE_TYPE_STRING) {
92+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
93+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_OBJECT_KEY_TYPE,
94+
"Invalid object key type");
95+
return FALSE;
96+
}
97+
writer.Key(fl_value_get_string(key));
98+
if (!write_value(writer, fl_value_get_map_value(value, i), error))
99+
return FALSE;
100+
}
101+
writer.EndObject();
102+
break;
103+
}
104+
default:
105+
g_set_error(error, FL_MESSAGE_CODEC_ERROR,
106+
FL_MESSAGE_CODEC_ERROR_UNSUPPORTED_TYPE,
107+
"Unexpected FlValue type %d", fl_value_get_type(value));
108+
return FALSE;
109+
}
110+
111+
return TRUE;
112+
}
113+
114+
// Handler to parse JSON using rapidjson in SAX mode
115+
struct FlValueHandler {
116+
GPtrArray* stack;
117+
FlValue* key;
118+
GError* error;
119+
120+
FlValueHandler() {
121+
stack = g_ptr_array_new_with_free_func(
122+
reinterpret_cast<GDestroyNotify>(fl_value_unref));
123+
key = nullptr;
124+
error = nullptr;
125+
}
126+
127+
~FlValueHandler() {
128+
g_ptr_array_unref(stack);
129+
if (key != nullptr)
130+
fl_value_unref(key);
131+
if (error != nullptr)
132+
g_error_free(error);
133+
}
134+
135+
// Gets the current head of the stack
136+
FlValue* get_head() {
137+
if (stack->len == 0)
138+
return nullptr;
139+
return static_cast<FlValue*>(g_ptr_array_index(stack, stack->len - 1));
140+
}
141+
142+
// Pushes a value onto the stack
143+
void push(FlValue* value) { g_ptr_array_add(stack, fl_value_ref(value)); }
144+
145+
// Pops the stack
146+
void pop() { g_ptr_array_remove_index(stack, stack->len - 1); }
147+
148+
// Adds a new value to the stack
149+
bool add(FlValue* value) {
150+
g_autoptr(FlValue) owned_value = value;
151+
FlValue* head = get_head();
152+
if (head == nullptr)
153+
push(owned_value);
154+
else if (fl_value_get_type(head) == FL_VALUE_TYPE_LIST)
155+
fl_value_append(head, owned_value);
156+
else if (fl_value_get_type(head) == FL_VALUE_TYPE_MAP) {
157+
fl_value_set_take(head, key, fl_value_ref(owned_value));
158+
key = nullptr;
159+
} else {
160+
g_set_error(&error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
161+
"Can't add value to non container");
162+
return false;
163+
}
164+
165+
if (fl_value_get_type(owned_value) == FL_VALUE_TYPE_LIST ||
166+
fl_value_get_type(owned_value) == FL_VALUE_TYPE_MAP)
167+
push(value);
168+
169+
return true;
170+
}
171+
172+
// The following implements the rapidjson SAX API
173+
174+
bool Null() { return add(fl_value_new_null()); }
175+
176+
bool Bool(bool b) { return add(fl_value_new_bool(b)); }
177+
178+
bool Int(int i) { return add(fl_value_new_int(i)); }
179+
180+
bool Uint(unsigned i) { return add(fl_value_new_int(i)); }
181+
182+
bool Int64(int64_t i) { return add(fl_value_new_int(i)); }
183+
184+
bool Uint64(uint64_t i) {
185+
// For some reason (bug in rapidjson?) this is not returned in Int64
186+
if (i == G_MAXINT64)
187+
return add(fl_value_new_int(i));
188+
else
189+
return add(fl_value_new_float(i));
190+
}
191+
192+
bool Double(double d) { return add(fl_value_new_float(d)); }
193+
194+
bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
195+
g_set_error(&error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
196+
"RawNumber not supported");
197+
return false;
198+
}
199+
200+
bool String(const char* str, rapidjson::SizeType length, bool copy) {
201+
FlValue* v = fl_value_new_string_sized(str, length);
202+
return add(v);
203+
}
204+
205+
bool StartObject() { return add(fl_value_new_map()); }
206+
207+
bool Key(const char* str, rapidjson::SizeType length, bool copy) {
208+
if (key != nullptr)
209+
fl_value_unref(key);
210+
key = fl_value_new_string_sized(str, length);
211+
return true;
212+
}
213+
214+
bool EndObject(rapidjson::SizeType memberCount) {
215+
pop();
216+
return true;
217+
}
218+
219+
bool StartArray() { return add(fl_value_new_list()); }
220+
221+
bool EndArray(rapidjson::SizeType elementCount) {
222+
pop();
223+
return true;
224+
}
225+
};
226+
227+
// Implements FlMessageCodec:encode_message
228+
static GBytes* fl_json_message_codec_encode_message(FlMessageCodec* codec,
229+
FlValue* message,
230+
GError** error) {
231+
rapidjson::StringBuffer buffer;
232+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
233+
234+
if (!write_value(writer, message, error))
235+
return nullptr;
236+
237+
const gchar* text = buffer.GetString();
238+
return g_bytes_new(text, strlen(text));
239+
}
240+
241+
// Implements FlMessageCodec:decode_message
242+
static FlValue* fl_json_message_codec_decode_message(FlMessageCodec* codec,
243+
GBytes* message,
244+
GError** error) {
245+
gsize data_length;
246+
const gchar* data =
247+
static_cast<const char*>(g_bytes_get_data(message, &data_length));
248+
if (!g_utf8_validate(data, data_length, nullptr)) {
249+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
250+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_UTF8,
251+
"Message is not valid UTF8");
252+
return nullptr;
253+
}
254+
255+
FlValueHandler handler;
256+
rapidjson::Reader reader;
257+
rapidjson::MemoryStream ss(data, data_length);
258+
if (!reader.Parse(ss, handler)) {
259+
if (handler.error != nullptr) {
260+
g_propagate_error(error, handler.error);
261+
handler.error = nullptr;
262+
} else
263+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
264+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
265+
"Message is not valid JSON");
266+
return nullptr;
267+
}
268+
269+
FlValue* value = handler.get_head();
270+
if (value == nullptr) {
271+
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
272+
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
273+
"Message is not valid JSON");
274+
return nullptr;
275+
}
276+
277+
return fl_value_ref(value);
278+
}
279+
280+
static void fl_json_message_codec_class_init(FlJsonMessageCodecClass* klass) {
281+
FL_MESSAGE_CODEC_CLASS(klass)->encode_message =
282+
fl_json_message_codec_encode_message;
283+
FL_MESSAGE_CODEC_CLASS(klass)->decode_message =
284+
fl_json_message_codec_decode_message;
285+
}
286+
287+
static void fl_json_message_codec_init(FlJsonMessageCodec* self) {}
288+
289+
G_MODULE_EXPORT FlJsonMessageCodec* fl_json_message_codec_new() {
290+
return static_cast<FlJsonMessageCodec*>(
291+
g_object_new(fl_json_message_codec_get_type(), nullptr));
292+
}
293+
294+
G_MODULE_EXPORT gchar* fl_json_message_codec_encode(FlJsonMessageCodec* codec,
295+
FlValue* value,
296+
GError** error) {
297+
g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);
298+
299+
rapidjson::StringBuffer buffer;
300+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
301+
302+
if (!write_value(writer, value, error))
303+
return nullptr;
304+
305+
return g_strdup(buffer.GetString());
306+
}
307+
308+
G_MODULE_EXPORT FlValue* fl_json_message_codec_decode(FlJsonMessageCodec* codec,
309+
const gchar* text,
310+
GError** error) {
311+
g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);
312+
313+
g_autoptr(GBytes) data = g_bytes_new_static(text, strlen(text));
314+
g_autoptr(FlValue) value = fl_json_message_codec_decode_message(
315+
FL_MESSAGE_CODEC(codec), data, error);
316+
if (value == nullptr)
317+
return nullptr;
318+
319+
return fl_value_ref(value);
320+
}

0 commit comments

Comments
 (0)