未验证 提交 5ad4f9ee 编写于 作者: R Robert Ancell 提交者: GitHub

Add FlJsonMessageCodec (#18221)

上级 df2dface
......@@ -1194,6 +1194,8 @@ 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_message_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc
......@@ -1213,6 +1215,7 @@ 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_message_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h
......
......@@ -49,6 +49,7 @@ _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_message_codec.h",
"public/flutter_linux/fl_standard_message_codec.h",
"public/flutter_linux/fl_string_codec.h",
......@@ -70,6 +71,7 @@ source_set("flutter_linux") {
"fl_binary_messenger.cc",
"fl_dart_project.cc",
"fl_engine.cc",
"fl_json_message_codec.cc",
"fl_message_codec.cc",
"fl_renderer.cc",
"fl_renderer_x11.cc",
......@@ -90,6 +92,7 @@ source_set("flutter_linux") {
deps = [
"//flutter/shell/platform/embedder:embedder_with_symbol_prefix",
"//third_party/rapidjson",
]
}
......@@ -103,6 +106,7 @@ executable("flutter_linux_unittests") {
sources = [
"fl_binary_codec_test.cc",
"fl_dart_project_test.cc",
"fl_json_message_codec_test.cc",
"fl_message_codec_test.cc",
"fl_standard_message_codec_test.cc",
"fl_string_codec_test.cc",
......
// 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_UNSUPPORTED_TYPE,
"Unexpected FlValue type %d", fl_value_get_type(value));
return FALSE;
}
return TRUE;
}
// Handler to parse JSON using rapidjson in SAX mode
struct FlValueHandler {
GPtrArray* stack;
FlValue* key;
GError* error;
FlValueHandler() {
stack = g_ptr_array_new_with_free_func(
reinterpret_cast<GDestroyNotify>(fl_value_unref));
key = nullptr;
error = nullptr;
}
~FlValueHandler() {
g_ptr_array_unref(stack);
if (key != nullptr)
fl_value_unref(key);
if (error != nullptr)
g_error_free(error);
}
// Gets 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));
}
// Pushes a value onto the stack
void push(FlValue* value) { g_ptr_array_add(stack, fl_value_ref(value)); }
// Pops the stack
void pop() { g_ptr_array_remove_index(stack, stack->len - 1); }
// Adds 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 {
g_set_error(&error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
"Can't add value to non container");
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) {
// For some reason (bug in rapidjson?) this is not returned in Int64
if (i == G_MAXINT64)
return add(fl_value_new_int(i));
else
return add(fl_value_new_float(i));
}
bool Double(double d) { return add(fl_value_new_float(d)); }
bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
g_set_error(&error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
"RawNumber not supported");
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)) {
if (handler.error != nullptr) {
g_propagate_error(error, handler.error);
handler.error = nullptr;
} else
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);
}
此差异已折叠。
// 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.
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_JSON_MESSAGE_CODEC_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_JSON_MESSAGE_CODEC_H_
#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
#error "Only <flutter_linux/flutter_linux.h> can be included directly."
#endif
#include "fl_message_codec.h"
G_BEGIN_DECLS
/**
* FlJsonMessageCodecError:
* @FL_JSON_MESSAGE_CODEC_ERROR_INVALID_UTF8: Message is not valid UTF-8.
* @FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON: Message is not valid JSON.
* @FL_JSON_MESSAGE_CODEC_ERROR_INVALID_OBJECT_KEY_TYPE: Invalid object key type
*
* Errors for #FlJsonMessageCodec objects to set on failures.
*/
#define FL_JSON_MESSAGE_CODEC_ERROR fl_json_message_codec_error_quark()
typedef enum {
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_UTF8,
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_JSON,
FL_JSON_MESSAGE_CODEC_ERROR_INVALID_OBJECT_KEY_TYPE,
} FlJsonMessageCodecError;
GQuark fl_json_message_codec_error_quark(void) G_GNUC_CONST;
G_DECLARE_FINAL_TYPE(FlJsonMessageCodec,
fl_json_message_codec,
FL,
JSON_CODEC,
FlMessageCodec)
/**
* FlJsonMessageCodec:
*
* #FlJsonMessageCodec is an #FlMessageCodec that implements the Flutter
* standard message encoding. This encodes and decodes #FlValue of type
* #FL_VALUE_TYPE_NULL, #FL_VALUE_TYPE_BOOL, #FL_VALUE_TYPE_INT,
* #FL_VALUE_TYPE_FLOAT, #FL_VALUE_TYPE_STRING, #FL_VALUE_TYPE_UINT8_LIST,
* #FL_VALUE_TYPE_INT32_LIST, #FL_VALUE_TYPE_INT64_LIST,
* #FL_VALUE_TYPE_FLOAT_LIST, #FL_VALUE_TYPE_LIST, and #FL_VALUE_TYPE_MAP
*
* #FlJsonMessageCodec matches the JSONMessageCodec class in the Flutter
* services library.
*/
/**
* fl_json_message_codec_new:
*
* Creates a #FlJsonMessageCodec.
*
* Returns: a new #FlJsonMessageCodec
*/
FlJsonMessageCodec* fl_json_message_codec_new();
/**
* fl_json_message_codec_encode:
* @codec: a #FlJsonMessageCodec
* @value: value to encode
* @error: (allow-none): #GError location to store the error occurring, or %NULL
*
* Encode a value to a JSON string.
*
* Returns: a JSON representation of this value or %NULL on error.
*/
gchar* fl_json_message_codec_encode(FlJsonMessageCodec* codec,
FlValue* value,
GError** error);
/**
* fl_json_message_codec_decode:
* @codec: a #FlJsonMessageCodec
* @text: UTF-8 text in JSON format
* @error: (allow-none): #GError location to store the error occurring, or %NULL
*
* Decode a value from a JSON string.
*
* Returns: a #FlValue or %NULL on error
*/
FlValue* fl_json_message_codec_decode(FlJsonMessageCodec* codec,
const gchar* text,
GError** error);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_JSON_MESSAGE_CODEC_H_
......@@ -12,6 +12,7 @@
#include <flutter_linux/fl_binary_messenger.h>
#include <flutter_linux/fl_dart_project.h>
#include <flutter_linux/fl_engine.h>
#include <flutter_linux/fl_json_message_codec.h>
#include <flutter_linux/fl_message_codec.h>
#include <flutter_linux/fl_standard_message_codec.h>
#include <flutter_linux/fl_string_codec.h>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册