From cbfe44aeb4c075d7d8ddc4de809c6290f5046308 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 31 Jul 2024 09:20:56 -0400 Subject: [PATCH] MT#55283 add native JSON parser Change-Id: Ib6adf8adbd3a14797932687c605395fdb20003fe --- daemon/control_ng.c | 196 ++++++++++++++++++++++++++++++++++++++++---- include/types.h | 2 + 2 files changed, 183 insertions(+), 15 deletions(-) diff --git a/daemon/control_ng.c b/daemon/control_ng.c index e41ae47f9..c4bbd821c 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -143,6 +143,172 @@ static parser_arg __bencode_dictionary_get_expect(bencode_item_t *arg, const cha return (parser_arg) bencode_dictionary_get_expect(arg, ele, type); } +static bool json_is_dict(JsonNode *n) { + return json_node_get_node_type(n) == JSON_NODE_OBJECT; +} +static bool json_is_list(JsonNode *n) { + return json_node_get_node_type(n) == JSON_NODE_ARRAY; +} +static bool json_is_int(JsonNode *n) { + if (json_node_get_node_type(n) != JSON_NODE_VALUE) + return false; + GType type = json_node_get_value_type(n); + switch (type) { + case G_TYPE_INT: + case G_TYPE_UINT: + case G_TYPE_LONG: + case G_TYPE_ULONG: + case G_TYPE_INT64: + case G_TYPE_UINT64: + case G_TYPE_BOOLEAN: + return true; + } + return false; +} +static char *json_dict_get_str(JsonNode *dict, const char *entry, str *out) { + JsonObject *o = json_node_get_object(dict); + if (!o) + goto out; + JsonNode *n = json_object_get_member(o, entry); + if (!n) + goto out; + const char *s = json_node_get_string(n); + if (!s) + goto out; + *out = STR(s); + return out->s; +out: + *out = STR_NULL; + return NULL; +} +static void json_pretty_print(JsonNode *a, GString *out) { + JsonGenerator *g = json_generator_new(); + json_generator_set_root(g, a); + json_generator_to_gstring(g, out); + g_object_unref(g); +} +static long long json_get_int_str(JsonNode *n, long long def) { + if (json_node_get_node_type(n) != JSON_NODE_VALUE) + return def; + GType type = json_node_get_value_type(n); + switch (type) { + case G_TYPE_INT: + case G_TYPE_UINT: + case G_TYPE_LONG: + case G_TYPE_ULONG: + case G_TYPE_INT64: + case G_TYPE_UINT64: + case G_TYPE_BOOLEAN: + return json_node_get_int(n); + case G_TYPE_STRING:; + const char *s = json_node_get_string(n); + char *ep; + long long r = strtoll(s, &ep, 0); + if (ep == s) + return def; + return r; + default: + return def; + } +} +static long long json_get_int(JsonNode *n) { + if (json_node_get_node_type(n) != JSON_NODE_VALUE) + return 0; + if (!json_is_int(n)) + return 0; + return json_node_get_int(n); +} +static long long json_dict_get_int_str(JsonNode *dict, const char *entry, long long def) { + JsonObject *o = json_node_get_object(dict); + if (!o) + return def; + JsonNode *n = json_object_get_member(o, entry); + if (!n) + return def; + if (json_node_get_node_type(n) != JSON_NODE_VALUE) + return def; + return json_get_int_str(n, def); +} +static parser_arg json_dict_get_expect(JsonNode *dict, const char *entry, bencode_type_t type) { + JsonObject *o = json_node_get_object(dict); + if (!o) + return (parser_arg) NULL; + JsonNode *n = json_object_get_member(o, entry); + if (!n) + return (parser_arg) NULL; + switch (type) { + case BENCODE_LIST: + if (json_node_get_value_type(n) != JSON_NODE_ARRAY) + return (parser_arg) NULL; + return (parser_arg) n; + default: + abort(); + } +} +static void json_dict_iter_fn(JsonObject *o, const char *key, JsonNode *val, void *arg) { + void **ptrs = arg; + void (*callback)(ng_parser_ctx_t *, str *key, JsonNode *value, helper_arg) = ptrs[1]; + callback(ptrs[0], &STR(key), val, ptrs[2]); +} + +static bool json_dict_iter(ng_parser_ctx_t *ctx, JsonNode *input, + void (*callback)(ng_parser_ctx_t *, str *key, JsonNode *value, helper_arg), + helper_arg arg) +{ + if (json_node_get_node_type(input) != JSON_NODE_OBJECT) + return false; + + JsonObject *o = json_node_get_object(input); + if (!o) + return false; + + void *ptrs[3] = { ctx, callback, arg.generic }; + json_object_foreach_member(o, json_dict_iter_fn, ptrs); + + return true; +} +static void json_list_iter(ng_parser_ctx_t *ctx, JsonNode *list, + void (*str_callback)(ng_parser_ctx_t *, str *key, helper_arg), + void (*item_callback)(ng_parser_ctx_t *, JsonNode *, helper_arg), + helper_arg arg) +{ + if (json_node_get_node_type(list) != JSON_NODE_ARRAY) + return; + + JsonArray *a = json_node_get_array(list); + if (!a) + return; + + unsigned int l = json_array_get_length(a); + for (unsigned int i = 0; i < l; i++) { + JsonNode *n = json_array_get_element(a, i); + if (json_node_get_node_type(n) == JSON_NODE_VALUE + && json_node_get_value_type(n) == G_TYPE_STRING) + { + const char *s = json_node_get_string(n); + if (s) + str_callback(ctx, &STR(s), arg); + } + else + item_callback(ctx, n, arg); + } +} +static str *json_get_str(JsonNode *a, str *out) { + const char *s = json_node_get_string(a); + if (!s) + return NULL; + *out = STR(s); + return out; +} +static int json_strcmp(JsonNode *n, const char *b) { + if (json_node_get_node_type(n) != JSON_NODE_VALUE) + return 2; + if (json_node_get_value_type(n) != G_TYPE_STRING) + return 1; + const char *s = json_node_get_string(n); + return strcmp(s, b); +} + const ng_parser_t ng_parser_native = { .collapse = bencode_collapse_str, .dict_iter = bencode_dict_iter, @@ -173,19 +339,19 @@ const ng_parser_t ng_parser_native = { }; const ng_parser_t ng_parser_json = { .collapse = bencode_collapse_str_json, - .dict_iter = bencode_dict_iter, - .is_list = bencode_is_list, - .list_iter = bencode_list_iter, - .get_str = bencode_get_str, - .strcmp = bencode_strcmp, - .get_int_str = bencode_get_integer_str, - .is_int = bencode_is_int, - .get_int = bencode_get_int, - .is_dict = bencode_is_dict, + .dict_iter = json_dict_iter, + .is_list = json_is_list, + .list_iter = json_list_iter, + .get_str = json_get_str, + .strcmp = json_strcmp, + .get_int_str = json_get_int_str, + .is_int = json_is_int, + .get_int = json_get_int, + .is_dict = json_is_dict, .dict = __bencode_dict, - .dict_get_str = bencode_dictionary_get_str, - .dict_get_int_str = bencode_dictionary_get_int_str, - .dict_get_expect = __bencode_dictionary_get_expect, + .dict_get_str = json_dict_get_str, + .dict_get_int_str = json_dict_get_int_str, + .dict_get_expect = json_dict_get_expect, .dict_add = bencode_dictionary_add, .dict_add_string = bencode_dictionary_add_string, .dict_add_str = bencode_dictionary_add_str, @@ -197,7 +363,7 @@ const ng_parser_t ng_parser_json = { .list_add = bencode_list_add, .list_add_dict = bencode_list_add_dictionary, .list_add_string = bencode_list_add_string, - .pretty_print = bencode_pretty_print, + .pretty_print = json_pretty_print, }; @@ -376,9 +542,9 @@ static void control_ng_process_payload(ng_ctx *hctx, str *reply, str *data, cons errstr = "Failed to parse JSON document"; if (!json_parser_load_from_data(parser_ctx.ngbuf->json, data->s, data->len, NULL)) goto err_send; - parser_ctx.req.benc = bencode_convert_json(&parser_ctx.ngbuf->buffer, parser_ctx.ngbuf->json); + parser_ctx.req.json = json_parser_get_root(parser_ctx.ngbuf->json); errstr = "Could not decode bencode dictionary"; - if (!parser_ctx.req.benc || parser_ctx.req.benc->type != BENCODE_DICTIONARY) + if (!parser_ctx.req.json || !parser_ctx.parser->is_dict(parser_ctx.req)) goto err_send; } diff --git a/include/types.h b/include/types.h index fb262e2cc..1c3ce179e 100644 --- a/include/types.h +++ b/include/types.h @@ -2,6 +2,7 @@ #define __TYPES__H__ #include +#include #include "socket.h" typedef struct sdp_ng_flags sdp_ng_flags; @@ -43,6 +44,7 @@ typedef struct bencode_item bencode_item_t; typedef union { bencode_item_t *benc; + JsonNode *json; void *gen; } parser_arg __attribute__ ((__transparent_union__));