Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1193,15 +1193,27 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_channel.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_codec_private.h
FILE: ../../../flutter/shell/platform/linux/fl_method_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_response.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_response_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer.h
FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.h
FILE: ../../../flutter/shell/platform/linux/fl_standard_message_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_standard_message_codec_private.h
FILE: ../../../flutter/shell/platform/linux/fl_standard_message_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_string_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_value.cc
Expand All @@ -1211,8 +1223,14 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_response.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_value.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h
Expand Down
18 changes: 18 additions & 0 deletions shell/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,14 @@ _public_headers = [
"public/flutter_linux/fl_binary_messenger.h",
"public/flutter_linux/fl_dart_project.h",
"public/flutter_linux/fl_engine.h",
"public/flutter_linux/fl_json_message_codec.h",
"public/flutter_linux/fl_json_method_codec.h",
"public/flutter_linux/fl_message_codec.h",
"public/flutter_linux/fl_method_channel.h",
"public/flutter_linux/fl_method_codec.h",
"public/flutter_linux/fl_method_response.h",
"public/flutter_linux/fl_standard_message_codec.h",
"public/flutter_linux/fl_standard_method_codec.h",
"public/flutter_linux/fl_string_codec.h",
"public/flutter_linux/fl_value.h",
"public/flutter_linux/fl_view.h",
Expand All @@ -68,10 +74,16 @@ source_set("flutter_linux") {
"fl_binary_messenger.cc",
"fl_dart_project.cc",
"fl_engine.cc",
"fl_json_message_codec.cc",
"fl_json_method_codec.cc",
"fl_message_codec.cc",
"fl_method_channel.cc",
"fl_method_codec.cc",
"fl_method_response.cc",
"fl_renderer.cc",
"fl_renderer_x11.cc",
"fl_standard_message_codec.cc",
"fl_standard_method_codec.cc",
"fl_string_codec.cc",
"fl_value.cc",
"fl_view.cc",
Expand All @@ -88,6 +100,7 @@ source_set("flutter_linux") {

deps = [
"//flutter/shell/platform/embedder:embedder_with_symbol_prefix",
"//third_party/rapidjson",
]
}

Expand All @@ -101,8 +114,13 @@ executable("flutter_linux_unittests") {
sources = [
"fl_binary_codec_test.cc",
"fl_dart_project_test.cc",
"fl_json_message_codec_test.cc",
"fl_json_method_codec_test.cc",
"fl_message_codec_test.cc",
"fl_method_codec_test.cc",
"fl_method_response_test.cc",
"fl_standard_message_codec_test.cc",
"fl_standard_method_codec_test.cc",
"fl_string_codec_test.cc",
"fl_value_test.cc",
"testing/fl_test.cc",
Expand Down
300 changes: 300 additions & 0 deletions shell/platform/linux/fl_json_message_codec.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
// 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/linux/public/flutter_linux/fl_json_message_codec.h"

#include "rapidjson/reader.h"
#include "rapidjson/writer.h"

#include <gmodule.h>

G_DEFINE_QUARK(fl_json_message_codec_error_quark, fl_json_message_codec_error)

struct _FlJsonMessageCodec {
FlMessageCodec parent_instance;
};

G_DEFINE_TYPE(FlJsonMessageCodec,
fl_json_message_codec,
fl_message_codec_get_type())

// Recursively writes #FlValue objects using rapidjson
static gboolean write_value(rapidjson::Writer<rapidjson::StringBuffer>& writer,
FlValue* value,
GError** error) {
if (value == nullptr) {
writer.Null();
return TRUE;
}

switch (fl_value_get_type(value)) {
case FL_VALUE_TYPE_NULL:
writer.Null();
break;
case FL_VALUE_TYPE_BOOL:
writer.Bool(fl_value_get_bool(value));
break;
case FL_VALUE_TYPE_INT:
writer.Int64(fl_value_get_int(value));
break;
case FL_VALUE_TYPE_FLOAT:
writer.Double(fl_value_get_float(value));
break;
case FL_VALUE_TYPE_STRING:
writer.String(fl_value_get_string(value));
break;
case FL_VALUE_TYPE_UINT8_LIST: {
writer.StartArray();
const uint8_t* data = fl_value_get_uint8_list(value);
for (size_t i = 0; i < fl_value_get_length(value); i++)
writer.Int(data[i]);
writer.EndArray();
break;
}
case FL_VALUE_TYPE_INT32_LIST: {
writer.StartArray();
const int32_t* data = fl_value_get_int32_list(value);
for (size_t i = 0; i < fl_value_get_length(value); i++)
writer.Int(data[i]);
writer.EndArray();
break;
}
case FL_VALUE_TYPE_INT64_LIST: {
writer.StartArray();
const int64_t* data = fl_value_get_int64_list(value);
for (size_t i = 0; i < fl_value_get_length(value); i++)
writer.Int64(data[i]);
writer.EndArray();
break;
}
case FL_VALUE_TYPE_FLOAT_LIST: {
writer.StartArray();
const double* data = fl_value_get_float_list(value);
for (size_t i = 0; i < fl_value_get_length(value); i++)
writer.Double(data[i]);
writer.EndArray();
break;
}
case FL_VALUE_TYPE_LIST:
writer.StartArray();
for (size_t i = 0; i < fl_value_get_length(value); i++)
if (!write_value(writer, fl_value_get_list_value(value, i), error))
return FALSE;
writer.EndArray();
break;
case FL_VALUE_TYPE_MAP:
writer.StartObject();
for (size_t i = 0; i < fl_value_get_length(value); i++) {
FlValue* key = fl_value_get_map_key(value, i);
if (fl_value_get_type(key) != FL_VALUE_TYPE_STRING) {
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_OBJECT_KEY_TYPE,
"Invalid object key type");
return FALSE;
}
writer.Key(fl_value_get_string(key));
if (!write_value(writer, fl_value_get_map_value(value, i), error))
return FALSE;
}
writer.EndObject();
break;
default:
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
"Encountered unknown FlValue type");
return FALSE;
}

return TRUE;
}

// Handler to parse JSON using rapidjson in SAX mode
struct FlValueHandler {
GPtrArray* stack;
FlValue* key;

FlValueHandler() {
stack = g_ptr_array_new_with_free_func(
reinterpret_cast<GDestroyNotify>(fl_value_unref));
key = nullptr;
}

~FlValueHandler() {
g_ptr_array_unref(stack);
if (key != nullptr)
fl_value_unref(key);
}

// Get the current head of the stack
FlValue* get_head() {
if (stack->len == 0)
return nullptr;
return static_cast<FlValue*>(g_ptr_array_index(stack, stack->len - 1));
}

// Push a value onto the stack
void push(FlValue* value) { g_ptr_array_add(stack, fl_value_ref(value)); }

// Pop the stack
void pop() { g_ptr_array_remove_index(stack, stack->len - 1); }

// Add a new value to the stack
bool add(FlValue* value) {
g_autoptr(FlValue) owned_value = value;
FlValue* head = get_head();
if (head == nullptr)
push(owned_value);
else if (fl_value_get_type(head) == FL_VALUE_TYPE_LIST)
fl_value_append(head, owned_value);
else if (fl_value_get_type(head) == FL_VALUE_TYPE_MAP) {
fl_value_set_take(head, key, fl_value_ref(owned_value));
key = nullptr;
} else
return false;

if (fl_value_get_type(owned_value) == FL_VALUE_TYPE_LIST ||
fl_value_get_type(owned_value) == FL_VALUE_TYPE_MAP)
push(value);

return true;
}

// The following implements the rapidjson SAX API

bool Null() { return add(fl_value_new_null()); }

bool Bool(bool b) { return add(fl_value_new_bool(b)); }

bool Int(int i) { return add(fl_value_new_int(i)); }

bool Uint(unsigned i) { return add(fl_value_new_int(i)); }

bool Int64(int64_t i) { return add(fl_value_new_int(i)); }

bool Uint64(uint64_t i) {
return add(fl_value_new_int(i)); // FIXME: Too big!
}

bool Double(double d) { return add(fl_value_new_float(d)); }

bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
return false;
}

bool String(const char* str, rapidjson::SizeType length, bool copy) {
FlValue* v = fl_value_new_string_sized(str, length);
return add(v);
}

bool StartObject() { return add(fl_value_new_map()); }

bool Key(const char* str, rapidjson::SizeType length, bool copy) {
if (key != nullptr)
fl_value_unref(key);
key = fl_value_new_string_sized(str, length);
return true;
}

bool EndObject(rapidjson::SizeType memberCount) {
pop();
return true;
}

bool StartArray() { return add(fl_value_new_list()); }

bool EndArray(rapidjson::SizeType elementCount) {
pop();
return true;
}
};

// Implements FlMessageCodec:encode_message
static GBytes* fl_json_message_codec_encode_message(FlMessageCodec* codec,
FlValue* message,
GError** error) {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

if (!write_value(writer, message, error))
return nullptr;

const gchar* text = buffer.GetString();
return g_bytes_new(text, strlen(text));
}

// Implements FlMessageCodec:decode_message
static FlValue* fl_json_message_codec_decode_message(FlMessageCodec* codec,
GBytes* message,
GError** error) {
gsize data_length;
const gchar* data =
static_cast<const char*>(g_bytes_get_data(message, &data_length));
if (!g_utf8_validate(data, data_length, nullptr)) {
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_UTF8,
"Message is not valid UTF8");
return nullptr;
}

FlValueHandler handler;
rapidjson::Reader reader;
rapidjson::MemoryStream ss(data, data_length);
if (!reader.Parse(ss, handler)) {
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
"Message is not valid JSON");
return nullptr;
}

