static void json_node_unset (JsonNode *node) { /* Note: Don't use JSON_NODE_IS_VALID here because this may legitimately be * called with (node->ref_count == 0) from json_node_unref(). */ g_assert (node != NULL); switch (node->type) { case JSON_NODE_OBJECT: if (node->data.object) json_object_unref (node->data.object); break; case JSON_NODE_ARRAY: if (node->data.array) json_array_unref (node->data.array); break; case JSON_NODE_VALUE: if (node->data.value) json_value_unref (node->data.value); break; case JSON_NODE_NULL: break; } }
static void json_builder_state_free (JsonBuilderState *state) { if (G_LIKELY (state)) { switch (state->mode) { case JSON_BUILDER_MODE_OBJECT: case JSON_BUILDER_MODE_MEMBER: json_object_unref (state->data.object); g_free (state->member_name); state->data.object = NULL; state->member_name = NULL; break; case JSON_BUILDER_MODE_ARRAY: json_array_unref (state->data.array); state->data.array = NULL; break; default: g_assert_not_reached (); } g_slice_free (JsonBuilderState, state); } }
static void json_node_unset (JsonNode *node) { g_assert (node != NULL); switch (node->type) { case JSON_NODE_OBJECT: if (node->data.object) json_object_unref (node->data.object); break; case JSON_NODE_ARRAY: if (node->data.array) json_array_unref (node->data.array); break; case JSON_NODE_VALUE: if (node->data.value) json_value_unref (node->data.value); break; case JSON_NODE_NULL: break; } }
static JsonGenerator * _model_to_generator (MexQueueModel *model) { gint i; JsonArray *json_array; JsonNode *root; JsonGenerator *generator; json_array = json_array_sized_new (mex_model_get_length (MEX_MODEL (model))); for (i = 0; i < mex_model_get_length (MEX_MODEL (model)); i++) { MexContent *content; JsonNode *content_node; content = mex_model_get_content (MEX_MODEL (model), i); content_node = json_gobject_serialize (G_OBJECT (content)); json_array_add_element (json_array, content_node); } generator = json_generator_new (); root = json_node_new (JSON_NODE_ARRAY); json_node_set_array (root, json_array); json_generator_set_root (generator, root); json_array_unref (json_array); json_node_free (root); return generator; }
/* Register a JSON-RPC method */ static void melo_jsonrpc_free_method (gpointer data) { MeloJSONRPCInternalMethod *m = data; /* Free nodes */ if (m->params) json_array_unref (m->params); if (m->result) json_object_unref (m->result); /* Free method */ g_slice_free (MeloJSONRPCInternalMethod, m); }
/** * json_node_set_array: * @node: a #JsonNode initialized to %JSON_NODE_ARRAY * @array: a #JsonArray * * Sets @array inside @node and increases the #JsonArray reference count */ void json_node_set_array (JsonNode *node, JsonArray *array) { g_return_if_fail (node != NULL); g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY); if (node->data.array) json_array_unref (node->data.array); if (array) node->data.array = json_array_ref (array); else node->data.array = NULL; }
static void consume_array_member (JsonBuilder *bob, const char* elm, JsonArray *arr) { JsonNode *node; if (!arr) return; /* nothing to do */ node = json_node_new (JSON_NODE_ARRAY); json_node_init_array (node, arr); json_array_unref (arr); bob = json_builder_set_member_name (bob, elm); bob = json_builder_add_value (bob, node); /* consumes */ }
/** * json_node_take_array: * @node: a #JsonNode initialized to %JSON_NODE_ARRAY * @array: (transfer full): a #JsonArray * * Sets @array into @node without increasing the #JsonArray reference count. */ void json_node_take_array (JsonNode *node, JsonArray *array) { g_return_if_fail (node != NULL); g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY); if (node->data.array) { json_array_unref (node->data.array); node->data.array = NULL; } if (array) node->data.array = array; }
static void postal_http_reply_devices (PostalHttp *http, SoupMessage *message, guint status, GPtrArray *devices) { JsonGenerator *g; PostalDevice *device; JsonArray *ar; JsonNode *node; JsonNode *child; gchar *json_buf; gsize length; guint i; g_assert(SOUP_IS_MESSAGE(message)); g_assert(devices); ar = json_array_new(); node = json_node_new(JSON_NODE_ARRAY); for (i = 0; i < devices->len; i++) { device = g_ptr_array_index(devices, i); if ((child = postal_device_save_to_json(device, NULL))) { json_array_add_element(ar, child); } } json_node_set_array(node, ar); json_array_unref(ar); g = json_generator_new(); json_generator_set_root(g, node); json_node_free(node); json_generator_set_indent(g, 2); json_generator_set_pretty(g, TRUE); json_buf = json_generator_to_data(g, &length); g_object_unref(g); soup_message_set_response(message, "application/json", SOUP_MEMORY_TAKE, json_buf, length); soup_message_set_status(message, status ?: SOUP_STATUS_OK); soup_server_unpause_message(http->priv->server, message); }
static JsonNode * gvariant_to_json_array (GVariant *variant) { JsonArray *array; JsonNode *json_node; array = json_array_new (); json_node = json_node_new (JSON_NODE_ARRAY); json_node_set_array (json_node, array); json_array_unref (array); gvariant_foreach (variant, gvariant_to_json_array_foreach, array); return json_node; }
/** * json_array_add_array_element: * @array: a #JsonArray * @value: (allow-none) (transfer full): a #JsonArray * * Conveniently adds an array into @array. The @array takes ownership * of the newly added #JsonArray * * See also: json_array_add_element(), json_node_take_array() * * Since: 0.8 */ void json_array_add_array_element (JsonArray *array, JsonArray *value) { JsonNode *node; g_return_if_fail (array != NULL); node = json_node_alloc (); if (value != NULL) { json_node_init_array (node, value); json_array_unref (value); } else json_node_init_null (node); g_ptr_array_add (array->elements, node); }
/** * melo_jsonrpc_get_array: * @schema_params: the schema to use for parameters conversion (see * #MeloJSONRPCMethod for more details) * @params: the parameters to convert * @error: a pointer to a #JsonNode which is set with a valid JSON-RPC error if * an error has occurred * * Convert the #JsonNode containing the parameters into a #JsonArray with all * items sorted as the provided schema. * * Returns: (transfer full): a new #JsonArray containing all parameters sorted * as provided schema, or %NULL if an error occurred. Use json_array_unref() * after usage. */ JsonArray * melo_jsonrpc_get_array (JsonArray *schema_params, JsonNode *params, JsonNode **error) { JsonArray *array; guint count; /* Get array length */ count = json_array_get_length (schema_params); /* Allocate new array */ array = json_array_sized_new (count); /* Get array */ if (!melo_jsonrpc_get_json_node (schema_params, params, NULL, array, error)) { json_array_unref (array); return NULL; } return array; }
/** * json_object_set_array_member: * @object: a #JsonObject * @member_name: the name of the member * @value: (transfer full): the value of the member * * Convenience function for setting an array @value of * @member_name inside @object. * * The @object will take ownership of the passed #JsonArray * * See also: json_object_set_member() * * Since: 0.8 */ void json_object_set_array_member (JsonObject *object, const gchar *member_name, JsonArray *value) { JsonNode *node; g_return_if_fail (object != NULL); g_return_if_fail (member_name != NULL); node = json_node_alloc (); if (value != NULL) { json_node_init_array (node, value); json_array_unref (value); } else json_node_init_null (node); object_set_member_internal (object, member_name, node); }
static void trg_torrent_move_response_cb(GtkDialog * dlg, gint res_id, gpointer data) { TrgTorrentMoveDialogPrivate *priv = TRG_TORRENT_MOVE_DIALOG_GET_PRIVATE(dlg); if (res_id == GTK_RESPONSE_ACCEPT) { gchar *location = trg_destination_combo_get_dir(TRG_DESTINATION_COMBO (priv->location_combo)); JsonNode *request = torrent_set_location(priv->ids, location, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->move_check))); g_free(location); trg_destination_combo_save_selection(TRG_DESTINATION_COMBO (priv->location_combo)); dispatch_async(priv->client, request, on_generic_interactive_action_response, data); } else { json_array_unref(priv->ids); } gtk_widget_destroy(GTK_WIDGET(dlg)); }
JsonNode * json_serialize_pspec (const GValue *real_value, GParamSpec *pspec) { JsonNode *retval = NULL; JsonNodeType node_type; switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (real_value))) { /* JSON native types */ case G_TYPE_INT64: retval = json_node_init_int (json_node_alloc (), g_value_get_int64 (real_value)); break; case G_TYPE_BOOLEAN: retval = json_node_init_boolean (json_node_alloc (), g_value_get_boolean (real_value)); break; case G_TYPE_DOUBLE: retval = json_node_init_double (json_node_alloc (), g_value_get_double (real_value)); break; case G_TYPE_STRING: retval = json_node_init_string (json_node_alloc (), g_value_get_string (real_value)); break; /* auto-promoted types */ case G_TYPE_INT: retval = json_node_init_int (json_node_alloc (), g_value_get_int (real_value)); break; case G_TYPE_UINT: retval = json_node_init_int (json_node_alloc (), g_value_get_uint (real_value)); break; case G_TYPE_LONG: retval = json_node_init_int (json_node_alloc (), g_value_get_long (real_value)); break; case G_TYPE_ULONG: retval = json_node_init_int (json_node_alloc (), g_value_get_ulong (real_value)); break; case G_TYPE_UINT64: retval = json_node_init_int (json_node_alloc (), g_value_get_uint64 (real_value)); break; case G_TYPE_FLOAT: retval = json_node_init_double (json_node_alloc (), g_value_get_float (real_value)); break; case G_TYPE_CHAR: retval = json_node_alloc (); json_node_init_int (retval, g_value_get_schar (real_value)); break; case G_TYPE_UCHAR: retval = json_node_init_int (json_node_alloc (), g_value_get_uchar (real_value)); break; case G_TYPE_ENUM: retval = json_node_init_int (json_node_alloc (), g_value_get_enum (real_value)); break; case G_TYPE_FLAGS: retval = json_node_init_int (json_node_alloc (), g_value_get_flags (real_value)); break; /* complex types */ case G_TYPE_BOXED: if (G_VALUE_HOLDS (real_value, G_TYPE_STRV)) { gchar **strv = g_value_get_boxed (real_value); gint i, strv_len; JsonArray *array; strv_len = g_strv_length (strv); array = json_array_sized_new (strv_len); for (i = 0; i < strv_len; i++) { JsonNode *str = json_node_new (JSON_NODE_VALUE); json_node_set_string (str, strv[i]); json_array_add_element (array, str); } retval = json_node_init_array (json_node_alloc (), array); json_array_unref (array); } else if (json_boxed_can_serialize (G_VALUE_TYPE (real_value), &node_type)) { gpointer boxed = g_value_get_boxed (real_value); retval = json_boxed_serialize (G_VALUE_TYPE (real_value), boxed); } else g_warning ("Boxed type '%s' is not handled by JSON-GLib", g_type_name (G_VALUE_TYPE (real_value))); break; case G_TYPE_OBJECT: { GObject *object = g_value_get_object (real_value); retval = json_node_alloc (); if (object != NULL) { json_node_init (retval, JSON_NODE_OBJECT); json_node_take_object (retval, json_gobject_dump (object)); } else json_node_init_null (retval); } break; case G_TYPE_NONE: retval = json_node_new (JSON_NODE_NULL); break; default: g_warning ("Unsupported type `%s'", g_type_name (G_VALUE_TYPE (real_value))); break; } return retval; }
JsonNode * js_util_tojsonnode(js_State *state, int idx) { const char *s; JsonNode *node; JsonNode *tmp; JsonObject *object; JsonArray *array; unsigned int i, length; node = json_node_alloc(); if (js_isstring(state, idx)) { json_node_init_string(node, js_tostring(state, idx)); } else if (js_isnumber(state, idx)) { json_node_init_int(node, js_tointeger(state, idx)); } else if (js_isboolean(state, idx)) { json_node_init_boolean(node, js_toboolean(state, idx)); } else if (js_isarray(state, idx)) { length = js_getlength(state, idx); array = json_array_new(); json_node_init_array(node, array); for (i = 0; i < length; i++) { js_getindex(state, idx, i); tmp = js_util_tojsonnode(state, -1); if (tmp) json_array_add_element(array, tmp); js_pop(state, 1); } json_array_unref(array); } else if (js_isobject(state, idx)) { object = json_object_new(); json_node_init_object(node, object); js_pushiterator(state, idx, 1); while((s = js_nextiterator(state, -1)) != NULL) { if (idx > 0) js_getproperty(state, idx, s); else js_getproperty(state, idx - 1, s); tmp = js_util_tojsonnode(state, -1); if (tmp) json_object_set_member(object, s, tmp); js_pop(state, 1); } js_pop(state, 1); json_object_unref(object); } else { json_node_free(node); return NULL; } return node; }
static guint json_parse_array (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonNode *old_current; JsonArray *array; guint token; gint idx; old_current = priv->current_node; priv->current_node = json_node_new (JSON_NODE_ARRAY); array = json_array_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_BRACE); g_signal_emit (parser, parser_signals[ARRAY_START], 0); idx = 0; while (token != G_TOKEN_RIGHT_BRACE) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *element = NULL; /* parse the element */ switch (next_token) { case G_TOKEN_LEFT_BRACE: token = json_parse_array (parser, scanner, &element); break; case G_TOKEN_LEFT_CURLY: token = json_parse_object (parser, scanner, &element); break; case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: case '-': case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: case JSON_TOKEN_NULL: token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &element); break; case G_TOKEN_RIGHT_BRACE: goto array_done; default: if (next_token != G_TOKEN_RIGHT_BRACE) token = G_TOKEN_RIGHT_BRACE; break; } if (token != G_TOKEN_NONE || element == NULL) { /* the json_parse_* functions will have set the error code */ json_array_unref (array); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_BRACE) { json_array_unref (array); json_node_free (priv->current_node); json_node_free (element); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } json_node_set_parent (element, priv->current_node); json_array_add_element (array, element); g_signal_emit (parser, parser_signals[ARRAY_ELEMENT], 0, array, idx); token = next_token; } array_done: json_scanner_get_next_token (scanner); json_node_take_array (priv->current_node, array); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[ARRAY_END], 0, array); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
/** * melo_jsonrpc_register_methods: * @group: prefix of the method * @methods: an array of #MeloJSONRPCMethod * @count: the number of methods in @methods * * Register multiple JSON-RPC method named with the same prefix @group. All * final methods will be as "@group.NAME". * * Returns: 0 if all methods have been registered or the number of methods which * has not been registered. */ guint melo_jsonrpc_register_methods (const gchar *group, MeloJSONRPCMethod *methods, guint count) { JsonParser *parser; JsonObject *result; JsonArray *params; JsonNode *node; guint errors = 0, i; gboolean ret; /* Create a parser */ parser = json_parser_new (); /* Register all methods */ for (i = 0; i < count; i++) { /* Generate params schema */ if (json_parser_load_from_data (parser, methods[i].params, -1, NULL)) { /* Convert string to node */ node = json_parser_get_root (parser); /* Node params type must be an array */ if (json_node_get_node_type (node) != JSON_NODE_ARRAY) continue; /* Get array */ params = json_node_dup_array (node); } else params = NULL; /* Generate result schema */ if (json_parser_load_from_data (parser, methods[i].result, -1, NULL)) { /* Convert string to node */ node = json_parser_get_root (parser); /* Node result type must be an object */ if (json_node_get_node_type (node) != JSON_NODE_OBJECT) continue; /* Get array */ result = json_node_dup_object (node); } else result = NULL; /* Register method */ ret = melo_jsonrpc_register_method (group, methods[i].method, params, result, methods[i].callback, methods[i].user_data); /* Failed to register method */ if (!ret) { if (params) json_array_unref (params); if (result) json_object_unref (result); errors++; } } /* Release parser */ g_object_unref (parser); return errors; }
/* Parse JSON-RPC request */ static JsonNode * melo_jsonrpc_parse_node (JsonNode *node) { MeloJSONRPCInternalMethod *m; MeloJSONRPCCallback callback = NULL; gpointer user_data = NULL; JsonArray *s_params = NULL; JsonNode *result = NULL; JsonNode *error = NULL; JsonNode *params; JsonObject *obj; const char *version; const char *method; const char *id = NULL; gint64 nid = -1; /* Not an object */ if (JSON_NODE_TYPE (node) != JSON_NODE_OBJECT) goto invalid; /* Get object from nide */ obj = json_node_get_object (node); if (!obj) goto internal; /* Check if jsonrpc is present */ if (!json_object_has_member (obj, "jsonrpc")) goto invalid; /* Check JSON-RPC version */ version = json_object_get_string_member (obj, "jsonrpc"); if (!version || strcmp (version, "2.0")) goto invalid; /* Check if method is present */ if (!json_object_has_member (obj, "method")) goto invalid; /* Get method */ method = json_object_get_string_member (obj, "method"); if (!method) goto invalid; /* Get params */ params = json_object_get_member (obj, "params"); if (params) { JsonNodeType type; /* Check params type: only object or array allowed */ type = json_node_get_node_type (params); if (type != JSON_NODE_ARRAY && type != JSON_NODE_OBJECT) goto invalid; } /* Get registered method */ G_LOCK (melo_jsonrpc_mutex); if (melo_jsonrpc_methods) { m = g_hash_table_lookup (melo_jsonrpc_methods, method); if (m) { callback = m->callback; user_data = m->user_data; if (m->params) s_params = json_array_ref (m->params); } } G_UNLOCK (melo_jsonrpc_mutex); /* Check if id is present */ if (!json_object_has_member (obj, "id")) { /* This is a notification: try to call callback */ if (callback) { callback (method, s_params, params, &result, &error, user_data); if (s_params) json_array_unref (s_params); if (error) json_node_free (error); if (result) json_node_free (result); } return NULL; } /* Get id */ nid = json_object_get_int_member (obj, "id"); id = json_object_get_string_member (obj, "id"); /* No callback provided */ if (!callback) goto not_found; /* Call user callback */ callback (method, s_params, params, &result, &error, user_data); if (s_params) json_array_unref (s_params); /* No error or result */ if (!error && !result) goto not_found; /* Build response */ return melo_jsonrpc_build_response_node (result, error, id, nid); invalid: return melo_jsonrpc_build_error (NULL, -1, MELO_JSONRPC_ERROR_INVALID_REQUEST, "Invalid request"); not_found: return melo_jsonrpc_build_error (id, nid, MELO_JSONRPC_ERROR_METHOD_NOT_FOUND, "Method not found"); internal: return melo_jsonrpc_build_error (id, -1, MELO_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error"); }
static guint json_parse_array (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonNode *old_current; JsonArray *array; guint token; gint idx; old_current = priv->current_node; priv->current_node = json_node_init_array (json_node_alloc (), NULL); array = json_array_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_BRACE); g_signal_emit (parser, parser_signals[ARRAY_START], 0); idx = 0; while (token != G_TOKEN_RIGHT_BRACE) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *element = NULL; /* parse the element */ switch (next_token) { case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Nested array at index %d", idx); token = json_parse_array (parser, scanner, &element); break; case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Nested object at index %d", idx); token = json_parse_object (parser, scanner, &element); break; case G_TOKEN_RIGHT_BRACE: goto array_done; default: token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &element); break; } if (token != G_TOKEN_NONE || element == NULL) { /* the json_parse_* functions will have set the error code */ json_array_unref (array); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_BRACE) { priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA; json_array_unref (array); json_node_free (priv->current_node); json_node_free (element); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } JSON_NOTE (PARSER, "Array element %d completed", idx + 1); json_node_set_parent (element, priv->current_node); json_array_add_element (array, element); g_signal_emit (parser, parser_signals[ARRAY_ELEMENT], 0, array, idx); token = next_token; } array_done: json_scanner_get_next_token (scanner); json_node_take_array (priv->current_node, array); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[ARRAY_END], 0, array); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
} END_TEST /* FIXME: more tests required for: * * - array containing an array (of various types). * - array containing an object (containing various types). */ START_TEST(test_cc_oci_json_arr_to_string) { gchar *str; JsonArray *array; gboolean ret; ck_assert (! cc_oci_json_arr_to_string (NULL, false)); ck_assert (! cc_oci_json_arr_to_string (NULL, true)); array = json_array_new (); /* empty array, non-pretty */ str = cc_oci_json_arr_to_string (array, false); ck_assert (str); ck_assert (! g_strcmp0 (str, "[]")); g_free (str); /* empty array, pretty */ str = cc_oci_json_arr_to_string (array, true); ck_assert (str); ret = g_regex_match_simple ( /* pair of braces containing optional * whitespace. */ "[\\s*]", str, 0, 0); ck_assert (ret); g_free (str); json_array_add_null_element (array); json_array_add_null_element (array); json_array_add_boolean_element (array, false); json_array_add_boolean_element (array, true); json_array_add_int_element (array, 123); json_array_add_double_element (array, 3.1412); json_array_add_string_element (array, "foo bar"); str = cc_oci_json_arr_to_string (array, false); ck_assert (str); ret = g_regex_match_simple ( "[\\s*" /* opening bracket */ "\\s*null\\s*," /* null */ "\\s*null\\s*," /* null */ "\\s*false\\s*," /* false */ "\\s*true\\s*," /* true */ "\\s*123\\s*," /* int */ "\\s*3\\.1412\\s*," /* double */ "\\s*\"foo\\ bar\"\\s*," /* string */ "\\s*]", /* closing bracket */ str, 0, 0); ck_assert (ret); g_free (str); /* clean up */ json_array_unref (array); } END_TEST