diff options
| author | Luca Bruno <lethalman88@gmail.com> | 2010-06-09 21:31:06 +0200 |
|---|---|---|
| committer | Emmanuele Bassi <ebassi@linux.intel.com> | 2010-06-16 12:00:24 +0100 |
| commit | 08f3073eeb0f7e2e0973abd23ba4ec978ad302d7 (patch) | |
| tree | f8cb9170c11b60cf858fb24e4b70b414375f7a05 | |
| parent | 3f8c8f99126dc1a70d847eded13afd4b64395250 (diff) | |
| download | json-glib-08f3073eeb0f7e2e0973abd23ba4ec978ad302d7.tar.gz | |
builder: Add convenience API for building JSON trees.
https://bugzilla.gnome.org/show_bug.cgi?id=621141
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | json-glib/Makefile.am | 2 | ||||
| -rw-r--r-- | json-glib/json-builder.c | 682 | ||||
| -rw-r--r-- | json-glib/json-builder.h | 100 | ||||
| -rw-r--r-- | json-glib/json-glib.h | 1 | ||||
| -rw-r--r-- | json-glib/tests/Makefile.am | 3 | ||||
| -rw-r--r-- | json-glib/tests/builder-test.c | 121 |
7 files changed, 910 insertions, 0 deletions
@@ -39,6 +39,7 @@ json-glib.pc /json-glib/stamp-enum-types /json-glib/stamp-marshal /json-glib/tests/array-test +/json-glib/tests/builder-test /json-glib/tests/generator-test /json-glib/tests/object-test /json-glib/tests/node-test diff --git a/json-glib/Makefile.am b/json-glib/Makefile.am index 717393c..2e61785 100644 --- a/json-glib/Makefile.am +++ b/json-glib/Makefile.am @@ -30,6 +30,7 @@ CLEANFILES = DISTCLEANFILES = json-version.h source_h = \ + $(top_srcdir)/json-glib/json-builder.h \ $(top_srcdir)/json-glib/json-generator.h \ $(top_srcdir)/json-glib/json-gobject.h \ $(top_srcdir)/json-glib/json-parser.h \ @@ -45,6 +46,7 @@ source_h_private = \ source_c = \ $(srcdir)/json-array.c \ + $(srcdir)/json-builder.c \ $(srcdir)/json-debug.c \ $(srcdir)/json-gboxed.c \ $(srcdir)/json-generator.c \ diff --git a/json-glib/json-builder.c b/json-glib/json-builder.c new file mode 100644 index 0000000..ea9bc05 --- /dev/null +++ b/json-glib/json-builder.c @@ -0,0 +1,682 @@ +/* json-generator.c - JSON tree builder + * + * This file is part of JSON-GLib + * Copyright (C) 2010 Luca Bruno <lethalman88@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: + * Luca Bruno <lethalman88@gmail.com> + */ + +/** + * SECTION:json-builder + * @short_description: Generates JSON trees + * + * #JsonBuilder provides an object for generating a JSON tree. + * You can generate only one tree with one #JsonBuilder instance. + * + * The root of the JSON tree can be either a #JsonObject or a #JsonArray. + * Thus the first call must necessarily be either + * json_builder_begin_object() or json_builder_begin_array(). + * + * For convenience to language bindings, #JsonBuilder returns itself from + * most of functions, making it easy to chain function calls. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "json-types-private.h" + +#include "json-builder.h" + +#define JSON_BUILDER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), JSON_TYPE_BUILDER, JsonBuilderPrivate)) + +struct _JsonBuilderPrivate +{ + GQueue *stack; + JsonNode *root; +}; + +typedef enum +{ + JSON_BUILDER_MODE_OBJECT, + JSON_BUILDER_MODE_ARRAY, + JSON_BUILDER_MODE_MEMBER +} JsonBuilderMode; + +typedef struct +{ + JsonBuilderMode mode; + + union + { + JsonObject *object; + JsonArray *array; + } data; + gchar *member_name; +} JsonBuilderState; + +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); + } +} + +G_DEFINE_TYPE (JsonBuilder, json_builder, G_TYPE_OBJECT); + +static void +json_builder_free_all_state (JsonBuilder *builder) +{ + JsonBuilderState *state; + + while (!g_queue_is_empty (builder->priv->stack)) + { + state = g_queue_pop_head (builder->priv->stack); + json_builder_state_free (state); + } + + if (builder->priv->root) + { + json_node_free (builder->priv->root); + builder->priv->root = NULL; + } +} + +static void +json_builder_finalize (GObject *gobject) +{ + JsonBuilderPrivate *priv = JSON_BUILDER_GET_PRIVATE (gobject); + + json_builder_free_all_state (JSON_BUILDER (gobject)); + + g_queue_free (priv->stack); + priv->stack = NULL; + + G_OBJECT_CLASS (json_builder_parent_class)->finalize (gobject); +} + +static void +json_builder_class_init (JsonBuilderClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (JsonBuilderPrivate)); + + gobject_class->finalize = json_builder_finalize; +} + +static void +json_builder_init (JsonBuilder *builder) +{ + JsonBuilderPrivate *priv; + + builder->priv = priv = JSON_BUILDER_GET_PRIVATE (builder); + + priv->stack = g_queue_new (); + priv->root = NULL; +} + +static inline JsonBuilderMode +json_builder_current_mode (JsonBuilder *builder) +{ + JsonBuilderState *state = g_queue_peek_head (builder->priv->stack); + return state->mode; +} + +static inline gboolean +json_builder_is_valid_add_mode (JsonBuilder *builder) +{ + JsonBuilderMode mode = json_builder_current_mode (builder); + return mode == JSON_BUILDER_MODE_MEMBER || mode == JSON_BUILDER_MODE_ARRAY; +} + +/** + * json_builder_new: + * + * Creates a new #JsonBuilder. You can use this object to generate a + * JSON tree and obtain the root #JsonNode<!-- -->s. + * + * Return value: the newly created #JsonBuilder instance + */ +JsonBuilder * +json_builder_new (void) +{ + return g_object_new (JSON_TYPE_BUILDER, NULL); +} + +/** + * json_builder_get_root: + * @builder: a #JsonBuilder + * + * Returns the root of the current constructed tree, if the build is complete + * (ie: all opened objects, object members and arrays are being closed). + * + * Return value: (transfer full): the #JsonNode, or %NULL if the build is not complete. + * Free the returned value with json_node_free(). + */ +JsonNode * +json_builder_get_root (JsonBuilder *builder) +{ + JsonNode *root = NULL; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + + if (builder->priv->root) + root = json_node_copy (builder->priv->root); + + return root; +} + +/** + * json_builder_reset: + * @builder: a #JsonBuilder + * + * Resets the state of the @builder back to its initial state. + */ +void +json_builder_reset (JsonBuilder *builder) +{ + g_return_if_fail (JSON_IS_BUILDER (builder)); + + json_builder_free_all_state (builder); +} + +/** + * json_builder_begin_object: + * @builder: a #JsonBuilder + * + * Opens a subobject inside the given @builder. When done adding members to + * the subobject, json_builder_end_object() must be called. + * + * Can be called for first or only if the call is associated to an object member + * or an array element. + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_begin_object (JsonBuilder *builder) +{ + JsonObject *object; + JsonBuilderState *state; + JsonBuilderState *cur_state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (builder->priv->root == NULL, NULL); + g_return_val_if_fail (g_queue_is_empty (builder->priv->stack) || json_builder_is_valid_add_mode (builder), NULL); + + object = json_object_new (); + cur_state = g_queue_peek_head (builder->priv->stack); + if (cur_state) + { + switch (cur_state->mode) + { + case JSON_BUILDER_MODE_ARRAY: + json_array_add_object_element (cur_state->data.array, json_object_ref (object)); + break; + + case JSON_BUILDER_MODE_MEMBER: + json_object_set_object_member (cur_state->data.object, cur_state->member_name, json_object_ref (object)); + g_free (cur_state->member_name); + cur_state->member_name = NULL; + cur_state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + default: + g_assert_not_reached (); + } + } + + state = g_slice_new (JsonBuilderState); + state->data.object = object; + state->mode = JSON_BUILDER_MODE_OBJECT; + g_queue_push_head (builder->priv->stack, state); + + return builder; +} + +/** + * json_builder_end_object: + * @builder: a #JsonBuilder + * + * Closes the subobject inside the given @builder that was opened by the most + * recent call to json_builder_begin_object(). + * + * Cannot be called after json_builder_set_member_name(). + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_end_object (JsonBuilder *builder) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_current_mode (builder) == JSON_BUILDER_MODE_OBJECT, NULL); + + state = g_queue_pop_head (builder->priv->stack); + + if (g_queue_is_empty (builder->priv->stack)) + { + builder->priv->root = json_node_new (JSON_NODE_OBJECT); + json_node_take_object (builder->priv->root, json_object_ref (state->data.object)); + } + + json_builder_state_free (state); + + return builder; +} + +/** + * json_builder_begin_array: + * @builder: a #JsonBuilder + * + * Opens a subarray inside the given @builder. When done adding members to + * the subarray, json_builder_end_array() must be called. + * + * Can be called for first or only if the call is associated to an object member + * or an array element. + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_begin_array (JsonBuilder *builder) +{ + JsonArray *array; + JsonBuilderState *state; + JsonBuilderState *cur_state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (builder->priv->root == NULL, NULL); + g_return_val_if_fail (g_queue_is_empty (builder->priv->stack) || json_builder_is_valid_add_mode (builder), NULL); + + array = json_array_new (); + cur_state = g_queue_peek_head (builder->priv->stack); + if (cur_state) + { + switch (cur_state->mode) + { + case JSON_BUILDER_MODE_ARRAY: + json_array_add_array_element (cur_state->data.array, json_array_ref (array)); + break; + + case JSON_BUILDER_MODE_MEMBER: + json_object_set_array_member (cur_state->data.object, cur_state->member_name, json_array_ref (array)); + g_free (cur_state->member_name); + cur_state->member_name = NULL; + cur_state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + default: + g_assert_not_reached (); + } + } + + state = g_slice_new (JsonBuilderState); + state->data.array = array; + state->mode = JSON_BUILDER_MODE_ARRAY; + g_queue_push_head (builder->priv->stack, state); + + return builder; +} + +/** + * json_builder_end_array: + * @builder: a #JsonBuilder + * + * Closes the subarray inside the given @builder that was opened by the most + * recent call to json_builder_begin_array(). + * + * Cannot be called after json_builder_set_member_name(). + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_end_array (JsonBuilder *builder) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_current_mode (builder) == JSON_BUILDER_MODE_ARRAY, NULL); + + state = g_queue_pop_head (builder->priv->stack); + + if (g_queue_is_empty (builder->priv->stack)) + { + builder->priv->root = json_node_new (JSON_NODE_ARRAY); + json_node_take_array (builder->priv->root, json_array_ref (state->data.array)); + } + + json_builder_state_free (state); + + return builder; +} + +/** + * json_builder_set_member_name: + * @builder: a #JsonBuilder + * @member_name: the name of the member + * + * Set the name of the next member in an object. The next call must add a value, + * open an object or an array. + * + * Can be called only if the call is associated to an object. + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_set_member_name (JsonBuilder *builder, const gchar *member_name) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (member_name != NULL, NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_current_mode (builder) == JSON_BUILDER_MODE_OBJECT, NULL); + + state = g_queue_peek_head (builder->priv->stack); + state->member_name = g_strdup (member_name); + state->mode = JSON_BUILDER_MODE_MEMBER; + + return builder; +} + +/** + * json_builder_add_value: + * @builder: a #JsonBuilder + * @node: the value of the member or element + * + * If called after json_builder_set_member_name(), sets @node as member of the + * most recent opened object, otherwise @node is added as element of the most + * recent opened array. + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_add_value (JsonBuilder *builder, JsonNode *node) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); + + state = g_queue_peek_head (builder->priv->stack); + switch (state->mode) + { + case JSON_BUILDER_MODE_MEMBER: + json_object_set_member (state->data.object, state->member_name, node); + g_free (state->member_name); + state->member_name = NULL; + state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + case JSON_BUILDER_MODE_ARRAY: + json_array_add_element (state->data.array, node); + break; + + default: + g_assert_not_reached (); + } + + return builder; +} + +/** + * json_builder_add_int_value: + * @builder: a #JsonBuilder + * @value: the value of the member or element + * + * If called after json_builder_set_member_name(), sets @value as member of the + * most recent opened object, otherwise @value is added as element of the most + * recent opened array. + * + * See also: json_builder_add_value() + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_add_int_value (JsonBuilder *builder, gint64 value) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); + + state = g_queue_peek_head (builder->priv->stack); + switch (state->mode) + { + case JSON_BUILDER_MODE_MEMBER: + json_object_set_int_member (state->data.object, state->member_name, value); + g_free (state->member_name); + state->member_name = NULL; + state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + case JSON_BUILDER_MODE_ARRAY: + json_array_add_int_element (state->data.array, value); + break; + + default: + g_assert_not_reached (); + } + + return builder; +} + +/** + * json_builder_add_double_value: + * @builder: a #JsonBuilder + * @value: the value of the member or element + * + * If called after json_builder_set_member_name(), sets @value as member of the + * most recent opened object, otherwise @value is added as element of the most + * recent opened array. + * + * See also: json_builder_add_value() + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_add_double_value (JsonBuilder *builder, gdouble value) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); + + state = g_queue_peek_head (builder->priv->stack); + + switch (state->mode) + { + case JSON_BUILDER_MODE_MEMBER: + json_object_set_double_member (state->data.object, state->member_name, value); + g_free (state->member_name); + state->member_name = NULL; + state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + case JSON_BUILDER_MODE_ARRAY: + json_array_add_double_element (state->data.array, value); + break; + + default: + g_assert_not_reached (); + } + + return builder; +} + +/** + * json_builder_add_boolean_value: + * @builder: a #JsonBuilder + * @value: the value of the member or element + * + * If called after json_builder_set_member_name(), sets @value as member of the + * most recent opened object, otherwise @value is added as element of the most + * recent opened array. + * + * See also: json_builder_add_value() + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_add_boolean_value (JsonBuilder *builder, gboolean value) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); + + state = g_queue_peek_head (builder->priv->stack); + + switch (state->mode) + { + case JSON_BUILDER_MODE_MEMBER: + json_object_set_boolean_member (state->data.object, state->member_name, value); + g_free (state->member_name); + state->member_name = NULL; + state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + case JSON_BUILDER_MODE_ARRAY: + json_array_add_boolean_element (state->data.array, value); + break; + + default: + g_assert_not_reached (); + } + + return builder; +} + +/** + * json_builder_add_string_value: + * @builder: a #JsonBuilder + * @value: the value of the member or element + * + * If called after json_builder_set_member_name(), sets @value as member of the + * most recent opened object, otherwise @value is added as element of the most + * recent opened array. + * + * See also: json_builder_add_value() + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_add_string_value (JsonBuilder *builder, const gchar *value) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); + + state = g_queue_peek_head (builder->priv->stack); + + switch (state->mode) + { + case JSON_BUILDER_MODE_MEMBER: + json_object_set_string_member (state->data.object, state->member_name, value); + g_free (state->member_name); + state->member_name = NULL; + state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + case JSON_BUILDER_MODE_ARRAY: + json_array_add_string_element (state->data.array, value); + break; + + default: + g_assert_not_reached (); + } + + return builder; +} + +/** + * json_builder_add_null_value: + * @builder: a #JsonBuilder + * @value: the value of the member or element + * + * If called after json_builder_set_member_name(), sets null as member of the + * most recent opened object, otherwise null is added as element of the most + * recent opened array. + * + * See also: json_builder_add_value() + * + * Return value: the #JsonBuilder, or %NULL if the call was inconsistent + */ +JsonBuilder * +json_builder_add_null_value (JsonBuilder *builder) +{ + JsonBuilderState *state; + + g_return_val_if_fail (JSON_IS_BUILDER (builder), NULL); + g_return_val_if_fail (!g_queue_is_empty (builder->priv->stack), NULL); + g_return_val_if_fail (json_builder_is_valid_add_mode (builder), NULL); + + state = g_queue_peek_head (builder->priv->stack); + + switch (state->mode) + { + case JSON_BUILDER_MODE_MEMBER: + json_object_set_null_member (state->data.object, state->member_name); + g_free (state->member_name); + state->member_name = NULL; + state->mode = JSON_BUILDER_MODE_OBJECT; + break; + + case JSON_BUILDER_MODE_ARRAY: + json_array_add_null_element (state->data.array); + break; + + default: + g_assert_not_reached (); + } + + return builder; +} diff --git a/json-glib/json-builder.h b/json-glib/json-builder.h new file mode 100644 index 0000000..33b16ab --- /dev/null +++ b/json-glib/json-builder.h @@ -0,0 +1,100 @@ +/* json-builder.h: JSON tree builder + * + * This file is part of JSON-GLib + * Copyright (C) 2010 Luca Bruno <lethalman88@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: + * Luca Bruno <lethalman88@gmail.com> + */ + +#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION) +#error "Only <json-glib/json-glib.h> can be included directly." +#endif + +#ifndef __JSON_BUILDER_H__ +#define __JSON_BUILDER_H__ + +#include <json-glib/json-types.h> + +G_BEGIN_DECLS + +#define JSON_TYPE_BUILDER (json_builder_get_type ()) +#define JSON_BUILDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JSON_TYPE_BUILDER, JsonBuilder)) +#define JSON_IS_BUILDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JSON_TYPE_BUILDER)) +#define JSON_BUILDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), JSON_TYPE_BUILDER, JsonBuilderClass)) +#define JSON_IS_BUILDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), JSON_TYPE_BUILDER)) +#define JSON_BUILDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), JSON_TYPE_BUILDER, JsonBuilderClass)) + +typedef struct _JsonBuilder JsonBuilder; +typedef struct _JsonBuilderPrivate JsonBuilderPrivate; +typedef struct _JsonBuilderClass JsonBuilderClass; + +/** + * JsonBuilder: + * + * JSON tree builder. + */ +struct _JsonBuilder +{ + /*< private >*/ + GObject parent_instance; + + JsonBuilderPrivate *priv; +}; + +/** + * JsonBuilderClass: + * + * #JsonBuilder class + */ +struct _JsonBuilderClass +{ + /*< private >*/ + GObjectClass parent_class; + + /* padding, for future expansion */ + void (* _json_reserved1) (void); + void (* _json_reserved2) (void); +}; + +GType json_builder_get_type (void) G_GNUC_CONST; + +JsonBuilder *json_builder_new (void); +JsonNode *json_builder_get_root (JsonBuilder *builder); +void json_builder_reset (JsonBuilder *builder); + +JsonBuilder *json_builder_begin_array (JsonBuilder *builder); +JsonBuilder *json_builder_end_array (JsonBuilder *builder); +JsonBuilder *json_builder_begin_object (JsonBuilder *builder); +JsonBuilder *json_builder_end_object (JsonBuilder *builder); + +JsonBuilder *json_builder_set_member_name (JsonBuilder *builder, + const gchar *member_name); +JsonBuilder *json_builder_add_value (JsonBuilder *builder, + JsonNode *node); +JsonBuilder *json_builder_add_int_value (JsonBuilder *builder, + gint64 value); +JsonBuilder *json_builder_add_double_value (JsonBuilder *builder, + gdouble value); +JsonBuilder *json_builder_add_boolean_value (JsonBuilder *builder, + gboolean value); +JsonBuilder *json_builder_add_string_value (JsonBuilder *builder, + const gchar *value); +JsonBuilder *json_builder_add_null_value (JsonBuilder *builder); + +G_END_DECLS + +#endif /* __JSON_BUILDER_H__ */ diff --git a/json-glib/json-glib.h b/json-glib/json-glib.h index 794a8be..9c3d6f0 100644 --- a/json-glib/json-glib.h +++ b/json-glib/json-glib.h @@ -27,6 +27,7 @@ #define __JSON_GLIB_INSIDE__ #include <json-glib/json-types.h> +#include <json-glib/json-builder.h> #include <json-glib/json-generator.h> #include <json-glib/json-parser.h> #include <json-glib/json-version.h> diff --git a/json-glib/tests/Makefile.am b/json-glib/tests/Makefile.am index 3fd3ce3..a027a70 100644 --- a/json-glib/tests/Makefile.am +++ b/json-glib/tests/Makefile.am @@ -34,3 +34,6 @@ TEST_PROGS += generator-test generator_test_SOURCES = generator-test.c generator_test_LDADD = $(progs_ldadd) +TEST_PROGS += builder-test +builder_test_SOURCES = builder-test.c +builder_test_LDADD = $(progs_ldadd) diff --git a/json-glib/tests/builder-test.c b/json-glib/tests/builder-test.c new file mode 100644 index 0000000..eba54c2 --- /dev/null +++ b/json-glib/tests/builder-test.c @@ -0,0 +1,121 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <glib-object.h> + +#include <json-glib/json-glib.h> + +static const gchar *complex_object = "{ \"depth1\" : [ 1, { \"depth2\" : [ 2.3, [ null ], \"after array\" ], \"value2\" : true } ], \"object1\" : { } }\") == 0)"; + +static const gchar *reset_object = "{ \"test\" : \"reset\" }"; +static const gchar *reset_array = "[ \"reset\" ]"; + +static void +test_builder_complex (void) +{ + JsonBuilder *builder = json_builder_new (); + JsonNode *node; + JsonGenerator *generator; + gsize length; + gchar *data; + + json_builder_begin_object (builder); + + json_builder_set_member_name (builder, "depth1"); + json_builder_begin_array (builder); + json_builder_add_int_value (builder, 1); + + json_builder_begin_object (builder); + + json_builder_set_member_name (builder, "depth2"); + json_builder_begin_array (builder); + json_builder_add_double_value (builder, 2.3); + + json_builder_begin_array (builder); + json_builder_add_null_value (builder); + json_builder_end_array (builder); + + json_builder_add_string_value (builder, "after array"); + json_builder_end_array (builder); /* depth2 */ + + json_builder_set_member_name (builder, "value2"); + json_builder_add_boolean_value (builder, TRUE); + json_builder_end_object (builder); + + json_builder_end_array (builder); /* depth1 */ + + json_builder_set_member_name (builder, "object1"); + json_builder_begin_object (builder); + json_builder_end_object (builder); + + json_builder_end_object (builder); + + node = json_builder_get_root (builder); + g_object_unref (builder); + + generator = json_generator_new (); + json_generator_set_root (generator, node); + data = json_generator_to_data (generator, &length); + if (g_test_verbose ()) + { + g_print ("Builder complex: %*s", (int)length, data); + } + g_assert (strncmp (data, complex_object, length) == 0); + + g_free (data); + json_node_free (node); + g_object_unref (generator); +} + +static void +test_builder_reset (oid) +{ + JsonBuilder *builder = json_builder_new (); + JsonGenerator *generator = json_generator_new (); + JsonNode *node; + gsize length; + gchar *data; + + json_builder_begin_object (builder); + json_builder_set_member_name (builder, "test"); + json_builder_add_string_value (builder, "reset"); + json_builder_end_object (builder); + + node = json_builder_get_root (builder); + json_generator_set_root (generator, node); + data = json_generator_to_data (generator, &length); + g_assert (strncmp (data, reset_object, length) == 0); + + g_free (data); + json_node_free (node); + + json_builder_reset (builder); + + json_builder_begin_array (builder); + json_builder_add_string_value (builder, "reset"); + json_builder_end_array (builder); + + node = json_builder_get_root (builder); + json_generator_set_root (generator, node); + data = json_generator_to_data (generator, &length); + g_assert (strncmp (data, reset_array, length) == 0); + + g_free (data); + json_node_free (node); + g_object_unref (builder); + g_object_unref (generator); +} + +int +main (int argc, + char *argv[]) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/builder/complex", test_builder_complex); + g_test_add_func ("/builder/reset", test_builder_reset); + + return g_test_run (); +} |