FlValue* value = handler.get_head();
if (value == nullptr) {
g_set_error(error, FL_JSON_MESSAGE_CODEC_ERROR,
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
"Message is not valid JSON");
return nullptr;
}

return fl_value_ref(value);
}

static void fl_json_message_codec_class_init(FlJsonMessageCodecClass* klass) {
FL_MESSAGE_CODEC_CLASS(klass)->encode_message =
fl_json_message_codec_encode_message;
FL_MESSAGE_CODEC_CLASS(klass)->decode_message =
fl_json_message_codec_decode_message;
}

static void fl_json_message_codec_init(FlJsonMessageCodec* self) {}

G_MODULE_EXPORT FlJsonMessageCodec* fl_json_message_codec_new() {
return static_cast<FlJsonMessageCodec*>(
g_object_new(fl_json_message_codec_get_type(), nullptr));
}

G_MODULE_EXPORT gchar* fl_json_message_codec_encode(FlJsonMessageCodec* codec,
FlValue* value,
GError** error) {
g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);

rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

if (!write_value(writer, value, error))
return nullptr;

return g_strdup(buffer.GetString());
}

G_MODULE_EXPORT FlValue* fl_json_message_codec_decode(FlJsonMessageCodec* codec,
const gchar* text,
GError** error) {
g_return_val_if_fail(FL_IS_JSON_CODEC(codec), nullptr);

g_autoptr(GBytes) data = g_bytes_new_static(text, strlen(text));
g_autoptr(FlValue) value = fl_json_message_codec_decode_message(
FL_MESSAGE_CODEC(codec), data, error);
if (value == nullptr)
return nullptr;

return fl_value_ref(value);
}
Loading