[giv] Embedded json-glib in source tree.
- From: Dov Grobgeld <dov src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [giv] Embedded json-glib in source tree.
- Date: Sat, 3 Mar 2012 22:28:14 +0000 (UTC)
commit e84d82bf8e2928c010e768139433f3042d7752a7
Author: Dov Grobgeld <dov grobgeld gmail com>
Date: Sun Mar 4 00:27:57 2012 +0200
Embedded json-glib in source tree.
ChangeLog | 4 +
SConstruct | 8 +-
src/SConscript | 2 +-
src/glib-jsonrpc/SConscript | 6 +-
src/glib-jsonrpc/json-glib/SConscript | 22 +
src/glib-jsonrpc/json-glib/json-array.c | 709 ++++++++
src/glib-jsonrpc/json-glib/json-builder.c | 684 ++++++++
src/glib-jsonrpc/json-glib/json-builder.h | 106 ++
src/glib-jsonrpc/json-glib/json-debug.c | 39 +
src/glib-jsonrpc/json-glib/json-debug.h | 47 +
src/glib-jsonrpc/json-glib/json-enum-types.c | 117 ++
src/glib-jsonrpc/json-glib/json-enum-types.h | 36 +
src/glib-jsonrpc/json-glib/json-gboxed.c | 354 ++++
src/glib-jsonrpc/json-glib/json-generator.c | 870 ++++++++++
src/glib-jsonrpc/json-glib/json-generator.h | 107 ++
src/glib-jsonrpc/json-glib/json-glib.h | 46 +
src/glib-jsonrpc/json-glib/json-gobject-private.h | 39 +
src/glib-jsonrpc/json-glib/json-gobject.c | 1005 +++++++++++
src/glib-jsonrpc/json-glib/json-gobject.h | 182 ++
src/glib-jsonrpc/json-glib/json-gvariant.c | 1341 +++++++++++++++
src/glib-jsonrpc/json-glib/json-gvariant.h | 46 +
src/glib-jsonrpc/json-glib/json-marshal.c | 132 ++
src/glib-jsonrpc/json-glib/json-marshal.h | 37 +
src/glib-jsonrpc/json-glib/json-node.c | 800 +++++++++
src/glib-jsonrpc/json-glib/json-object.c | 856 ++++++++++
src/glib-jsonrpc/json-glib/json-parser.c | 1434 ++++++++++++++++
src/glib-jsonrpc/json-glib/json-parser.h | 173 ++
src/glib-jsonrpc/json-glib/json-path.c | 1033 ++++++++++++
src/glib-jsonrpc/json-glib/json-path.h | 97 ++
src/glib-jsonrpc/json-glib/json-reader.c | 1069 ++++++++++++
src/glib-jsonrpc/json-glib/json-reader.h | 150 ++
src/glib-jsonrpc/json-glib/json-scanner.c | 1861 +++++++++++++++++++++
src/glib-jsonrpc/json-glib/json-scanner.h | 171 ++
src/glib-jsonrpc/json-glib/json-serializable.c | 341 ++++
src/glib-jsonrpc/json-glib/json-types-private.h | 66 +
src/glib-jsonrpc/json-glib/json-types.h | 334 ++++
src/glib-jsonrpc/json-glib/json-version.h | 100 ++
37 files changed, 14420 insertions(+), 4 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 3e23839..ce38d19 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-03-04 Dov Grobgeld <dov grobgeld gmail com>
+
+ * Added private copy of glib-jsonrpc.
+
2012-01-31 Dov Grobgeld <dov grobgeld gmail com>
* configure.in: Bumped version to 0.1.22
diff --git a/SConstruct b/SConstruct
index 4fea9cb..c33ff11 100644
--- a/SConstruct
+++ b/SConstruct
@@ -121,12 +121,16 @@ env.Append(CPPPATH=[],
"#/src/plis",
"#/src/gtkimageviewer",
"#/src/glib-jsonrpc",
+ "#/src/glib-jsonrpc/json-glib",
],
RPATH=["agg/src"],
- LIBS=['gtkimageviewer_local', 'agg', 'glib-jsonrpc_local']
+ LIBS=['gtkimageviewer_local',
+ 'agg',
+ 'glib-jsonrpc_local',
+ 'json-glib_local']
)
-env.ParseConfig("${PKGCONFIG} --cflags --libs gtk+-2.0 glib-2.0 json-glib-1.0 gio-2.0 gthread-2.0")
+env.ParseConfig("${PKGCONFIG} --cflags --libs gtk+-2.0 glib-2.0 gio-2.0 gthread-2.0")
SConscript(['src/SConscript',
'doc/SConscript',
diff --git a/src/SConscript b/src/SConscript
index 29a1113..bbd2671 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -3,7 +3,7 @@ Import('env')
libpath = ["#/src","#/src/plis",'#/src'] + env['LIBPATH']
libs = env['LIBS']
-cpppath = ["gtkimageviewer"] + env['CPPPATH']
+cpppath = ["gtkimageviewer"] + env['CPPPATH'] + ["glib-jsonrpc/"]
cppdefines = ['PACKAGE_DOC_DIR=\'"${PACKAGE_DOC_DIR}"\'',
'PACKAGE_PLUGIN_DIR=\'"${PACKAGE_PLUGIN_DIR}"\'',
]
diff --git a/src/glib-jsonrpc/SConscript b/src/glib-jsonrpc/SConscript
index ad65c7a..48dff41 100644
--- a/src/glib-jsonrpc/SConscript
+++ b/src/glib-jsonrpc/SConscript
@@ -3,4 +3,8 @@ Import('env')
env.Library("glib-jsonrpc_local",
["glib-jsonrpc-json.c",
"glib-jsonrpc-server.c",
- "glib-jsonrpc-client.c"])
+ "glib-jsonrpc-client.c"],
+ CPPPATH=["."]+env['CPPPATH'])
+
+SConscript(['json-glib/SConscript'],
+ exports='env')
diff --git a/src/glib-jsonrpc/json-glib/SConscript b/src/glib-jsonrpc/json-glib/SConscript
new file mode 100644
index 0000000..8d4b94c
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/SConscript
@@ -0,0 +1,22 @@
+Import('env')
+
+env2 = env.Clone()
+env2.Library("json-glib_local",
+ ["json-array.c",
+ "json-builder.c",
+ "json-debug.c",
+ "json-enum-types.c",
+ "json-gboxed.c",
+ "json-generator.c",
+ "json-gobject.c",
+ "json-gvariant.c",
+ "json-marshal.c",
+ "json-node.c",
+ "json-object.c",
+ "json-parser.c",
+ "json-path.c",
+ "json-reader.c",
+ "json-scanner.c",
+ "json-serializable.c"],
+ CPPDEFINES=['JSON_COMPILATION'],
+ CPPPATH=['..']+env['CPPPATH'])
diff --git a/src/glib-jsonrpc/json-glib/json-array.c b/src/glib-jsonrpc/json-glib/json-array.c
new file mode 100644
index 0000000..44caf1e
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-array.c
@@ -0,0 +1,709 @@
+/* json-array.c - JSON array implementation
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "json-types-private.h"
+
+/**
+ * SECTION:json-array
+ * @short_description: a JSON array representation
+ *
+ * #JsonArray is the representation of the array type inside JSON. It contains
+ * #JsonNode<!-- -->s, which may contain fundamental types, other arrays or
+ * objects.
+ *
+ * Since arrays can be expensive, they are reference counted. You can control
+ * the lifetime of a #JsonArray using json_array_ref() and json_array_unref().
+ *
+ * To append an element, use json_array_add_element().
+ * To extract an element at a given index, use json_array_get_element().
+ * To retrieve the entire array in list form, use json_array_get_elements().
+ * To retrieve the length of the array, use json_array_get_length().
+ */
+
+G_DEFINE_BOXED_TYPE (JsonArray, json_array, json_array_ref, json_array_unref);
+
+/**
+ * json_array_new:
+ *
+ * Creates a new #JsonArray.
+ *
+ * Return value: the newly created #JsonArray
+ */
+JsonArray *
+json_array_new (void)
+{
+ JsonArray *array;
+
+ array = g_slice_new (JsonArray);
+
+ array->ref_count = 1;
+ array->elements = g_ptr_array_new ();
+
+ return array;
+}
+
+/**
+ * json_array_sized_new:
+ * @n_elements: number of slots to pre-allocate
+ *
+ * Creates a new #JsonArray with @n_elements slots already allocated.
+ *
+ * Return value: the newly created #JsonArray
+ */
+JsonArray *
+json_array_sized_new (guint n_elements)
+{
+ JsonArray *array;
+
+ array = g_slice_new (JsonArray);
+
+ array->ref_count = 1;
+ array->elements = g_ptr_array_sized_new (n_elements);
+
+ return array;
+}
+
+/**
+ * json_array_ref:
+ * @array: a #JsonArray
+ *
+ * Increase by one the reference count of a #JsonArray.
+ *
+ * Return value: the passed #JsonArray, with the reference count
+ * increased by one.
+ */
+JsonArray *
+json_array_ref (JsonArray *array)
+{
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (array->ref_count > 0, NULL);
+
+ g_atomic_int_add (&array->ref_count, 1);
+
+ return array;
+}
+
+/**
+ * json_array_unref:
+ * @array: a #JsonArray
+ *
+ * Decreases by one the reference count of a #JsonArray. If the
+ * reference count reaches zero, the array is destroyed and all
+ * its allocated resources are freed.
+ */
+void
+json_array_unref (JsonArray *array)
+{
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (array->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&array->ref_count))
+ {
+ guint i;
+
+ for (i = 0; i < array->elements->len; i++)
+ json_node_free (g_ptr_array_index (array->elements, i));
+
+ g_ptr_array_free (array->elements, TRUE);
+ array->elements = NULL;
+
+ g_slice_free (JsonArray, array);
+ }
+}
+
+/**
+ * json_array_get_elements:
+ * @array: a #JsonArray
+ *
+ * Gets the elements of a #JsonArray as a list of #JsonNode<!-- -->s.
+ *
+ * Return value: (element-type JsonNode) (transfer container): a #GList
+ * containing the elements of the array. The contents of the list are
+ * owned by the array and should never be modified or freed. Use
+ * g_list_free() on the returned list when done using it
+ */
+GList *
+json_array_get_elements (JsonArray *array)
+{
+ GList *retval;
+ guint i;
+
+ g_return_val_if_fail (array != NULL, NULL);
+
+ retval = NULL;
+ for (i = 0; i < array->elements->len; i++)
+ retval = g_list_prepend (retval,
+ g_ptr_array_index (array->elements, i));
+
+ return g_list_reverse (retval);
+}
+
+/**
+ * json_array_dup_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Retrieves a copy of the #JsonNode containing the value of the
+ * element at @index_ inside a #JsonArray
+ *
+ * Return value: (transfer full): a copy of the #JsonNode at the requested
+ * index. Use json_node_free() when done.
+ *
+ * Since: 0.6
+ */
+JsonNode *
+json_array_dup_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *retval;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index_ < array->elements->len, NULL);
+
+ retval = json_array_get_element (array, index_);
+ if (!retval)
+ return NULL;
+
+ return json_node_copy (retval);
+}
+
+/**
+ * json_array_get_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Retrieves the #JsonNode containing the value of the element at @index_
+ * inside a #JsonArray.
+ *
+ * Return value: (transfer none): a pointer to the #JsonNode at the requested index
+ */
+JsonNode *
+json_array_get_element (JsonArray *array,
+ guint index_)
+{
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index_ < array->elements->len, NULL);
+
+ return g_ptr_array_index (array->elements, index_);
+}
+
+/**
+ * json_array_get_int_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves the integer value of the element at @index_
+ * inside @array
+ *
+ * See also: json_array_get_element(), json_node_get_int()
+ *
+ * Return value: the integer value
+ *
+ * Since: 0.8
+ */
+gint64
+json_array_get_int_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, 0);
+ g_return_val_if_fail (index_ < array->elements->len, 0);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, 0);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0);
+
+ return json_node_get_int (node);
+}
+
+/**
+ * json_array_get_double_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves the floating point value of the element at
+ * @index_ inside @array
+ *
+ * See also: json_array_get_element(), json_node_get_double()
+ *
+ * Return value: the floating point value
+ *
+ * Since: 0.8
+ */
+gdouble
+json_array_get_double_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, 0.0);
+ g_return_val_if_fail (index_ < array->elements->len, 0.0);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, 0.0);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0.0);
+
+ return json_node_get_double (node);
+}
+
+/**
+ * json_array_get_boolean_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves the boolean value of the element at @index_
+ * inside @array
+ *
+ * See also: json_array_get_element(), json_node_get_boolean()
+ *
+ * Return value: the integer value
+ *
+ * Since: 0.8
+ */
+gboolean
+json_array_get_boolean_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index_ < array->elements->len, FALSE);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, FALSE);
+
+ return json_node_get_boolean (node);
+}
+
+/**
+ * json_array_get_string_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves the string value of the element at @index_
+ * inside @array
+ *
+ * See also: json_array_get_element(), json_node_get_string()
+ *
+ * Return value: the string value; the returned string is owned by
+ * the #JsonArray and should not be modified or freed
+ *
+ * Since: 0.8
+ */
+const gchar *
+json_array_get_string_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index_ < array->elements->len, NULL);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_HOLDS_VALUE (node) || JSON_NODE_HOLDS_NULL (node), NULL);
+
+ if (JSON_NODE_HOLDS_NULL (node))
+ return NULL;
+
+ return json_node_get_string (node);
+}
+
+/**
+ * json_array_get_null_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves whether the element at @index_ is set to null
+ *
+ * See also: json_array_get_element(), JSON_NODE_TYPE(), %JSON_NODE_NULL
+ *
+ * Return value: %TRUE if the element is null
+ *
+ * Since: 0.8
+ */
+gboolean
+json_array_get_null_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, FALSE);
+ g_return_val_if_fail (index_ < array->elements->len, FALSE);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ return JSON_NODE_TYPE (node) == JSON_NODE_NULL;
+}
+
+/**
+ * json_array_get_array_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves the array from the element at @index_
+ * inside @array
+ *
+ * See also: json_array_get_element(), json_node_get_array()
+ *
+ * Return value: (transfer none): the array
+ *
+ * Since: 0.8
+ */
+JsonArray *
+json_array_get_array_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index_ < array->elements->len, NULL);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (node) || JSON_NODE_HOLDS_NULL (node), NULL);
+
+ if (JSON_NODE_HOLDS_NULL (node))
+ return NULL;
+
+ return json_node_get_array (node);
+}
+
+/**
+ * json_array_get_object_element:
+ * @array: a #JsonArray
+ * @index_: the index of the element to retrieve
+ *
+ * Conveniently retrieves the object from the element at @index_
+ * inside @array
+ *
+ * See also: json_array_get_element(), json_node_get_object()
+ *
+ * Return value: (transfer none): the object
+ *
+ * Since: 0.8
+ */
+JsonObject *
+json_array_get_object_element (JsonArray *array,
+ guint index_)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (array != NULL, NULL);
+ g_return_val_if_fail (index_ < array->elements->len, NULL);
+
+ node = g_ptr_array_index (array->elements, index_);
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_HOLDS_OBJECT (node) || JSON_NODE_HOLDS_NULL (node), NULL);
+
+ if (JSON_NODE_HOLDS_NULL (node))
+ return NULL;
+
+ return json_node_get_object (node);
+}
+
+/**
+ * json_array_get_length:
+ * @array: a #JsonArray
+ *
+ * Retrieves the length of a #JsonArray
+ *
+ * Return value: the length of the array
+ */
+guint
+json_array_get_length (JsonArray *array)
+{
+ g_return_val_if_fail (array != NULL, 0);
+
+ return array->elements->len;
+}
+
+/**
+ * json_array_add_element:
+ * @array: a #JsonArray
+ * @node: (transfer full): a #JsonNode
+ *
+ * Appends @node inside @array. The array will take ownership of the
+ * #JsonNode.
+ */
+void
+json_array_add_element (JsonArray *array,
+ JsonNode *node)
+{
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (node != NULL);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_int_element:
+ * @array: a #JsonArray
+ * @value: an integer value
+ *
+ * Conveniently adds an integer @value into @array
+ *
+ * See also: json_array_add_element(), json_node_set_int()
+ *
+ * Since: 0.8
+ */
+void
+json_array_add_int_element (JsonArray *array,
+ gint64 value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (array != NULL);
+
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (node, value);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_double_element:
+ * @array: a #JsonArray
+ * @value: a floating point value
+ *
+ * Conveniently adds a floating point @value into @array
+ *
+ * See also: json_array_add_element(), json_node_set_double()
+ *
+ * Since: 0.8
+ */
+void
+json_array_add_double_element (JsonArray *array,
+ gdouble value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (array != NULL);
+
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_double (node, value);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_boolean_element:
+ * @array: a #JsonArray
+ * @value: a boolean value
+ *
+ * Conveniently adds a boolean @value into @array
+ *
+ * See also: json_array_add_element(), json_node_set_boolean()
+ *
+ * Since: 0.8
+ */
+void
+json_array_add_boolean_element (JsonArray *array,
+ gboolean value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (array != NULL);
+
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_boolean (node, value);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_string_element:
+ * @array: a #JsonArray
+ * @value: a string value
+ *
+ * Conveniently adds a string @value into @array
+ *
+ * See also: json_array_add_element(), json_node_set_string()
+ *
+ * Since: 0.8
+ */
+void
+json_array_add_string_element (JsonArray *array,
+ const gchar *value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (value != NULL);
+
+ if (value != NULL)
+ {
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_string (node, value);
+ }
+ else
+ node = json_node_new (JSON_NODE_NULL);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_null_element:
+ * @array: a #JsonArray
+ *
+ * Conveniently adds a null element into @array
+ *
+ * See also: json_array_add_element(), %JSON_NODE_NULL
+ *
+ * Since: 0.8
+ */
+void
+json_array_add_null_element (JsonArray *array)
+{
+ JsonNode *node;
+
+ g_return_if_fail (array != NULL);
+
+ node = json_node_new (JSON_NODE_NULL);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_array_element:
+ * @array: a #JsonArray
+ * @value: (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);
+ g_return_if_fail (value != NULL);
+
+ if (value != NULL)
+ {
+ node = json_node_new (JSON_NODE_ARRAY);
+ json_node_take_array (node, value);
+ }
+ else
+ node = json_node_new (JSON_NODE_NULL);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_add_object_element:
+ * @array: a #JsonArray
+ * @value: (transfer full): a #JsonObject
+ *
+ * Conveniently adds an object into @array. The @array takes ownership
+ * of the newly added #JsonObject
+ *
+ * See also: json_array_add_element(), json_node_take_object()
+ *
+ * Since: 0.8
+ */
+void
+json_array_add_object_element (JsonArray *array,
+ JsonObject *value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (value != NULL);
+
+ if (value != NULL)
+ {
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (node, value);
+ }
+ else
+ node = json_node_new (JSON_NODE_NULL);
+
+ g_ptr_array_add (array->elements, node);
+}
+
+/**
+ * json_array_remove_element:
+ * @array: a #JsonArray
+ * @index_: the position of the element to be removed
+ *
+ * Removes the #JsonNode inside @array at @index_ freeing its allocated
+ * resources.
+ */
+void
+json_array_remove_element (JsonArray *array,
+ guint index_)
+{
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (index_ < array->elements->len);
+
+ json_node_free (g_ptr_array_remove_index (array->elements, index_));
+}
+
+/**
+ * json_array_foreach_element:
+ * @array: a #JsonArray
+ * @func: (scope call): the function to be called on each element
+ * @data: (closure): data to be passed to the function
+ *
+ * Iterates over all elements of @array and calls @func on
+ * each one of them.
+ *
+ * It is safe to change the value of a #JsonNode of the @array
+ * from within the iterator @func, but it is not safe to add or
+ * remove elements from the @array.
+ *
+ * Since: 0.8
+ */
+void
+json_array_foreach_element (JsonArray *array,
+ JsonArrayForeach func,
+ gpointer data)
+{
+ gint i;
+
+ g_return_if_fail (array != NULL);
+ g_return_if_fail (func != NULL);
+
+ for (i = 0; i < array->elements->len; i++)
+ {
+ JsonNode *element_node;
+
+ element_node = g_ptr_array_index (array->elements, i);
+
+ (* func) (array, i, element_node, data);
+ }
+}
diff --git a/src/glib-jsonrpc/json-glib/json-builder.c b/src/glib-jsonrpc/json-glib/json-builder.c
new file mode 100644
index 0000000..9fa6859
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-builder.c
@@ -0,0 +1,684 @@
+/* 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
+ * @Title: JsonBuilder
+ * @short_description: Generates JSON trees
+ * @See_Also: JsonGenerator
+ *
+ * #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: (transfer none): 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->member_name = NULL;
+ 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: (transfer none): 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: (transfer none): 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: (transfer none): 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: (transfer none): 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: (transfer none): 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: (transfer none): 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: (transfer none): 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: (transfer none): 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: (transfer none): 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
+ *
+ * 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: (transfer none): 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/src/glib-jsonrpc/json-glib/json-builder.h b/src/glib-jsonrpc/json-glib/json-builder.h
new file mode 100644
index 0000000..e034193
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-builder.h
@@ -0,0 +1,106 @@
+/* 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:
+ *
+ * The <structname>JsonBuilder</structname> structure contains only
+ * private data and shouls be accessed using the provided API
+ *
+ * Since: 0.12
+ */
+struct _JsonBuilder
+{
+ /*< private >*/
+ GObject parent_instance;
+
+ JsonBuilderPrivate *priv;
+};
+
+/**
+ * JsonBuilderClass:
+ *
+ * The <structname>JsonBuilder</structname> structure contains only
+ * private data
+ *
+ * Since: 0.12
+ */
+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/src/glib-jsonrpc/json-glib/json-debug.c b/src/glib-jsonrpc/json-glib/json-debug.c
new file mode 100644
index 0000000..c0dc2e9
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-debug.c
@@ -0,0 +1,39 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "json-debug.h"
+
+static unsigned int json_debug_flags = 0;
+static gboolean json_debug_flags_set = FALSE;
+
+#ifdef JSON_ENABLE_DEBUG
+static const GDebugKey json_debug_keys[] = {
+ { "parser", JSON_DEBUG_PARSER },
+ { "gobject", JSON_DEBUG_GOBJECT },
+ { "path", JSON_DEBUG_PATH }
+};
+#endif /* JSON_ENABLE_DEBUG */
+
+JsonDebugFlags
+_json_get_debug_flags (void)
+{
+#ifdef JSON_ENABLE_DEBUG
+ const gchar *env_str;
+
+ if (json_debug_flags_set)
+ return json_debug_flags;
+
+ env_str = g_getenv ("JSON_DEBUG");
+ if (env_str != NULL && *env_str != '\0')
+ {
+ json_debug_flags |= g_parse_debug_string (env_str,
+ json_debug_keys,
+ G_N_ELEMENTS (json_debug_keys));
+ }
+
+ json_debug_flags_set = TRUE;
+#endif /* JSON_ENABLE_DEBUG */
+
+ return json_debug_flags;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-debug.h b/src/glib-jsonrpc/json-glib/json-debug.h
new file mode 100644
index 0000000..695917f
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-debug.h
@@ -0,0 +1,47 @@
+#ifndef __JSON_DEBUG_H__
+#define __JSON_DEBUG_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ JSON_DEBUG_PARSER = 1 << 0,
+ JSON_DEBUG_GOBJECT = 1 << 1,
+ JSON_DEBUG_PATH = 1 << 2
+} JsonDebugFlags;
+
+#ifdef JSON_ENABLE_DEBUG
+
+# ifdef __GNUC__
+
+# define JSON_NOTE(type,x,a...) G_STMT_START { \
+ if (_json_get_debug_flags () & JSON_DEBUG_##type) { \
+ g_message ("[" #type "] " G_STRLOC ": " x, ##a); \
+ } } G_STMT_END
+
+# else
+/* Try the C99 version; unfortunately, this does not allow us to pass
+ * empty arguments to the macro, which means we have to
+ * do an intemediate printf.
+ */
+# define JSON_NOTE(type,...) G_STMT_START { \
+ if (_json_get_debug_flags () & JSON_DEBUG_##type) { \
+ gchar * _fmt = g_strdup_printf (__VA_ARGS__); \
+ g_message ("[" #type "] " G_STRLOC ": %s",_fmt); \
+ g_free (_fmt); \
+ } } G_STMT_END
+
+# endif /* __GNUC__ */
+
+#else
+
+#define JSON_NOTE(type,...) G_STMT_START { } G_STMT_END
+
+#endif /* JSON_ENABLE_DEBUG */
+
+JsonDebugFlags _json_get_debug_flags (void);
+
+G_END_DECLS
+
+#endif /* __JSON_DEBUG_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-enum-types.c b/src/glib-jsonrpc/json-glib/json-enum-types.c
new file mode 100644
index 0000000..cd4b27d
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-enum-types.c
@@ -0,0 +1,117 @@
+
+/* Generated data (by glib-mkenums) */
+
+#include "json-enum-types.h"
+
+/* enumerations from "../json-glib/json-parser.h" */
+#include "../json-glib/json-parser.h"
+
+GType
+json_parser_error_get_type(void) {
+ static volatile gsize g_enum_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_enum_type_id__volatile))
+ {
+ static const GEnumValue values[] = {
+ { JSON_PARSER_ERROR_PARSE, "JSON_PARSER_ERROR_PARSE", "parse" },
+ { JSON_PARSER_ERROR_TRAILING_COMMA, "JSON_PARSER_ERROR_TRAILING_COMMA", "trailing-comma" },
+ { JSON_PARSER_ERROR_MISSING_COMMA, "JSON_PARSER_ERROR_MISSING_COMMA", "missing-comma" },
+ { JSON_PARSER_ERROR_MISSING_COLON, "JSON_PARSER_ERROR_MISSING_COLON", "missing-colon" },
+ { JSON_PARSER_ERROR_INVALID_BAREWORD, "JSON_PARSER_ERROR_INVALID_BAREWORD", "invalid-bareword" },
+ { JSON_PARSER_ERROR_UNKNOWN, "JSON_PARSER_ERROR_UNKNOWN", "unknown" },
+ { 0, NULL, NULL }
+ };
+ GType g_enum_type_id;
+
+ g_enum_type_id =
+ g_enum_register_static (g_intern_static_string ("JsonParserError"), values);
+
+ g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
+ }
+
+ return g_enum_type_id__volatile;
+}
+
+/* enumerations from "../json-glib/json-path.h" */
+#include "../json-glib/json-path.h"
+
+GType
+json_path_error_get_type(void) {
+ static volatile gsize g_enum_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_enum_type_id__volatile))
+ {
+ static const GEnumValue values[] = {
+ { JSON_PATH_ERROR_INVALID_QUERY, "JSON_PATH_ERROR_INVALID_QUERY", "query" },
+ { 0, NULL, NULL }
+ };
+ GType g_enum_type_id;
+
+ g_enum_type_id =
+ g_enum_register_static (g_intern_static_string ("JsonPathError"), values);
+
+ g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
+ }
+
+ return g_enum_type_id__volatile;
+}
+
+/* enumerations from "../json-glib/json-reader.h" */
+#include "../json-glib/json-reader.h"
+
+GType
+json_reader_error_get_type(void) {
+ static volatile gsize g_enum_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_enum_type_id__volatile))
+ {
+ static const GEnumValue values[] = {
+ { JSON_READER_ERROR_NO_ARRAY, "JSON_READER_ERROR_NO_ARRAY", "no-array" },
+ { JSON_READER_ERROR_INVALID_INDEX, "JSON_READER_ERROR_INVALID_INDEX", "invalid-index" },
+ { JSON_READER_ERROR_NO_OBJECT, "JSON_READER_ERROR_NO_OBJECT", "no-object" },
+ { JSON_READER_ERROR_INVALID_MEMBER, "JSON_READER_ERROR_INVALID_MEMBER", "invalid-member" },
+ { JSON_READER_ERROR_INVALID_NODE, "JSON_READER_ERROR_INVALID_NODE", "invalid-node" },
+ { JSON_READER_ERROR_NO_VALUE, "JSON_READER_ERROR_NO_VALUE", "no-value" },
+ { JSON_READER_ERROR_INVALID_TYPE, "JSON_READER_ERROR_INVALID_TYPE", "invalid-type" },
+ { 0, NULL, NULL }
+ };
+ GType g_enum_type_id;
+
+ g_enum_type_id =
+ g_enum_register_static (g_intern_static_string ("JsonReaderError"), values);
+
+ g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
+ }
+
+ return g_enum_type_id__volatile;
+}
+
+/* enumerations from "../json-glib/json-types.h" */
+#include "../json-glib/json-types.h"
+
+GType
+json_node_type_get_type(void) {
+ static volatile gsize g_enum_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_enum_type_id__volatile))
+ {
+ static const GEnumValue values[] = {
+ { JSON_NODE_OBJECT, "JSON_NODE_OBJECT", "object" },
+ { JSON_NODE_ARRAY, "JSON_NODE_ARRAY", "array" },
+ { JSON_NODE_VALUE, "JSON_NODE_VALUE", "value" },
+ { JSON_NODE_NULL, "JSON_NODE_NULL", "null" },
+ { 0, NULL, NULL }
+ };
+ GType g_enum_type_id;
+
+ g_enum_type_id =
+ g_enum_register_static (g_intern_static_string ("JsonNodeType"), values);
+
+ g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
+ }
+
+ return g_enum_type_id__volatile;
+}
+
+/* Generated data ends here */
+
diff --git a/src/glib-jsonrpc/json-glib/json-enum-types.h b/src/glib-jsonrpc/json-glib/json-enum-types.h
new file mode 100644
index 0000000..93dc672
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-enum-types.h
@@ -0,0 +1,36 @@
+
+/* Generated data (by glib-mkenums) */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_ENUM_TYPES_H__
+#define __JSON_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* enumerations from "../json-glib/json-parser.h" */
+GType json_parser_error_get_type (void) G_GNUC_CONST;
+#define JSON_TYPE_PARSER_ERROR (json_parser_error_get_type())
+
+/* enumerations from "../json-glib/json-path.h" */
+GType json_path_error_get_type (void) G_GNUC_CONST;
+#define JSON_TYPE_PATH_ERROR (json_path_error_get_type())
+
+/* enumerations from "../json-glib/json-reader.h" */
+GType json_reader_error_get_type (void) G_GNUC_CONST;
+#define JSON_TYPE_READER_ERROR (json_reader_error_get_type())
+
+/* enumerations from "../json-glib/json-types.h" */
+GType json_node_type_get_type (void) G_GNUC_CONST;
+#define JSON_TYPE_NODE_TYPE (json_node_type_get_type())
+
+G_END_DECLS
+
+#endif /* !__JSON_ENUM_TYPES_H__ */
+
+/* Generated data ends here */
+
diff --git a/src/glib-jsonrpc/json-glib/json-gboxed.c b/src/glib-jsonrpc/json-glib/json-gboxed.c
new file mode 100644
index 0000000..8f21f75
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-gboxed.c
@@ -0,0 +1,354 @@
+/* json-gboxed.c - JSON GBoxed integration
+ *
+ * This file is part of JSON-GLib
+ *
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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.
+ *
+ * Author:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:json-gboxed
+ * @short_description: Serialize and deserialize GBoxed types
+ *
+ * GLib's #GBoxed type is a generic wrapper for arbitrary C structures.
+ *
+ * JSON-GLib allows serialization and deserialization of a #GBoxed type
+ * by registering functions mapping a #JsonNodeType to a specific
+ * #GType.
+ *
+ * When registering a #GBoxed type you should also register the
+ * corresponding transformation functions, e.g.:
+ *
+ * |[
+ * GType
+ * my_struct_get_type (void)
+ * {
+ * static GType boxed_type = 0;
+ *
+ * if (boxed_type == 0)
+ * {
+ * boxed_type =
+ * g_boxed_type_register_static (g_intern_static_string ("MyStruct"),
+ * (GBoxedCopyFunc) my_struct_copy,
+ * (GBoxedFreeFunc) my_struct_free);
+ *
+ * json_boxed_register_serialize_func (boxed_type, JSON_NODE_OBJECT,
+ * my_struct_serialize);
+ * json_boxed_register_deserialize_func (boxed_type, JSON_NODE_OBJECT,
+ * my_struct_deserialize);
+ * }
+ *
+ * return boxed_type;
+ * }
+ * ]|
+ *
+ * The serialization function will be invoked by json_boxed_serialize():
+ * it will be passed a pointer to the C structure and it must return a
+ * #JsonNode. The deserialization function will be invoked by
+ * json_boxed_deserialize(): it will be passed a #JsonNode for the
+ * declared type and it must return a newly allocated C structure.
+ *
+ * It is possible to check whether a #GBoxed type can be deserialized
+ * from a specific #JsonNodeType, and whether a #GBoxed can be serialized
+ * and to which specific #JsonNodeType.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "json-types-private.h"
+#include "json-gobject.h"
+
+typedef struct _BoxedTransform BoxedTransform;
+
+struct _BoxedTransform
+{
+ GType boxed_type;
+ gint node_type;
+
+ JsonBoxedSerializeFunc serialize;
+ JsonBoxedDeserializeFunc deserialize;
+};
+
+G_LOCK_DEFINE_STATIC (boxed_serialize);
+static GSList *boxed_serialize = NULL;
+
+G_LOCK_DEFINE_STATIC (boxed_deserialize);
+static GSList *boxed_deserialize = NULL;
+
+static gint
+boxed_transforms_cmp (gconstpointer a,
+ gconstpointer b)
+{
+ const BoxedTransform *ta = a;
+ const BoxedTransform *tb = b;
+
+ return tb->boxed_type - ta->boxed_type;
+}
+
+static gint
+boxed_transforms_find (gconstpointer a,
+ gconstpointer b)
+{
+ const BoxedTransform *haystack = a;
+ const BoxedTransform *needle = b;
+
+ if (needle->node_type != -1)
+ return (haystack->boxed_type == needle->boxed_type &&
+ haystack->node_type == needle->node_type) ? 0 : 1;
+ else
+ return (haystack->boxed_type == needle->boxed_type) ? 0 : 1;
+}
+
+static BoxedTransform *
+lookup_boxed_transform (GSList *transforms,
+ GType gboxed_type,
+ JsonNodeType node_type)
+{
+ BoxedTransform lookup;
+ GSList *t;
+
+ lookup.boxed_type = gboxed_type;
+ lookup.node_type = node_type;
+
+ t = g_slist_find_custom (transforms, &lookup, boxed_transforms_find);
+ if (t == NULL)
+ return NULL;
+
+ return t->data;
+}
+
+/**
+ * json_boxed_register_serialize_func: (skip)
+ * @gboxed_type: a boxed type
+ * @node_type: a node type
+ * @serialize_func: serialization function for @boxed_type into
+ * a #JsonNode of type @node_type
+ *
+ * Registers a serialization function for a #GBoxed of type @gboxed_type
+ * to a #JsonNode of type @node_type
+ *
+ * Since: 0.10
+ */
+void
+json_boxed_register_serialize_func (GType gboxed_type,
+ JsonNodeType node_type,
+ JsonBoxedSerializeFunc serialize_func)
+{
+ BoxedTransform *t;
+
+ g_return_if_fail (G_TYPE_IS_BOXED (gboxed_type));
+ g_return_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE);
+
+ G_LOCK (boxed_serialize);
+
+ t = lookup_boxed_transform (boxed_serialize, gboxed_type, node_type);
+ if (t == NULL)
+ {
+ t = g_slice_new (BoxedTransform);
+
+ t->boxed_type = gboxed_type;
+ t->node_type = node_type;
+ t->serialize = serialize_func;
+
+ boxed_serialize = g_slist_insert_sorted (boxed_serialize, t,
+ boxed_transforms_cmp);
+ }
+ else
+ g_warning ("A serialization function for the boxed type %s into "
+ "JSON nodes of type %s already exists",
+ g_type_name (gboxed_type),
+ json_node_type_get_name (node_type));
+
+ G_UNLOCK (boxed_serialize);
+}
+
+/**
+ * json_boxed_register_deserialize_func: (skip)
+ * @gboxed_type: a boxed type
+ * @node_type: a node type
+ * @deserialize_func: deserialization function for @boxed_type from
+ * a #JsonNode of type @node_type
+ *
+ * Registers a deserialization function for a #GBoxed of type @gboxed_type
+ * from a #JsonNode of type @node_type
+ *
+ * Since: 0.10
+ */
+void
+json_boxed_register_deserialize_func (GType gboxed_type,
+ JsonNodeType node_type,
+ JsonBoxedDeserializeFunc deserialize_func)
+{
+ BoxedTransform *t;
+
+ g_return_if_fail (G_TYPE_IS_BOXED (gboxed_type));
+ g_return_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE);
+
+ G_LOCK (boxed_deserialize);
+
+ t = lookup_boxed_transform (boxed_deserialize, gboxed_type, node_type);
+ if (t == NULL)
+ {
+ t = g_slice_new (BoxedTransform);
+
+ t->boxed_type = gboxed_type;
+ t->node_type = node_type;
+ t->deserialize = deserialize_func;
+
+ boxed_deserialize = g_slist_insert_sorted (boxed_deserialize, t,
+ boxed_transforms_cmp);
+ }
+ else
+ g_warning ("A deserialization function for the boxed type %s from "
+ "JSON nodes of type %s already exists",
+ g_type_name (gboxed_type),
+ json_node_type_get_name (node_type));
+
+ G_UNLOCK (boxed_deserialize);
+}
+
+/**
+ * json_boxed_can_serialize:
+ * @gboxed_type: a boxed type
+ * @node_type: (out): the #JsonNode type to which the boxed type can be
+ * serialized into
+ *
+ * Checks whether it is possible to serialize a #GBoxed of
+ * type @gboxed_type into a #JsonNode. The type of the
+ * #JsonNode is placed inside @node_type if the function
+ * returns %TRUE and it's undefined otherwise.
+ *
+ * Return value: %TRUE if the type can be serialized,
+ * and %FALSE otherwise.
+ *
+ * Since: 0.10
+ */
+gboolean
+json_boxed_can_serialize (GType gboxed_type,
+ JsonNodeType *node_type)
+{
+ BoxedTransform *t;
+
+ g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), FALSE);
+ g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, FALSE);
+
+ t = lookup_boxed_transform (boxed_serialize, gboxed_type, -1);
+ if (t != NULL)
+ {
+ if (node_type)
+ *node_type = t->node_type;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * json_boxed_can_deserialize:
+ * @gboxed_type: a boxed type
+ * @node_type: a #JsonNode type
+ *
+ * Checks whether it is possible to deserialize a #GBoxed of
+ * type @gboxed_type from a #JsonNode of type @node_type
+ *
+ * Return value: %TRUE if the type can be deserialized, %FALSE otherwise
+ *
+ * Since: 0.10
+ */
+gboolean
+json_boxed_can_deserialize (GType gboxed_type,
+ JsonNodeType node_type)
+{
+ BoxedTransform *t;
+
+ g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), FALSE);
+ g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, FALSE);
+
+ t = lookup_boxed_transform (boxed_deserialize, gboxed_type, node_type);
+ if (t != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * json_boxed_serialize:
+ * @gboxed_type: a boxed type
+ * @boxed: a pointer to a #GBoxed of type @gboxed_type
+ *
+ * Serializes @boxed, a pointer to a #GBoxed of type @gboxed_type,
+ * into a #JsonNode
+ *
+ * Return value: (transfer full): a #JsonNode with the serialization of the
+ * boxed type, or %NULL if serialization either failed or was not possible
+ *
+ * Since: 0.10
+ */
+JsonNode *
+json_boxed_serialize (GType gboxed_type,
+ gconstpointer boxed)
+{
+ BoxedTransform *t;
+
+ g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), NULL);
+ g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, NULL);
+ g_return_val_if_fail (boxed != NULL, NULL);
+
+ t = lookup_boxed_transform (boxed_serialize, gboxed_type, -1);
+ if (t != NULL && t->serialize != NULL)
+ return t->serialize (boxed);
+
+ return NULL;
+}
+
+/**
+ * json_boxed_deserialize:
+ * @gboxed_type: a boxed type
+ * @node: a #JsonNode
+ *
+ * Deserializes @node into a #GBoxed of @gboxed_type
+ *
+ * Return value: (transfer full): the newly allocated #GBoxed. Use
+ * g_boxed_free() to release the resources allocated by this
+ * function
+ *
+ * Since: 0.10
+ */
+gpointer
+json_boxed_deserialize (GType gboxed_type,
+ JsonNode *node)
+{
+ JsonNodeType node_type;
+ BoxedTransform *t;
+
+ g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), NULL);
+ g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, NULL);
+ g_return_val_if_fail (node != NULL, NULL);
+
+ node_type = json_node_get_node_type (node);
+
+ t = lookup_boxed_transform (boxed_deserialize, gboxed_type, node_type);
+ if (t != NULL && t->deserialize != NULL)
+ return t->deserialize (node);
+
+ return NULL;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-generator.c b/src/glib-jsonrpc/json-glib/json-generator.c
new file mode 100644
index 0000000..6a36bcf
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-generator.c
@@ -0,0 +1,870 @@
+/* json-generator.c - JSON streams generator
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:json-generator
+ * @short_description: Generates JSON data streams
+ *
+ * #JsonGenerator provides an object for generating a JSON data stream and
+ * put it into a buffer or a file.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "json-types-private.h"
+
+#include "json-marshal.h"
+#include "json-generator.h"
+
+#define JSON_GENERATOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), JSON_TYPE_GENERATOR, JsonGeneratorPrivate))
+
+struct _JsonGeneratorPrivate
+{
+ JsonNode *root;
+
+ guint indent;
+ gunichar indent_char;
+
+ guint pretty : 1;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_PRETTY,
+ PROP_INDENT,
+ PROP_ROOT,
+ PROP_INDENT_CHAR,
+
+ PROP_LAST
+};
+
+static gchar *dump_value (JsonGenerator *generator,
+ gint level,
+ const gchar *name,
+ JsonNode *node,
+ gsize *length);
+static gchar *dump_array (JsonGenerator *generator,
+ gint level,
+ const gchar *name,
+ JsonArray *array,
+ gsize *length);
+static gchar *dump_object (JsonGenerator *generator,
+ gint level,
+ const gchar *name,
+ JsonObject *object,
+ gsize *length);
+
+/* non-ASCII characters can't be escaped, otherwise UTF-8
+ * chars will break, so we just pregenerate this table of
+ * high characters and then we feed it to g_strescape()
+ */
+static const char json_exceptions[] = {
+ 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+ 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+ 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+ 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+ 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe,
+ 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+ 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
+ 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+ 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
+ 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee,
+ 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+ 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
+ 0xff,
+ '\0' /* g_strescape() expects a NUL-terminated string */
+};
+
+static GParamSpec *generator_props[PROP_LAST] = { NULL, };
+
+G_DEFINE_TYPE (JsonGenerator, json_generator, G_TYPE_OBJECT);
+
+static gchar *
+json_strescape (const gchar *str)
+{
+ return g_strescape (str, json_exceptions);
+}
+
+static void
+json_generator_finalize (GObject *gobject)
+{
+ JsonGeneratorPrivate *priv = JSON_GENERATOR_GET_PRIVATE (gobject);
+
+ if (priv->root)
+ json_node_free (priv->root);
+
+ G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject);
+}
+
+static void
+json_generator_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ JsonGenerator *generator = JSON_GENERATOR (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_PRETTY:
+ json_generator_set_pretty (generator, g_value_get_boolean (value));
+ break;
+
+ case PROP_INDENT:
+ json_generator_set_indent (generator, g_value_get_uint (value));
+ break;
+
+ case PROP_INDENT_CHAR:
+ json_generator_set_indent_char (generator, g_value_get_uint (value));
+ break;
+
+ case PROP_ROOT:
+ json_generator_set_root (generator, g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+json_generator_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ JsonGeneratorPrivate *priv = JSON_GENERATOR (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PRETTY:
+ g_value_set_boolean (value, priv->pretty);
+ break;
+ case PROP_INDENT:
+ g_value_set_uint (value, priv->indent);
+ break;
+ case PROP_INDENT_CHAR:
+ g_value_set_uint (value, priv->indent_char);
+ break;
+ case PROP_ROOT:
+ g_value_set_boxed (value, priv->root);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+json_generator_class_init (JsonGeneratorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (JsonGeneratorPrivate));
+
+ /**
+ * JsonGenerator:pretty:
+ *
+ * Whether the output should be "pretty-printed", with indentation and
+ * newlines. The indentation level can be controlled by using the
+ * JsonGenerator:indent property
+ */
+ generator_props[PROP_PRETTY] =
+ g_param_spec_boolean ("pretty",
+ "Pretty",
+ "Pretty-print the output",
+ FALSE,
+ G_PARAM_READWRITE);
+
+ /**
+ * JsonGenerator:indent:
+ *
+ * Number of spaces to be used to indent when pretty printing.
+ */
+ generator_props[PROP_INDENT] =
+ g_param_spec_uint ("indent",
+ "Indent",
+ "Number of indentation spaces",
+ 0, G_MAXUINT,
+ 2,
+ G_PARAM_READWRITE);
+
+ /**
+ * JsonGenerator:root:
+ *
+ * The root #JsonNode to be used when constructing a JSON data
+ * stream.
+ *
+ * Since: 0.4
+ */
+ generator_props[PROP_ROOT] =
+ g_param_spec_boxed ("root",
+ "Root",
+ "Root of the JSON data tree",
+ JSON_TYPE_NODE,
+ G_PARAM_READWRITE);
+
+ /**
+ * JsonGenerator:indent-char:
+ *
+ * The character that should be used when indenting in pretty print.
+ *
+ * Since: 0.6
+ */
+ generator_props[PROP_INDENT_CHAR] =
+ g_param_spec_unichar ("indent-char",
+ "Indent Char",
+ "Character that should be used when indenting",
+ ' ',
+ G_PARAM_READWRITE);
+
+ gobject_class->set_property = json_generator_set_property;
+ gobject_class->get_property = json_generator_get_property;
+ gobject_class->finalize = json_generator_finalize;
+ g_object_class_install_properties (gobject_class, PROP_LAST, generator_props);
+}
+
+static void
+json_generator_init (JsonGenerator *generator)
+{
+ JsonGeneratorPrivate *priv;
+
+ generator->priv = priv = JSON_GENERATOR_GET_PRIVATE (generator);
+
+ priv->pretty = FALSE;
+ priv->indent = 2;
+ priv->indent_char = ' ';
+}
+
+static gchar *
+dump_value (JsonGenerator *generator,
+ gint level,
+ const gchar *name,
+ JsonNode *node,
+ gsize *length)
+{
+ JsonGeneratorPrivate *priv = generator->priv;
+ gboolean pretty = priv->pretty;
+ guint indent = priv->indent;
+ GValue value = { 0, };
+ GString *buffer;
+
+ buffer = g_string_new ("");
+
+ if (pretty)
+ {
+ guint i;
+
+ for (i = 0; i < (level * indent); i++)
+ g_string_append_c (buffer, priv->indent_char);
+ }
+
+ if (name && name[0] != '\0')
+ {
+ if (pretty)
+ g_string_append_printf (buffer, "\"%s\" : ", name);
+ else
+ g_string_append_printf (buffer, "\"%s\":", name);
+ }
+
+ json_node_get_value (node, &value);
+
+ switch (G_VALUE_TYPE (&value))
+ {
+ case G_TYPE_INT64:
+ g_string_append_printf (buffer, "%" G_GINT64_FORMAT, g_value_get_int64 (&value));
+ break;
+
+ case G_TYPE_STRING:
+ {
+ gchar *tmp;
+
+ tmp = json_strescape (g_value_get_string (&value));
+ g_string_append_printf (buffer, "\"%s\"", tmp);
+
+ g_free (tmp);
+ }
+ break;
+
+ case G_TYPE_DOUBLE:
+ {
+ gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ g_string_append (buffer,
+ g_ascii_dtostr (buf, sizeof (buf),
+ g_value_get_double (&value)));
+ }
+ break;
+
+ case G_TYPE_BOOLEAN:
+ g_string_append_printf (buffer, "%s",
+ g_value_get_boolean (&value) ? "true" : "false");
+ break;
+
+ default:
+ break;
+ }
+
+ g_value_unset (&value);
+
+ if (length)
+ *length = buffer->len;
+
+ return g_string_free (buffer, FALSE);
+}
+
+static gchar *
+dump_array (JsonGenerator *generator,
+ gint level,
+ const gchar *name,
+ JsonArray *array,
+ gsize *length)
+{
+ JsonGeneratorPrivate *priv = generator->priv;
+ guint array_len = json_array_get_length (array);
+ guint i;
+ GString *buffer;
+ gboolean pretty = priv->pretty;
+ guint indent = priv->indent;
+
+ buffer = g_string_new ("");
+
+ if (pretty)
+ {
+ for (i = 0; i < (level * indent); i++)
+ g_string_append_c (buffer, priv->indent_char);
+ }
+
+ if (name && name[0] != '\0')
+ {
+ if (pretty)
+ g_string_append_printf (buffer, "\"%s\" : ", name);
+ else
+ g_string_append_printf (buffer, "\"%s\":", name);
+ }
+
+ g_string_append_c (buffer, '[');
+
+ if (pretty)
+ g_string_append_c (buffer, '\n');
+
+ for (i = 0; i < array_len; i++)
+ {
+ JsonNode *cur = json_array_get_element (array, i);
+ guint sub_level = level + 1;
+ guint j;
+ gchar *value;
+
+ switch (JSON_NODE_TYPE (cur))
+ {
+ case JSON_NODE_NULL:
+ if (pretty)
+ {
+ for (j = 0; j < (sub_level * indent); j++)
+ g_string_append_c (buffer, priv->indent_char);
+ }
+ g_string_append (buffer, "null");
+ break;
+
+ case JSON_NODE_VALUE:
+ value = dump_value (generator, sub_level, NULL, cur, NULL);
+ g_string_append (buffer, value);
+ g_free (value);
+ break;
+
+ case JSON_NODE_ARRAY:
+ value = dump_array (generator, sub_level, NULL, json_node_get_array (cur), NULL);
+ g_string_append (buffer, value);
+ g_free (value);
+ break;
+
+ case JSON_NODE_OBJECT:
+ value = dump_object (generator, sub_level, NULL, json_node_get_object (cur), NULL);
+ g_string_append (buffer, value);
+ g_free (value);
+ break;
+ }
+
+ if ((i + 1) != array_len)
+ g_string_append_c (buffer, ',');
+
+ if (pretty)
+ g_string_append_c (buffer, '\n');
+ }
+
+ if (pretty)
+ {
+ for (i = 0; i < (level * indent); i++)
+ g_string_append_c (buffer, priv->indent_char);
+ }
+
+ g_string_append_c (buffer, ']');
+
+ if (length)
+ *length = buffer->len;
+
+ return g_string_free (buffer, FALSE);
+}
+
+static gchar *
+dump_object (JsonGenerator *generator,
+ gint level,
+ const gchar *name,
+ JsonObject *object,
+ gsize *length)
+{
+ JsonGeneratorPrivate *priv = generator->priv;
+ GList *members, *l;
+ GString *buffer;
+ gboolean pretty = priv->pretty;
+ guint indent = priv->indent;
+ guint i;
+
+ buffer = g_string_new ("");
+
+ if (pretty)
+ {
+ for (i = 0; i < (level * indent); i++)
+ g_string_append_c (buffer, priv->indent_char);
+ }
+
+ if (name && name[0] != '\0')
+ {
+ if (pretty)
+ g_string_append_printf (buffer, "\"%s\" : ", name);
+ else
+ g_string_append_printf (buffer, "\"%s\":", name);
+ }
+
+ g_string_append_c (buffer, '{');
+
+ if (pretty)
+ g_string_append_c (buffer, '\n');
+
+ members = json_object_get_members (object);
+
+ for (l = members; l != NULL; l = l->next)
+ {
+ const gchar *member_name = l->data;
+ JsonNode *cur = json_object_get_member (object, member_name);
+ guint sub_level = level + 1;
+ guint j;
+ gchar *value;
+
+ switch (JSON_NODE_TYPE (cur))
+ {
+ case JSON_NODE_NULL:
+ if (pretty)
+ {
+ for (j = 0; j < (sub_level * indent); j++)
+ g_string_append_c (buffer, priv->indent_char);
+ g_string_append_printf (buffer, "\"%s\" : null", member_name);
+ }
+ else
+ {
+ g_string_append_printf (buffer, "\"%s\":null", member_name);
+ }
+ break;
+
+ case JSON_NODE_VALUE:
+ value = dump_value (generator, sub_level, member_name, cur, NULL);
+ g_string_append (buffer, value);
+ g_free (value);
+ break;
+
+ case JSON_NODE_ARRAY:
+ value = dump_array (generator, sub_level, member_name,
+ json_node_get_array (cur), NULL);
+ g_string_append (buffer, value);
+ g_free (value);
+ break;
+
+ case JSON_NODE_OBJECT:
+ value = dump_object (generator, sub_level, member_name,
+ json_node_get_object (cur), NULL);
+ g_string_append (buffer, value);
+ g_free (value);
+ break;
+ }
+
+ if (l->next != NULL)
+ g_string_append_c (buffer, ',');
+
+ if (pretty)
+ g_string_append_c (buffer, '\n');
+ }
+
+ g_list_free (members);
+
+ if (pretty)
+ {
+ for (i = 0; i < (level * indent); i++)
+ g_string_append_c (buffer, priv->indent_char);
+ }
+
+ g_string_append_c (buffer, '}');
+
+ if (length)
+ *length = buffer->len;
+
+ return g_string_free (buffer, FALSE);
+}
+
+/**
+ * json_generator_new:
+ *
+ * Creates a new #JsonGenerator. You can use this object to generate a
+ * JSON data stream starting from a data object model composed by
+ * #JsonNode<!-- -->s.
+ *
+ * Return value: the newly created #JsonGenerator instance
+ */
+JsonGenerator *
+json_generator_new (void)
+{
+ return g_object_new (JSON_TYPE_GENERATOR, NULL);
+}
+
+/**
+ * json_generator_to_data:
+ * @generator: a #JsonGenerator
+ * @length: (out): return location for the length of the returned
+ * buffer, or %NULL
+ *
+ * Generates a JSON data stream from @generator and returns it as a
+ * buffer.
+ *
+ * Return value: a newly allocated buffer holding a JSON data stream.
+ * Use g_free() to free the allocated resources.
+ */
+gchar *
+json_generator_to_data (JsonGenerator *generator,
+ gsize *length)
+{
+ JsonNode *root;
+ gchar *retval = NULL;
+
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
+
+ root = generator->priv->root;
+ if (!root)
+ {
+ if (length)
+ *length = 0;
+
+ return NULL;
+ }
+
+ switch (JSON_NODE_TYPE (root))
+ {
+ case JSON_NODE_ARRAY:
+ retval = dump_array (generator, 0, NULL, json_node_get_array (root), length);
+ break;
+
+ case JSON_NODE_OBJECT:
+ retval = dump_object (generator, 0, NULL, json_node_get_object (root), length);
+ break;
+
+ case JSON_NODE_NULL:
+ retval = g_strdup ("null");
+ if (length)
+ *length = 4;
+ break;
+
+ case JSON_NODE_VALUE:
+ retval = dump_value (generator, 0, NULL, root, length);
+ break;
+ }
+
+ return retval;
+}
+
+/**
+ * json_generator_to_file:
+ * @generator: a #JsonGenerator
+ * @filename: path to the target file
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates a JSON data stream and puts it inside @filename, overwriting the
+ * current file contents. This operation is atomic.
+ *
+ * Return value: %TRUE if saving was successful.
+ */
+gboolean
+json_generator_to_file (JsonGenerator *generator,
+ const gchar *filename,
+ GError **error)
+{
+ gchar *buffer;
+ gsize len;
+ gboolean retval;
+
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ buffer = json_generator_to_data (generator, &len);
+ retval = g_file_set_contents (filename, buffer, len, error);
+ g_free (buffer);
+
+ return retval;
+}
+
+/**
+ * json_generator_to_stream:
+ * @generator: a #JsonGenerator
+ * @stream: a #GOutputStream
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Outputs JSON data and streams it (synchronously) to @stream.
+ *
+ * Return value: %TRUE if the write operation was successful, and %FALSE
+ * on failure. In case of error, the #GError will be filled accordingly
+ *
+ * Since: 0.12
+ */
+gboolean
+json_generator_to_stream (JsonGenerator *generator,
+ GOutputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean retval;
+ gchar *buffer;
+ gsize len;
+
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
+ g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ buffer = json_generator_to_data (generator, &len);
+ retval = g_output_stream_write (stream, buffer, len, cancellable, error);
+ g_free (buffer);
+
+ return retval;
+}
+
+/**
+ * json_generator_set_root:
+ * @generator: a #JsonGenerator
+ * @node: a #JsonNode
+ *
+ * Sets @node as the root of the JSON data stream to be serialized by
+ * the #JsonGenerator.
+ *
+ * <note>The node is copied by the generator object, so it can be safely
+ * freed after calling this function.</note>
+ */
+void
+json_generator_set_root (JsonGenerator *generator,
+ JsonNode *node)
+{
+ g_return_if_fail (JSON_IS_GENERATOR (generator));
+
+ if (generator->priv->root != NULL)
+ {
+ json_node_free (generator->priv->root);
+ generator->priv->root = NULL;
+ }
+
+ if (node != NULL)
+ generator->priv->root = json_node_copy (node);
+
+ g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]);
+}
+
+/**
+ * json_generator_get_root:
+ * @generator: a #JsonGenerator
+ *
+ * Retrieves a pointer to the root #JsonNode set using
+ * json_generator_set_root().
+ *
+ * Return value: (transfer none): a #JsonNode, or %NULL. The returned node
+ * is owned by the #JsonGenerator and it should not be freed
+ *
+ * Since: 0.14
+ */
+JsonNode *
+json_generator_get_root (JsonGenerator *generator)
+{
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
+
+ return generator->priv->root;
+}
+
+/**
+ * json_generator_set_pretty:
+ * @generator: a #JsonGenerator
+ * @is_pretty: whether the generated string should be pretty printed
+ *
+ * Sets whether the generated JSON should be pretty printed, using the
+ * indentation character specified in the #JsonGenerator:indent-char
+ * property and the spacing specified in #JsonGenerator:indent property.
+ *
+ * Since: 0.14
+ */
+void
+json_generator_set_pretty (JsonGenerator *generator,
+ gboolean is_pretty)
+{
+ JsonGeneratorPrivate *priv;
+
+ g_return_if_fail (JSON_IS_GENERATOR (generator));
+
+ priv = generator->priv;
+
+ is_pretty = !!is_pretty;
+
+ if (priv->pretty != is_pretty)
+ {
+ priv->pretty = is_pretty;
+
+ g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_PRETTY]);
+ }
+}
+
+/**
+ * json_generator_get_pretty:
+ * @generator: a #JsonGenerator
+ *
+ * Retrieves the value set using json_generator_set_pretty().
+ *
+ * Return value: %TRUE if the generated JSON should be pretty-printed, and
+ * %FALSE otherwise
+ *
+ * Since: 0.14
+ */
+gboolean
+json_generator_get_pretty (JsonGenerator *generator)
+{
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
+
+ return generator->priv->pretty;
+}
+
+/**
+ * json_generator_set_indent:
+ * @generator: a #JsonGenerator
+ * @indent_level: the number of repetitions of the indentation character
+ * that should be applied when pretty printing
+ *
+ * Sets the number of repetitions for each indentation level.
+ *
+ * Since: 0.14
+ */
+void
+json_generator_set_indent (JsonGenerator *generator,
+ guint indent_level)
+{
+ JsonGeneratorPrivate *priv;
+
+ g_return_if_fail (JSON_IS_GENERATOR (generator));
+
+ priv = generator->priv;
+
+ if (priv->indent != indent_level)
+ {
+ priv->indent = indent_level;
+
+ g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT]);
+ }
+}
+
+/**
+ * json_generator_get_indent:
+ * @generator: a #JsonGenerator
+ *
+ * Retrieves the value set using json_generator_set_indent().
+ *
+ * Return value: the number of repetitions per indentation level
+ *
+ * Since: 0.14
+ */
+guint
+json_generator_get_indent (JsonGenerator *generator)
+{
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
+
+ return generator->priv->indent;
+}
+
+/**
+ * json_generator_set_indent_char:
+ * @generator: a #JsonGenerator
+ * @indent_char: a Unicode character to be used when indenting
+ *
+ * Sets the character to be used when indenting
+ *
+ * Since: 0.14
+ */
+void
+json_generator_set_indent_char (JsonGenerator *generator,
+ gunichar indent_char)
+{
+ JsonGeneratorPrivate *priv;
+
+ g_return_if_fail (JSON_IS_GENERATOR (generator));
+
+ priv = generator->priv;
+
+ if (priv->indent_char != indent_char)
+ {
+ priv->indent_char = indent_char;
+
+ g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT_CHAR]);
+ }
+}
+
+/**
+ * json_generator_get_indent_char:
+ * @generator: a #JsonGenerator
+ *
+ * Retrieves the value set using json_generator_set_indent_char().
+ *
+ * Return value: the character to be used when indenting
+ *
+ * Since: 0.14
+ */
+gunichar
+json_generator_get_indent_char (JsonGenerator *generator)
+{
+ g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
+
+ return generator->priv->indent_char;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-generator.h b/src/glib-jsonrpc/json-glib/json-generator.h
new file mode 100644
index 0000000..eb7cdba
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-generator.h
@@ -0,0 +1,107 @@
+/* json-generator.h - JSON streams generator
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_GENERATOR_H__
+#define __JSON_GENERATOR_H__
+
+#include <json-glib/json-types.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define JSON_TYPE_GENERATOR (json_generator_get_type ())
+#define JSON_GENERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JSON_TYPE_GENERATOR, JsonGenerator))
+#define JSON_IS_GENERATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JSON_TYPE_GENERATOR))
+#define JSON_GENERATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), JSON_TYPE_GENERATOR, JsonGeneratorClass))
+#define JSON_IS_GENERATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), JSON_TYPE_GENERATOR))
+#define JSON_GENERATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), JSON_TYPE_GENERATOR, JsonGeneratorClass))
+
+typedef struct _JsonGenerator JsonGenerator;
+typedef struct _JsonGeneratorPrivate JsonGeneratorPrivate;
+typedef struct _JsonGeneratorClass JsonGeneratorClass;
+
+/**
+ * JsonGenerator:
+ *
+ * JSON data streams generator. The contents of the #JsonGenerator structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _JsonGenerator
+{
+ /*< private >*/
+ GObject parent_instance;
+
+ JsonGeneratorPrivate *priv;
+};
+
+/**
+ * JsonGeneratorClass:
+ *
+ * #JsonGenerator class
+ */
+struct _JsonGeneratorClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /* padding, for future expansion */
+ void (* _json_reserved1) (void);
+ void (* _json_reserved2) (void);
+ void (* _json_reserved3) (void);
+ void (* _json_reserved4) (void);
+};
+
+GType json_generator_get_type (void) G_GNUC_CONST;
+
+JsonGenerator * json_generator_new (void);
+
+void json_generator_set_pretty (JsonGenerator *generator,
+ gboolean is_pretty);
+gboolean json_generator_get_pretty (JsonGenerator *generator);
+void json_generator_set_indent (JsonGenerator *generator,
+ guint indent_level);
+guint json_generator_get_indent (JsonGenerator *generator);
+void json_generator_set_indent_char (JsonGenerator *generator,
+ gunichar indent_char);
+gunichar json_generator_get_indent_char (JsonGenerator *generator);
+void json_generator_set_root (JsonGenerator *generator,
+ JsonNode *node);
+JsonNode * json_generator_get_root (JsonGenerator *generator);
+
+gchar * json_generator_to_data (JsonGenerator *generator,
+ gsize *length);
+gboolean json_generator_to_file (JsonGenerator *generator,
+ const gchar *filename,
+ GError **error);
+gboolean json_generator_to_stream (JsonGenerator *generator,
+ GOutputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __JSON_GENERATOR_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-glib.h b/src/glib-jsonrpc/json-glib/json-glib.h
new file mode 100644
index 0000000..257bcdf
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-glib.h
@@ -0,0 +1,46 @@
+/* json-glib.h: Main header
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifndef __JSON_GLIB_H__
+#define __JSON_GLIB_H__
+
+#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-path.h>
+#include <json-glib/json-reader.h>
+#include <json-glib/json-version.h>
+
+#include <json-glib/json-enum-types.h>
+
+#include <json-glib/json-gobject.h>
+
+#include <json-glib/json-gvariant.h>
+
+#undef __JSON_GLIB_INSIDE__
+
+#endif /* __JSON_GLIB_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-gobject-private.h b/src/glib-jsonrpc/json-glib/json-gobject-private.h
new file mode 100644
index 0000000..5369ebf
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-gobject-private.h
@@ -0,0 +1,39 @@
+/* json-gobject-private.h - GObject private
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifndef __JSON_GOBJECT_PRIVATE_H__
+#define __JSON_GOBJECT_PRIVATE_H__
+
+#include "json-gobject.h"
+
+G_BEGIN_DECLS
+
+JsonNode *json_serialize_pspec (const GValue *real_value,
+ GParamSpec *pspec);
+gboolean json_deserialize_pspec (GValue *value,
+ GParamSpec *pspec,
+ JsonNode *node);
+
+G_END_DECLS
+
+#endif /* __JSON_GOBJECT_PRIVATE_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-gobject.c b/src/glib-jsonrpc/json-glib/json-gobject.c
new file mode 100644
index 0000000..073d247
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-gobject.c
@@ -0,0 +1,1005 @@
+/* json-gobject.c - JSON GObject integration
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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 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.
+ *
+ * Author:
+ * Emmanuele Bassi <ebassi openedhand com>
+ */
+
+/**
+ * SECTION:json-gobject
+ * @short_description: Serialize and deserialize GObjects
+ *
+ * JSON-GLib provides API for serializing and deserializing #GObject<!-- -->s
+ * to and from JSON data streams.
+ *
+ * Simple #GObject classes can be (de)serialized into JSON objects, if the
+ * properties have compatible types with the native JSON types (integers,
+ * booleans, strings, string vectors). If the class to be (de)serialized has
+ * complex data types for properties (like boxed types or other objects)
+ * then the class should implement the provided #JsonSerializable interface
+ * and its virtual functions.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#if 0
+#include <glib/gi18n-lib.h>
+#else
+#define _(s) s
+#endif
+
+#include "json-types-private.h"
+#include "json-gobject-private.h"
+
+#include "json-debug.h"
+#include "json-parser.h"
+#include "json-generator.h"
+
+static gboolean
+enum_from_string (GType type,
+ const gchar *string,
+ gint *enum_value)
+{
+ GEnumClass *eclass;
+ GEnumValue *ev;
+ gchar *endptr;
+ gint value;
+ gboolean retval = TRUE;
+
+ g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
+ g_return_val_if_fail (string != NULL, 0);
+
+ value = strtoul (string, &endptr, 0);
+ if (endptr != string) /* parsed a number */
+ *enum_value = value;
+ else
+ {
+ eclass = g_type_class_ref (type);
+ ev = g_enum_get_value_by_name (eclass, string);
+ if (!ev)
+ ev = g_enum_get_value_by_nick (eclass, string);
+
+ if (ev)
+ *enum_value = ev->value;
+ else
+ retval = FALSE;
+
+ g_type_class_unref (eclass);
+ }
+
+ return retval;
+}
+
+static gboolean
+flags_from_string (GType type,
+ const gchar *string,
+ gint *flags_value)
+{
+ GFlagsClass *fclass;
+ gchar *endptr, *prevptr;
+ guint i, j, ret, value;
+ gchar *flagstr;
+ GFlagsValue *fv;
+ const gchar *flag;
+ gunichar ch;
+ gboolean eos;
+
+ g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
+ g_return_val_if_fail (string != 0, 0);
+
+ ret = TRUE;
+
+ value = strtoul (string, &endptr, 0);
+ if (endptr != string) /* parsed a number */
+ *flags_value = value;
+ else
+ {
+ fclass = g_type_class_ref (type);
+
+ flagstr = g_strdup (string);
+ for (value = i = j = 0; ; i++)
+ {
+ eos = flagstr[i] == '\0';
+
+ if (!eos && flagstr[i] != '|')
+ continue;
+
+ flag = &flagstr[j];
+ endptr = &flagstr[i];
+
+ if (!eos)
+ {
+ flagstr[i++] = '\0';
+ j = i;
+ }
+
+ /* trim spaces */
+ for (;;)
+ {
+ ch = g_utf8_get_char (flag);
+ if (!g_unichar_isspace (ch))
+ break;
+ flag = g_utf8_next_char (flag);
+ }
+
+ while (endptr > flag)
+ {
+ prevptr = g_utf8_prev_char (endptr);
+ ch = g_utf8_get_char (prevptr);
+ if (!g_unichar_isspace (ch))
+ break;
+ endptr = prevptr;
+ }
+
+ if (endptr > flag)
+ {
+ *endptr = '\0';
+ fv = g_flags_get_value_by_name (fclass, flag);
+
+ if (!fv)
+ fv = g_flags_get_value_by_nick (fclass, flag);
+
+ if (fv)
+ value |= fv->value;
+ else
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ if (eos)
+ {
+ *flags_value = value;
+ break;
+ }
+ }
+
+ g_free (flagstr);
+
+ g_type_class_unref (fclass);
+ }
+
+ return ret;
+}
+
+static GObject *
+json_gobject_new (GType gtype,
+ JsonObject *object)
+{
+ JsonSerializableIface *iface = NULL;
+ JsonSerializable *serializable = NULL;
+ gboolean find_property;
+ gboolean deserialize_property;
+ gboolean set_property;
+ GList *members, *members_left, *l;
+ guint n_members;
+ GObjectClass *klass;
+ GObject *retval;
+ GArray *construct_params;
+ gint i;
+
+ klass = g_type_class_ref (gtype);
+
+ n_members = json_object_get_size (object);
+ members = json_object_get_members (object);
+ members_left = NULL;
+
+ /* first pass: construct-only properties; here we cannot use Serializable
+ * because we don't have an instance yet; we use the default implementation
+ * of json_deserialize_pspec() to deserialize known types
+ *
+ * FIXME - find a way to allow deserialization for these properties
+ */
+ construct_params = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_members);
+
+ for (l = members; l != NULL; l = l->next)
+ {
+ const gchar *member_name = l->data;
+ GParamSpec *pspec;
+ GParameter param = { NULL, };
+ JsonNode *val;
+ gboolean res = FALSE;
+
+ pspec = g_object_class_find_property (klass, member_name);
+ if (!pspec)
+ goto next_member;
+
+ /* we only apply construct-only properties here */
+ if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0)
+ goto next_member;
+
+ if (!(pspec->flags & G_PARAM_WRITABLE))
+ goto next_member;
+
+ g_value_init (¶m.value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ val = json_object_get_member (object, member_name);
+ res = json_deserialize_pspec (¶m.value, pspec, val);
+ if (!res)
+ {
+ g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"",
+ pspec->name, G_VALUE_TYPE_NAME (¶m.value), g_type_name (gtype));
+
+ g_value_unset (¶m.value);
+ }
+ else
+ {
+ param.name = g_strdup (pspec->name);
+
+ g_array_append_val (construct_params, param);
+
+ continue;
+ }
+
+ next_member:
+ members_left = g_list_prepend (members_left, l->data);
+ }
+
+ retval = g_object_newv (gtype,
+ construct_params->len,
+ (GParameter *) construct_params->data);
+
+ /* free the contents of the GArray */
+ for (i = 0; i < construct_params->len; i++)
+ {
+ GParameter *param = &g_array_index (construct_params, GParameter, i);
+
+ g_free ((gchar *) param->name);
+ g_value_unset (¶m->value);
+ }
+
+ g_array_free (construct_params, TRUE);
+ g_list_free (members);
+
+ /* we use g_list_prepend() above, but we want to maintain
+ * the ordering of json_object_get_members() here
+ */
+ members = g_list_reverse (members_left);
+
+ /* do the Serializable type check once */
+ if (g_type_is_a (gtype, JSON_TYPE_SERIALIZABLE))
+ {
+ serializable = JSON_SERIALIZABLE (retval);
+ iface = JSON_SERIALIZABLE_GET_IFACE (serializable);
+ find_property = (iface->find_property != NULL);
+ deserialize_property = (iface->deserialize_property != NULL);
+ set_property = (iface->set_property != NULL);
+ }
+ else
+ {
+ find_property = FALSE;
+ deserialize_property = FALSE;
+ set_property = FALSE;
+ }
+
+ g_object_freeze_notify (retval);
+
+ for (l = members; l != NULL; l = l->next)
+ {
+ const gchar *member_name = l->data;
+ GParamSpec *pspec;
+ JsonNode *val;
+ GValue value = { 0, };
+ gboolean res = FALSE;
+
+ if (find_property)
+ pspec = json_serializable_find_property (serializable, member_name);
+ else
+ pspec = g_object_class_find_property (klass, member_name);
+
+ if (pspec == NULL)
+ continue;
+
+ /* we should have dealt with these above */
+ if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+ continue;
+
+ if (!(pspec->flags & G_PARAM_WRITABLE))
+ continue;
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ val = json_object_get_member (object, member_name);
+
+ if (deserialize_property)
+ {
+ JSON_NOTE (GOBJECT, "Using JsonSerializable for property '%s'", pspec->name);
+ res = iface->deserialize_property (serializable, pspec->name,
+ &value,
+ pspec,
+ val);
+ }
+
+ if (!res)
+ {
+ JSON_NOTE (GOBJECT, "Using json_deserialize_pspec for property '%s'", pspec->name);
+ res = json_deserialize_pspec (&value, pspec, val);
+ }
+
+ if (res)
+ {
+ JSON_NOTE (GOBJECT, "Calling set_property('%s', '%s')",
+ pspec->name,
+ g_type_name (G_VALUE_TYPE (&value)));
+
+ if (set_property)
+ json_serializable_set_property (serializable, pspec, &value);
+ else
+ g_object_set_property (retval, pspec->name, &value);
+ }
+ else
+ g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"",
+ pspec->name, g_type_name (G_VALUE_TYPE (&value)), g_type_name (gtype));
+
+ g_value_unset (&value);
+ }
+
+ g_list_free (members);
+
+ g_object_thaw_notify (retval);
+
+ g_type_class_unref (klass);
+
+ return retval;
+}
+
+static JsonObject *
+json_gobject_dump (GObject *gobject)
+{
+ JsonSerializableIface *iface = NULL;
+ JsonSerializable *serializable = NULL;
+ gboolean list_properties = FALSE;
+ gboolean serialize_property = FALSE;
+ gboolean get_property = FALSE;
+ JsonObject *object;
+ GParamSpec **pspecs;
+ guint n_pspecs, i;
+
+ if (JSON_IS_SERIALIZABLE (gobject))
+ {
+ serializable = JSON_SERIALIZABLE (gobject);
+ iface = JSON_SERIALIZABLE_GET_IFACE (gobject);
+ list_properties = (iface->list_properties != NULL);
+ serialize_property = (iface->serialize_property != NULL);
+ get_property = (iface->get_property != NULL);
+ }
+
+ object = json_object_new ();
+
+ if (list_properties)
+ pspecs = json_serializable_list_properties (serializable, &n_pspecs);
+ else
+ pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (gobject), &n_pspecs);
+
+ for (i = 0; i < n_pspecs; i++)
+ {
+ GParamSpec *pspec = pspecs[i];
+ GValue value = { 0, };
+ JsonNode *node = NULL;
+
+ /* read only what we can */
+ if (!(pspec->flags & G_PARAM_READABLE))
+ continue;
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ if (get_property)
+ json_serializable_get_property (serializable, pspec, &value);
+ else
+ g_object_get_property (gobject, pspec->name, &value);
+
+ /* if there is a serialization vfunc, then it is completely responsible
+ * for serializing the property, possibly by calling the implementation
+ * of the default JsonSerializable interface through chaining up
+ */
+ if (serialize_property)
+ {
+ node = iface->serialize_property (serializable, pspec->name,
+ &value,
+ pspec);
+ }
+ /* skip if the value is the default for the property */
+ else if (!g_param_value_defaults (pspec, &value))
+ node = json_serialize_pspec (&value, pspec);
+
+ if (node)
+ json_object_set_member (object, pspec->name, node);
+
+ g_value_unset (&value);
+ }
+
+ g_free (pspecs);
+
+ return object;
+}
+
+gboolean
+json_deserialize_pspec (GValue *value,
+ GParamSpec *pspec,
+ JsonNode *node)
+{
+ GValue node_value = { 0, };
+ gboolean retval = FALSE;
+
+ if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_BOXED)
+ {
+ JsonNodeType node_type = json_node_get_node_type (node);
+ GType boxed_type = G_VALUE_TYPE (value);
+
+ if (json_boxed_can_deserialize (boxed_type, node_type))
+ {
+ gpointer boxed = json_boxed_deserialize (boxed_type, node);
+
+ g_value_take_boxed (value, boxed);
+
+ return TRUE;
+ }
+ }
+
+ switch (JSON_NODE_TYPE (node))
+ {
+ case JSON_NODE_OBJECT:
+ if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_OBJECT))
+ {
+ GObject *object;
+
+ object = json_gobject_new (G_VALUE_TYPE (value), json_node_get_object (node));
+ if (object != NULL)
+ g_value_take_object (value, object);
+ else
+ g_value_set_object (value, NULL);
+
+ retval = TRUE;
+ }
+ break;
+
+ case JSON_NODE_ARRAY:
+ if (G_VALUE_HOLDS (value, G_TYPE_STRV))
+ {
+ JsonArray *array = json_node_get_array (node);
+ guint i, array_len = json_array_get_length (array);
+ GPtrArray *str_array = g_ptr_array_sized_new (array_len + 1);
+
+ for (i = 0; i < array_len; i++)
+ {
+ JsonNode *val = json_array_get_element (array, i);
+
+ if (JSON_NODE_TYPE (val) != JSON_NODE_VALUE)
+ continue;
+
+ if (json_node_get_string (val) != NULL)
+ g_ptr_array_add (str_array, (gpointer) json_node_get_string (val));
+ }
+
+ g_ptr_array_add (str_array, NULL);
+
+ g_value_set_boxed (value, str_array->pdata);
+
+ g_ptr_array_free (str_array, TRUE);
+
+ retval = TRUE;
+ }
+ break;
+
+ case JSON_NODE_VALUE:
+ json_node_get_value (node, &node_value);
+#if 0
+ {
+ gchar *node_str = g_strdup_value_contents (&node_value);
+ g_debug ("%s: value type '%s' := node value type '%s' -> '%s'",
+ G_STRLOC,
+ g_type_name (G_VALUE_TYPE (value)),
+ g_type_name (G_VALUE_TYPE (&node_value)),
+ node_str);
+ g_free (node_str);
+ }
+#endif
+
+ switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT64:
+ case G_TYPE_STRING:
+ if (G_VALUE_HOLDS (&node_value, G_VALUE_TYPE (value)))
+ {
+ g_value_copy (&node_value, value);
+ retval = TRUE;
+ }
+ break;
+
+ case G_TYPE_INT:
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ g_value_set_int (value, (gint) g_value_get_int64 (&node_value));
+ retval = TRUE;
+ }
+ break;
+
+ case G_TYPE_CHAR:
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ g_value_set_char (value, (gchar) g_value_get_int64 (&node_value));
+ retval = TRUE;
+ }
+ break;
+
+ case G_TYPE_UINT:
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ g_value_set_uint (value, (guint) g_value_get_int64 (&node_value));
+ retval = TRUE;
+ }
+ break;
+
+ case G_TYPE_UCHAR:
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ g_value_set_uchar (value, (guchar) g_value_get_int64 (&node_value));
+ retval = TRUE;
+ }
+ break;
+
+ case G_TYPE_DOUBLE:
+
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_DOUBLE))
+ {
+ g_value_set_double (value, g_value_get_double (&node_value));
+ retval = TRUE;
+ }
+ else if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ g_value_set_double (value, (gdouble) g_value_get_int64 (&node_value));
+ retval = TRUE;
+ }
+
+ break;
+
+ case G_TYPE_FLOAT:
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_DOUBLE))
+ {
+ g_value_set_float (value, (gfloat) g_value_get_double (&node_value));
+ retval = TRUE;
+ }
+ else if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ g_value_set_float (value, (gfloat) g_value_get_int64 (&node_value));
+ retval = TRUE;
+ }
+
+ break;
+
+ case G_TYPE_ENUM:
+ {
+ gint enum_value = 0;
+
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ enum_value = g_value_get_int64 (&node_value);
+ retval = TRUE;
+ }
+ else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
+ {
+ retval = enum_from_string (G_VALUE_TYPE (value),
+ g_value_get_string (&node_value),
+ &enum_value);
+ }
+
+ if (retval)
+ g_value_set_enum (value, enum_value);
+ }
+ break;
+
+ case G_TYPE_FLAGS:
+ {
+ gint flags_value = 0;
+
+ if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
+ {
+ flags_value = g_value_get_int64 (&node_value);
+ retval = TRUE;
+ }
+ else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
+ {
+ retval = flags_from_string (G_VALUE_TYPE (value),
+ g_value_get_string (&node_value),
+ &flags_value);
+ }
+
+ if (retval)
+ g_value_set_flags (value, flags_value);
+ }
+ break;
+
+ default:
+ retval = FALSE;
+ break;
+ }
+
+ g_value_unset (&node_value);
+ break;
+
+ case JSON_NODE_NULL:
+ if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_STRING)
+ {
+ g_value_set_string (value, NULL);
+ retval = TRUE;
+ }
+ else if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_OBJECT)
+ {
+ g_value_set_object (value, NULL);
+ retval = TRUE;
+ }
+ else
+ retval = FALSE;
+
+ break;
+ }
+
+ return retval;
+}
+
+JsonNode *
+json_serialize_pspec (const GValue *real_value,
+ GParamSpec *pspec)
+{
+ JsonNode *retval = NULL;
+ GValue value = { 0, };
+ JsonNodeType node_type;
+
+ switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (real_value)))
+ {
+ case G_TYPE_INT64:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_DOUBLE:
+ /* JSON native types */
+ retval = json_node_new (JSON_NODE_VALUE);
+ g_value_init (&value, G_VALUE_TYPE (real_value));
+ g_value_copy (real_value, &value);
+ json_node_set_value (retval, &value);
+ g_value_unset (&value);
+ break;
+
+ case G_TYPE_STRING:
+ /* strings might be NULL, so we handle it differently */
+ if (!g_value_get_string (real_value))
+ retval = json_node_new (JSON_NODE_NULL);
+ else
+ {
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_string (retval, g_value_get_string (real_value));
+ break;
+ }
+ break;
+
+ case G_TYPE_INT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_int (real_value));
+ break;
+
+ case G_TYPE_FLOAT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_double (retval, g_value_get_float (real_value));
+ break;
+
+ 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_new (JSON_NODE_ARRAY);
+ json_node_take_array (retval, 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_UINT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_uint (real_value));
+ break;
+
+ case G_TYPE_LONG:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_long (real_value));
+ break;
+
+ case G_TYPE_ULONG:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_long (real_value));
+ break;
+
+ case G_TYPE_CHAR:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_char (real_value));
+ break;
+
+ case G_TYPE_UCHAR:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_uchar (real_value));
+ break;
+
+ case G_TYPE_ENUM:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_enum (real_value));
+ break;
+
+ case G_TYPE_FLAGS:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_flags (real_value));
+ break;
+
+ case G_TYPE_OBJECT:
+ {
+ GObject *object = g_value_get_object (real_value);
+
+ if (object != NULL)
+ {
+ retval = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (retval, json_gobject_dump (object));
+ }
+ else
+ retval = json_node_new (JSON_NODE_NULL);
+ }
+ 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;
+}
+
+/**
+ * json_gobject_deserialize:
+ * @gtype: the type of the #GObject to create
+ * @node: a #JsonNode of type %JSON_NODE_OBJECT describing the
+ * instance of type @gtype
+ *
+ * Creates a new #GObject of type @gtype, and constructs it
+ * using the members of the passed #JsonObject
+ *
+ * Return value: (transfer full): The newly created #GObject
+ * instance. Use g_object_unref() to free the resources
+ * allocated by this function
+ *
+ * Since: 0.10
+ */
+GObject *
+json_gobject_deserialize (GType gtype,
+ JsonNode *node)
+{
+ g_return_val_if_fail (g_type_is_a (gtype, G_TYPE_OBJECT), NULL);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL);
+
+ return json_gobject_new (gtype, json_node_get_object (node));
+}
+
+/**
+ * json_gobject_serialize:
+ * @gobject: a #GObject
+ *
+ * Creates a #JsonNode representing the passed #GObject
+ * instance. Each member of the returned JSON object will
+ * map to a property of the #GObject
+ *
+ * Return value: (transfer full): the newly created #JsonNode
+ * of type %JSON_NODE_OBJECT. Use json_node_free() to free
+ * the resources allocated by this function
+ *
+ * Since: 0.10
+ */
+JsonNode *
+json_gobject_serialize (GObject *gobject)
+{
+ JsonNode *retval;
+
+ g_return_val_if_fail (G_IS_OBJECT (gobject), NULL);
+
+ retval = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (retval, json_gobject_dump (gobject));
+
+ return retval;
+}
+
+/**
+ * json_construct_gobject:
+ * @gtype: the #GType of object to construct
+ * @data: a JSON data stream
+ * @length: length of the data stream
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deserializes a JSON data stream and creates the corresponding
+ * #GObject class. If @gtype implements the #JsonSerializableIface
+ * interface, it will be asked to deserialize all the JSON members
+ * into the respective properties; otherwise, the default implementation
+ * will be used to translate the compatible JSON native types.
+ *
+ * Note: the JSON data stream must be an object declaration.
+ *
+ * Return value: (transfer full): a #GObject or %NULL
+ *
+ * Since: 0.4
+ *
+ * Deprecated: 0.10: Use json_gobject_from_data() instead
+ */
+GObject *
+json_construct_gobject (GType gtype,
+ const gchar *data,
+ gsize length,
+ GError **error)
+{
+ return json_gobject_from_data (gtype, data, strlen (data), error);
+}
+
+/**
+ * json_gobject_from_data:
+ * @gtype: the #GType of object to construct
+ * @data: a JSON data stream
+ * @length: length of the data stream, or -1 if it is NUL-terminated
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deserializes a JSON data stream and creates the corresponding
+ * #GObject class. If @gtype implements the #JsonSerializableIface
+ * interface, it will be asked to deserialize all the JSON members
+ * into the respective properties; otherwise, the default implementation
+ * will be used to translate the compatible JSON native types.
+ *
+ * Note: the JSON data stream must be an object declaration.
+ *
+ * Return value: (transfer full): a #GObject or %NULL
+ *
+ * Since: 0.10
+ */
+GObject *
+json_gobject_from_data (GType gtype,
+ const gchar *data,
+ gssize length,
+ GError **error)
+{
+ JsonParser *parser;
+ JsonNode *root;
+ GError *parse_error;
+ GObject *retval;
+
+ g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+
+ if (length < 0)
+ length = strlen (data);
+
+ parser = json_parser_new ();
+
+ parse_error = NULL;
+ json_parser_load_from_data (parser, data, length, &parse_error);
+ if (parse_error)
+ {
+ g_propagate_error (error, parse_error);
+ g_object_unref (parser);
+ return NULL;
+ }
+
+ root = json_parser_get_root (parser);
+ if (root == NULL || JSON_NODE_TYPE (root) != JSON_NODE_OBJECT)
+ {
+ /* translators: the %s is the name of the data structure */
+ g_set_error (error, JSON_PARSER_ERROR,
+ JSON_PARSER_ERROR_PARSE,
+ _("Expecting a JSON object, but the root node is of type `%s'"),
+ json_node_type_name (root));
+ g_object_unref (parser);
+ return NULL;
+ }
+
+ retval = json_gobject_deserialize (gtype, root);
+
+ g_object_unref (parser);
+
+ return retval;
+}
+
+/**
+ * json_serialize_gobject:
+ * @gobject: a #GObject
+ * @length: (out): return value for the length of the buffer, or %NULL
+ *
+ * Serializes a #GObject into a JSON data stream. If @gobject implements
+ * the #JsonSerializableIface interface, it will be asked to serizalize all
+ * its properties; otherwise, the default implementation will be use to
+ * translate the compatible types into JSON native types.
+ *
+ * Return value: a JSON data stream representing the passed #GObject
+ *
+ * Deprecated: 0.10: Use json_gobject_to_data() instead
+ */
+gchar *
+json_serialize_gobject (GObject *gobject,
+ gsize *length)
+{
+ return json_gobject_to_data (gobject, length);
+}
+
+/**
+ * json_gobject_to_data:
+ * @gobject: a #GObject
+ * @length: (out): return value for the length of the buffer, or %NULL
+ *
+ * Serializes a #GObject into a JSON data stream, iterating recursively
+ * over each property.
+ *
+ * If @gobject implements the #JsonSerializableIface interface, it will
+ * be asked to serialize all its properties; otherwise, the default
+ * implementation will be use to translate the compatible types into
+ * JSON native types.
+ *
+ * Return value: a JSON data stream representing the passed #GObject
+ *
+ * Since: 0.10
+ */
+gchar *
+json_gobject_to_data (GObject *gobject,
+ gsize *length)
+{
+ JsonGenerator *gen;
+ JsonNode *root;
+ gchar *data;
+
+ g_return_val_if_fail (G_OBJECT (gobject), NULL);
+
+ root = json_gobject_serialize (gobject);
+
+ gen = g_object_new (JSON_TYPE_GENERATOR,
+ "root", root,
+ "pretty", TRUE,
+ "indent", 2,
+ NULL);
+
+ data = json_generator_to_data (gen, length);
+ g_object_unref (gen);
+
+ json_node_free (root);
+
+ return data;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-gobject.h b/src/glib-jsonrpc/json-glib/json-gobject.h
new file mode 100644
index 0000000..2e06d88
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-gobject.h
@@ -0,0 +1,182 @@
+/* json-gobject.h - JSON GObject integration
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifndef __JSON_GOBJECT_H__
+#define __JSON_GOBJECT_H__
+
+#include <json-glib/json-types.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define JSON_TYPE_SERIALIZABLE (json_serializable_get_type ())
+#define JSON_SERIALIZABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JSON_TYPE_SERIALIZABLE, JsonSerializable))
+#define JSON_IS_SERIALIZABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JSON_TYPE_SERIALIZABLE))
+#define JSON_SERIALIZABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), JSON_TYPE_SERIALIZABLE, JsonSerializableIface))
+
+typedef struct _JsonSerializable JsonSerializable; /* dummy */
+typedef struct _JsonSerializableIface JsonSerializableIface;
+
+/**
+ * JsonSerializableIface:
+ * @serialize_property: virtual function for serializing a #GObject property
+ * into a #JsonNode
+ * @deserialize_property: virtual function for deserializing a #JsonNode
+ * into a #GObject property
+ * @find_property: virtual function for finding a property definition using
+ * its name
+ * @list_properties: virtual function for listing the installed property
+ * definitions
+ * @set_property: virtual function for setting a property
+ * @get_property: virtual function for getting a property
+ *
+ * Interface that allows serializing and deserializing #GObject<!-- -->s
+ * with properties storing complex data types. The json_serialize_gobject()
+ * function will check if the passed #GObject implements this interface,
+ * so it can also be used to override the default property serialization
+ * sequence.
+ */
+struct _JsonSerializableIface
+{
+ /*< private >*/
+ GTypeInterface g_iface;
+
+ /*< public >*/
+ JsonNode *(* serialize_property) (JsonSerializable *serializable,
+ const gchar *property_name,
+ const GValue *value,
+ GParamSpec *pspec);
+ gboolean (* deserialize_property) (JsonSerializable *serializable,
+ const gchar *property_name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *property_node);
+
+ GParamSpec * (* find_property) (JsonSerializable *serializable,
+ const char *name);
+ GParamSpec **(* list_properties) (JsonSerializable *serializable,
+ guint *n_pspecs);
+ void (* set_property) (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ const GValue *value);
+ void (* get_property) (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ GValue *value);
+};
+
+GType json_serializable_get_type (void) G_GNUC_CONST;
+
+JsonNode *json_serializable_serialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ const GValue *value,
+ GParamSpec *pspec);
+gboolean json_serializable_deserialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *property_node);
+
+GParamSpec * json_serializable_find_property (JsonSerializable *serializable,
+ const char *name);
+GParamSpec ** json_serializable_list_properties (JsonSerializable *serializable,
+ guint *n_pspecs);
+void json_serializable_set_property (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ const GValue *value);
+void json_serializable_get_property (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ GValue *value);
+
+JsonNode *json_serializable_default_serialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ const GValue *value,
+ GParamSpec *pspec);
+gboolean json_serializable_default_deserialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *property_node);
+
+/**
+ * JsonBoxedSerializeFunc:
+ * @boxed: a #GBoxed
+ *
+ * Serializes the passed #GBoxed and stores it inside a #JsonNode
+ *
+ * Return value: the newly created #JsonNode
+ *
+ * Since: 0.10
+ */
+typedef JsonNode *(* JsonBoxedSerializeFunc) (gconstpointer boxed);
+
+/**
+ * JsonBoxedDeserializeFunc:
+ * @node: a #JsonNode
+ *
+ * Deserializes the contents of the passed #JsonNode into a #GBoxed
+ *
+ * Return value: the newly created boxed type
+ *
+ * Since: 0.10
+ */
+typedef gpointer (* JsonBoxedDeserializeFunc) (JsonNode *node);
+
+void json_boxed_register_serialize_func (GType gboxed_type,
+ JsonNodeType node_type,
+ JsonBoxedSerializeFunc serialize_func);
+void json_boxed_register_deserialize_func (GType gboxed_type,
+ JsonNodeType node_type,
+ JsonBoxedDeserializeFunc deserialize_func);
+gboolean json_boxed_can_serialize (GType gboxed_type,
+ JsonNodeType *node_type);
+gboolean json_boxed_can_deserialize (GType gboxed_type,
+ JsonNodeType node_type);
+JsonNode *json_boxed_serialize (GType gboxed_type,
+ gconstpointer boxed);
+gpointer json_boxed_deserialize (GType gboxed_type,
+ JsonNode *node);
+
+JsonNode *json_gobject_serialize (GObject *gobject);
+GObject * json_gobject_deserialize (GType gtype,
+ JsonNode *node);
+
+GObject * json_gobject_from_data (GType gtype,
+ const gchar *data,
+ gssize length,
+ GError **error);
+gchar * json_gobject_to_data (GObject *gobject,
+ gsize *length);
+
+#ifndef JSON_DISABLE_DEPRECATED
+GObject * json_construct_gobject (GType gtype,
+ const gchar *data,
+ gsize length,
+ GError **error) G_GNUC_DEPRECATED;
+gchar * json_serialize_gobject (GObject *gobject,
+ gsize *length) G_GNUC_MALLOC G_GNUC_DEPRECATED;
+#endif /* JSON_DISABLE_DEPRECATED */
+
+
+G_END_DECLS
+
+#endif /* __JSON_GOBJECT_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-gvariant.c b/src/glib-jsonrpc/json-glib/json-gvariant.c
new file mode 100644
index 0000000..dc40ec5
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-gvariant.c
@@ -0,0 +1,1341 @@
+/* json-gvariant.c - JSON GVariant integration
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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 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.
+ *
+ * Author:
+ * Eduardo Lima Mitev <elima igalia com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#if 0
+#include <glib/gi18n-lib.h>
+#else
+#define _(s) s
+#endif
+
+#include "json-gvariant.h"
+
+/**
+ * SECTION:json-gvariant
+ * @short_description: Serialize and deserialize GVariant types
+ * @Title: JSON GVariant Integration
+ *
+ * Use json_gvariant_serialize() and json_gvariant_serialize_data() to
+ * convert from any #GVariant value to a #JsonNode tree or its string
+ * representation.
+ *
+ * Use json_gvariant_deserialize() and json_gvariant_deserialize_data() to
+ * obtain the #GVariant value from a #JsonNode tree or directly from a JSON
+ * string.
+ * Since many #GVariant data types cannot be directly represented as
+ * JSON, a #GVariant type string (signature) should be provided to these
+ * methods in order to obtain a correct, type-contrained result.
+ * If no signature is provided, conversion can still be done, but the
+ * resulting #GVariant value will be "guessed" from the JSON data types,
+ * according to the following table:
+ *
+ * <table frame='all'><title>Default JSON to GVariant conversion (without signature constrains)</title>
+ * <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ * <thead>
+ * <row>
+ * <entry>JSON</entry>
+ * <entry>GVariant</entry>
+ * </row>
+ * </thead>
+ * <tfoot>
+ * <row>
+ * <entry>string</entry>
+ * <entry>string (s)</entry>
+ * </row>
+ * <row>
+ * <entry>int64</entry>
+ * <entry>int64 (x)</entry>
+ * </row>
+ * <row>
+ * <entry>boolean</entry>
+ * <entry>boolean (b)</entry>
+ * </row>
+ * <row>
+ * <entry>double</entry>
+ * <entry>double (d)</entry>
+ * </row>
+ * <row>
+ * <entry>array</entry>
+ * <entry>array of variants (av)</entry>
+ * </row>
+ * <row>
+ * <entry>object</entry>
+ * <entry>dictionary of string-variant (a{sv})</entry>
+ * </row>
+ * <row>
+ * <entry>null</entry>
+ * <entry>maybe variant (mv)</entry>
+ * </row>
+ * </tfoot>
+ * </tgroup>
+ * </table>
+ */
+
+/* custom extension to the GVariantClass enumeration to differentiate
+ * a single dictionary entry from an array of dictionary entries
+ */
+#define JSON_G_VARIANT_CLASS_DICTIONARY 'c'
+
+typedef void (* GVariantForeachFunc) (GVariant *variant_child,
+ gpointer user_data);
+
+static GVariant * json_to_gvariant_recurse (JsonNode *json_node,
+ const gchar **signature,
+ GError **error);
+
+/* ========================================================================== */
+/* GVariant to JSON */
+/* ========================================================================== */
+
+static void
+gvariant_foreach (GVariant *variant,
+ GVariantForeachFunc func,
+ gpointer user_data)
+{
+ GVariantIter iter;
+ GVariant *variant_child;
+
+ g_variant_iter_init (&iter, variant);
+ while ((variant_child = g_variant_iter_next_value (&iter)) != NULL)
+ {
+ func (variant_child, user_data);
+ g_variant_unref (variant_child);
+ }
+}
+
+static void
+gvariant_to_json_array_foreach (GVariant *variant_child,
+ gpointer user_data)
+{
+ JsonArray *array = user_data;
+ JsonNode *json_child;
+
+ json_child = json_gvariant_serialize (variant_child);
+ json_array_add_element (array, json_child);
+}
+
+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;
+}
+
+static gchar *
+gvariant_simple_to_string (GVariant *variant)
+{
+ GVariantClass class;
+ gchar *str;
+
+ class = g_variant_classify (variant);
+ switch (class)
+ {
+ case G_VARIANT_CLASS_BOOLEAN:
+ if (g_variant_get_boolean (variant))
+ str = g_strdup ("true");
+ else
+ str = g_strdup ("false");
+ break;
+
+ case G_VARIANT_CLASS_BYTE:
+ str = g_strdup_printf ("%u", g_variant_get_byte (variant));
+ break;
+ case G_VARIANT_CLASS_INT16:
+ str = g_strdup_printf ("%d", g_variant_get_int16 (variant));
+ break;
+ case G_VARIANT_CLASS_UINT16:
+ str = g_strdup_printf ("%u", g_variant_get_uint16 (variant));
+ break;
+ case G_VARIANT_CLASS_INT32:
+ str = g_strdup_printf ("%d", g_variant_get_int32 (variant));
+ break;
+ case G_VARIANT_CLASS_UINT32:
+ str = g_strdup_printf ("%u", g_variant_get_uint32 (variant));
+ break;
+ case G_VARIANT_CLASS_INT64:
+ str = g_strdup_printf ("%" G_GINT64_FORMAT,
+ g_variant_get_int64 (variant));
+ break;
+ case G_VARIANT_CLASS_UINT64:
+ str = g_strdup_printf ("%" G_GUINT64_FORMAT,
+ g_variant_get_uint64 (variant));
+ break;
+ case G_VARIANT_CLASS_HANDLE:
+ str = g_strdup_printf ("%d", g_variant_get_handle (variant));
+ break;
+
+ case G_VARIANT_CLASS_DOUBLE:
+ {
+ gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ g_ascii_formatd (buf,
+ G_ASCII_DTOSTR_BUF_SIZE,
+ "%f",
+ g_variant_get_double (variant));
+
+ str = g_strdup (buf);
+ break;
+ }
+
+ case G_VARIANT_CLASS_STRING:
+ case G_VARIANT_CLASS_OBJECT_PATH:
+ case G_VARIANT_CLASS_SIGNATURE:
+ str = g_strdup (g_variant_get_string (variant, NULL));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return str;
+}
+
+static JsonNode *
+gvariant_dict_entry_to_json (GVariant *variant, gchar **member_name)
+{
+ GVariant *member;
+ GVariant *value;
+ JsonNode *json_node;
+
+ member = g_variant_get_child_value (variant, 0);
+ *member_name = gvariant_simple_to_string (member);
+
+ value = g_variant_get_child_value (variant, 1);
+ json_node = json_gvariant_serialize (value);
+
+ g_variant_unref (member);
+ g_variant_unref (value);
+
+ return json_node;
+}
+
+static void
+gvariant_to_json_object_foreach (GVariant *variant_child, gpointer user_data)
+{
+ gchar *member_name;
+ JsonNode *json_child;
+ JsonObject *object = (JsonObject *) user_data;
+
+ json_child = gvariant_dict_entry_to_json (variant_child, &member_name);
+ json_object_set_member (object, member_name, json_child);
+ g_free (member_name);
+}
+
+static JsonNode *
+gvariant_to_json_object (GVariant *variant)
+{
+ JsonNode *json_node;
+ JsonObject *object;
+
+ json_node = json_node_new (JSON_NODE_OBJECT);
+ object = json_object_new ();
+ json_node_set_object (json_node, object);
+ json_object_unref (object);
+
+ gvariant_foreach (variant,
+ gvariant_to_json_object_foreach,
+ object);
+
+ return json_node;
+}
+
+/**
+ * json_gvariant_serialize:
+ * @variant: A #GVariant to convert
+ *
+ * Converts @variant to a JSON tree.
+ *
+ * Return value: (transfer full): A #JsonNode representing the root of the
+ * JSON data structure obtained from @variant
+ *
+ * Since: 0.14
+ */
+JsonNode *
+json_gvariant_serialize (GVariant *variant)
+{
+ JsonNode *json_node = NULL;
+ GVariantClass class;
+
+ g_return_val_if_fail (variant != NULL, NULL);
+
+ class = g_variant_classify (variant);
+
+ if (! g_variant_is_container (variant))
+ {
+ json_node = json_node_new (JSON_NODE_VALUE);
+
+ switch (class)
+ {
+ case G_VARIANT_CLASS_BOOLEAN:
+ json_node_set_boolean (json_node, g_variant_get_boolean (variant));
+ break;
+
+ case G_VARIANT_CLASS_BYTE:
+ json_node_set_int (json_node, g_variant_get_byte (variant));
+ break;
+ case G_VARIANT_CLASS_INT16:
+ json_node_set_int (json_node, g_variant_get_int16 (variant));
+ break;
+ case G_VARIANT_CLASS_UINT16:
+ json_node_set_int (json_node, g_variant_get_uint16 (variant));
+ break;
+ case G_VARIANT_CLASS_INT32:
+ json_node_set_int (json_node, g_variant_get_int32 (variant));
+ break;
+ case G_VARIANT_CLASS_UINT32:
+ json_node_set_int (json_node, g_variant_get_uint32 (variant));
+ break;
+ case G_VARIANT_CLASS_INT64:
+ json_node_set_int (json_node, g_variant_get_int64 (variant));
+ break;
+ case G_VARIANT_CLASS_UINT64:
+ json_node_set_int (json_node, g_variant_get_uint64 (variant));
+ break;
+ case G_VARIANT_CLASS_HANDLE:
+ json_node_set_int (json_node, g_variant_get_handle (variant));
+ break;
+
+ case G_VARIANT_CLASS_DOUBLE:
+ json_node_set_double (json_node, g_variant_get_double (variant));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ case G_VARIANT_CLASS_OBJECT_PATH:
+ case G_VARIANT_CLASS_SIGNATURE:
+ json_node_set_string (json_node, g_variant_get_string (variant, NULL));
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (class)
+ {
+ case G_VARIANT_CLASS_MAYBE:
+ {
+ GVariant *value;
+
+ value = g_variant_get_maybe (variant);
+ if (value == NULL)
+ {
+ json_node = json_node_new (JSON_NODE_NULL);
+ }
+ else
+ {
+ json_node = json_gvariant_serialize (value);
+ g_variant_unref (value);
+ }
+
+ break;
+ }
+
+ case G_VARIANT_CLASS_VARIANT:
+ {
+ GVariant *value;
+
+ value = g_variant_get_variant (variant);
+ json_node = json_gvariant_serialize (value);
+ g_variant_unref (value);
+
+ break;
+ }
+
+ case G_VARIANT_CLASS_ARRAY:
+ {
+ const gchar *type;
+
+ type = g_variant_get_type_string (variant);
+
+ if (type[1] == G_VARIANT_CLASS_DICT_ENTRY)
+ {
+ /* array of dictionary entries => JsonObject */
+ json_node = gvariant_to_json_object (variant);
+ }
+ else
+ {
+ /* array of anything else => JsonArray */
+ json_node = gvariant_to_json_array (variant);
+ }
+
+ break;
+ }
+
+ case G_VARIANT_CLASS_DICT_ENTRY:
+ {
+ gchar *member_name;
+ JsonObject *object;
+ JsonNode *child;
+
+ /* a single dictionary entry => JsonObject */
+ json_node = json_node_new (JSON_NODE_OBJECT);
+ object = json_object_new ();
+ json_node_set_object (json_node, object);
+ json_object_unref (object);
+
+ child = gvariant_dict_entry_to_json (variant, &member_name);
+
+ json_object_set_member (object, member_name, child);
+ g_free (member_name);
+
+ break;
+ }
+
+ case G_VARIANT_CLASS_TUPLE:
+ json_node = gvariant_to_json_array (variant);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return json_node;
+}
+
+/**
+ * json_gvariant_serialize_data:
+ * @variant: A #GVariant to convert
+ * @length: (out) (allow-none): Return location for the length of the returned
+ * string, or %NULL
+ *
+ * Converts @variant to its JSON encoded string representation. This method
+ * is actually a helper function. It uses json_gvariant_serialize() to obtain the
+ * JSON tree, and then #JsonGenerator to stringify it.
+ *
+ * Return value: (transfer full): The JSON encoded string corresponding to
+ * @variant
+ *
+ * Since: 0.14
+ */
+gchar *
+json_gvariant_serialize_data (GVariant *variant, gsize *length)
+{
+ JsonNode *json_node;
+ JsonGenerator *generator;
+ gchar *json;
+
+ json_node = json_gvariant_serialize (variant);
+
+ generator = json_generator_new ();
+
+ json_generator_set_root (generator, json_node);
+ json = json_generator_to_data (generator, length);
+
+ g_object_unref (generator);
+
+ json_node_free (json_node);
+
+ return json;
+}
+
+/* ========================================================================== */
+/* JSON to GVariant */
+/* ========================================================================== */
+
+static GVariantClass
+json_to_gvariant_get_next_class (JsonNode *json_node,
+ const gchar **signature)
+{
+ if (signature == NULL)
+ {
+ GVariantClass class = 0;
+
+ switch (json_node_get_node_type (json_node))
+ {
+ case JSON_NODE_VALUE:
+ switch (json_node_get_value_type (json_node))
+ {
+ case G_TYPE_BOOLEAN:
+ class = G_VARIANT_CLASS_BOOLEAN;
+ break;
+
+ case G_TYPE_INT64:
+ class = G_VARIANT_CLASS_INT64;
+ break;
+
+ case G_TYPE_DOUBLE:
+ class = G_VARIANT_CLASS_DOUBLE;
+ break;
+
+ case G_TYPE_STRING:
+ class = G_VARIANT_CLASS_STRING;
+ break;
+ }
+
+ break;
+
+ case JSON_NODE_ARRAY:
+ class = G_VARIANT_CLASS_ARRAY;
+ break;
+
+ case JSON_NODE_OBJECT:
+ class = JSON_G_VARIANT_CLASS_DICTIONARY;
+ break;
+
+ case JSON_NODE_NULL:
+ class = G_VARIANT_CLASS_MAYBE;
+ break;
+ }
+
+ return class;
+ }
+ else
+ {
+ if ((*signature)[0] == G_VARIANT_CLASS_ARRAY &&
+ (*signature)[1] == G_VARIANT_CLASS_DICT_ENTRY)
+ return JSON_G_VARIANT_CLASS_DICTIONARY;
+ else
+ return (*signature)[0];
+ }
+}
+
+static gboolean
+json_node_assert_type (JsonNode *json_node,
+ JsonNodeType type,
+ GType sub_type,
+ GError **error)
+{
+ if (JSON_NODE_TYPE (json_node) != type ||
+ (type == JSON_NODE_VALUE &&
+ (json_node_get_value_type (json_node) != sub_type)))
+ {
+ /* translators: the '%s' is the type name */
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Unexpected type '%s' in JSON node"),
+ g_type_name (json_node_get_value_type (json_node)));
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+static void
+json_to_gvariant_foreach_add (gpointer data, gpointer user_data)
+{
+ GVariantBuilder *builder = (GVariantBuilder *) user_data;
+ GVariant *child = (GVariant *) data;
+
+ g_variant_builder_add_value (builder, child);
+}
+
+static void
+json_to_gvariant_foreach_free (gpointer data, gpointer user_data)
+{
+ GVariant *child = (GVariant *) data;
+
+ g_variant_unref (child);
+}
+
+static GVariant *
+json_to_gvariant_build_from_glist (GList *list, const gchar *signature)
+{
+ GVariantBuilder *builder;
+ GVariant *result;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE (signature));
+
+ g_list_foreach (list, json_to_gvariant_foreach_add, builder);
+ result = g_variant_builder_end (builder);
+
+ g_variant_builder_unref (builder);
+
+ return result;
+}
+
+static GVariant *
+json_to_gvariant_tuple (JsonNode *json_node,
+ const gchar **signature,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ JsonArray *array;
+ gint i;
+ GList *children = NULL;
+ gboolean roll_back = FALSE;
+ const gchar *initial_signature;
+
+ array = json_node_get_array (json_node);
+
+ initial_signature = *signature;
+ (*signature)++;
+ i = 1;
+ while ((*signature)[0] != ')' && (*signature)[0] != '\0')
+ {
+ JsonNode *json_child;
+ GVariant *variant_child;
+
+ if (i - 1 >= json_array_get_length (array))
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Missing elements in JSON array to conform to a tuple"));
+ roll_back = TRUE;
+ break;
+ }
+
+ json_child = json_array_get_element (array, i - 1);
+
+ variant_child = json_to_gvariant_recurse (json_child, signature, error);
+ if (variant_child != NULL)
+ {
+ children = g_list_append (children, variant_child);
+ }
+ else
+ {
+ roll_back = TRUE;
+ break;
+ }
+
+ i++;
+ }
+
+ if (! roll_back)
+ {
+ if ( (*signature)[0] != ')')
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Missing closing symbol ')' in the GVariant tuple type"));
+ roll_back = TRUE;
+ }
+ else if (json_array_get_length (array) >= i)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Unexpected extra elements in JSON array"));
+ roll_back = TRUE;
+ }
+ else
+ {
+ gchar *tuple_type;
+
+ tuple_type = g_strndup (initial_signature,
+ (*signature) - initial_signature + 1);
+
+ variant = json_to_gvariant_build_from_glist (children, tuple_type);
+
+ g_free (tuple_type);
+ }
+ }
+
+ if (roll_back)
+ g_list_foreach (children, json_to_gvariant_foreach_free, NULL);
+
+ g_list_free (children);
+
+ return variant;
+}
+
+static gchar *
+signature_get_next_complete_type (const gchar **signature)
+{
+ GVariantClass class;
+ const gchar *initial_signature;
+ gchar *result;
+
+ /* here it is assumed that 'signature' is a valid type string */
+
+ initial_signature = *signature;
+ class = (*signature)[0];
+
+ if (class == G_VARIANT_CLASS_TUPLE || class == G_VARIANT_CLASS_DICT_ENTRY)
+ {
+ gchar stack[256] = {0};
+ guint stack_len = 0;
+
+ do
+ {
+ if ( (*signature)[0] == G_VARIANT_CLASS_TUPLE)
+ {
+ stack[stack_len] = ')';
+ stack_len++;
+ }
+ else if ( (*signature)[0] == G_VARIANT_CLASS_DICT_ENTRY)
+ {
+ stack[stack_len] = '}';
+ stack_len++;
+ }
+
+ (*signature)++;
+
+ if ( (*signature)[0] == stack[stack_len - 1])
+ stack_len--;
+ }
+ while (stack_len > 0);
+
+ (*signature)++;
+ }
+ else if (class == G_VARIANT_CLASS_ARRAY || class == G_VARIANT_CLASS_MAYBE)
+ {
+ gchar *tmp_sig;
+
+ (*signature)++;
+ tmp_sig = signature_get_next_complete_type (signature);
+ g_free (tmp_sig);
+ }
+ else
+ {
+ (*signature)++;
+ }
+
+ result = g_strndup (initial_signature, (*signature) - initial_signature);
+
+ return result;
+}
+
+static GVariant *
+json_to_gvariant_maybe (JsonNode *json_node,
+ const gchar **signature,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ GVariant *value;
+ gchar *maybe_signature;
+
+ if (signature)
+ {
+ (*signature)++;
+ maybe_signature = signature_get_next_complete_type (signature);
+ }
+ else
+ {
+ maybe_signature = g_strdup ("v");
+ }
+
+ if (json_node_get_node_type (json_node) == JSON_NODE_NULL)
+ {
+ variant = g_variant_new_maybe (G_VARIANT_TYPE (maybe_signature), NULL);
+ }
+ else
+ {
+ const gchar *tmp_signature;
+
+ tmp_signature = maybe_signature;
+ value = json_to_gvariant_recurse (json_node,
+ &tmp_signature,
+ error);
+
+ if (value != NULL)
+ variant = g_variant_new_maybe (G_VARIANT_TYPE (maybe_signature), value);
+ }
+
+ g_free (maybe_signature);
+
+ /* compensate the (*signature)++ call at the end of 'recurse()' */
+ if (signature)
+ (*signature)--;
+
+ return variant;
+}
+
+static GVariant *
+json_to_gvariant_array (JsonNode *json_node,
+ const gchar **signature,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ JsonArray *array;
+ GList *children = NULL;
+ gboolean roll_back = FALSE;
+ const gchar *orig_signature;
+ gchar *child_signature;
+
+ array = json_node_get_array (json_node);
+
+ if (signature != NULL)
+ {
+ orig_signature = *signature;
+
+ (*signature)++;
+ child_signature = signature_get_next_complete_type (signature);
+ }
+ else
+ child_signature = g_strdup ("v");
+
+ if (json_array_get_length (array) > 0)
+ {
+ gint i;
+ guint len;
+
+ len = json_array_get_length (array);
+ for (i = 0; i < len; i++)
+ {
+ JsonNode *json_child;
+ GVariant *variant_child;
+ const gchar *tmp_signature;
+
+ json_child = json_array_get_element (array, i);
+
+ tmp_signature = child_signature;
+ variant_child = json_to_gvariant_recurse (json_child,
+ &tmp_signature,
+ error);
+ if (variant_child != NULL)
+ {
+ children = g_list_append (children, variant_child);
+ }
+ else
+ {
+ roll_back = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!roll_back)
+ {
+ gchar *array_signature;
+
+ if (signature)
+ array_signature = g_strndup (orig_signature, (*signature) - orig_signature);
+ else
+ array_signature = g_strdup ("av");
+
+ variant = json_to_gvariant_build_from_glist (children, array_signature);
+
+ g_free (array_signature);
+
+ /* compensate the (*signature)++ call at the end of 'recurse()' */
+ if (signature)
+ (*signature)--;
+ }
+ else
+ g_list_foreach (children, json_to_gvariant_foreach_free, NULL);
+
+ g_list_free (children);
+ g_free (child_signature);
+
+ return variant;
+}
+
+static GVariant *
+gvariant_simple_from_string (const gchar *st,
+ GVariantClass class,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ gchar *nptr = NULL;
+
+ errno = 0;
+
+ switch (class)
+ {
+ case G_VARIANT_CLASS_BOOLEAN:
+ if (g_strcmp0 (st, "true") == 0)
+ variant = g_variant_new_boolean (TRUE);
+ else if (g_strcmp0 (st, "false") == 0)
+ variant = g_variant_new_boolean (FALSE);
+ else
+ errno = 1;
+ break;
+
+ case G_VARIANT_CLASS_BYTE:
+ variant = g_variant_new_byte (g_ascii_strtoll (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_INT16:
+ variant = g_variant_new_int16 (g_ascii_strtoll (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_UINT16:
+ variant = g_variant_new_uint16 (g_ascii_strtoll (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_INT32:
+ variant = g_variant_new_int32 (g_ascii_strtoll (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_UINT32:
+ variant = g_variant_new_uint32 (g_ascii_strtoull (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_INT64:
+ variant = g_variant_new_int64 (g_ascii_strtoll (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_UINT64:
+ variant = g_variant_new_uint64 (g_ascii_strtoull (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_HANDLE:
+ variant = g_variant_new_handle (strtol (st, &nptr, 10));
+ break;
+
+ case G_VARIANT_CLASS_DOUBLE:
+ variant = g_variant_new_double (g_ascii_strtod (st, &nptr));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ case G_VARIANT_CLASS_OBJECT_PATH:
+ case G_VARIANT_CLASS_SIGNATURE:
+ variant = g_variant_new_string (st);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (errno != 0 || nptr == st)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Invalid string value converting to GVariant"));
+ if (variant != NULL)
+ {
+ g_variant_unref (variant);
+ variant = NULL;
+ }
+ }
+
+ return variant;
+}
+
+static void
+parse_dict_entry_signature (const gchar **signature,
+ gchar **entry_signature,
+ gchar **key_signature,
+ gchar **value_signature)
+{
+ const gchar *tmp_sig;
+
+ if (signature != NULL)
+ *entry_signature = signature_get_next_complete_type (signature);
+ else
+ *entry_signature = g_strdup ("{sv}");
+
+ tmp_sig = (*entry_signature) + 1;
+ *key_signature = signature_get_next_complete_type (&tmp_sig);
+ *value_signature = signature_get_next_complete_type (&tmp_sig);
+}
+
+static GVariant *
+json_to_gvariant_dict_entry (JsonNode *json_node,
+ const gchar **signature,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ JsonObject *obj;
+
+ gchar *entry_signature;
+ gchar *key_signature;
+ gchar *value_signature;
+ const gchar *tmp_signature;
+
+ GList *member;
+
+ const gchar *json_member;
+ JsonNode *json_value;
+ GVariant *variant_member;
+ GVariant *variant_value;
+
+ obj = json_node_get_object (json_node);
+
+ if (json_object_get_size (obj) != 1)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("A GVariant dictionary entry expects a JSON object with exactly one member"));
+ return NULL;
+ }
+
+ parse_dict_entry_signature (signature,
+ &entry_signature,
+ &key_signature,
+ &value_signature);
+
+ member = json_object_get_members (obj);
+
+ json_member = (const gchar *) member->data;
+ variant_member = gvariant_simple_from_string (json_member,
+ key_signature[0],
+ error);
+ if (variant_member != NULL)
+ {
+ json_value = json_object_get_member (obj, json_member);
+
+ tmp_signature = value_signature;
+ variant_value = json_to_gvariant_recurse (json_value,
+ &tmp_signature,
+ error);
+
+ if (variant_value != NULL)
+ {
+ GVariantBuilder *builder;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE (entry_signature));
+ g_variant_builder_add_value (builder, variant_member);
+ g_variant_builder_add_value (builder, variant_value);
+ variant = g_variant_builder_end (builder);
+
+ g_variant_builder_unref (builder);
+ }
+ }
+
+ g_list_free (member);
+ g_free (value_signature);
+ g_free (key_signature);
+ g_free (entry_signature);
+
+ /* compensate the (*signature)++ call at the end of 'recurse()' */
+ if (signature)
+ (*signature)--;
+
+ return variant;
+}
+
+static GVariant *
+json_to_gvariant_dictionary (JsonNode *json_node,
+ const gchar **signature,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ JsonObject *obj;
+ gboolean roll_back = FALSE;
+
+ gchar *dict_signature;
+ gchar *entry_signature;
+ gchar *key_signature;
+ gchar *value_signature;
+ const gchar *tmp_signature;
+
+ GVariantBuilder *builder;
+ GList *members;
+ GList *member;
+
+ obj = json_node_get_object (json_node);
+
+ if (signature != NULL)
+ (*signature)++;
+
+ parse_dict_entry_signature (signature,
+ &entry_signature,
+ &key_signature,
+ &value_signature);
+
+ dict_signature = g_strdup_printf ("a%s", entry_signature);
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE (dict_signature));
+
+ members = json_object_get_members (obj);
+
+ member = members;
+ while (member != NULL)
+ {
+ const gchar *json_member;
+ JsonNode *json_value;
+ GVariant *variant_member;
+ GVariant *variant_value;
+
+ json_member = (const gchar *) member->data;
+ variant_member = gvariant_simple_from_string (json_member,
+ key_signature[0],
+ error);
+ if (variant_member == NULL)
+ {
+ roll_back = TRUE;
+ break;
+ }
+
+ json_value = json_object_get_member (obj, json_member);
+
+ tmp_signature = value_signature;
+ variant_value = json_to_gvariant_recurse (json_value,
+ &tmp_signature,
+ error);
+
+ if (variant_value != NULL)
+ {
+ g_variant_builder_open (builder, G_VARIANT_TYPE (entry_signature));
+ g_variant_builder_add_value (builder, variant_member);
+ g_variant_builder_add_value (builder, variant_value);
+ g_variant_builder_close (builder);
+ }
+ else
+ {
+ roll_back = TRUE;
+ break;
+ }
+
+ member = member->next;
+ }
+
+ if (! roll_back)
+ variant = g_variant_builder_end (builder);
+
+ g_variant_builder_unref (builder);
+ g_list_free (members);
+ g_free (value_signature);
+ g_free (key_signature);
+ g_free (entry_signature);
+ g_free (dict_signature);
+
+ /* compensate the (*signature)++ call at the end of 'recurse()' */
+ if (signature != NULL)
+ (*signature)--;
+
+ return variant;
+}
+
+static GVariant *
+json_to_gvariant_recurse (JsonNode *json_node,
+ const gchar **signature,
+ GError **error)
+{
+ GVariant *variant = NULL;
+ GVariantClass class;
+
+ class = json_to_gvariant_get_next_class (json_node, signature);
+
+ if (class == JSON_G_VARIANT_CLASS_DICTIONARY)
+ {
+ if (json_node_assert_type (json_node, JSON_NODE_OBJECT, 0, error))
+ variant = json_to_gvariant_dictionary (json_node, signature, error);
+
+ goto out;
+ }
+
+ switch (class)
+ {
+ case G_VARIANT_CLASS_BOOLEAN:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_BOOLEAN, error))
+ variant = g_variant_new_boolean (json_node_get_boolean (json_node));
+ break;
+
+ case G_VARIANT_CLASS_BYTE:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_byte (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_INT16:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_int16 (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_UINT16:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_uint16 (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_INT32:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_int32 (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_UINT32:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_uint32 (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_INT64:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_int64 (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_UINT64:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_uint64 (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_HANDLE:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_INT64, error))
+ variant = g_variant_new_handle (json_node_get_int (json_node));
+ break;
+
+ case G_VARIANT_CLASS_DOUBLE:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_DOUBLE, error))
+ variant = g_variant_new_double (json_node_get_double (json_node));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_STRING, error))
+ variant = g_variant_new_string (json_node_get_string (json_node));
+ break;
+
+ case G_VARIANT_CLASS_OBJECT_PATH:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_STRING, error))
+ variant = g_variant_new_object_path (json_node_get_string (json_node));
+ break;
+
+ case G_VARIANT_CLASS_SIGNATURE:
+ if (json_node_assert_type (json_node, JSON_NODE_VALUE, G_TYPE_STRING, error))
+ variant = g_variant_new_signature (json_node_get_string (json_node));
+ break;
+
+ case G_VARIANT_CLASS_VARIANT:
+ variant = g_variant_new_variant (json_to_gvariant_recurse (json_node,
+ NULL,
+ error));
+ break;
+
+ case G_VARIANT_CLASS_MAYBE:
+ variant = json_to_gvariant_maybe (json_node, signature, error);
+ break;
+
+ case G_VARIANT_CLASS_ARRAY:
+ if (json_node_assert_type (json_node, JSON_NODE_ARRAY, 0, error))
+ variant = json_to_gvariant_array (json_node, signature, error);
+ break;
+
+ case G_VARIANT_CLASS_TUPLE:
+ if (json_node_assert_type (json_node, JSON_NODE_ARRAY, 0, error))
+ variant = json_to_gvariant_tuple (json_node, signature, error);
+ break;
+
+ case G_VARIANT_CLASS_DICT_ENTRY:
+ if (json_node_assert_type (json_node, JSON_NODE_OBJECT, 0, error))
+ variant = json_to_gvariant_dict_entry (json_node, signature, error);
+ break;
+
+ default:
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("GVariant class '%c' not supported"), class);
+ break;
+ }
+
+out:
+ if (signature)
+ (*signature)++;
+
+ return variant;
+}
+
+/**
+ * json_gvariant_deserialize:
+ * @json_node: A #JsonNode to convert
+ * @signature: (allow-none): A valid #GVariant type string, or %NULL
+ * @error: A pointer to a #GError
+ *
+ * Converts a JSON data structure to a GVariant value using @signature to
+ * resolve ambiguous data types. If no error occurs, the resulting #GVariant
+ * is guaranteed to conform to @signature.
+ *
+ * If @signature is not %NULL but does not represent a valid GVariant type
+ * string, %NULL is returned and error is set to %G_IO_ERROR_INVALID_ARGUMENT.
+ * If a @signature is provided but the JSON structure cannot be mapped to it,
+ * %NULL is returned and error is set to %G_IO_ERROR_INVALID_DATA.
+ * If @signature is %NULL, the conversion is done based strictly on the types
+ * in the JSON nodes.
+ *
+ * Return value: (transfer full): A newly created #GVariant compliant with
+ * @signature, or %NULL on error
+ *
+ * Since: 0.14
+ */
+GVariant *
+json_gvariant_deserialize (JsonNode *json_node,
+ const gchar *signature,
+ GError **error)
+{
+ g_return_val_if_fail (json_node != NULL, NULL);
+
+ if (signature != NULL && ! g_variant_type_string_is_valid (signature))
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Invalid GVariant signature"));
+ return NULL;
+ }
+
+ return json_to_gvariant_recurse (json_node, signature ? &signature : NULL, error);
+}
+
+/**
+ * json_gvariant_deserialize_data:
+ * @json: A JSON data string
+ * @length: The length of @json, or -1 if %NULL-terminated
+ * @signature: (allow-none): A valid #GVariant type string, or %NULL
+ * @error: A pointer to a #GError
+ *
+ * Converts a JSON string to a #GVariant value. This method works exactly
+ * like json_gvariant_deserialize(), but takes a JSON encoded string instead.
+ * The string is first converted to a #JsonNode using #JsonParser, and then
+ * json_gvariant_deserialize() is called.
+ *
+ * Returns: (transfer full): A newly created #GVariant compliant with
+ * @signature, or %NULL on error
+ *
+ * Since: 0.14
+ */
+GVariant *
+json_gvariant_deserialize_data (const gchar *json,
+ gssize length,
+ const gchar *signature,
+ GError **error)
+{
+ JsonParser *parser;
+ GVariant *variant = NULL;
+ JsonNode *root;
+
+ parser = json_parser_new ();
+
+ if (! json_parser_load_from_data (parser, json, length, error))
+ return NULL;
+
+ root = json_parser_get_root (parser);
+ if (root == NULL)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("JSON data is empty"));
+ }
+ else
+ {
+ variant =
+ json_gvariant_deserialize (json_parser_get_root (parser), signature, error);
+ }
+
+ g_object_unref (parser);
+
+ return variant;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-gvariant.h b/src/glib-jsonrpc/json-glib/json-gvariant.h
new file mode 100644
index 0000000..6644b21
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-gvariant.h
@@ -0,0 +1,46 @@
+/* json-gvariant.h - JSON GVariant integration
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Eduardo Lima Mitev <elima igalia com>
+ */
+
+#ifndef __JSON_GVARIANT_H__
+#define __JSON_GVARIANT_H__
+
+#include <glib.h>
+#include <json-glib/json-glib.h>
+
+G_BEGIN_DECLS
+
+JsonNode * json_gvariant_serialize (GVariant *variant);
+gchar * json_gvariant_serialize_data (GVariant *variant,
+ gsize *length);
+
+GVariant * json_gvariant_deserialize (JsonNode *json_node,
+ const gchar *signature,
+ GError **error);
+GVariant * json_gvariant_deserialize_data (const gchar *json,
+ gssize length,
+ const gchar *signature,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __JSON_GVARIANT_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-marshal.c b/src/glib-jsonrpc/json-glib/json-marshal.c
new file mode 100644
index 0000000..dae8b56
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-marshal.c
@@ -0,0 +1,132 @@
+#include "json-marshal.h"
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:VOID (./json-marshal.list:1) */
+
+/* VOID:BOXED (./json-marshal.list:2) */
+
+/* VOID:BOXED,STRING (./json-marshal.list:3) */
+void
+_json_marshal_VOID__BOXED_STRING (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__BOXED_STRING) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__BOXED_STRING callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__BOXED_STRING) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ g_marshal_value_peek_string (param_values + 2),
+ data2);
+}
+
+/* VOID:BOXED,INT (./json-marshal.list:4) */
+void
+_json_marshal_VOID__BOXED_INT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__BOXED_INT) (gpointer data1,
+ gpointer arg_1,
+ gint arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__BOXED_INT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__BOXED_INT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ g_marshal_value_peek_int (param_values + 2),
+ data2);
+}
+
+/* VOID:POINTER (./json-marshal.list:5) */
+
diff --git a/src/glib-jsonrpc/json-glib/json-marshal.h b/src/glib-jsonrpc/json-glib/json-marshal.h
new file mode 100644
index 0000000..f4f7658
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-marshal.h
@@ -0,0 +1,37 @@
+
+#ifndef ___json_marshal_MARSHAL_H__
+#define ___json_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:VOID (./json-marshal.list:1) */
+#define _json_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
+
+/* VOID:BOXED (./json-marshal.list:2) */
+#define _json_marshal_VOID__BOXED g_cclosure_marshal_VOID__BOXED
+
+/* VOID:BOXED,STRING (./json-marshal.list:3) */
+extern void _json_marshal_VOID__BOXED_STRING (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:BOXED,INT (./json-marshal.list:4) */
+extern void _json_marshal_VOID__BOXED_INT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:POINTER (./json-marshal.list:5) */
+#define _json_marshal_VOID__POINTER g_cclosure_marshal_VOID__POINTER
+
+G_END_DECLS
+
+#endif /* ___json_marshal_MARSHAL_H__ */
+
diff --git a/src/glib-jsonrpc/json-glib/json-node.c b/src/glib-jsonrpc/json-glib/json-node.c
new file mode 100644
index 0000000..67cdc95
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-node.c
@@ -0,0 +1,800 @@
+/* json-node.c - JSON object model node
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "json-types-private.h"
+
+/**
+ * SECTION:json-node
+ * @short_description: Node in a JSON object model
+ *
+ * A #JsonNode is a generic container of elements inside a JSON stream.
+ * It can contain fundamental types (integers, booleans, floating point
+ * numbers, strings) and complex types (arrays and objects).
+ *
+ * When parsing a JSON data stream you extract the root node and walk
+ * the node tree by retrieving the type of data contained inside the
+ * node with the %JSON_NODE_TYPE macro. If the node contains a fundamental
+ * type you can retrieve a copy of the #GValue holding it with the
+ * json_node_get_value() function, and then use the #GValue API to extract
+ * the data; if the node contains a complex type you can retrieve the
+ * #JsonObject or the #JsonArray using json_node_get_object() or
+ * json_node_get_array() respectively, and then retrieve the nodes
+ * they contain.
+ */
+
+G_DEFINE_BOXED_TYPE (JsonNode, json_node, json_node_copy, json_node_free);
+
+/**
+ * json_node_get_value_type:
+ * @node: a #JsonNode
+ *
+ * Returns the #GType of the payload of the node.
+ *
+ * Return value: a #GType for the payload.
+ *
+ * Since: 0.4
+ */
+GType
+json_node_get_value_type (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, G_TYPE_INVALID);
+
+ switch (node->type)
+ {
+ case JSON_NODE_OBJECT:
+ return JSON_TYPE_OBJECT;
+
+ case JSON_NODE_ARRAY:
+ return JSON_TYPE_ARRAY;
+
+ case JSON_NODE_NULL:
+ return G_TYPE_INVALID;
+
+ case JSON_NODE_VALUE:
+ return G_VALUE_TYPE (&(node->data.value));
+
+ default:
+ g_assert_not_reached ();
+ return G_TYPE_INVALID;
+ }
+}
+
+/**
+ * json_node_new:
+ * @type: a #JsonNodeType
+ *
+ * Creates a new #JsonNode of @type.
+ *
+ * Return value: the newly created #JsonNode
+ */
+JsonNode *
+json_node_new (JsonNodeType type)
+{
+ JsonNode *data;
+
+ g_return_val_if_fail (type >= JSON_NODE_OBJECT &&
+ type <= JSON_NODE_NULL, NULL);
+
+ data = g_slice_new0 (JsonNode);
+ data->type = type;
+
+ return data;
+}
+
+/**
+ * json_node_copy:
+ * @node: a #JsonNode
+ *
+ * Copies @node. If the node contains complex data types then the reference
+ * count of the objects is increased.
+ *
+ * Return value: (transfer full): the copied #JsonNode
+ */
+JsonNode *
+json_node_copy (JsonNode *node)
+{
+ JsonNode *copy;
+
+ g_return_val_if_fail (node != NULL, NULL);
+
+ copy = g_slice_new0 (JsonNode);
+ copy->type = node->type;
+
+ switch (copy->type)
+ {
+ case JSON_NODE_OBJECT:
+ if (node->data.object)
+ copy->data.object = json_object_ref (node->data.object);
+ break;
+
+ case JSON_NODE_ARRAY:
+ if (node->data.array)
+ copy->data.array = json_array_ref (node->data.array);
+ break;
+
+ case JSON_NODE_VALUE:
+ if (G_VALUE_TYPE (&(node->data.value)) != G_TYPE_INVALID)
+ {
+ g_value_init (&(copy->data.value), G_VALUE_TYPE (&(node->data.value)));
+ g_value_copy (&(node->data.value), &(copy->data.value));
+ }
+ break;
+
+ case JSON_NODE_NULL:
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return copy;
+}
+
+/**
+ * json_node_set_object:
+ * @node: a #JsonNode
+ * @object: a #JsonObject
+ *
+ * Sets @objects inside @node. The reference count of @object is increased.
+ */
+void
+json_node_set_object (JsonNode *node,
+ JsonObject *object)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT);
+
+ if (node->data.object)
+ json_object_unref (node->data.object);
+
+ if (object)
+ node->data.object = json_object_ref (object);
+ else
+ node->data.object = NULL;
+}
+
+/**
+ * json_node_take_object:
+ * @node: a #JsonNode
+ * @object: (transfer full): a #JsonObject
+ *
+ * Sets @object inside @node. The reference count of @object is not increased.
+ */
+void
+json_node_take_object (JsonNode *node,
+ JsonObject *object)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT);
+
+ if (node->data.object)
+ {
+ json_object_unref (node->data.object);
+ node->data.object = NULL;
+ }
+
+ if (object)
+ node->data.object = object;
+}
+
+/**
+ * json_node_get_object:
+ * @node: a #JsonNode
+ *
+ * Retrieves the #JsonObject stored inside a #JsonNode
+ *
+ * Return value: (transfer none): the #JsonObject
+ */
+JsonObject *
+json_node_get_object (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL);
+
+ return node->data.object;
+}
+
+/**
+ * json_node_dup_object:
+ * @node: a #JsonNode
+ *
+ * Retrieves the #JsonObject inside @node. The reference count of
+ * the returned object is increased.
+ *
+ * Return value: (transfer full): the #JsonObject
+ */
+JsonObject *
+json_node_dup_object (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT, NULL);
+
+ if (node->data.object)
+ return json_object_ref (node->data.object);
+
+ return NULL;
+}
+
+/**
+ * json_node_set_array:
+ * @node: a #JsonNode
+ * @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;
+}
+
+/**
+ * json_node_take_array:
+ * @node: a #JsonNode
+ * @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;
+}
+
+/**
+ * json_node_get_array:
+ * @node: a #JsonNode
+ *
+ * Retrieves the #JsonArray stored inside a #JsonNode
+ *
+ * Return value: (transfer none): the #JsonArray
+ */
+JsonArray *
+json_node_get_array (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY, NULL);
+
+ return node->data.array;
+}
+
+/**
+ * json_node_dup_array
+ * @node: a #JsonNode
+ *
+ * Retrieves the #JsonArray stored inside a #JsonNode and returns it
+ * with its reference count increased by one.
+ *
+ * Return value: (transfer full): the #JsonArray with its reference
+ * count increased.
+ */
+JsonArray *
+json_node_dup_array (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY, NULL);
+
+ if (node->data.array)
+ return json_array_ref (node->data.array);
+
+ return NULL;
+}
+
+/**
+ * json_node_get_value:
+ * @node: a #JsonNode
+ * @value: (out caller-allocates): return location for an uninitialized value
+ *
+ * Retrieves a value from a #JsonNode and copies into @value. When done
+ * using it, call g_value_unset() on the #GValue.
+ */
+void
+json_node_get_value (JsonNode *node,
+ GValue *value)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
+
+ if (G_VALUE_TYPE (&(node->data.value)) != G_TYPE_INVALID)
+ {
+ g_value_init (value, G_VALUE_TYPE (&(node->data.value)));
+ g_value_copy (&(node->data.value), value);
+ }
+}
+
+static void inline
+node_value_unset (JsonNode *node)
+{
+ if (G_VALUE_TYPE (&(node->data.value)) != G_TYPE_INVALID)
+ g_value_unset (&(node->data.value));
+}
+
+/**
+ * json_node_set_value:
+ * @node: a #JsonNode
+ * @value: the #GValue to set
+ *
+ * Sets @value inside @node. The passed #GValue is copied into the #JsonNode
+ */
+void
+json_node_set_value (JsonNode *node,
+ const GValue *value)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
+ g_return_if_fail (G_VALUE_TYPE (value) != G_TYPE_INVALID);
+
+ switch (G_VALUE_TYPE (value))
+ {
+ /* direct copy for the types we use */
+ case G_TYPE_INT64:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_DOUBLE:
+ case G_TYPE_STRING:
+ node_value_unset (node);
+ g_value_init (&(node->data.value), G_VALUE_TYPE (value));
+ g_value_copy (value, &(node->data.value));
+ break;
+
+ /* auto-promote ints to long longs */
+ case G_TYPE_INT:
+ node_value_unset (node);
+ g_value_init (&(node->data.value), G_TYPE_INT64);
+ g_value_set_int64 (&(node->data.value),
+ g_value_get_int (value));
+ break;
+
+ /* auto-promote single precision to double precision */
+ case G_TYPE_FLOAT:
+ node_value_unset (node);
+ g_value_init (&(node->data.value), G_TYPE_DOUBLE);
+ g_value_set_double (&(node->data.value),
+ g_value_get_float (value));
+ break;
+
+ default:
+ g_warning ("Invalid value of type '%s'",
+ g_type_name (G_VALUE_TYPE (value)));
+ return;
+ }
+
+}
+
+/**
+ * json_node_free:
+ * @node: a #JsonNode
+ *
+ * Frees the resources allocated by @node.
+ */
+void
+json_node_free (JsonNode *node)
+{
+ if (G_LIKELY (node))
+ {
+ 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:
+ g_value_unset (&(node->data.value));
+ break;
+
+ case JSON_NODE_NULL:
+ break;
+ }
+
+ g_slice_free (JsonNode, node);
+ }
+}
+
+/**
+ * json_node_type_name:
+ * @node: a #JsonNode
+ *
+ * Retrieves the user readable name of the data type contained by @node.
+ *
+ * Return value: a string containing the name of the type. The returned string
+ * is owned by the node and should never be modified or freed
+ */
+const gchar *
+json_node_type_name (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, "(null)");
+
+ switch (node->type)
+ {
+ case JSON_NODE_OBJECT:
+ case JSON_NODE_ARRAY:
+ case JSON_NODE_NULL:
+ return json_node_type_get_name (node->type);
+
+ case JSON_NODE_VALUE:
+ return g_type_name (G_VALUE_TYPE (&(node->data.value)));
+ }
+
+ return "unknown";
+}
+
+const gchar *
+json_node_type_get_name (JsonNodeType node_type)
+{
+ switch (node_type)
+ {
+ case JSON_NODE_OBJECT:
+ return "JsonObject";
+
+ case JSON_NODE_ARRAY:
+ return "JsonArray";
+
+ case JSON_NODE_NULL:
+ return "NULL";
+
+ case JSON_NODE_VALUE:
+ return "Value";
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return "unknown";
+}
+
+/**
+ * json_node_set_parent:
+ * @node: a #JsonNode
+ * @parent: (transfer none): the parent #JsonNode of @node
+ *
+ * Sets the parent #JsonNode of @node
+ *
+ * Since: 0.8
+ */
+void
+json_node_set_parent (JsonNode *node,
+ JsonNode *parent)
+{
+ g_return_if_fail (node != NULL);
+
+ node->parent = parent;
+}
+
+/**
+ * json_node_get_parent:
+ * @node: a #JsonNode
+ *
+ * Retrieves the parent #JsonNode of @node.
+ *
+ * Return value: (transfer none): the parent node, or %NULL if @node is
+ * the root node
+ */
+JsonNode *
+json_node_get_parent (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ return node->parent;
+}
+
+/**
+ * json_node_set_string:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ * @value: a string value
+ *
+ * Sets @value as the string content of the @node, replacing any existing
+ * content.
+ */
+void
+json_node_set_string (JsonNode *node,
+ const gchar *value)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_STRING)
+ g_value_set_string (&(node->data.value), value);
+ else
+ {
+ GValue copy = { 0, };
+
+ g_value_init (©, G_TYPE_STRING);
+ g_value_set_string (©, value);
+
+ json_node_set_value (node, ©);
+
+ g_value_unset (©);
+ }
+}
+
+/**
+ * json_node_get_string:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ *
+ * Gets the string value stored inside a #JsonNode
+ *
+ * Return value: a string value.
+ */
+const gchar *
+json_node_get_string (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
+ return NULL;
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_STRING)
+ return g_value_get_string (&(node->data.value));
+
+ return NULL;
+}
+
+/**
+ * json_node_dup_string:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ *
+ * Gets a copy of the string value stored inside a #JsonNode
+ *
+ * Return value: (transfer full): a newly allocated string containing a copy
+ * of the #JsonNode contents. Use g_free() to free the allocated resources
+ */
+gchar *
+json_node_dup_string (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+
+ if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
+ return NULL;
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_STRING)
+ return g_value_dup_string (&(node->data.value));
+
+ return NULL;
+}
+
+/**
+ * json_node_set_int:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ * @value: an integer value
+ *
+ * Sets @value as the integer content of the @node, replacing any existing
+ * content.
+ */
+void
+json_node_set_int (JsonNode *node,
+ gint64 value)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_INT64)
+ g_value_set_int64 (&(node->data.value), value);
+ else
+ {
+ GValue copy = { 0, };
+
+ g_value_init (©, G_TYPE_INT64);
+ g_value_set_int64 (©, value);
+
+ json_node_set_value (node, ©);
+
+ g_value_unset (©);
+ }
+}
+
+/**
+ * json_node_get_int:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ *
+ * Gets the integer value stored inside a #JsonNode
+ *
+ * Return value: an integer value.
+ */
+gint64
+json_node_get_int (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, 0);
+
+ if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
+ return 0;
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_INT64)
+ return g_value_get_int64 (&(node->data.value));
+
+ return 0;
+}
+
+/**
+ * json_node_set_double:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ * @value: a double value
+ *
+ * Sets @value as the double content of the @node, replacing any existing
+ * content.
+ */
+void
+json_node_set_double (JsonNode *node,
+ gdouble value)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_DOUBLE)
+ g_value_set_double (&(node->data.value), value);
+ else
+ {
+ GValue copy = { 0, };
+
+ g_value_init (©, G_TYPE_DOUBLE);
+ g_value_set_double (©, value);
+
+ json_node_set_value (node, ©);
+
+ g_value_unset (©);
+ }
+}
+
+/**
+ * json_node_get_double:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ *
+ * Gets the double value stored inside a #JsonNode
+ *
+ * Return value: a double value.
+ */
+gdouble
+json_node_get_double (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, 0.0);
+
+ if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
+ return 0;
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_DOUBLE)
+ return g_value_get_double (&(node->data.value));
+
+ return 0.0;
+}
+
+/**
+ * json_node_set_boolean:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ * @value: a boolean value
+ *
+ * Sets @value as the boolean content of the @node, replacing any existing
+ * content.
+ */
+void
+json_node_set_boolean (JsonNode *node,
+ gboolean value)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE);
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_BOOLEAN)
+ g_value_set_boolean (&(node->data.value), value);
+ else
+ {
+ GValue copy = { 0, };
+
+ g_value_init (©, G_TYPE_BOOLEAN);
+ g_value_set_boolean (©, value);
+
+ json_node_set_value (node, ©);
+
+ g_value_unset (©);
+ }
+}
+
+/**
+ * json_node_get_boolean:
+ * @node: a #JsonNode of type %JSON_NODE_VALUE
+ *
+ * Gets the boolean value stored inside a #JsonNode
+ *
+ * Return value: a boolean value.
+ */
+gboolean
+json_node_get_boolean (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ if (JSON_NODE_TYPE (node) == JSON_NODE_NULL)
+ return FALSE;
+
+ if (G_VALUE_TYPE (&(node->data.value)) == G_TYPE_BOOLEAN)
+ return g_value_get_boolean (&(node->data.value));
+
+ return FALSE;
+}
+
+/**
+ * json_node_get_node_type:
+ * @node: a #JsonNode
+ *
+ * Retrieves the #JsonNodeType of @node
+ *
+ * Return value: the type of the node
+ *
+ * Since: 0.8
+ */
+JsonNodeType
+json_node_get_node_type (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, JSON_NODE_NULL);
+
+ return node->type;
+}
+
+/**
+ * json_node_is_null:
+ * @node: a #JsonNode
+ *
+ * Checks whether @node is a %JSON_NODE_NULL
+ *
+ * <note>A null node is not the same as a %NULL #JsonNode</note>
+ *
+ * Return value: %TRUE if the node is null
+ *
+ * Since: 0.8
+ */
+gboolean
+json_node_is_null (JsonNode *node)
+{
+ g_return_val_if_fail (node != NULL, TRUE);
+
+ return node->type == JSON_NODE_NULL;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-object.c b/src/glib-jsonrpc/json-glib/json-object.c
new file mode 100644
index 0000000..9c6d585
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-object.c
@@ -0,0 +1,856 @@
+/* json-object.c - JSON object implementation
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "json-types-private.h"
+
+/**
+ * SECTION:json-object
+ * @short_description: a JSON object representation
+ *
+ * #JsonArray is the representation of the object type inside JSON. It contains
+ * #JsonNode<!-- -->s, which may contain fundamental types, arrays or other
+ * objects. Each member of an object is accessed using its name.
+ *
+ * Since objects can be expensive, they are reference counted. You can control
+ * the lifetime of a #JsonObject using json_object_ref() and json_object_unref().
+ *
+ * To add or overwrite a member with a given name, use json_object_set_member().
+ * To extract a member with a given name, use json_object_get_member().
+ * To retrieve the list of members, use json_object_get_members().
+ * To retrieve the size of the object (that is, the number of members it has),
+ * use json_object_get_size().
+ */
+
+G_DEFINE_BOXED_TYPE (JsonObject, json_object, json_object_ref, json_object_unref);
+
+/**
+ * json_object_new:
+ *
+ * Creates a new #JsonObject, an JSON object type representation.
+ *
+ * Return value: the newly created #JsonObject
+ */
+JsonObject *
+json_object_new (void)
+{
+ JsonObject *object;
+
+ object = g_slice_new (JsonObject);
+
+ object->ref_count = 1;
+ object->members = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free,
+ (GDestroyNotify) json_node_free);
+ object->members_ordered = NULL;
+
+ return object;
+}
+
+/**
+ * json_object_ref:
+ * @object: a #JsonObject
+ *
+ * Increase by one the reference count of a #JsonObject.
+ *
+ * Return value: the passed #JsonObject, with the reference count
+ * increased by one.
+ */
+JsonObject *
+json_object_ref (JsonObject *object)
+{
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (object->ref_count > 0, NULL);
+
+ g_atomic_int_add (&object->ref_count, 1);
+
+ return object;
+}
+
+/**
+ * json_object_unref:
+ * @object: a #JsonObject
+ *
+ * Decreases by one the reference count of a #JsonObject. If the
+ * reference count reaches zero, the object is destroyed and all
+ * its allocated resources are freed.
+ */
+void
+json_object_unref (JsonObject *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (object->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&object->ref_count))
+ {
+ g_list_free (object->members_ordered);
+ g_hash_table_destroy (object->members);
+ object->members_ordered = NULL;
+ object->members = NULL;
+
+ g_slice_free (JsonObject, object);
+ }
+}
+
+static inline void
+object_set_member_internal (JsonObject *object,
+ const gchar *member_name,
+ JsonNode *node)
+{
+ gchar *name = g_strdup (member_name);
+
+ if (g_hash_table_lookup (object->members, name) == NULL)
+ object->members_ordered = g_list_prepend (object->members_ordered, name);
+ else
+ {
+ GList *l;
+
+ /* if the member already exists then we need to replace the
+ * pointer to its name, to avoid keeping invalid pointers
+ * once we replace the key in the hash table
+ */
+ l = g_list_find_custom (object->members_ordered, name, (GCompareFunc) strcmp);
+ if (l != NULL)
+ l->data = name;
+ }
+
+ g_hash_table_replace (object->members, name, node);
+}
+
+/**
+ * json_object_add_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @node: (transfer full): the value of the member
+ *
+ * Adds a member named @member_name and containing @node into a #JsonObject.
+ * The object will take ownership of the #JsonNode.
+ *
+ * This function will return if the @object already contains a member
+ * @member_name.
+ *
+ * Deprecated: 0.8: Use json_object_set_member() instead
+ */
+void
+json_object_add_member (JsonObject *object,
+ const gchar *member_name,
+ JsonNode *node)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+ g_return_if_fail (node != NULL);
+
+ if (json_object_has_member (object, member_name))
+ {
+ g_warning ("JsonObject already has a `%s' member of type `%s'",
+ member_name,
+ json_node_type_name (node));
+ return;
+ }
+
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @node: (transfer full): the value of the member
+ *
+ * Sets @node as the value of @member_name inside @object.
+ *
+ * If @object already contains a member called @member_name then
+ * the member's current value is overwritten. Otherwise, a new
+ * member is added to @object.
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_member (JsonObject *object,
+ const gchar *member_name,
+ JsonNode *node)
+{
+ JsonNode *old_node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+ g_return_if_fail (node != NULL);
+
+ old_node = g_hash_table_lookup (object->members, member_name);
+ if (old_node == NULL)
+ goto set_member;
+
+ if (old_node == node)
+ return;
+
+set_member:
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_int_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @value: the value of the member
+ *
+ * Convenience function for setting an integer @value of
+ * @member_name inside @object.
+ *
+ * See also: json_object_set_member()
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_int_member (JsonObject *object,
+ const gchar *member_name,
+ gint64 value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (node, value);
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_double_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @value: the value of the member
+ *
+ * Convenience function for setting a floating point @value
+ * of @member_name inside @object.
+ *
+ * See also: json_object_set_member()
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_double_member (JsonObject *object,
+ const gchar *member_name,
+ gdouble value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_double (node, value);
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_boolean_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @value: the value of the member
+ *
+ * Convenience function for setting a boolean @value of
+ * @member_name inside @object.
+ *
+ * See also: json_object_set_member()
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_boolean_member (JsonObject *object,
+ const gchar *member_name,
+ gboolean value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_boolean (node, value);
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_string_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @value: the value of the member
+ *
+ * Convenience function for setting a string @value of
+ * @member_name inside @object.
+ *
+ * See also: json_object_set_member()
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_string_member (JsonObject *object,
+ const gchar *member_name,
+ const gchar *value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ if (value != NULL)
+ {
+ node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_string (node, value);
+ }
+ else
+ node = json_node_new (JSON_NODE_NULL);
+
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_null_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function for setting a null @value of
+ * @member_name inside @object.
+ *
+ * See also: json_object_set_member()
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_null_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ node = json_node_new (JSON_NODE_NULL);
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * 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);
+
+ if (value != NULL)
+ {
+ node = json_node_new (JSON_NODE_ARRAY);
+ json_node_take_array (node, value);
+ }
+ else
+ node = json_node_new (JSON_NODE_NULL);
+
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_set_object_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ * @value: (transfer full): the value of the member
+ *
+ * Convenience function for setting an object @value of
+ * @member_name inside @object.
+ *
+ * The @object will take ownership of the passed #JsonObject
+ *
+ * See also: json_object_set_member()
+ *
+ * Since: 0.8
+ */
+void
+json_object_set_object_member (JsonObject *object,
+ const gchar *member_name,
+ JsonObject *value)
+{
+ JsonNode *node;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ if (value != NULL)
+ {
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (node, value);
+ }
+ else
+ node = json_node_new (JSON_NODE_NULL);
+
+ object_set_member_internal (object, member_name, node);
+}
+
+/**
+ * json_object_get_members:
+ * @object: a #JsonObject
+ *
+ * Retrieves all the names of the members of a #JsonObject. You can
+ * obtain the value for each member using json_object_get_member().
+ *
+ * Return value: (element-type utf8) (transfer container): a #GList
+ * of member names. The content of the list is owned by the #JsonObject
+ * and should never be modified or freed. When you have finished using
+ * the returned list, use g_list_free() to free the resources it has
+ * allocated.
+ */
+GList *
+json_object_get_members (JsonObject *object)
+{
+ GList *copy;
+
+ g_return_val_if_fail (object != NULL, NULL);
+
+ copy = g_list_copy (object->members_ordered);
+
+ return g_list_reverse (copy);
+}
+
+/**
+ * json_object_get_values:
+ * @object: a #JsonObject
+ *
+ * Retrieves all the values of the members of a #JsonObject.
+ *
+ * Return value: (element-type JsonNode) (transfer container): a #GList of
+ * #JsonNode<!-- -->s. The content of the list is owned by the #JsonObject
+ * and should never be modified or freed. When you have finished using the
+ * returned list, use g_list_free() to free the resources it has allocated.
+ */
+GList *
+json_object_get_values (JsonObject *object)
+{
+ GList *values, *l;
+
+ g_return_val_if_fail (object != NULL, NULL);
+
+ values = NULL;
+ for (l = object->members_ordered; l != NULL; l = l->next)
+ values = g_list_prepend (values, g_hash_table_lookup (object->members, l->data));
+
+ return values;
+}
+
+/**
+ * json_object_dup_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the JSON object member to access
+ *
+ * Retrieves a copy of the #JsonNode containing the value of @member_name
+ * inside a #JsonObject
+ *
+ * Return value: (transfer full): a copy of the node for the requested
+ * object member or %NULL. Use json_node_free() when done.
+ *
+ * Since: 0.6
+ */
+JsonNode *
+json_object_dup_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *retval;
+
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (member_name != NULL, NULL);
+
+ retval = json_object_get_member (object, member_name);
+ if (!retval)
+ return NULL;
+
+ return json_node_copy (retval);
+}
+
+static inline JsonNode *
+object_get_member_internal (JsonObject *object,
+ const gchar *member_name)
+{
+ return g_hash_table_lookup (object->members, member_name);
+}
+
+/**
+ * json_object_get_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the JSON object member to access
+ *
+ * Retrieves the #JsonNode containing the value of @member_name inside
+ * a #JsonObject.
+ *
+ * Return value: (transfer none): a pointer to the node for the requested object
+ * member, or %NULL
+ */
+JsonNode *
+json_object_get_member (JsonObject *object,
+ const gchar *member_name)
+{
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (member_name != NULL, NULL);
+
+ return object_get_member_internal (object, member_name);
+}
+
+/**
+ * json_object_get_int_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the integer value
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: the integer value of the object's member
+ *
+ * Since: 0.8
+ */
+gint64
+json_object_get_int_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, 0);
+ g_return_val_if_fail (member_name != NULL, 0);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, 0);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0);
+
+ return json_node_get_int (node);
+}
+
+/**
+ * json_object_get_double_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the floating point value
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: the floating point value of the object's member
+ *
+ * Since: 0.8
+ */
+gdouble
+json_object_get_double_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, 0.0);
+ g_return_val_if_fail (member_name != NULL, 0.0);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, 0.0);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, 0.0);
+
+ return json_node_get_double (node);
+}
+
+/**
+ * json_object_get_boolean_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the boolean value
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: the boolean value of the object's member
+ *
+ * Since: 0.8
+ */
+gboolean
+json_object_get_boolean_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, FALSE);
+ g_return_val_if_fail (member_name != NULL, FALSE);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, FALSE);
+
+ return json_node_get_boolean (node);
+}
+
+/**
+ * json_object_get_null_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that checks whether the value
+ * stored in @member_name of @object is null
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: %TRUE if the value is null
+ *
+ * Since: 0.8
+ */
+gboolean
+json_object_get_null_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, FALSE);
+ g_return_val_if_fail (member_name != NULL, FALSE);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ return JSON_NODE_TYPE (node) == JSON_NODE_NULL;
+}
+
+/**
+ * json_object_get_string_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the string value
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: the string value of the object's member
+ *
+ * Since: 0.8
+ */
+const gchar *
+json_object_get_string_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (member_name != NULL, NULL);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_HOLDS_VALUE (node) || JSON_NODE_HOLDS_NULL (node), NULL);
+
+ if (JSON_NODE_HOLDS_NULL (node))
+ return NULL;
+
+ return json_node_get_string (node);
+}
+
+/**
+ * json_object_get_array_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the array
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: (transfer none): the array inside the object's member
+ *
+ * Since: 0.8
+ */
+JsonArray *
+json_object_get_array_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (member_name != NULL, NULL);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (node) || JSON_NODE_HOLDS_NULL (node), NULL);
+
+ if (JSON_NODE_HOLDS_NULL (node))
+ return NULL;
+
+ return json_node_get_array (node);
+}
+
+/**
+ * json_object_get_object_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member
+ *
+ * Convenience function that retrieves the object
+ * stored in @member_name of @object
+ *
+ * See also: json_object_get_member()
+ *
+ * Return value: (transfer none): the object inside the object's member
+ *
+ * Since: 0.8
+ */
+JsonObject *
+json_object_get_object_member (JsonObject *object,
+ const gchar *member_name)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (member_name != NULL, NULL);
+
+ node = object_get_member_internal (object, member_name);
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (JSON_NODE_HOLDS_OBJECT (node) || JSON_NODE_HOLDS_NULL (node), NULL);
+
+ if (JSON_NODE_HOLDS_NULL (node))
+ return NULL;
+
+ return json_node_get_object (node);
+}
+
+/**
+ * json_object_has_member:
+ * @object: a #JsonObject
+ * @member_name: the name of a JSON object member
+ *
+ * Checks whether @object has a member named @member_name.
+ *
+ * Return value: %TRUE if the JSON object has the requested member
+ */
+gboolean
+json_object_has_member (JsonObject *object,
+ const gchar *member_name)
+{
+ g_return_val_if_fail (object != NULL, FALSE);
+ g_return_val_if_fail (member_name != NULL, FALSE);
+
+ return (g_hash_table_lookup (object->members, member_name) != NULL);
+}
+
+/**
+ * json_object_get_size:
+ * @object: a #JsonObject
+ *
+ * Retrieves the number of members of a #JsonObject.
+ *
+ * Return value: the number of members
+ */
+guint
+json_object_get_size (JsonObject *object)
+{
+ g_return_val_if_fail (object != NULL, 0);
+
+ return g_hash_table_size (object->members);
+}
+
+/**
+ * json_object_remove_member:
+ * @object: a #JsonObject
+ * @member_name: the name of the member to remove
+ *
+ * Removes @member_name from @object, freeing its allocated resources.
+ */
+void
+json_object_remove_member (JsonObject *object,
+ const gchar *member_name)
+{
+ GList *l;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (member_name != NULL);
+
+ for (l = object->members_ordered; l != NULL; l = l->next)
+ {
+ const gchar *name = l->data;
+
+ if (g_strcmp0 (name, member_name) == 0)
+ {
+ object->members_ordered = g_list_delete_link (object->members_ordered, l);
+ break;
+ }
+ }
+
+ g_hash_table_remove (object->members, member_name);
+}
+
+/**
+ * json_object_foreach_member:
+ * @object: a #JsonObject
+ * @func: (scope call): the function to be called on each member
+ * @data: (closure): data to be passed to the function
+ *
+ * Iterates over all members of @object and calls @func on
+ * each one of them.
+ *
+ * It is safe to change the value of a #JsonNode of the @object
+ * from within the iterator @func, but it is not safe to add or
+ * remove members from the @object.
+ *
+ * Since: 0.8
+ */
+void
+json_object_foreach_member (JsonObject *object,
+ JsonObjectForeach func,
+ gpointer data)
+{
+ GList *members, *l;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (func != NULL);
+
+ /* the list is stored in reverse order to have constant time additions */
+ members = g_list_last (object->members_ordered);
+ for (l = members; l != NULL; l = l->prev)
+ {
+ const gchar *member_name = l->data;
+ JsonNode *member_node = g_hash_table_lookup (object->members, member_name);
+
+ func (object, member_name, member_node, data);
+ }
+}
diff --git a/src/glib-jsonrpc/json-glib/json-parser.c b/src/glib-jsonrpc/json-glib/json-parser.c
new file mode 100644
index 0000000..4fe6bef
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-parser.c
@@ -0,0 +1,1434 @@
+/* json-parser.c - JSON streams parser
+ *
+ * This file is part of JSON-GLib
+ *
+ * Copyright  2007, 2008, 2009 OpenedHand Ltd
+ * Copyright  2009, 2010 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:json-parser
+ * @short_description: Parse JSON data streams
+ *
+ * #JsonParser provides an object for parsing a JSON data stream, either
+ * inside a file or inside a static buffer.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#if 0
+#include <glib/gi18n-lib.h>
+#else
+#define _(s) s
+#endif
+
+#include "json-types-private.h"
+
+#include "json-debug.h"
+#include "json-marshal.h"
+#include "json-parser.h"
+#include "json-scanner.h"
+
+GQuark
+json_parser_error_quark (void)
+{
+ return g_quark_from_static_string ("json-parser-error");
+}
+
+#define JSON_PARSER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), JSON_TYPE_PARSER, JsonParserPrivate))
+
+struct _JsonParserPrivate
+{
+ JsonNode *root;
+ JsonNode *current_node;
+
+ JsonScanner *scanner;
+
+ JsonParserError error_code;
+ GError *last_error;
+
+ gchar *variable_name;
+ gchar *filename;
+
+ guint has_assignment : 1;
+ guint is_filename : 1;
+};
+
+static const gchar symbol_names[] =
+ "true\0"
+ "false\0"
+ "null\0"
+ "var\0";
+
+static const struct
+{
+ guint name_offset;
+ guint token;
+} symbols[] = {
+ { 0, JSON_TOKEN_TRUE },
+ { 5, JSON_TOKEN_FALSE },
+ { 11, JSON_TOKEN_NULL },
+ { 16, JSON_TOKEN_VAR }
+};
+
+static const guint n_symbols = G_N_ELEMENTS (symbols);
+
+enum
+{
+ PARSE_START,
+ OBJECT_START,
+ OBJECT_MEMBER,
+ OBJECT_END,
+ ARRAY_START,
+ ARRAY_ELEMENT,
+ ARRAY_END,
+ PARSE_END,
+ ERROR,
+
+ LAST_SIGNAL
+};
+
+static guint parser_signals[LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (JsonParser, json_parser, G_TYPE_OBJECT);
+
+static guint json_parse_array (JsonParser *parser,
+ JsonScanner *scanner,
+ JsonNode **node);
+static guint json_parse_object (JsonParser *parser,
+ JsonScanner *scanner,
+ JsonNode **node);
+
+static inline void
+json_parser_clear (JsonParser *parser)
+{
+ JsonParserPrivate *priv = parser->priv;
+
+ g_free (priv->variable_name);
+ priv->variable_name = NULL;
+
+ if (priv->last_error)
+ {
+ g_error_free (priv->last_error);
+ priv->last_error = NULL;
+ }
+
+ if (priv->root)
+ {
+ json_node_free (priv->root);
+ priv->root = NULL;
+ }
+}
+
+static void
+json_parser_dispose (GObject *gobject)
+{
+ json_parser_clear (JSON_PARSER (gobject));
+
+ G_OBJECT_CLASS (json_parser_parent_class)->dispose (gobject);
+}
+
+static void
+json_parser_finalize (GObject *gobject)
+{
+ JsonParserPrivate *priv = JSON_PARSER (gobject)->priv;
+
+ g_free (priv->variable_name);
+ g_free (priv->filename);
+
+ G_OBJECT_CLASS (json_parser_parent_class)->finalize (gobject);
+}
+
+static void
+json_parser_class_init (JsonParserClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (JsonParserPrivate));
+
+ gobject_class->dispose = json_parser_dispose;
+ gobject_class->finalize = json_parser_finalize;
+
+ /**
+ * JsonParser::parse-start:
+ * @parser: the #JsonParser that received the signal
+ *
+ * The ::parse-start signal is emitted when the parser began parsing
+ * a JSON data stream.
+ */
+ parser_signals[PARSE_START] =
+ g_signal_new ("parse-start",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, parse_start),
+ NULL, NULL,
+ _json_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ /**
+ * JsonParser::parse-end:
+ * @parser: the #JsonParser that received the signal
+ *
+ * The ::parse-end signal is emitted when the parser successfully
+ * finished parsing a JSON data stream
+ */
+ parser_signals[PARSE_END] =
+ g_signal_new ("parse-end",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, parse_end),
+ NULL, NULL,
+ _json_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ /**
+ * JsonParser::object-start:
+ * @parser: the #JsonParser that received the signal
+ *
+ * The ::object-start signal is emitted each time the #JsonParser
+ * starts parsing a #JsonObject.
+ */
+ parser_signals[OBJECT_START] =
+ g_signal_new ("object-start",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, object_start),
+ NULL, NULL,
+ _json_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ /**
+ * JsonParser::object-member:
+ * @parser: the #JsonParser that received the signal
+ * @object: a #JsonObject
+ * @member_name: the name of the newly parsed member
+ *
+ * The ::object-member signal is emitted each time the #JsonParser
+ * has successfully parsed a single member of a #JsonObject. The
+ * object and member are passed to the signal handlers.
+ */
+ parser_signals[OBJECT_MEMBER] =
+ g_signal_new ("object-member",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, object_member),
+ NULL, NULL,
+ _json_marshal_VOID__BOXED_STRING,
+ G_TYPE_NONE, 2,
+ JSON_TYPE_OBJECT,
+ G_TYPE_STRING);
+ /**
+ * JsonParser::object-end:
+ * @parser: the #JsonParser that received the signal
+ * @object: the parsed #JsonObject
+ *
+ * The ::object-end signal is emitted each time the #JsonParser
+ * has successfully parsed an entire #JsonObject.
+ */
+ parser_signals[OBJECT_END] =
+ g_signal_new ("object-end",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, object_end),
+ NULL, NULL,
+ _json_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ JSON_TYPE_OBJECT);
+ /**
+ * JsonParser::array-start:
+ * @parser: the #JsonParser that received the signal
+ *
+ * The ::array-start signal is emitted each time the #JsonParser
+ * starts parsing a #JsonArray
+ */
+ parser_signals[ARRAY_START] =
+ g_signal_new ("array-start",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, array_start),
+ NULL, NULL,
+ _json_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ /**
+ * JsonParser::array-element:
+ * @parser: the #JsonParser that received the signal
+ * @array: a #JsonArray
+ * @index_: the index of the newly parsed element
+ *
+ * The ::array-element signal is emitted each time the #JsonParser
+ * has successfully parsed a single element of a #JsonArray. The
+ * array and element index are passed to the signal handlers.
+ */
+ parser_signals[ARRAY_ELEMENT] =
+ g_signal_new ("array-element",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, array_element),
+ NULL, NULL,
+ _json_marshal_VOID__BOXED_INT,
+ G_TYPE_NONE, 2,
+ JSON_TYPE_ARRAY,
+ G_TYPE_INT);
+ /**
+ * JsonParser::array-end:
+ * @parser: the #JsonParser that received the signal
+ * @array: the parsed #JsonArray
+ *
+ * The ::array-end signal is emitted each time the #JsonParser
+ * has successfully parsed an entire #JsonArray
+ */
+ parser_signals[ARRAY_END] =
+ g_signal_new ("array-end",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, array_end),
+ NULL, NULL,
+ _json_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ JSON_TYPE_ARRAY);
+ /**
+ * JsonParser::error:
+ * @parser: the parser instance that received the signal
+ * @error: a pointer to the #GError
+ *
+ * The ::error signal is emitted each time a #JsonParser encounters
+ * an error in a JSON stream.
+ */
+ parser_signals[ERROR] =
+ g_signal_new ("error",
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (JsonParserClass, error),
+ NULL, NULL,
+ _json_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+}
+
+static void
+json_parser_init (JsonParser *parser)
+{
+ JsonParserPrivate *priv;
+
+ parser->priv = priv = JSON_PARSER_GET_PRIVATE (parser);
+
+ priv->root = NULL;
+ priv->current_node = NULL;
+
+ priv->error_code = JSON_PARSER_ERROR_PARSE;
+ priv->last_error = NULL;
+
+ priv->has_assignment = FALSE;
+ priv->variable_name = NULL;
+
+ priv->is_filename = FALSE;
+ priv->filename = FALSE;
+}
+
+static guint
+json_parse_value (JsonParser *parser,
+ JsonScanner *scanner,
+ guint token,
+ JsonNode **node)
+{
+ JsonParserPrivate *priv = parser->priv;
+ JsonNode *current_node = priv->current_node;
+ gboolean is_negative = FALSE;
+
+ if (token == '-')
+ {
+ guint next_token = json_scanner_peek_next_token (scanner);
+
+ if (next_token == G_TOKEN_INT ||
+ next_token == G_TOKEN_FLOAT)
+ {
+ is_negative = TRUE;
+ token = json_scanner_get_next_token (scanner);
+ }
+ else
+ return G_TOKEN_INT;
+ }
+
+ switch (token)
+ {
+ case G_TOKEN_INT:
+ *node = json_node_new (JSON_NODE_VALUE);
+ JSON_NOTE (PARSER, "abs(node): %" G_GINT64_FORMAT " (sign: %s)",
+ scanner->value.v_int64,
+ is_negative ? "negative" : "positive");
+ json_node_set_int (*node, is_negative ? scanner->value.v_int64 * -1
+ : scanner->value.v_int64);
+ break;
+
+ case G_TOKEN_FLOAT:
+ *node = json_node_new (JSON_NODE_VALUE);
+ JSON_NOTE (PARSER, "abs(node): %.6f (sign: %s)",
+ scanner->value.v_float,
+ is_negative ? "negative" : "positive");
+ json_node_set_double (*node, is_negative ? scanner->value.v_float * -1.0
+ : scanner->value.v_float);
+ break;
+
+ case G_TOKEN_STRING:
+ *node = json_node_new (JSON_NODE_VALUE);
+ JSON_NOTE (PARSER, "node: '%s'",
+ scanner->value.v_string);
+ json_node_set_string (*node, scanner->value.v_string);
+ break;
+
+ case JSON_TOKEN_TRUE:
+ case JSON_TOKEN_FALSE:
+ *node = json_node_new (JSON_NODE_VALUE);
+ JSON_NOTE (PARSER, "node: '%s'",
+ JSON_TOKEN_TRUE ? "<true>" : "<false>");
+ json_node_set_boolean (*node, token == JSON_TOKEN_TRUE ? TRUE : FALSE);
+ break;
+
+ case JSON_TOKEN_NULL:
+ *node = json_node_new (JSON_NODE_NULL);
+ JSON_NOTE (PARSER, "node: <null>");
+ break;
+
+ default:
+ {
+ JsonNodeType cur_type;
+
+ *node = NULL;
+
+ cur_type = json_node_get_node_type (current_node);
+ if (cur_type == JSON_NODE_ARRAY)
+ return G_TOKEN_RIGHT_BRACE;
+ else if (cur_type == JSON_NODE_OBJECT)
+ return G_TOKEN_RIGHT_CURLY;
+ else
+ {
+ priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD;
+ return G_TOKEN_SYMBOL;
+ }
+ }
+ }
+
+ return G_TOKEN_NONE;
+}
+
+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:
+ 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_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)
+ {
+ 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;
+}
+
+static guint
+json_parse_object (JsonParser *parser,
+ JsonScanner *scanner,
+ JsonNode **node)
+{
+ JsonParserPrivate *priv = parser->priv;
+ JsonObject *object;
+ JsonNode *old_current;
+ guint token;
+
+ old_current = priv->current_node;
+ priv->current_node = json_node_new (JSON_NODE_OBJECT);
+
+ object = json_object_new ();
+
+ token = json_scanner_get_next_token (scanner);
+ g_assert (token == G_TOKEN_LEFT_CURLY);
+
+ g_signal_emit (parser, parser_signals[OBJECT_START], 0);
+
+ while (token != G_TOKEN_RIGHT_CURLY)
+ {
+ guint next_token = json_scanner_peek_next_token (scanner);
+ JsonNode *member = NULL;
+ gchar *name;
+
+ /* we need to abort here because empty objects do not
+ * have member names
+ */
+ if (next_token == G_TOKEN_RIGHT_CURLY)
+ break;
+
+ /* parse the member's name */
+ if (next_token != G_TOKEN_STRING)
+ {
+ JSON_NOTE (PARSER, "Missing object member name");
+
+ priv->error_code = JSON_PARSER_ERROR_PARSE;
+
+ json_object_unref (object);
+ json_node_free (priv->current_node);
+ priv->current_node = old_current;
+
+ return G_TOKEN_STRING;
+ }
+
+ /* member name */
+ token = json_scanner_get_next_token (scanner);
+ name = g_strdup (scanner->value.v_string);
+ JSON_NOTE (PARSER, "Object member '%s'", name);
+
+ /* a colon separates names from values */
+ next_token = json_scanner_peek_next_token (scanner);
+ if (next_token != ':')
+ {
+ JSON_NOTE (PARSER, "Missing object member name separator");
+
+ priv->error_code = JSON_PARSER_ERROR_MISSING_COLON;
+
+ g_free (name);
+ json_object_unref (object);
+ json_node_free (priv->current_node);
+ priv->current_node = old_current;
+
+ return ':';
+ }
+
+ /* we swallow the ':' */
+ token = json_scanner_get_next_token (scanner);
+ g_assert (token == ':');
+ next_token = json_scanner_peek_next_token (scanner);
+
+ /* parse the member's value */
+ switch (next_token)
+ {
+ case G_TOKEN_LEFT_BRACE:
+ JSON_NOTE (PARSER, "Nested array at member %s", name);
+ token = json_parse_array (parser, scanner, &member);
+ break;
+
+ case G_TOKEN_LEFT_CURLY:
+ JSON_NOTE (PARSER, "Nested object at member %s", name);
+ token = json_parse_object (parser, scanner, &member);
+ 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, &member);
+ break;
+
+ default:
+ /* once a member name is defined we need a value */
+ token = G_TOKEN_SYMBOL;
+ break;
+ }
+
+ if (token != G_TOKEN_NONE || member == NULL)
+ {
+ /* the json_parse_* functions will have set the error code */
+ g_free (name);
+ json_object_unref (object);
+ 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_CURLY)
+ {
+ priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA;
+
+ json_object_unref (object);
+ json_node_free (member);
+ json_node_free (priv->current_node);
+ priv->current_node = old_current;
+
+ return G_TOKEN_RIGHT_BRACE;
+ }
+ }
+ else if (next_token == G_TOKEN_STRING)
+ {
+ priv->error_code = JSON_PARSER_ERROR_MISSING_COMMA;
+
+ json_object_unref (object);
+ json_node_free (member);
+ json_node_free (priv->current_node);
+ priv->current_node = old_current;
+
+ return G_TOKEN_COMMA;
+ }
+
+ JSON_NOTE (PARSER, "Object member '%s' completed", name);
+ json_node_set_parent (member, priv->current_node);
+ json_object_set_member (object, name, member);
+
+ g_signal_emit (parser, parser_signals[OBJECT_MEMBER], 0,
+ object,
+ name);
+
+ g_free (name);
+
+ token = next_token;
+ }
+
+ json_scanner_get_next_token (scanner);
+
+ json_node_take_object (priv->current_node, object);
+ json_node_set_parent (priv->current_node, old_current);
+
+ g_signal_emit (parser, parser_signals[OBJECT_END], 0, object);
+
+ if (node != NULL && *node == NULL)
+ *node = priv->current_node;
+
+ priv->current_node = old_current;
+
+ return G_TOKEN_NONE;
+}
+
+static guint
+json_parse_statement (JsonParser *parser,
+ JsonScanner *scanner)
+{
+ JsonParserPrivate *priv = parser->priv;
+ guint token;
+
+ token = json_scanner_peek_next_token (scanner);
+ switch (token)
+ {
+ case G_TOKEN_LEFT_CURLY:
+ JSON_NOTE (PARSER, "Statement is object declaration");
+ return json_parse_object (parser, scanner, &priv->root);
+
+ case G_TOKEN_LEFT_BRACE:
+ JSON_NOTE (PARSER, "Statement is array declaration");
+ return json_parse_array (parser, scanner, &priv->root);
+
+ /* some web APIs are not only passing the data structures: they are
+ * also passing an assigment, which makes parsing horribly complicated
+ * only because web developers are lazy, and writing "var foo = " is
+ * evidently too much to request from them.
+ */
+ case JSON_TOKEN_VAR:
+ {
+ guint next_token;
+ gchar *name;
+
+ JSON_NOTE (PARSER, "Statement is an assignment");
+
+ /* swallow the 'var' token... */
+ token = json_scanner_get_next_token (scanner);
+
+ /* ... swallow the variable name... */
+ next_token = json_scanner_get_next_token (scanner);
+ if (next_token != G_TOKEN_IDENTIFIER)
+ {
+ priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD;
+ return G_TOKEN_IDENTIFIER;
+ }
+
+ name = g_strdup (scanner->value.v_identifier);
+
+ /* ... and finally swallow the '=' */
+ next_token = json_scanner_get_next_token (scanner);
+ if (next_token != '=')
+ return '=';
+
+ priv->has_assignment = TRUE;
+ priv->variable_name = name;
+
+ token = json_parse_statement (parser, scanner);
+
+ /* remove the trailing semi-colon */
+ next_token = json_scanner_peek_next_token (scanner);
+ if (next_token == ';')
+ {
+ token = json_scanner_get_next_token (scanner);
+ return G_TOKEN_NONE;
+ }
+
+ return token;
+ }
+ break;
+
+ case JSON_TOKEN_NULL:
+ case JSON_TOKEN_TRUE:
+ case JSON_TOKEN_FALSE:
+ case '-':
+ case G_TOKEN_INT:
+ case G_TOKEN_FLOAT:
+ case G_TOKEN_STRING:
+ JSON_NOTE (PARSER, "Statement is a value");
+ token = json_scanner_get_next_token (scanner);
+ return json_parse_value (parser, scanner, token, &priv->root);
+
+ default:
+ JSON_NOTE (PARSER, "Unknown statement");
+ json_scanner_get_next_token (scanner);
+ priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD;
+ return G_TOKEN_SYMBOL;
+ }
+}
+
+static void
+json_scanner_msg_handler (JsonScanner *scanner,
+ gchar *message,
+ gboolean is_error)
+{
+ JsonParser *parser = scanner->user_data;
+ JsonParserPrivate *priv = parser->priv;
+
+ if (is_error)
+ {
+ GError *error = NULL;
+
+ /* translators: %s: is the file name, %d is the line number
+ * and %s is the error message
+ */
+ g_set_error (&error, JSON_PARSER_ERROR,
+ priv->error_code,
+ _("%s:%d: Parse error: %s"),
+ priv->is_filename ? priv->filename : "<none>",
+ scanner->line,
+ message);
+
+ parser->priv->last_error = error;
+ g_signal_emit (parser, parser_signals[ERROR], 0, error);
+ }
+ else
+ g_warning ("%s:%d: Parse error: %s",
+ priv->is_filename ? priv->filename : "<none>",
+ scanner->line,
+ message);
+}
+
+static JsonScanner *
+json_scanner_create (JsonParser *parser)
+{
+ JsonScanner *scanner;
+ gint i;
+
+ scanner = json_scanner_new ();
+ scanner->msg_handler = json_scanner_msg_handler;
+ scanner->user_data = parser;
+
+ for (i = 0; i < n_symbols; i++)
+ {
+ json_scanner_scope_add_symbol (scanner, 0,
+ symbol_names + symbols[i].name_offset,
+ GINT_TO_POINTER (symbols[i].token));
+ }
+
+ return scanner;
+}
+
+/**
+ * json_parser_new:
+ *
+ * Creates a new #JsonParser instance. You can use the #JsonParser to
+ * load a JSON stream from either a file or a buffer and then walk the
+ * hierarchy using the data types API.
+ *
+ * Return value: the newly created #JsonParser. Use g_object_unref()
+ * to release all the memory it allocates.
+ */
+JsonParser *
+json_parser_new (void)
+{
+ return g_object_new (JSON_TYPE_PARSER, NULL);
+}
+
+static gboolean
+json_parser_load (JsonParser *parser,
+ const gchar *data,
+ gsize length,
+ GError **error)
+{
+ JsonParserPrivate *priv = parser->priv;
+ JsonScanner *scanner;
+ gboolean done;
+ gboolean retval = TRUE;
+ gint i;
+
+ json_parser_clear (parser);
+
+ scanner = json_scanner_create (parser);
+ json_scanner_input_text (scanner, data, length);
+
+ priv->scanner = scanner;
+
+ g_signal_emit (parser, parser_signals[PARSE_START], 0);
+
+ done = FALSE;
+ while (!done)
+ {
+ if (json_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
+ done = TRUE;
+ else
+ {
+ guint expected_token;
+ gint cur_token;
+
+ /* we try to show the expected token, if possible */
+ expected_token = json_parse_statement (parser, scanner);
+ if (expected_token != G_TOKEN_NONE)
+ {
+ const gchar *symbol_name;
+ gchar *msg;
+
+ cur_token = scanner->token;
+ msg = NULL;
+ symbol_name = NULL;
+
+ if (scanner->scope_id == 0)
+ {
+ if (expected_token > JSON_TOKEN_INVALID &&
+ expected_token < JSON_TOKEN_LAST)
+ {
+ for (i = 0; i < n_symbols; i++)
+ if (symbols[i].token == expected_token)
+ symbol_name = symbol_names + symbols[i].name_offset;
+
+ if (!msg)
+ msg = g_strconcat ("e.g. '", symbol_name, "'", NULL);
+ }
+
+ if (cur_token > JSON_TOKEN_INVALID &&
+ cur_token < JSON_TOKEN_LAST)
+ {
+ symbol_name = "???";
+
+ for (i = 0; i < n_symbols; i++)
+ if (symbols[i].token == cur_token)
+ symbol_name = symbol_names + symbols[i].name_offset;
+ }
+ }
+
+ /* this will emit the ::error signal via the custom
+ * message handler we install
+ */
+ json_scanner_unexp_token (scanner, expected_token,
+ NULL, "value",
+ symbol_name, msg,
+ TRUE);
+
+ /* and this will propagate the error we create in the
+ * same message handler
+ */
+ if (priv->last_error)
+ {
+ g_propagate_error (error, priv->last_error);
+ priv->last_error = NULL;
+ }
+
+ retval = FALSE;
+
+ g_free (msg);
+ done = TRUE;
+ }
+ }
+ }
+
+ g_signal_emit (parser, parser_signals[PARSE_END], 0);
+
+ /* remove the scanner */
+ json_scanner_destroy (scanner);
+ priv->scanner = NULL;
+ priv->current_node = NULL;
+
+ return retval;
+}
+
+/**
+ * json_parser_load_from_file:
+ * @parser: a #JsonParser
+ * @filename: the path for the file to parse
+ * @error: return location for a #GError, or %NULL
+ *
+ * Loads a JSON stream from the content of @filename and parses it. See
+ * json_parser_load_from_data().
+ *
+ * Return value: %TRUE if the file was successfully loaded and parsed.
+ * In case of error, @error is set accordingly and %FALSE is returned
+ */
+gboolean
+json_parser_load_from_file (JsonParser *parser,
+ const gchar *filename,
+ GError **error)
+{
+ JsonParserPrivate *priv;
+ GError *internal_error;
+ gchar *data;
+ gsize length;
+ gboolean retval = TRUE;
+
+ g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ priv = parser->priv;
+
+ internal_error = NULL;
+ if (!g_file_get_contents (filename, &data, &length, &internal_error))
+ {
+ g_propagate_error (error, internal_error);
+ return FALSE;
+ }
+
+ g_free (priv->filename);
+
+ priv->is_filename = TRUE;
+ priv->filename = g_strdup (filename);
+
+ if (!json_parser_load (parser, data, length, &internal_error))
+ {
+ g_propagate_error (error, internal_error);
+ retval = FALSE;
+ }
+
+ g_free (data);
+
+ return retval;
+}
+
+/**
+ * json_parser_load_from_data:
+ * @parser: a #JsonParser
+ * @data: the buffer to parse
+ * @length: the length of the buffer, or -1
+ * @error: return location for a #GError, or %NULL
+ *
+ * Loads a JSON stream from a buffer and parses it. You can call this function
+ * multiple times with the same #JsonParser object, but the contents of the
+ * parser will be destroyed each time.
+ *
+ * Return value: %TRUE if the buffer was succesfully parser. In case
+ * of error, @error is set accordingly and %FALSE is returned
+ */
+gboolean
+json_parser_load_from_data (JsonParser *parser,
+ const gchar *data,
+ gssize length,
+ GError **error)
+{
+ JsonParserPrivate *priv;
+ GError *internal_error;
+ gboolean retval = TRUE;
+
+ g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ priv = parser->priv;
+
+ if (length < 0)
+ length = strlen (data);
+
+ priv->is_filename = FALSE;
+ g_free (priv->filename);
+ priv->filename = NULL;
+
+ internal_error = NULL;
+ if (!json_parser_load (parser, data, length, &internal_error))
+ {
+ g_propagate_error (error, internal_error);
+ retval = FALSE;
+ }
+
+ return retval;
+}
+
+/**
+ * json_parser_get_root:
+ * @parser: a #JsonParser
+ *
+ * Retrieves the top level node from the parsed JSON stream.
+ *
+ * Return value: (transfer none): the root #JsonNode . The returned
+ * node is owned by the #JsonParser and should never be modified
+ * or freed.
+ */
+JsonNode *
+json_parser_get_root (JsonParser *parser)
+{
+ g_return_val_if_fail (JSON_IS_PARSER (parser), NULL);
+
+ return parser->priv->root;
+}
+
+/**
+ * json_parser_get_current_line:
+ * @parser: a #JsonParser
+ *
+ * Retrieves the line currently parsed, starting from 1.
+ *
+ * This function has defined behaviour only while parsing; calling this
+ * function from outside the signal handlers emitted by #JsonParser will
+ * yield 0.
+ *
+ * Return value: the currently parsed line, or 0.
+ */
+guint
+json_parser_get_current_line (JsonParser *parser)
+{
+ g_return_val_if_fail (JSON_IS_PARSER (parser), 0);
+
+ if (parser->priv->scanner)
+ return json_scanner_cur_line (parser->priv->scanner);
+
+ return 0;
+}
+
+/**
+ * json_parser_get_current_pos:
+ * @parser: a #JsonParser
+ *
+ * Retrieves the current position inside the current line, starting
+ * from 0.
+ *
+ * This function has defined behaviour only while parsing; calling this
+ * function from outside the signal handlers emitted by #JsonParser will
+ * yield 0.
+ *
+ * Return value: the position in the current line, or 0.
+ */
+guint
+json_parser_get_current_pos (JsonParser *parser)
+{
+ g_return_val_if_fail (JSON_IS_PARSER (parser), 0);
+
+ if (parser->priv->scanner)
+ return json_scanner_cur_line (parser->priv->scanner);
+
+ return 0;
+}
+
+/**
+ * json_parser_has_assignment:
+ * @parser: a #JsonParser
+ * @variable_name: (out) (allow-none) (transfer none): Return location for the variable
+ * name, or %NULL
+ *
+ * A JSON data stream might sometimes contain an assignment, like:
+ *
+ * |[
+ * var _json_data = { "member_name" : [ ...
+ * ]|
+ *
+ * even though it would technically constitute a violation of the RFC.
+ *
+ * #JsonParser will ignore the left hand identifier and parse the right
+ * hand value of the assignment. #JsonParser will record, though, the
+ * existence of the assignment in the data stream and the variable name
+ * used.
+ *
+ * Return value: %TRUE if there was an assignment, %FALSE otherwise. If
+ * @variable_name is not %NULL it will be set to the name of the variable
+ * used in the assignment. The string is owned by #JsonParser and should
+ * never be modified or freed.
+ *
+ * Since: 0.4
+ */
+gboolean
+json_parser_has_assignment (JsonParser *parser,
+ gchar **variable_name)
+{
+ JsonParserPrivate *priv;
+
+ g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE);
+
+ priv = parser->priv;
+
+ if (priv->has_assignment && variable_name)
+ *variable_name = priv->variable_name;
+
+ return priv->has_assignment;
+}
+
+#define GET_DATA_BLOCK_SIZE 8192
+
+/**
+ * json_parser_load_from_stream:
+ * @parser: a #JsonParser
+ * @stream: an open #GInputStream
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: the return location for a #GError, or %NULL
+ *
+ * Loads the contents of an input stream and parses them.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the @cancellable object from another thread. If the
+ * operation was cancelled, the error %G_IO_ERROR_CANCELLED will be set
+ * on the passed @error.
+ *
+ * Return value: %TRUE if the data stream was successfully read and
+ * parsed, and %FALSE otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_parser_load_from_stream (JsonParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GByteArray *content;
+ gsize pos;
+ gssize res;
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ content = g_byte_array_new ();
+ pos = 0;
+
+ g_byte_array_set_size (content, pos + GET_DATA_BLOCK_SIZE + 1);
+ while ((res = g_input_stream_read (stream, content->data + pos,
+ GET_DATA_BLOCK_SIZE,
+ cancellable, error)) > 0)
+ {
+ pos += res;
+ g_byte_array_set_size (content, pos + GET_DATA_BLOCK_SIZE + 1);
+ }
+
+ if (res < 0)
+ {
+ /* error has already been set */
+ retval = FALSE;
+ goto out;
+ }
+
+ /* zero-terminate the content; we allocated an extra byte for this */
+ content->data[pos] = 0;
+
+ retval = json_parser_load (parser, (const gchar *) content->data, content->len, error);
+
+out:
+ g_byte_array_free (content, TRUE);
+
+ return retval;
+}
+
+typedef struct _LoadStreamData
+{
+ JsonParser *parser;
+ GError *error;
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GByteArray *content;
+ gsize pos;
+} LoadStreamData;
+
+static void
+load_stream_data_free (gpointer data)
+{
+ LoadStreamData *closure;
+
+ if (G_UNLIKELY (data == NULL))
+ return;
+
+ closure = data;
+
+ if (closure->error)
+ g_error_free (closure->error);
+
+ if (closure->cancellable)
+ g_object_unref (closure->cancellable);
+
+ if (closure->content)
+ g_byte_array_free (closure->content, TRUE);
+
+ g_object_unref (closure->parser);
+
+ g_free (closure);
+}
+
+static void
+load_stream_data_read_callback (GObject *object,
+ GAsyncResult *read_res,
+ gpointer user_data)
+{
+ GInputStream *stream = G_INPUT_STREAM (object);
+ LoadStreamData *data = user_data;
+ GError *error = NULL;
+ gssize read_size;
+
+ read_size = g_input_stream_read_finish (stream, read_res, &error);
+ if (read_size < 0)
+ {
+ if (error != NULL)
+ data->error = error;
+ else
+ {
+ GSimpleAsyncResult *res;
+
+ /* EOF */
+ res = g_simple_async_result_new (G_OBJECT (data->parser),
+ data->callback,
+ data->user_data,
+ json_parser_load_from_stream_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, load_stream_data_free);
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+ }
+ }
+ else if (read_size > 0)
+ {
+ data->pos += read_size;
+
+ g_byte_array_set_size (data->content, data->pos + GET_DATA_BLOCK_SIZE);
+
+ g_input_stream_read_async (stream, data->content->data + data->pos,
+ GET_DATA_BLOCK_SIZE,
+ 0,
+ data->cancellable,
+ load_stream_data_read_callback,
+ data);
+ }
+ else
+ {
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (data->parser),
+ data->callback,
+ data->user_data,
+ json_parser_load_from_stream_async);
+ g_simple_async_result_set_op_res_gpointer (res, data, load_stream_data_free);
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+ }
+}
+
+/**
+ * json_parser_load_from_stream_finish:
+ * @parser: a #JsonParser
+ * @result: a #GAsyncResult
+ * @error: the return location for a #GError or %NULL
+ *
+ * Finishes an asynchronous stream loading started with
+ * json_parser_load_from_stream_async().
+ *
+ * Return value: %TRUE if the content of the stream was successfully retrieves
+ * and parsed, and %FALSE otherwise. In case of error, the #GError will be
+ * filled accordingly.
+ *
+ * Since: 0.12
+ */
+gboolean
+json_parser_load_from_stream_finish (JsonParser *parser,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ LoadStreamData *data;
+
+ g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == json_parser_load_from_stream_async);
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (data->error)
+ {
+ g_propagate_error (error, data->error);
+ data->error = NULL;
+ return FALSE;
+ }
+
+ g_byte_array_set_size (data->content, data->pos + 1);
+ data->content->data[data->pos] = 0;
+
+ return json_parser_load (parser, (const gchar *) data->content->data, data->content->len, error);
+}
+
+/**
+ * json_parser_load_from_stream_async:
+ * @parser: a #JsonParser
+ * @stream: a #GInputStream
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: the data to pass to @callback
+ *
+ * Asynchronously reads the contents of @stream.
+ *
+ * For more details, see json_parser_load_from_stream() which is the
+ * synchronous version of this call.
+ *
+ * When the operation is finished, @callback will be called. You should
+ * then call json_parser_load_from_stream_finish() to get the result
+ * of the operation.
+ *
+ * Since: 0.12
+ */
+void
+json_parser_load_from_stream_async (JsonParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LoadStreamData *data;
+
+ g_return_if_fail (JSON_IS_PARSER (parser));
+ g_return_if_fail (G_IS_INPUT_STREAM (stream));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ data = g_new0 (LoadStreamData, 1);
+
+ if (cancellable != NULL)
+ data->cancellable = g_object_ref (cancellable);
+
+ data->callback = callback;
+ data->user_data = user_data;
+ data->content = g_byte_array_new ();
+ data->parser = g_object_ref (parser);
+
+ g_byte_array_set_size (data->content, data->pos + GET_DATA_BLOCK_SIZE);
+ g_input_stream_read_async (stream, data->content->data + data->pos,
+ GET_DATA_BLOCK_SIZE, 0,
+ data->cancellable,
+ load_stream_data_read_callback,
+ data);
+}
diff --git a/src/glib-jsonrpc/json-glib/json-parser.h b/src/glib-jsonrpc/json-glib/json-parser.h
new file mode 100644
index 0000000..36107f4
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-parser.h
@@ -0,0 +1,173 @@
+/* json-parser.h - JSON streams parser
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_PARSER_H__
+#define __JSON_PARSER_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <json-glib/json-types.h>
+
+G_BEGIN_DECLS
+
+#define JSON_TYPE_PARSER (json_parser_get_type ())
+#define JSON_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JSON_TYPE_PARSER, JsonParser))
+#define JSON_IS_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JSON_TYPE_PARSER))
+#define JSON_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), JSON_TYPE_PARSER, JsonParserClass))
+#define JSON_IS_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), JSON_TYPE_PARSER))
+#define JSON_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), JSON_TYPE_PARSER, JsonParserClass))
+
+#define JSON_PARSER_ERROR (json_parser_error_quark ())
+
+typedef struct _JsonParser JsonParser;
+typedef struct _JsonParserPrivate JsonParserPrivate;
+typedef struct _JsonParserClass JsonParserClass;
+
+/**
+ * JsonParserError:
+ * @JSON_PARSER_ERROR_PARSE: parse error
+ * @JSON_PARSER_ERROR_TRAILING_COMMA: unexpected trailing comma
+ * @JSON_PARSER_ERROR_MISSING_COMMA: expected comma
+ * @JSON_PARSER_ERROR_MISSING_COLON: expected colon
+ * @JSON_PARSER_ERROR_INVALID_BAREWORD: invalid bareword
+ * @JSON_PARSER_ERROR_UNKNOWN: unknown error
+ *
+ * Error enumeration for #JsonParser
+ *
+ * This enumeration can be extended at later date
+ */
+typedef enum {
+ JSON_PARSER_ERROR_PARSE,
+ JSON_PARSER_ERROR_TRAILING_COMMA,
+ JSON_PARSER_ERROR_MISSING_COMMA,
+ JSON_PARSER_ERROR_MISSING_COLON,
+ JSON_PARSER_ERROR_INVALID_BAREWORD,
+
+ JSON_PARSER_ERROR_UNKNOWN
+} JsonParserError;
+
+/**
+ * JsonParser:
+ *
+ * JSON data streams parser. The contents of the #JsonParser structure are
+ * private and should only be accessed via the provided API.
+ */
+struct _JsonParser
+{
+ /*< private >*/
+ GObject parent_instance;
+
+ JsonParserPrivate *priv;
+};
+
+/**
+ * JsonParserClass:
+ * @parse_start: class handler for the JsonParser::parse-start signal
+ * @object_start: class handler for the JsonParser::object-start signal
+ * @object_member: class handler for the JsonParser::object-member signal
+ * @object_end: class handler for the JsonParser::object-end signal
+ * @array_start: class handler for the JsonParser::array-start signal
+ * @array_element: class handler for the JsonParser::array-element signal
+ * @array_end: class handler for the JsonParser::array-end signal
+ * @parse_end: class handler for the JsonParser::parse-end signal
+ * @error: class handler for the JsonParser::error signal
+ *
+ * #JsonParser class.
+ */
+struct _JsonParserClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+ void (* parse_start) (JsonParser *parser);
+
+ void (* object_start) (JsonParser *parser);
+ void (* object_member) (JsonParser *parser,
+ JsonObject *object,
+ const gchar *member_name);
+ void (* object_end) (JsonParser *parser,
+ JsonObject *object);
+
+ void (* array_start) (JsonParser *parser);
+ void (* array_element) (JsonParser *parser,
+ JsonArray *array,
+ gint index_);
+ void (* array_end) (JsonParser *parser,
+ JsonArray *array);
+
+ void (* parse_end) (JsonParser *parser);
+
+ void (* error) (JsonParser *parser,
+ const GError *error);
+
+ /*< private >*/
+ /* padding for future expansion */
+ void (* _json_reserved1) (void);
+ void (* _json_reserved2) (void);
+ void (* _json_reserved3) (void);
+ void (* _json_reserved4) (void);
+ void (* _json_reserved5) (void);
+ void (* _json_reserved6) (void);
+ void (* _json_reserved7) (void);
+ void (* _json_reserved8) (void);
+};
+
+GQuark json_parser_error_quark (void);
+GType json_parser_get_type (void) G_GNUC_CONST;
+
+JsonParser *json_parser_new (void);
+gboolean json_parser_load_from_file (JsonParser *parser,
+ const gchar *filename,
+ GError **error);
+gboolean json_parser_load_from_data (JsonParser *parser,
+ const gchar *data,
+ gssize length,
+ GError **error);
+gboolean json_parser_load_from_stream (JsonParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+void json_parser_load_from_stream_async (JsonParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean json_parser_load_from_stream_finish (JsonParser *parser,
+ GAsyncResult *result,
+ GError **error);
+
+JsonNode * json_parser_get_root (JsonParser *parser);
+
+guint json_parser_get_current_line (JsonParser *parser);
+guint json_parser_get_current_pos (JsonParser *parser);
+gboolean json_parser_has_assignment (JsonParser *parser,
+ gchar **variable_name);
+
+G_END_DECLS
+
+#endif /* __JSON_PARSER_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-path.c b/src/glib-jsonrpc/json-glib/json-path.c
new file mode 100644
index 0000000..09d9543
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-path.c
@@ -0,0 +1,1033 @@
+/* json-path.h - JSONPath implementation
+ *
+ * This file is part of JSON-GLib
+ * Copyright  2011 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:json-path
+ * @Title: JsonPath
+ * @short_description: JSONPath implementation
+ *
+ * #JsonPath is a simple class implementing the JSONPath syntax for extracting
+ * data out of a JSON tree. While the semantics of the JSONPath expressions are
+ * heavily borrowed by the XPath specification for XML, the syntax follows the
+ * ECMAScript origins of JSON.
+ *
+ * Once a #JsonPath instance has been created, it has to compile a JSONPath
+ * expression using json_path_compile() before being able to match it to a
+ * JSON tree; the same #JsonPath instance can be used to match multiple JSON
+ * trees. It it also possible to compile a new JSONPath expression using the
+ * same #JsonPath instance; the previous expression will be discarded only if
+ * the compilation of the new expression is successful.
+ *
+ * The simple convenience function json_path_query() can be used for one-off
+ * matching.
+ *
+ * <refsect2 id="json-path-syntax">
+ * <title>Syntax of the JSONPath expressions</title>
+ * <para>A JSONPath expression is composed by path indices and operators.
+ * Each path index can either be a member name or an element index inside
+ * a JSON tree. A JSONPath expression must start with the '$' operator; each
+ * path index is separated using either the dot notation or the bracket
+ * notation, e.g.:</para>
+ * |[
+ * /* dot notation */
+ * $.store.book[0].title
+ * /* bracket notation */
+ * $['store']['book'][0]['title']
+ * ]|
+ * <para>The available operators are:</para>
+ * <table frame='all' id="json-path-operators">
+ * <title>Operators</title>
+ * <tgroup cols='4'>
+ * <colspec name='operator'/>
+ * <colspec name='description'/>
+ * <colspec name='example'/>
+ * <colspec name='results'/>
+ * <thead>
+ * <row>
+ * <entry>Operator</entry>
+ * <entry>Description</entry>
+ * <entry>Example</entry>
+ * <entry>Results</entry>
+ * </row>
+ * </thead>
+ * <tbody>
+ * <row>
+ * <entry>$</entry>
+ * <entry>The root node</entry>
+ * <entry>$</entry>
+ * <entry>The whole document</entry>
+ * </row>
+ * <row>
+ * <entry>. or []</entry>
+ * <entry>The child member or element</entry>
+ * <entry>$.store.book</entry>
+ * <entry>The contents of the book member of the store object</entry>
+ * </row>
+ * <row>
+ * <entry>..</entry>
+ * <entry>Recursive descent</entry>
+ * <entry>$..author</entry>
+ * <entry>The content of the author member in every object</entry>
+ * </row>
+ * <row>
+ * <entry>*</entry>
+ * <entry>Wildcard</entry>
+ * <entry>$.store.book[*].author</entry>
+ * <entry>The content of the author member of any object of the
+ * array contained in the book member of the store object</entry>
+ * </row>
+ * <row>
+ * <entry>[]</entry>
+ * <entry>Subscript</entry>
+ * <entry>$.store.book[0]</entry>
+ * <entry>The first element of the array contained in the book
+ * member of the store object</entry>
+ * </row>
+ * <row>
+ * <entry>[,]</entry>
+ * <entry>Set</entry>
+ * <entry>$.store.book[0,1]</entry>
+ * <entry>The first two elements of the array contained in the
+ * book member of the store object</entry>
+ * </row>
+ * <row>
+ * <entry>[start:end:step]</entry>
+ * <entry>Slice</entry>
+ * <entry>$.store.book[:2]</entry>
+ * <entry>The first two elements of the array contained in the
+ * book member of the store object; the start and step are omitted
+ * and implied to be 0 and 1, respectively</entry>
+ * </row>
+ * </tbody>
+ * </tgroup>
+ * </table>
+ * <para>More information about JSONPath is available on Stefan GÃssner's
+ * <ulink url="http://goessner.net/articles/JsonPath/">website</ulink>.</para>
+ * </refsect2>
+ *
+ * <example id="json-path-example">
+ * <title>Example of JsonPath usage</title>
+ * <para>The following example shows some of the results of using #JsonPath
+ * on a JSON tree. We use the following JSON description of a
+ * bookstore:</para>
+ * <programlisting><![CDATA[
+{ "store": {
+ "book": [
+ { "category": "reference",
+ "author": "Nigel Rees",
+ "title": "Sayings of the Century",
+ "price": "8.95"
+ },
+ { "category": "fiction",
+ "author": "Evelyn Waugh",
+ "title": "Sword of Honour",
+ "price": "12.99"
+ },
+ { "category": "fiction",
+ "author": "Herman Melville",
+ "title": "Moby Dick",
+ "isbn": "0-553-21311-3",
+ "price": "8.99"
+ },
+ { "category": "fiction",
+ "author": "J. R. R. Tolkien",
+ "title": "The Lord of the Rings",
+ "isbn": "0-395-19395-8",
+ "price": "22.99"
+ }
+ ],
+ "bicycle": {
+ "color": "red",
+ "price": "19.95"
+ }
+ }
+}
+]]></programlisting>
+ * <para>We can parse the JSON using #JsonParser:</para>
+ * <programlisting>
+ * JsonParser *parser = json_parser_new ();
+ * json_parser_load_from_data (parser, json_data, -1, NULL);
+ * </programlisting>
+ * <para>If we run the following code:</para>
+ * <programlisting>
+ * JsonNode *result;
+ * JsonPath *path = json_path_new ();
+ * json_path_compile (path, "$.store..author", NULL);
+ * result = json_path_match (path, json_parser_get_root (parser));
+ * </programlisting>
+ * <para>The <emphasis>result</emphasis> #JsonNode will contain an array
+ * with all values of the <emphasis>author</emphasis> member of the objects
+ * in the JSON tree. If we use a #JsonGenerator to convert the #JsonNode
+ * to a string and print it:</para>
+ * <programlisting>
+ * JsonGenerator *generator = json_generator_new ();
+ * char *str;
+ * json_generator_set_pretty (generator, TRUE);
+ * json_generator_set_root (generator, result);
+ * str = json_generator_to_data (generator, NULL);
+ * g_print ("Results: %s\n", str);
+ * </programlisting>
+ * <para>The output will be:</para>
+ * <programlisting><![CDATA[
+[
+ "Nigel Rees",
+ "Evelyn Waugh",
+ "Herman Melville",
+ "J. R. R. Tolkien"
+]
+]]></programlisting>
+ * </example>
+ *
+ * #JsonPath is available since JSON-GLib 0.14
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#if 0
+#include <glib/gi18n-lib.h>
+#else
+#define _(s) s
+#endif
+
+#include "json-path.h"
+
+#include "json-debug.h"
+#include "json-types-private.h"
+
+typedef enum {
+ JSON_PATH_NODE_ROOT,
+ JSON_PATH_NODE_CHILD_MEMBER,
+ JSON_PATH_NODE_CHILD_ELEMENT,
+ JSON_PATH_NODE_RECURSIVE_DESCENT,
+ JSON_PATH_NODE_WILDCARD_MEMBER,
+ JSON_PATH_NODE_WILDCARD_ELEMENT,
+ JSON_PATH_NODE_ELEMENT_SET,
+ JSON_PATH_NODE_ELEMENT_SLICE
+} PathNodeType;
+
+typedef struct _PathNode PathNode;
+
+struct _JsonPath
+{
+ GObject parent_instance;
+
+ /* the compiled path */
+ GList *nodes;
+
+ guint is_compiled : 1;
+};
+
+struct _JsonPathClass
+{
+ GObjectClass parent_class;
+};
+
+struct _PathNode
+{
+ PathNodeType node_type;
+
+ union {
+ /* JSON_PATH_NODE_CHILD_ELEMENT */
+ int element_index;
+
+ /* JSON_PATH_NODE_CHILD_MEMBER */
+ char *member_name;
+
+ /* JSON_PATH_NODE_ELEMENT_SET */
+ struct { int n_indices; int *indices; } set;
+
+ /* JSON_PATH_NODE_ELEMENT_SLICE */
+ struct { int start, end, step; } slice;
+ } data;
+};
+
+G_DEFINE_TYPE (JsonPath, json_path, G_TYPE_OBJECT)
+
+static void
+path_node_free (gpointer data)
+{
+ if (data != NULL)
+ {
+ PathNode *node = data;
+
+ switch (node->node_type)
+ {
+ case JSON_PATH_NODE_CHILD_MEMBER:
+ g_free (node->data.member_name);
+ break;
+
+ case JSON_PATH_NODE_ELEMENT_SET:
+ g_free (node->data.set.indices);
+ break;
+
+ default:
+ break;
+ }
+
+ g_free (node);
+ }
+}
+
+static void
+json_path_finalize (GObject *gobject)
+{
+ JsonPath *self = JSON_PATH (gobject);
+
+ g_list_free_full (self->nodes, path_node_free);
+
+ G_OBJECT_CLASS (json_path_parent_class)->finalize (gobject);
+}
+
+static void
+json_path_class_init (JsonPathClass *klass)
+{
+ G_OBJECT_CLASS (klass)->finalize = json_path_finalize;
+}
+
+static void
+json_path_init (JsonPath *self)
+{
+}
+
+GQuark
+json_path_error_quark (void)
+{
+ return g_quark_from_static_string ("json-path-error");
+}
+
+/**
+ * json_path_new:
+ *
+ * Creates a new #JsonPath instance.
+ *
+ * Once created, the #JsonPath object should be used with json_path_compile()
+ * and json_path_match().
+ *
+ * Return value: (transfer full): the newly created #JsonPath instance. Use
+ * g_object_unref() to free the allocated resources when done
+ *
+ * Since: 0.14
+ */
+JsonPath *
+json_path_new (void)
+{
+ return g_object_new (JSON_TYPE_PATH, NULL);
+}
+
+/**
+ * json_path_compile:
+ * @path: a #JsonPath
+ * @expression: a JSONPath expression
+ * @error: return location for a #GError, or %NULL
+ *
+ * Validates and decomposes @expression.
+ *
+ * A JSONPath expression must be compiled before calling json_path_match().
+ *
+ * Return value: %TRUE on success; on error, @error will be set with
+ * the %JSON_PATH_ERROR domain and a code from the #JsonPathError
+ * enumeration, and %FALSE will be returned
+ *
+ * Since: 0.14
+ */
+gboolean
+json_path_compile (JsonPath *path,
+ const char *expression,
+ GError **error)
+{
+ const char *p, *end_p;
+ PathNode *root = NULL;
+ GList *nodes, *l;
+
+ p = expression;
+
+ while (*p != '\0')
+ {
+ switch (*p)
+ {
+ case '$':
+ {
+ PathNode *node;
+
+ if (root != NULL)
+ {
+ g_set_error_literal (error, JSON_PATH_ERROR,
+ JSON_PATH_ERROR_INVALID_QUERY,
+ _("Only one root node is allowed in a JSONPath expression"));
+ return FALSE;
+ }
+
+ if (!(*(p + 1) == '.' || *(p + 1) == '['))
+ {
+ /* translators: the %c is the invalid character */
+ g_set_error (error, JSON_PATH_ERROR,
+ JSON_PATH_ERROR_INVALID_QUERY,
+ _("Root node followed by invalid character '%c'"),
+ *(p + 1));
+ return FALSE;
+ }
+
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_ROOT;
+
+ root = node;
+ nodes = g_list_prepend (NULL, root);
+ }
+ break;
+
+ case '.':
+ case '[':
+ {
+ PathNode *node = NULL;
+
+ if (*p == '.' && *(p + 1) == '.')
+ {
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_RECURSIVE_DESCENT;
+ }
+ else if (*p == '.' && *(p + 1) == '*')
+ {
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_WILDCARD_MEMBER;
+
+ p += 1;
+ }
+ else if (*p == '.')
+ {
+ end_p = p + 1;
+ while (!(*end_p == '.' || *end_p == '[' || *end_p == '\0'))
+ end_p += 1;
+
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_CHILD_MEMBER;
+ node->data.member_name = g_strndup (p + 1, end_p - p - 1);
+
+ p = end_p - 1;
+ }
+ else if (*p == '[' && *(p + 1) == '\'')
+ {
+ if (*(p + 2) == '*' && *(p + 3) == '\'' && *(p + 4) == ']')
+ {
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_WILDCARD_MEMBER;
+
+ p += 4;
+ }
+ else
+ {
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_CHILD_MEMBER;
+
+ end_p = strchr (p + 2, '\'');
+ node->data.member_name = g_strndup (p + 2, end_p - p - 2);
+
+ p = end_p + 1;
+ }
+ }
+ else if (*p == '[' && *(p + 1) == '*' && *(p + 2) == ']')
+ {
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_WILDCARD_ELEMENT;
+
+ p += 1;
+ }
+ else if (*p == '[')
+ {
+ int sign = 1;
+ int idx;
+
+ end_p = p + 1;
+
+ if (*end_p == '-')
+ {
+ sign = -1;
+ end_p += 1;
+ }
+
+ /* slice with missing start */
+ if (*end_p == ':')
+ {
+ int slice_end = g_ascii_strtoll (end_p + 1, (char **) &end_p, 10) * sign;
+ int slice_step = 1;
+
+ if (*end_p == ':')
+ {
+ end_p += 1;
+
+ if (*end_p == '-')
+ {
+ sign = -1;
+ end_p += 1;
+ }
+ else
+ sign = 1;
+
+ slice_step = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
+
+ if (*end_p != ']')
+ {
+ g_set_error (error, JSON_PATH_ERROR,
+ JSON_PATH_ERROR_INVALID_QUERY,
+ _("Malformed slice expression '%*s'"),
+ end_p - p,
+ p + 1);
+ goto fail;
+ }
+ }
+
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_ELEMENT_SLICE;
+ node->data.slice.start = 0;
+ node->data.slice.end = slice_end;
+ node->data.slice.step = slice_step;
+
+ nodes = g_list_prepend (nodes, node);
+ p = end_p;
+ break;
+ }
+
+ idx = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
+
+ if (*end_p == ',')
+ {
+ GArray *indices = g_array_new (FALSE, TRUE, sizeof (int));
+
+ g_array_append_val (indices, idx);
+
+ while (*end_p != ']')
+ {
+ end_p += 1;
+
+ if (*end_p == '-')
+ {
+ sign = -1;
+ end_p += 1;
+ }
+ else
+ sign = 1;
+
+ idx = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
+ if (!(*end_p == ',' || *end_p == ']'))
+ {
+ g_array_unref (indices);
+ g_set_error (error, JSON_PATH_ERROR,
+ JSON_PATH_ERROR_INVALID_QUERY,
+ _("Invalid set definition '%*s'"),
+ end_p - p,
+ p + 1);
+ goto fail;
+ }
+
+ g_array_append_val (indices, idx);
+ }
+
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_ELEMENT_SET;
+ node->data.set.n_indices = indices->len;
+ node->data.set.indices = (int *) g_array_free (indices, FALSE);
+ nodes = g_list_prepend (nodes, node);
+ p = end_p;
+ break;
+ }
+ else if (*end_p == ':')
+ {
+ int slice_start = idx;
+ int slice_end = 0;
+ int slice_step = 1;
+
+ end_p += 1;
+
+ if (*end_p == '-')
+ {
+ sign = -1;
+ end_p += 1;
+ }
+ else
+ sign = 1;
+
+ slice_end = g_ascii_strtoll (end_p, (char **) &end_p, 10) * sign;
+ if (*end_p == ':')
+ {
+ end_p += 1;
+
+ if (*end_p == '-')
+ {
+ sign = -1;
+ end_p += 1;
+ }
+ else
+ sign = 1;
+
+ slice_step = g_ascii_strtoll (end_p + 1, (char **) &end_p, 10) * sign;
+ }
+
+ if (*end_p != ']')
+ {
+ g_set_error (error, JSON_PATH_ERROR,
+ JSON_PATH_ERROR_INVALID_QUERY,
+ _("Invalid slice definition '%*s'"),
+ end_p - p,
+ p + 1);
+ goto fail;
+ }
+
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_ELEMENT_SLICE;
+ node->data.slice.start = slice_start;
+ node->data.slice.end = slice_end;
+ node->data.slice.step = slice_step;
+ nodes = g_list_prepend (nodes, node);
+ p = end_p;
+ break;
+ }
+ else if (*end_p == ']')
+ {
+ node = g_new0 (PathNode, 1);
+ node->node_type = JSON_PATH_NODE_CHILD_ELEMENT;
+ node->data.element_index = idx;
+ nodes = g_list_prepend (nodes, node);
+ p = end_p;
+ break;
+ }
+ else
+ {
+ g_set_error (error, JSON_PATH_ERROR,
+ JSON_PATH_ERROR_INVALID_QUERY,
+ _("Invalid array index definition '%*s'"),
+ end_p - p,
+ p + 1);
+ goto fail;
+ }
+ }
+ else
+ break;
+
+ if (node != NULL)
+ nodes = g_list_prepend (nodes, node);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ p += 1;
+ }
+
+ nodes = g_list_reverse (nodes);
+
+#ifdef JSON_ENABLE_DEBUG
+ if (_json_get_debug_flags () & JSON_DEBUG_PATH)
+ {
+ GString *buf = g_string_new (NULL);
+
+ for (l = nodes; l != NULL; l = l->next)
+ {
+ PathNode *cur_node = l->data;
+
+ switch (cur_node->node_type)
+ {
+ case JSON_PATH_NODE_ROOT:
+ g_string_append (buf, "<root");
+ break;
+
+ case JSON_PATH_NODE_CHILD_MEMBER:
+ g_string_append_printf (buf, "<member '%s'", cur_node->data.member_name);
+ break;
+
+ case JSON_PATH_NODE_CHILD_ELEMENT:
+ g_string_append_printf (buf, "<element '%d'", cur_node->data.element_index);
+ break;
+
+ case JSON_PATH_NODE_RECURSIVE_DESCENT:
+ g_string_append (buf, "<recursive descent");
+ break;
+
+ case JSON_PATH_NODE_WILDCARD_MEMBER:
+ g_string_append (buf, "<wildcard member");
+ break;
+
+ case JSON_PATH_NODE_WILDCARD_ELEMENT:
+ g_string_append (buf, "<wildcard element");
+ break;
+
+ case JSON_PATH_NODE_ELEMENT_SET:
+ {
+ int i;
+
+ g_string_append (buf, "<element set ");
+ for (i = 0; i < cur_node->data.set.n_indices - 1; i++)
+ g_string_append_printf (buf, "'%d', ", cur_node->data.set.indices[i]);
+
+ g_string_append_printf (buf, "'%d'", cur_node->data.set.indices[i]);
+ }
+ break;
+
+ case JSON_PATH_NODE_ELEMENT_SLICE:
+ g_string_append_printf (buf, "<slice start '%d', end '%d', step '%d'",
+ cur_node->data.slice.start,
+ cur_node->data.slice.end,
+ cur_node->data.slice.step);
+ break;
+
+ default:
+ g_string_append (buf, "<unknown node");
+ break;
+ }
+
+ if (l->next != NULL)
+ g_string_append (buf, ">, ");
+ else
+ g_string_append (buf, ">");
+ }
+
+ g_message ("[PATH] " G_STRLOC ": expression '%s' => '%s'", expression, buf->str);
+ g_string_free (buf, TRUE);
+ }
+#endif /* JSON_ENABLE_DEBUG */
+
+ if (path->nodes != NULL)
+ g_list_free_full (path->nodes, path_node_free);
+
+ path->nodes = nodes;
+ path->is_compiled = (path->nodes != NULL);
+
+ return path->nodes != NULL;
+
+fail:
+ g_list_free_full (nodes, path_node_free);
+
+ return FALSE;
+}
+
+static void
+walk_path_node (GList *path,
+ JsonNode *root,
+ JsonArray *results)
+{
+ PathNode *node = path->data;
+
+ switch (node->node_type)
+ {
+ case JSON_PATH_NODE_ROOT:
+ walk_path_node (path->next, root, results);
+ break;
+
+ case JSON_PATH_NODE_CHILD_MEMBER:
+ if (JSON_NODE_HOLDS_OBJECT (root))
+ {
+ JsonObject *object = json_node_get_object (root);
+
+ if (json_object_has_member (object, node->data.member_name))
+ {
+ JsonNode *member = json_object_get_member (object, node->data.member_name);
+
+ if (path->next == NULL)
+ {
+ JSON_NOTE (PATH, "end of path at member '%s'", node->data.member_name);
+ json_array_add_element (results, json_node_copy (member));
+ }
+ else
+ walk_path_node (path->next, member, results);
+ }
+ }
+ break;
+
+ case JSON_PATH_NODE_CHILD_ELEMENT:
+ if (JSON_NODE_HOLDS_ARRAY (root))
+ {
+ JsonArray *array = json_node_get_array (root);
+
+ if (json_array_get_length (array) >= node->data.element_index)
+ {
+ JsonNode *element = json_array_get_element (array, node->data.element_index);
+
+ if (path->next == NULL)
+ {
+ JSON_NOTE (PATH, "end of path at element '%d'", node->data.element_index);
+ json_array_add_element (results, json_node_copy (element));
+ }
+ else
+ walk_path_node (path->next, element, results);
+ }
+ }
+ break;
+
+ case JSON_PATH_NODE_RECURSIVE_DESCENT:
+ {
+ PathNode *tmp = path->next->data;
+
+ switch (json_node_get_node_type (root))
+ {
+ case JSON_NODE_OBJECT:
+ {
+ JsonObject *object = json_node_get_object (root);
+ GList *members, *l;
+
+ members = json_object_get_members (object);
+ for (l = members; l != NULL; l = l->next)
+ {
+ JsonNode *m = json_object_get_member (object, l->data);
+
+ if (tmp->node_type == JSON_PATH_NODE_CHILD_MEMBER &&
+ strcmp (tmp->data.member_name, l->data) == 0)
+ {
+ JSON_NOTE (PATH, "entering '%s'", tmp->data.member_name);
+ walk_path_node (path->next, root, results);
+ }
+ else
+ {
+ JSON_NOTE (PATH, "recursing into '%s'", (char *) l->data);
+ walk_path_node (path, m, results);
+ }
+ }
+ g_list_free (members);
+ }
+ break;
+
+ case JSON_NODE_ARRAY:
+ {
+ JsonArray *array = json_node_get_array (root);
+ GList *members, *l;
+ int i;
+
+ members = json_array_get_elements (array);
+ for (l = members, i = 0; l != NULL; l = l->next, i += 1)
+ {
+ JsonNode *m = l->data;
+
+ if (tmp->node_type == JSON_PATH_NODE_CHILD_ELEMENT &&
+ tmp->data.element_index == i)
+ {
+ JSON_NOTE (PATH, "entering '%d'", tmp->data.element_index);
+ walk_path_node (path->next, root, results);
+ }
+ else
+ {
+ JSON_NOTE (PATH, "recursing into '%d'", i);
+ walk_path_node (path, m, results);
+ }
+ }
+ g_list_free (members);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case JSON_PATH_NODE_WILDCARD_MEMBER:
+ if (JSON_NODE_HOLDS_OBJECT (root))
+ {
+ JsonObject *object = json_node_get_object (root);
+ GList *members, *l;
+
+ members = json_object_get_members (object);
+ for (l = members; l != NULL; l = l->next)
+ {
+ JsonNode *member = json_object_get_member (object, l->data);
+
+ if (path->next != NULL)
+ walk_path_node (path->next, member, results);
+ else
+ {
+ JSON_NOTE (PATH, "glob match member '%s'", (char *) l->data);
+ json_array_add_element (results, json_node_copy (root));
+ }
+ }
+ g_list_free (members);
+ }
+ else
+ json_array_add_element (results, json_node_copy (root));
+ break;
+
+ case JSON_PATH_NODE_WILDCARD_ELEMENT:
+ if (JSON_NODE_HOLDS_ARRAY (root))
+ {
+ JsonArray *array = json_node_get_array (root);
+ GList *elements, *l;
+ int i;
+
+ elements = json_array_get_elements (array);
+ for (l = elements, i = 0; l != NULL; l = l->next, i += 1)
+ {
+ JsonNode *element = l->data;
+
+ if (path->next != NULL)
+ walk_path_node (path->next, element, results);
+ else
+ {
+ JSON_NOTE (PATH, "glob match element '%d'", i);
+ json_array_add_element (results, json_node_copy (root));
+ }
+ }
+ g_list_free (elements);
+ }
+ else
+ json_array_add_element (results, json_node_copy (root));
+ break;
+
+ case JSON_PATH_NODE_ELEMENT_SET:
+ if (JSON_NODE_HOLDS_ARRAY (root))
+ {
+ JsonArray *array = json_node_get_array (root);
+ int i;
+
+ for (i = 0; i < node->data.set.n_indices; i += 1)
+ {
+ int idx = node->data.set.indices[i];
+ JsonNode *element = json_array_get_element (array, idx);
+
+ if (path->next != NULL)
+ walk_path_node (path->next, element, results);
+ else
+ {
+ JSON_NOTE (PATH, "set element '%d'", idx);
+ json_array_add_element (results, json_node_copy (element));
+ }
+ }
+ }
+ break;
+
+ case JSON_PATH_NODE_ELEMENT_SLICE:
+ if (JSON_NODE_HOLDS_ARRAY (root))
+ {
+ JsonArray *array = json_node_get_array (root);
+ int i, start, end;
+
+ if (node->data.slice.start < 0)
+ {
+ start = json_array_get_length (array)
+ + node->data.slice.start;
+
+ end = json_array_get_length (array)
+ + node->data.slice.end;
+ }
+ else
+ {
+ start = node->data.slice.start;
+ end = node->data.slice.end;
+ }
+
+ for (i = start; i < end; i += node->data.slice.step)
+ {
+ JsonNode *element = json_array_get_element (array, i);
+
+ if (path->next != NULL)
+ walk_path_node (path->next, element, results);
+ else
+ {
+ JSON_NOTE (PATH, "slice element '%d'", i);
+ json_array_add_element (results, json_node_copy (element));
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * json_path_match:
+ * @path: a compiled #JsonPath
+ * @root: a #JsonNode
+ *
+ * Matches the JSON tree pointed by @root using the expression compiled
+ * into the #JsonPath.
+ *
+ * The matching #JsonNode<!-- -->s will be copied into a #JsonArray and
+ * returned wrapped in a #JsonNode.
+ *
+ * Return value: (transfer full): a newly-created #JsonNode of type
+ * %JSON_NODE_ARRAY containing an array of matching #JsonNode<!-- -->s.
+ * Use json_node_free() when done
+ *
+ * Since: 0.14
+ */
+JsonNode *
+json_path_match (JsonPath *path,
+ JsonNode *root)
+{
+ JsonArray *results;
+ JsonNode *retval;
+
+ g_return_val_if_fail (JSON_IS_PATH (path), NULL);
+ g_return_val_if_fail (path->is_compiled, NULL);
+ g_return_val_if_fail (root != NULL, NULL);
+
+ results = json_array_new ();
+
+ walk_path_node (path->nodes, root, results);
+
+ retval = json_node_new (JSON_NODE_ARRAY);
+ json_node_take_array (retval, results);
+
+ return retval;
+}
+
+/**
+ * json_path_query:
+ * @expression: a JSONPath expression
+ * @root: the root of a JSON tree
+ * @error: return location for a #GError, or %NULL
+ *
+ * Queries a JSON tree using a JSONPath expression.
+ *
+ * This function is a simple wrapper around json_path_new(),
+ * json_path_compile() and json_path_match(). It implicitly
+ * creates a #JsonPath instance, compiles @expression and
+ * matches it against the JSON tree pointed by @root.
+ *
+ * Return value: (transfer full): a newly-created #JsonNode of type
+ * %JSON_NODE_ARRAY containing an array of matching #JsonNode<!-- -->s.
+ * Use json_node_free() when done
+ *
+ * Since: 0.14
+ */
+JsonNode *
+json_path_query (const char *expression,
+ JsonNode *root,
+ GError **error)
+{
+ JsonPath *path = json_path_new ();
+ JsonNode *retval;
+
+ if (!json_path_compile (path, expression, error))
+ {
+ g_object_unref (path);
+ return NULL;
+ }
+
+ retval = json_path_match (path, root);
+
+ g_object_unref (path);
+
+ return retval;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-path.h b/src/glib-jsonrpc/json-glib/json-path.h
new file mode 100644
index 0000000..2bae608
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-path.h
@@ -0,0 +1,97 @@
+/* json-path.h - JSONPath implementation
+ *
+ * This file is part of JSON-GLib
+ * Copyright  2011 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_PATH_H__
+#define __JSON_PATH_H__
+
+#include <json-glib/json-types.h>
+
+G_BEGIN_DECLS
+
+#define JSON_TYPE_PATH (json_path_get_type ())
+#define JSON_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JSON_TYPE_PATH, JsonPath))
+#define JSON_IS_PATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JSON_TYPE_PATH))
+
+/**
+ * JSON_PATH_ERROR:
+ *
+ * Error domain for #JsonPath errors
+ *
+ * Since: 0.14
+ */
+#define JSON_PATH_ERROR (json_path_error_quark ())
+
+/**
+ * JsonPathError:
+ * @JSON_PATH_ERROR_INVALID_QUERY: Invalid query
+ *
+ * Error code enumeration for the %JSON_PATH_ERROR domain.
+ *
+ * Since: 0.14
+ */
+typedef enum {
+ JSON_PATH_ERROR_INVALID_QUERY
+} JsonPathError;
+
+/**
+ * JsonPath:
+ *
+ * The <structname>JsonPath</structname> structure is an opaque object
+ * whose members cannot be directly accessed except through the provided
+ * API.
+ *
+ * Since: 0.14
+ */
+typedef struct _JsonPath JsonPath;
+
+/**
+ * JsonPathClass:
+ *
+ * The <structname>JsonPathClass</structname> structure is an opaque
+ * object class whose members cannot be directly accessed.
+ *
+ * Since: 0.14
+ */
+typedef struct _JsonPathClass JsonPathClass;
+
+GType json_path_get_type (void) G_GNUC_CONST;
+GQuark json_path_error_quark (void);
+
+JsonPath * json_path_new (void);
+
+gboolean json_path_compile (JsonPath *path,
+ const char *expression,
+ GError **error);
+JsonNode * json_path_match (JsonPath *path,
+ JsonNode *root);
+
+JsonNode * json_path_query (const char *expression,
+ JsonNode *root,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __JSON_PATH_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-reader.c b/src/glib-jsonrpc/json-glib/json-reader.c
new file mode 100644
index 0000000..89e422f
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-reader.c
@@ -0,0 +1,1069 @@
+/* json-reader.h - JSON cursor parser
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+/**
+ * SECTION:json-reader
+ * @Title: JsonReader
+ * @short_description: A cursor-based parser
+ *
+ * #JsonReader provides a simple, cursor-based API for parsing a JSON DOM. It
+ * is similar, in spirit, to the XML Reader API.
+ *
+ * In case of error, #JsonReader will be set in an error state; all subsequent
+ * calls will simply be ignored until a function that resets the error state is
+ * called, e.g.:
+ *
+ * |[
+ * /* ask for the 7th element; if the element does not exist, the
+ * * reader will be put in an error state
+ * */
+ * json_reader_read_element (reader, 6);
+ *
+ * /* in case of error, this will return NULL, otherwise it will
+ * * return the value of the element
+ * */
+ * str = json_reader_get_string_value (value);
+ *
+ * /* this function resets the error state if any was set */
+ * json_reader_end_element (reader);
+ * ]|
+ *
+ * If you want to detect the error state as soon as possible, you can use
+ * json_reader_get_error():
+ *
+ * |[
+ * /* like the example above, but in this case we print out the
+ * * error immediately
+ * */
+ * if (!json_reader_read_element (reader, 6))
+ * {
+ * const GError *error = json_reader_get_error (reader);
+ * g_print ("Unable to read the element: %s", error->message);
+ * }
+ * ]|
+ *
+ * #JsonReader is available since JSON-GLib 0.12.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#if 0
+#include <glib/gi18n-lib.h>
+#else
+#define _(s) s
+#endif
+
+#include "json-reader.h"
+
+#include "json-types-private.h"
+
+#include "json-debug.h"
+
+#define json_reader_return_if_error_set(r) G_STMT_START { \
+ if (((JsonReader *) (r))->priv->error != NULL) \
+ return; } G_STMT_END
+
+#define json_reader_return_val_if_error_set(r,v) G_STMT_START { \
+ if (((JsonReader *) (r))->priv->error != NULL) \
+ return (v); } G_STMT_END
+
+struct _JsonReaderPrivate
+{
+ JsonNode *root;
+
+ JsonNode *current_node;
+ JsonNode *previous_node;
+
+ gchar *current_member;
+
+ GError *error;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_ROOT,
+
+ PROP_LAST
+};
+
+static GParamSpec *reader_properties[PROP_LAST] = { NULL, };
+
+G_DEFINE_TYPE (JsonReader, json_reader, G_TYPE_OBJECT);
+
+static void
+json_reader_finalize (GObject *gobject)
+{
+ JsonReaderPrivate *priv = JSON_READER (gobject)->priv;
+
+ if (priv->root != NULL)
+ json_node_free (priv->root);
+
+ if (priv->error != NULL)
+ g_clear_error (&priv->error);
+
+ g_free (priv->current_member);
+
+ G_OBJECT_CLASS (json_reader_parent_class)->finalize (gobject);
+}
+
+static void
+json_reader_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ json_reader_set_root (JSON_READER (gobject), g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+json_reader_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_boxed (value, JSON_READER (gobject)->priv->root);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+json_reader_class_init (JsonReaderClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (JsonReaderPrivate));
+
+ /**
+ * JsonReader:root:
+ *
+ * The root of the JSON tree that the #JsonReader should read.
+ *
+ * Since: 0.12
+ */
+ reader_properties[PROP_ROOT] =
+ g_param_spec_boxed ("root",
+ "Root Node",
+ "The root of the tree to read",
+ JSON_TYPE_NODE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ gobject_class->finalize = json_reader_finalize;
+ gobject_class->set_property = json_reader_set_property;
+ gobject_class->get_property = json_reader_get_property;
+ g_object_class_install_properties (gobject_class, PROP_LAST, reader_properties);
+}
+
+static void
+json_reader_init (JsonReader *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, JSON_TYPE_READER,
+ JsonReaderPrivate);
+}
+
+GQuark
+json_reader_error_quark (void)
+{
+ return g_quark_from_static_string ("json-reader-error");
+}
+
+/**
+ * json_reader_new:
+ * @node: (allow-none): a #JsonNode, or %NULL
+ *
+ * Creates a new #JsonReader. You can use this object to read the contents of
+ * the JSON tree starting from @node
+ *
+ * Return value: the newly created #JsonReader. Use g_object_unref() to
+ * release the allocated resources when done
+ *
+ * Since: 0.12
+ */
+JsonReader *
+json_reader_new (JsonNode *node)
+{
+ return g_object_new (JSON_TYPE_READER, "root", node, NULL);
+}
+
+/*
+ * json_reader_unset_error:
+ * @reader: a #JsonReader
+ *
+ * Unsets the error state of @reader, if set
+ */
+static inline void
+json_reader_unset_error (JsonReader *reader)
+{
+ if (reader->priv->error != NULL)
+ g_clear_error (&(reader->priv->error));
+}
+
+/**
+ * json_reader_set_root:
+ * @reader: a #JsonReader
+ * @root: (allow-none): a #JsonNode
+ *
+ * Sets the root #JsonNode to be read by @reader. The @reader will take
+ * a copy of @root
+ *
+ * If another #JsonNode is currently set as root, it will be replaced.
+ *
+ * Since: 0.12
+ */
+void
+json_reader_set_root (JsonReader *reader,
+ JsonNode *root)
+{
+ JsonReaderPrivate *priv;
+
+ g_return_if_fail (JSON_IS_READER (reader));
+
+ priv = reader->priv;
+
+ if (priv->root == root)
+ return;
+
+ if (priv->root != NULL)
+ {
+ json_node_free (priv->root);
+ priv->root = NULL;
+ priv->current_node = NULL;
+ priv->previous_node = NULL;
+ }
+
+ if (root != NULL)
+ {
+ priv->root = json_node_copy (root);
+ priv->current_node = priv->root;
+ priv->previous_node = NULL;
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (reader), reader_properties[PROP_ROOT]);
+}
+
+/*
+ * json_reader_ser_error:
+ * @reader: a #JsonReader
+ * @error_code: the #JsonReaderError code for the error
+ * @error_fmt: format string
+ * @Varargs: list of arguments for the @error_fmt string
+ *
+ * Sets the error state of @reader using the given error code
+ * and string
+ *
+ * Return value: %FALSE, to be used to return immediately from
+ * the caller function
+ */
+static gboolean
+json_reader_set_error (JsonReader *reader,
+ JsonReaderError error_code,
+ const gchar *error_fmt,
+ ...)
+{
+ JsonReaderPrivate *priv = reader->priv;
+ va_list args;
+ gchar *error_msg;
+
+ if (priv->error != NULL)
+ g_clear_error (&priv->error);
+
+ va_start (args, error_fmt);
+ error_msg = g_strdup_vprintf (error_fmt, args);
+ va_end (args);
+
+ g_set_error_literal (&priv->error, JSON_READER_ERROR,
+ error_code,
+ error_msg);
+
+ g_free (error_msg);
+
+ return FALSE;
+}
+
+/**
+ * json_reader_get_error:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the #GError currently set on @reader, if the #JsonReader
+ * is in error state
+ *
+ * Return value: (transfer none): the pointer to the error, or %NULL
+ *
+ * Since: 0.12
+ */
+const GError *
+json_reader_get_error (JsonReader *reader)
+{
+ g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
+
+ return reader->priv->error;
+}
+
+/**
+ * json_reader_is_array:
+ * @reader: a #JsonReader
+ *
+ * Checks whether the @reader is currently on an array
+ *
+ * Return value: %TRUE if the #JsonReader is on an array, and %FALSE
+ * otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_is_array (JsonReader *reader)
+{
+ g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ if (reader->priv->current_node == NULL)
+ return FALSE;
+
+ return JSON_NODE_HOLDS_ARRAY (reader->priv->current_node);
+}
+
+/**
+ * json_reader_is_object:
+ * @reader: a #JsonReader
+ *
+ * Checks whether the @reader is currently on an object
+ *
+ * Return value: %TRUE if the #JsonReader is on an object, and %FALSE
+ * otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_is_object (JsonReader *reader)
+{
+ g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ if (reader->priv->current_node == NULL)
+ return FALSE;
+
+ return JSON_NODE_HOLDS_OBJECT (reader->priv->current_node);
+}
+
+/**
+ * json_reader_is_value:
+ * @reader: a #JsonReader
+ *
+ * Checks whether the @reader is currently on a value
+ *
+ * Return value: %TRUE if the #JsonReader is on a value, and %FALSE
+ * otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_is_value (JsonReader *reader)
+{
+ g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ if (reader->priv->current_node == NULL)
+ return FALSE;
+
+ return JSON_NODE_HOLDS_VALUE (reader->priv->current_node);
+}
+
+/**
+ * json_reader_read_element:
+ * @reader: a #JsonReader
+ * @index_: the index of the element
+ *
+ * Advances the cursor of @reader to the element @index_ of the array
+ * or the object at the current position.
+ *
+ * You can use the json_reader_get_value* family of functions to retrieve
+ * the value of the element; for instance:
+ *
+ * |[
+ * json_reader_read_element (reader, 0);
+ * int_value = json_reader_get_int_value (reader);
+ * ]|
+ *
+ * After reading the value, json_reader_end_element() should be called to
+ * reposition the cursor inside the #JsonReader, e.g.:
+ *
+ * |[
+ * json_reader_read_element (reader, 1);
+ * str_value = json_reader_get_string_value (reader);
+ * json_reader_end_element (reader);
+ *
+ * json_reader_read_element (reader, 2);
+ * str_value = json_reader_get_string_value (reader);
+ * json_reader_end_element (reader);
+ * ]|
+ *
+ * If @reader is not currently on an array or an object, or if the @index_ is
+ * bigger than the size of the array or the object, the #JsonReader will be
+ * put in an error state until json_reader_end_element() is called.
+ *
+ * Return value: %TRUE on success, and %FALSE otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_read_element (JsonReader *reader,
+ guint index_)
+{
+ JsonReaderPrivate *priv;
+
+ g_return_val_if_fail (JSON_READER (reader), FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ priv = reader->priv;
+
+ if (priv->current_node == NULL)
+ priv->current_node = priv->root;
+
+ if (!(JSON_NODE_HOLDS_ARRAY (priv->current_node) ||
+ JSON_NODE_HOLDS_OBJECT (priv->current_node)))
+ return json_reader_set_error (reader, JSON_READER_ERROR_NO_ARRAY,
+ _("The current node is of type '%s', but "
+ "an array or an object was expected."),
+ json_node_type_name (priv->current_node));
+
+ switch (json_node_get_node_type (priv->current_node))
+ {
+ case JSON_NODE_ARRAY:
+ {
+ JsonArray *array = json_node_get_array (priv->current_node);
+
+ if (index_ >= json_array_get_length (array))
+ return json_reader_set_error (reader, JSON_READER_ERROR_INVALID_INDEX,
+ _("The index '%d' is greater than the size "
+ "of the array at the current position."),
+ index_);
+
+ priv->previous_node = priv->current_node;
+ priv->current_node = json_array_get_element (array, index_);
+ }
+ break;
+
+ case JSON_NODE_OBJECT:
+ {
+ JsonObject *object = json_node_get_object (priv->current_node);
+ GList *members;
+ const gchar *name;
+
+ if (index_ >= json_object_get_size (object))
+ return json_reader_set_error (reader, JSON_READER_ERROR_INVALID_INDEX,
+ _("The index '%d' is greater than the size "
+ "of the object at the current position."),
+ index_);
+
+ priv->previous_node = priv->current_node;
+ g_free (priv->current_member);
+
+ members = json_object_get_members (object);
+ name = g_list_nth_data (members, index_);
+
+ priv->current_node = json_object_get_member (object, name);
+ priv->current_member = g_strdup (name);
+
+ g_list_free (members);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * json_reader_end_element:
+ * @reader: a #JsonReader
+ *
+ * Moves the cursor back to the previous node after being positioned
+ * inside an array
+ *
+ * This function resets the error state of @reader, if any was set
+ *
+ * Since: 0.12
+ */
+void
+json_reader_end_element (JsonReader *reader)
+{
+ JsonReaderPrivate *priv;
+ JsonNode *tmp;
+
+ g_return_if_fail (JSON_IS_READER (reader));
+
+ json_reader_unset_error (reader);
+
+ priv = reader->priv;
+
+ if (priv->previous_node != NULL)
+ tmp = json_node_get_parent (priv->previous_node);
+ else
+ tmp = NULL;
+
+ g_free (priv->current_member);
+ priv->current_member = NULL;
+
+ priv->current_node = priv->previous_node;
+ priv->previous_node = tmp;
+}
+
+/**
+ * json_reader_count_elements:
+ * @reader: a #JsonReader
+ *
+ * Counts the elements of the current position, if @reader is
+ * positioned on an array
+ *
+ * Return value: the number of elements, or -1. In case of failure
+ * the #JsonReader is set in an error state
+ *
+ * Since: 0.12
+ */
+gint
+json_reader_count_elements (JsonReader *reader)
+{
+ JsonReaderPrivate *priv;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), -1);
+
+ priv = reader->priv;
+
+ if (priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return -1;
+ }
+
+ if (!JSON_NODE_HOLDS_ARRAY (priv->current_node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_ARRAY,
+ _("The current position holds a '%s' and not an array"),
+ json_node_type_get_name (JSON_NODE_TYPE (priv->current_node)));
+ return -1;
+ }
+
+ return json_array_get_length (json_node_get_array (priv->current_node));
+}
+
+/**
+ * json_reader_read_member:
+ * @reader: a #JsonReader
+ * @member_name: the name of the member to read
+ *
+ * Advances the cursor of @reader to the @member_name of the object at the
+ * current position.
+ *
+ * You can use the json_reader_get_value* family of functions to retrieve
+ * the value of the member; for instance:
+ *
+ * |[
+ * json_reader_read_member (reader, "width");
+ * width = json_reader_get_int_value (reader);
+ * ]|
+ *
+ * After reading the value, json_reader_end_member() should be called to
+ * reposition the cursor inside the #JsonReader, e.g.:
+ *
+ * |[
+ * json_reader_read_member (reader, "author");
+ * author = json_reader_get_string_value (reader);
+ * json_reader_end_element (reader);
+ *
+ * json_reader_read_element (reader, "title");
+ * title = json_reader_get_string_value (reader);
+ * json_reader_end_element (reader);
+ * ]|
+ *
+ * If @reader is not currently on an object, or if the @member_name is not
+ * defined in the object, the #JsonReader will be put in an error state until
+ * json_reader_end_member() is called.
+ *
+ * Return value: %TRUE on success, and %FALSE otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_read_member (JsonReader *reader,
+ const gchar *member_name)
+{
+ JsonReaderPrivate *priv;
+ JsonObject *object;
+
+ g_return_val_if_fail (JSON_READER (reader), FALSE);
+ g_return_val_if_fail (member_name != NULL, FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ priv = reader->priv;
+
+ if (priv->current_node == NULL)
+ priv->current_node = priv->root;
+
+ if (!JSON_NODE_HOLDS_OBJECT (priv->current_node))
+ return json_reader_set_error (reader, JSON_READER_ERROR_NO_OBJECT,
+ _("The current node is of type '%s', but "
+ "an object was expected."),
+ json_node_type_name (priv->current_node));
+
+ object = json_node_get_object (priv->current_node);
+ if (!json_object_has_member (object, member_name))
+ return json_reader_set_error (reader, JSON_READER_ERROR_INVALID_MEMBER,
+ _("The member '%s' is not defined in the "
+ "object at the current position."),
+ member_name);
+
+ g_free (priv->current_member);
+
+ priv->previous_node = priv->current_node;
+ priv->current_node = json_object_get_member (object, member_name);
+ priv->current_member = g_strdup (member_name);
+
+ return TRUE;
+}
+
+/**
+ * json_reader_end_member:
+ * @reader: a #JsonReader
+ *
+ * Moves the cursor back to the previous node after being positioned
+ * inside an object
+ *
+ * This function resets the error state of @reader, if any was set
+ *
+ * Since: 0.12
+ */
+void
+json_reader_end_member (JsonReader *reader)
+{
+ JsonReaderPrivate *priv;
+ JsonNode *tmp;
+
+ g_return_if_fail (JSON_IS_READER (reader));
+
+ json_reader_unset_error (reader);
+
+ priv = reader->priv;
+
+ if (priv->previous_node != NULL)
+ tmp = json_node_get_parent (priv->previous_node);
+ else
+ tmp = NULL;
+
+ g_free (priv->current_member);
+ priv->current_member = NULL;
+
+ priv->current_node = priv->previous_node;
+ priv->previous_node = tmp;
+}
+
+/**
+ * json_reader_list_members:
+ * @reader: a #JsonReader
+ *
+ * Retrieves a list of member names from the current position, if @reader
+ * is positioned on an object.
+ *
+ * Return value: (transfer full): a newly allocated, %NULL-terminated
+ * array of strings holding the members name. Use g_strfreev() when
+ * done.
+ *
+ * Since: 0.14
+ */
+gchar **
+json_reader_list_members (JsonReader *reader)
+{
+ JsonReaderPrivate *priv;
+ GList *members, *l;
+ gchar **retval;
+ gint i;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), NULL);
+
+ priv = reader->priv;
+
+ if (priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return NULL;
+ }
+
+ if (!JSON_NODE_HOLDS_OBJECT (priv->current_node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_OBJECT,
+ _("The current position holds a '%s' and not an object"),
+ json_node_type_get_name (JSON_NODE_TYPE (priv->current_node)));
+ return NULL;
+ }
+
+ members = json_object_get_members (json_node_get_object (priv->current_node));
+ if (members == NULL)
+ return NULL;
+
+ retval = g_new (gchar*, g_list_length (members) + 1);
+ for (l = members, i = 0; l != NULL; l = l->next, i += 1)
+ retval[i] = g_strdup (l->data);
+
+ retval[i] = NULL;
+
+ g_list_free (members);
+
+ return retval;
+}
+
+/**
+ * json_reader_count_members:
+ * @reader: a #JsonReader
+ *
+ * Counts the members of the current position, if @reader is
+ * positioned on an object
+ *
+ * Return value: the number of members, or -1. In case of failure
+ * the #JsonReader is set in an error state
+ *
+ * Since: 0.12
+ */
+gint
+json_reader_count_members (JsonReader *reader)
+{
+ JsonReaderPrivate *priv;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), -1);
+
+ priv = reader->priv;
+
+ if (priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return -1;
+ }
+
+ if (!JSON_NODE_HOLDS_OBJECT (priv->current_node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_OBJECT,
+ _("The current position holds a '%s' and not an object"),
+ json_node_type_get_name (JSON_NODE_TYPE (priv->current_node)));
+ return -1;
+ }
+
+ return json_object_get_size (json_node_get_object (priv->current_node));
+}
+
+/**
+ * json_reader_get_value:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the #JsonNode of the current position of @reader
+ *
+ * Return value: (transfer none): a #JsonNode, or %NULL. The returned node
+ * is owned by the #JsonReader and it should not be modified or freed
+ * directly
+ *
+ * Since: 0.12
+ */
+JsonNode *
+json_reader_get_value (JsonReader *reader)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), NULL);
+ json_reader_return_val_if_error_set (reader, NULL);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return NULL;
+ }
+
+ node = reader->priv->current_node;
+
+ if (!JSON_NODE_HOLDS_VALUE (node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
+ _("The current position holds a '%s' and not a value"),
+ json_node_type_get_name (JSON_NODE_TYPE (node)));
+ return NULL;
+ }
+
+ return reader->priv->current_node;
+}
+
+/**
+ * json_reader_get_int_value:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the integer value of the current position of @reader
+ *
+ * Return value: the integer value
+ *
+ * Since: 0.12
+ */
+gint64
+json_reader_get_int_value (JsonReader *reader)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), 0);
+ json_reader_return_val_if_error_set (reader, 0);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return 0;
+ }
+
+ node = reader->priv->current_node;
+
+ if (!JSON_NODE_HOLDS_VALUE (node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
+ _("The current position holds a '%s' and not a value"),
+ json_node_type_get_name (JSON_NODE_TYPE (node)));
+ return 0;
+ }
+
+ if (json_node_get_value_type (node) != G_TYPE_INT64)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_TYPE,
+ _("The current position does not hold an integer type"));
+ return 0;
+ }
+
+ return json_node_get_int (reader->priv->current_node);
+}
+
+/**
+ * json_reader_get_double_value:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the floating point value of the current position of @reader
+ *
+ * Return value: the floating point value
+ *
+ * Since: 0.12
+ */
+gdouble
+json_reader_get_double_value (JsonReader *reader)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), 0.0);
+ json_reader_return_val_if_error_set (reader, 0.0);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return 0.0;
+ }
+
+ node = reader->priv->current_node;
+
+ if (!JSON_NODE_HOLDS_VALUE (node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
+ _("The current position holds a '%s' and not a value"),
+ json_node_type_get_name (JSON_NODE_TYPE (node)));
+ return 0.0;
+ }
+
+ if (json_node_get_value_type (node) != G_TYPE_DOUBLE)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_TYPE,
+ _("The current position does not hold a floating point type"));
+ return 0.0;
+ }
+
+ return json_node_get_double (reader->priv->current_node);
+}
+
+/**
+ * json_reader_get_string_value:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the string value of the current position of @reader
+ *
+ * Return value: the string value
+ *
+ * Since: 0.12
+ */
+const gchar *
+json_reader_get_string_value (JsonReader *reader)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), NULL);
+ json_reader_return_val_if_error_set (reader, NULL);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return NULL;
+ }
+
+ node = reader->priv->current_node;
+
+ if (!JSON_NODE_HOLDS_VALUE (node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
+ _("The current position holds a '%s' and not a value"),
+ json_node_type_get_name (JSON_NODE_TYPE (node)));
+ return NULL;
+ }
+
+ if (json_node_get_value_type (node) != G_TYPE_STRING)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_TYPE,
+ _("The current position does not hold a string type"));
+ return NULL;
+ }
+
+ return json_node_get_string (reader->priv->current_node);
+}
+
+/**
+ * json_reader_get_boolean_value:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the boolean value of the current position of @reader
+ *
+ * Return value: the boolean value
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_get_boolean_value (JsonReader *reader)
+{
+ JsonNode *node;
+
+ g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return FALSE;
+ }
+
+ node = reader->priv->current_node;
+
+ if (!JSON_NODE_HOLDS_VALUE (node))
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
+ _("The current position holds a '%s' and not a value"),
+ json_node_type_get_name (JSON_NODE_TYPE (node)));
+ return FALSE;
+ }
+
+ if (json_node_get_value_type (node) != G_TYPE_BOOLEAN)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_TYPE,
+ _("The current position does not hold a boolean type"));
+ return FALSE;
+ }
+
+ return json_node_get_boolean (node);
+}
+
+/**
+ * json_reader_get_null_value:
+ * @reader: a #JsonReader
+ *
+ * Checks whether the value of the current position of @reader is 'null'
+ *
+ * Return value: %TRUE if 'null' is set, and %FALSE otherwise
+ *
+ * Since: 0.12
+ */
+gboolean
+json_reader_get_null_value (JsonReader *reader)
+{
+ g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
+ json_reader_return_val_if_error_set (reader, FALSE);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return FALSE;
+ }
+
+ return JSON_NODE_HOLDS_NULL (reader->priv->current_node);
+}
+
+/**
+ * json_reader_get_member_name:
+ * @reader: a #JsonReader
+ *
+ * Retrieves the name of the current member.
+ *
+ * Return value: (transfer none): the name of the member, or %NULL
+ *
+ * Since: 0.14
+ */
+const gchar *
+json_reader_get_member_name (JsonReader *reader)
+{
+ g_return_val_if_fail (JSON_IS_READER (reader), NULL);
+ json_reader_return_val_if_error_set (reader, NULL);
+
+ if (reader->priv->current_node == NULL)
+ {
+ json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
+ _("No node available at the current position"));
+ return FALSE;
+ }
+
+ return reader->priv->current_member;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-reader.h b/src/glib-jsonrpc/json-glib/json-reader.h
new file mode 100644
index 0000000..6ee0b54
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-reader.h
@@ -0,0 +1,150 @@
+/* json-reader.h - JSON cursor parser
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2010 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_READER_H__
+#define __JSON_READER_H__
+
+#include <json-glib/json-types.h>
+
+G_BEGIN_DECLS
+
+#define JSON_TYPE_READER (json_reader_get_type ())
+#define JSON_READER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JSON_TYPE_READER, JsonReader))
+#define JSON_IS_READER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), JSON_TYPE_READER))
+#define JSON_READER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), JSON_TYPE_READER, JsonReaderClass))
+#define JSON_IS_READER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), JSON_TYPE_READER))
+#define JSON_READER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), JSON_TYPE_READER, JsonReaderClass))
+
+/**
+ * JSON_READER_ERROR:
+ *
+ * Error domain for #JsonReader errors
+ *
+ * Since: 0.12
+ */
+#define JSON_READER_ERROR (json_reader_error_quark ())
+
+typedef struct _JsonReader JsonReader;
+typedef struct _JsonReaderPrivate JsonReaderPrivate;
+typedef struct _JsonReaderClass JsonReaderClass;
+
+/**
+ * JsonReaderError:
+ * @JSON_READER_ERROR_NO_ARRAY: No array found at the current position
+ * @JSON_READER_ERROR_INVALID_INDEX: Index out of bounds
+ * @JSON_READER_ERROR_NO_OBJECT: No object found at the current position
+ * @JSON_READER_ERROR_INVALID_MEMBER: Member not found
+ * @JSON_READER_ERROR_INVALID_NODE: No valid node found at the current position
+ * @JSON_READER_ERROR_NO_VALUE: The node at the current position does not
+ * hold a value
+ * @JSON_READER_ERROR_INVALID_TYPE: The node at the current position does not
+ * hold a value of the desired type
+ *
+ * Error codes enumeration for #JsonReader errors
+ *
+ * Since: 0.12
+ */
+typedef enum {
+ JSON_READER_ERROR_NO_ARRAY,
+ JSON_READER_ERROR_INVALID_INDEX,
+ JSON_READER_ERROR_NO_OBJECT,
+ JSON_READER_ERROR_INVALID_MEMBER,
+ JSON_READER_ERROR_INVALID_NODE,
+ JSON_READER_ERROR_NO_VALUE,
+ JSON_READER_ERROR_INVALID_TYPE
+} JsonReaderError;
+
+/**
+ * JsonReader:
+ *
+ * The <structname>JsonReader</structname> structure contains only
+ * private data and should only be accessed using the provided API
+ *
+ * Since: 0.12
+ */
+struct _JsonReader
+{
+ /*< private >*/
+ GObject parent_instance;
+
+ JsonReaderPrivate *priv;
+};
+
+/**
+ * JsonReaderClass:
+ *
+ * The <structname>JsonReaderClass</structname> structure contains only
+ * private data
+ *
+ * Since: 0.12
+ */
+struct _JsonReaderClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ void (*_json_padding0) (void);
+ void (*_json_padding1) (void);
+ void (*_json_padding2) (void);
+ void (*_json_padding3) (void);
+ void (*_json_padding4) (void);
+};
+
+GQuark json_reader_error_quark (void);
+GType json_reader_get_type (void) G_GNUC_CONST;
+
+JsonReader * json_reader_new (JsonNode *node);
+
+void json_reader_set_root (JsonReader *reader,
+ JsonNode *root);
+
+const GError * json_reader_get_error (JsonReader *reader);
+
+gboolean json_reader_is_array (JsonReader *reader);
+gboolean json_reader_read_element (JsonReader *reader,
+ guint index_);
+void json_reader_end_element (JsonReader *reader);
+gint json_reader_count_elements (JsonReader *reader);
+
+gboolean json_reader_is_object (JsonReader *reader);
+gboolean json_reader_read_member (JsonReader *reader,
+ const gchar *member_name);
+void json_reader_end_member (JsonReader *reader);
+gint json_reader_count_members (JsonReader *reader);
+gchar ** json_reader_list_members (JsonReader *reader);
+const gchar * json_reader_get_member_name (JsonReader *reader);
+
+gboolean json_reader_is_value (JsonReader *reader);
+JsonNode * json_reader_get_value (JsonReader *reader);
+gint64 json_reader_get_int_value (JsonReader *reader);
+gdouble json_reader_get_double_value (JsonReader *reader);
+const gchar * json_reader_get_string_value (JsonReader *reader);
+gboolean json_reader_get_boolean_value (JsonReader *reader);
+gboolean json_reader_get_null_value (JsonReader *reader);
+
+G_END_DECLS
+
+#endif /* __JSON_READER_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-scanner.c b/src/glib-jsonrpc/json-glib/json-scanner.c
new file mode 100644
index 0000000..6eca2ba
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-scanner.c
@@ -0,0 +1,1861 @@
+/* json-scanner.c: Tokenizer for JSON
+ * Copyright (C) 2008 OpenedHand
+ *
+ * Based on JsonScanner: Flexible lexical scanner for general purpose.
+ * Copyright (C) 1997, 1998 Tim Janik
+ *
+ * Modified by Emmanuele Bassi <ebassi openedhand 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include "json-scanner.h"
+
+#ifdef G_OS_WIN32
+#include <io.h> /* For _read() */
+#endif
+
+struct _JsonScannerConfig
+{
+ /* Character sets
+ */
+ gchar *cset_skip_characters; /* default: " \t\n" */
+ gchar *cset_identifier_first;
+ gchar *cset_identifier_nth;
+ gchar *cpair_comment_single; /* default: "#\n" */
+
+ /* Should symbol lookup work case sensitive? */
+ guint case_sensitive : 1;
+
+ /* Boolean values to be adjusted "on the fly"
+ * to configure scanning behaviour.
+ */
+ guint skip_comment_multi : 1; /* C like comment */
+ guint skip_comment_single : 1; /* single line comment */
+ guint scan_comment_multi : 1; /* scan multi line comments? */
+ guint scan_identifier : 1;
+ guint scan_identifier_1char : 1;
+ guint scan_identifier_NULL : 1;
+ guint scan_symbols : 1;
+ guint scan_binary : 1;
+ guint scan_octal : 1;
+ guint scan_float : 1;
+ guint scan_hex : 1; /* `0x0ff0' */
+ guint scan_hex_dollar : 1; /* `$0ff0' */
+ guint scan_string_sq : 1; /* string: 'anything' */
+ guint scan_string_dq : 1; /* string: "\\-escapes!\n" */
+ guint numbers_2_int : 1; /* bin, octal, hex => int */
+ guint int_2_float : 1; /* int => G_TOKEN_FLOAT? */
+ guint identifier_2_string : 1;
+ guint char_2_token : 1; /* return G_TOKEN_CHAR? */
+ guint symbol_2_token : 1;
+ guint scope_0_fallback : 1; /* try scope 0 on lookups? */
+ guint store_int64 : 1; /* use value.v_int64 rather than v_int */
+ guint padding_dummy;
+};
+
+static JsonScannerConfig json_scanner_config_template =
+{
+ ( " \t\r\n" ) /* cset_skip_characters */,
+ (
+ "_"
+ G_CSET_a_2_z
+ G_CSET_A_2_Z
+ ) /* cset_identifier_first */,
+ (
+ G_CSET_DIGITS
+ "-_"
+ G_CSET_a_2_z
+ G_CSET_A_2_Z
+ ) /* cset_identifier_nth */,
+ ( "//\n" ) /* cpair_comment_single */,
+ TRUE /* case_sensitive */,
+ TRUE /* skip_comment_multi */,
+ TRUE /* skip_comment_single */,
+ FALSE /* scan_comment_multi */,
+ TRUE /* scan_identifier */,
+ TRUE /* scan_identifier_1char */,
+ FALSE /* scan_identifier_NULL */,
+ TRUE /* scan_symbols */,
+ TRUE /* scan_binary */,
+ TRUE /* scan_octal */,
+ TRUE /* scan_float */,
+ TRUE /* scan_hex */,
+ TRUE /* scan_hex_dollar */,
+ TRUE /* scan_string_sq */,
+ TRUE /* scan_string_dq */,
+ TRUE /* numbers_2_int */,
+ FALSE /* int_2_float */,
+ FALSE /* identifier_2_string */,
+ TRUE /* char_2_token */,
+ TRUE /* symbol_2_token */,
+ FALSE /* scope_0_fallback */,
+ TRUE /* store_int64 */
+};
+
+/* --- defines --- */
+#define to_lower(c) ( \
+ (guchar) ( \
+ ( (((guchar)(c))>='A' && ((guchar)(c))<='Z') * ('a'-'A') ) | \
+ ( (((guchar)(c))>=192 && ((guchar)(c))<=214) * (224-192) ) | \
+ ( (((guchar)(c))>=216 && ((guchar)(c))<=222) * (248-216) ) | \
+ ((guchar)(c)) \
+ ) \
+)
+
+#define READ_BUFFER_SIZE (4000)
+
+static const gchar json_symbol_names[] =
+ "true\0"
+ "false\0"
+ "null\0"
+ "var\0";
+
+static const struct
+{
+ guint name_offset;
+ guint token;
+} json_symbols[] = {
+ { 0, JSON_TOKEN_TRUE },
+ { 5, JSON_TOKEN_FALSE },
+ { 11, JSON_TOKEN_NULL },
+ { 16, JSON_TOKEN_VAR }
+};
+
+static const guint n_json_symbols = G_N_ELEMENTS (json_symbols);
+
+/* --- typedefs --- */
+typedef struct _JsonScannerKey JsonScannerKey;
+
+struct _JsonScannerKey
+{
+ guint scope_id;
+ gchar *symbol;
+ gpointer value;
+};
+
+/* --- prototypes --- */
+static gboolean json_scanner_key_equal (gconstpointer v1,
+ gconstpointer v2);
+static guint json_scanner_key_hash (gconstpointer v);
+
+static inline
+JsonScannerKey *json_scanner_lookup_internal (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol);
+static void json_scanner_get_token_ll (JsonScanner *scanner,
+ GTokenType *token_p,
+ GTokenValue *value_p,
+ guint *line_p,
+ guint *position_p);
+static void json_scanner_get_token_i (JsonScanner *scanner,
+ GTokenType *token_p,
+ GTokenValue *value_p,
+ guint *line_p,
+ guint *position_p);
+
+static guchar json_scanner_peek_next_char (JsonScanner *scanner);
+static guchar json_scanner_get_char (JsonScanner *scanner,
+ guint *line_p,
+ guint *position_p);
+static gunichar json_scanner_get_unichar (JsonScanner *scanner,
+ guint *line_p,
+ guint *position_p);
+static void json_scanner_msg_handler (JsonScanner *scanner,
+ gchar *message,
+ gboolean is_error);
+
+/* --- functions --- */
+static inline gint
+json_scanner_char_2_num (guchar c,
+ guchar base)
+{
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ return -1;
+
+ if (c < base)
+ return c;
+
+ return -1;
+}
+
+JsonScanner *
+json_scanner_new (void)
+{
+ JsonScanner *scanner;
+ JsonScannerConfig *config_templ;
+
+ config_templ = &json_scanner_config_template;
+
+ scanner = g_new0 (JsonScanner, 1);
+
+ scanner->user_data = NULL;
+ scanner->max_parse_errors = 1;
+ scanner->parse_errors = 0;
+ scanner->input_name = NULL;
+ g_datalist_init (&scanner->qdata);
+
+ scanner->config = g_new0 (JsonScannerConfig, 1);
+
+ scanner->config->case_sensitive = config_templ->case_sensitive;
+ scanner->config->cset_skip_characters = config_templ->cset_skip_characters;
+ if (!scanner->config->cset_skip_characters)
+ scanner->config->cset_skip_characters = "";
+ scanner->config->cset_identifier_first = config_templ->cset_identifier_first;
+ scanner->config->cset_identifier_nth = config_templ->cset_identifier_nth;
+ scanner->config->cpair_comment_single = config_templ->cpair_comment_single;
+ scanner->config->skip_comment_multi = config_templ->skip_comment_multi;
+ scanner->config->skip_comment_single = config_templ->skip_comment_single;
+ scanner->config->scan_comment_multi = config_templ->scan_comment_multi;
+ scanner->config->scan_identifier = config_templ->scan_identifier;
+ scanner->config->scan_identifier_1char = config_templ->scan_identifier_1char;
+ scanner->config->scan_identifier_NULL = config_templ->scan_identifier_NULL;
+ scanner->config->scan_symbols = config_templ->scan_symbols;
+ scanner->config->scan_binary = config_templ->scan_binary;
+ scanner->config->scan_octal = config_templ->scan_octal;
+ scanner->config->scan_float = config_templ->scan_float;
+ scanner->config->scan_hex = config_templ->scan_hex;
+ scanner->config->scan_hex_dollar = config_templ->scan_hex_dollar;
+ scanner->config->scan_string_sq = config_templ->scan_string_sq;
+ scanner->config->scan_string_dq = config_templ->scan_string_dq;
+ scanner->config->numbers_2_int = config_templ->numbers_2_int;
+ scanner->config->int_2_float = config_templ->int_2_float;
+ scanner->config->identifier_2_string = config_templ->identifier_2_string;
+ scanner->config->char_2_token = config_templ->char_2_token;
+ scanner->config->symbol_2_token = config_templ->symbol_2_token;
+ scanner->config->scope_0_fallback = config_templ->scope_0_fallback;
+ scanner->config->store_int64 = config_templ->store_int64;
+
+ scanner->token = G_TOKEN_NONE;
+ scanner->value.v_int64 = 0;
+ scanner->line = 1;
+ scanner->position = 0;
+
+ scanner->next_token = G_TOKEN_NONE;
+ scanner->next_value.v_int64 = 0;
+ scanner->next_line = 1;
+ scanner->next_position = 0;
+
+ scanner->symbol_table = g_hash_table_new (json_scanner_key_hash,
+ json_scanner_key_equal);
+ scanner->input_fd = -1;
+ scanner->text = NULL;
+ scanner->text_end = NULL;
+ scanner->buffer = NULL;
+ scanner->scope_id = 0;
+
+ scanner->msg_handler = json_scanner_msg_handler;
+
+ return scanner;
+}
+
+static inline void
+json_scanner_free_value (GTokenType *token_p,
+ GTokenValue *value_p)
+{
+ switch (*token_p)
+ {
+ case G_TOKEN_STRING:
+ case G_TOKEN_IDENTIFIER:
+ case G_TOKEN_IDENTIFIER_NULL:
+ case G_TOKEN_COMMENT_SINGLE:
+ case G_TOKEN_COMMENT_MULTI:
+ g_free (value_p->v_string);
+ break;
+
+ default:
+ break;
+ }
+
+ *token_p = G_TOKEN_NONE;
+}
+
+static void
+json_scanner_destroy_symbol_table_entry (gpointer _key,
+ gpointer _value,
+ gpointer _data)
+{
+ JsonScannerKey *key = _key;
+
+ g_free (key->symbol);
+ g_slice_free (JsonScannerKey, key);
+}
+
+void
+json_scanner_destroy (JsonScanner *scanner)
+{
+ g_return_if_fail (scanner != NULL);
+
+ g_datalist_clear (&scanner->qdata);
+ g_hash_table_foreach (scanner->symbol_table,
+ json_scanner_destroy_symbol_table_entry,
+ NULL);
+ g_hash_table_destroy (scanner->symbol_table);
+ json_scanner_free_value (&scanner->token, &scanner->value);
+ json_scanner_free_value (&scanner->next_token, &scanner->next_value);
+ g_free (scanner->config);
+ g_free (scanner->buffer);
+ g_free (scanner);
+}
+
+static void
+json_scanner_msg_handler (JsonScanner *scanner,
+ gchar *message,
+ gboolean is_error)
+{
+ g_return_if_fail (scanner != NULL);
+
+ g_fprintf (stderr, "%s:%d: ",
+ scanner->input_name ? scanner->input_name : "<memory>",
+ scanner->line);
+ if (is_error)
+ g_fprintf (stderr, "error: ");
+
+ g_fprintf (stderr, "%s\n", message);
+}
+
+void
+json_scanner_error (JsonScanner *scanner,
+ const gchar *format,
+ ...)
+{
+ g_return_if_fail (scanner != NULL);
+ g_return_if_fail (format != NULL);
+
+ scanner->parse_errors++;
+
+ if (scanner->msg_handler)
+ {
+ va_list args;
+ gchar *string;
+
+ va_start (args, format);
+ string = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ scanner->msg_handler (scanner, string, TRUE);
+
+ g_free (string);
+ }
+}
+
+void
+json_scanner_warn (JsonScanner *scanner,
+ const gchar *format,
+ ...)
+{
+ g_return_if_fail (scanner != NULL);
+ g_return_if_fail (format != NULL);
+
+ if (scanner->msg_handler)
+ {
+ va_list args;
+ gchar *string;
+
+ va_start (args, format);
+ string = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ scanner->msg_handler (scanner, string, FALSE);
+
+ g_free (string);
+ }
+}
+
+static gboolean
+json_scanner_key_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ const JsonScannerKey *key1 = v1;
+ const JsonScannerKey *key2 = v2;
+
+ return (key1->scope_id == key2->scope_id) &&
+ (strcmp (key1->symbol, key2->symbol) == 0);
+}
+
+static guint
+json_scanner_key_hash (gconstpointer v)
+{
+ const JsonScannerKey *key = v;
+ gchar *c;
+ guint h;
+
+ h = key->scope_id;
+ for (c = key->symbol; *c; c++)
+ h = (h << 5) - h + *c;
+
+ return h;
+}
+
+static inline JsonScannerKey *
+json_scanner_lookup_internal (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol)
+{
+ JsonScannerKey *key_p;
+ JsonScannerKey key;
+
+ key.scope_id = scope_id;
+
+ if (!scanner->config->case_sensitive)
+ {
+ gchar *d;
+ const gchar *c;
+
+ key.symbol = g_new (gchar, strlen (symbol) + 1);
+ for (d = key.symbol, c = symbol; *c; c++, d++)
+ *d = to_lower (*c);
+ *d = 0;
+ key_p = g_hash_table_lookup (scanner->symbol_table, &key);
+ g_free (key.symbol);
+ }
+ else
+ {
+ key.symbol = (gchar*) symbol;
+ key_p = g_hash_table_lookup (scanner->symbol_table, &key);
+ }
+
+ return key_p;
+}
+
+void
+json_scanner_scope_add_symbol (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol,
+ gpointer value)
+{
+ JsonScannerKey *key;
+
+ g_return_if_fail (scanner != NULL);
+ g_return_if_fail (symbol != NULL);
+
+ key = json_scanner_lookup_internal (scanner, scope_id, symbol);
+ if (!key)
+ {
+ key = g_slice_new (JsonScannerKey);
+ key->scope_id = scope_id;
+ key->symbol = g_strdup (symbol);
+ key->value = value;
+ if (!scanner->config->case_sensitive)
+ {
+ gchar *c;
+
+ c = key->symbol;
+ while (*c != 0)
+ {
+ *c = to_lower (*c);
+ c++;
+ }
+ }
+
+ g_hash_table_insert (scanner->symbol_table, key, key);
+ }
+ else
+ key->value = value;
+}
+
+void
+json_scanner_scope_remove_symbol (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol)
+{
+ JsonScannerKey *key;
+
+ g_return_if_fail (scanner != NULL);
+ g_return_if_fail (symbol != NULL);
+
+ key = json_scanner_lookup_internal (scanner, scope_id, symbol);
+ if (key)
+ {
+ g_hash_table_remove (scanner->symbol_table, key);
+ g_free (key->symbol);
+ g_slice_free (JsonScannerKey, key);
+ }
+}
+
+gpointer
+json_scanner_lookup_symbol (JsonScanner *scanner,
+ const gchar *symbol)
+{
+ JsonScannerKey *key;
+ guint scope_id;
+
+ g_return_val_if_fail (scanner != NULL, NULL);
+
+ if (!symbol)
+ return NULL;
+
+ scope_id = scanner->scope_id;
+ key = json_scanner_lookup_internal (scanner, scope_id, symbol);
+ if (!key && scope_id && scanner->config->scope_0_fallback)
+ key = json_scanner_lookup_internal (scanner, 0, symbol);
+
+ if (key)
+ return key->value;
+ else
+ return NULL;
+}
+
+gpointer
+json_scanner_scope_lookup_symbol (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol)
+{
+ JsonScannerKey *key;
+
+ g_return_val_if_fail (scanner != NULL, NULL);
+
+ if (!symbol)
+ return NULL;
+
+ key = json_scanner_lookup_internal (scanner, scope_id, symbol);
+
+ if (key)
+ return key->value;
+ else
+ return NULL;
+}
+
+guint
+json_scanner_set_scope (JsonScanner *scanner,
+ guint scope_id)
+{
+ guint old_scope_id;
+
+ g_return_val_if_fail (scanner != NULL, 0);
+
+ old_scope_id = scanner->scope_id;
+ scanner->scope_id = scope_id;
+
+ return old_scope_id;
+}
+
+typedef struct {
+ GHFunc func;
+ gpointer data;
+ guint scope_id;
+} ForeachClosure;
+
+static void
+json_scanner_foreach_internal (gpointer _key,
+ gpointer _value,
+ gpointer _user_data)
+{
+ JsonScannerKey *key = _value;
+ ForeachClosure *closure = _user_data;
+
+ if (key->scope_id == closure->scope_id)
+ closure->func (key->symbol, key->value, closure->data);
+}
+
+void
+json_scanner_scope_foreach_symbol (JsonScanner *scanner,
+ guint scope_id,
+ GHFunc func,
+ gpointer user_data)
+{
+ ForeachClosure closure;
+
+ g_return_if_fail (scanner != NULL);
+ g_return_if_fail (func != NULL);
+
+ closure.func = func;
+ closure.data = user_data;
+ closure.scope_id = scope_id;
+
+ g_hash_table_foreach (scanner->symbol_table,
+ json_scanner_foreach_internal,
+ &closure);
+}
+
+GTokenType
+json_scanner_peek_next_token (JsonScanner *scanner)
+{
+ g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
+
+ if (scanner->next_token == G_TOKEN_NONE)
+ {
+ scanner->next_line = scanner->line;
+ scanner->next_position = scanner->position;
+ json_scanner_get_token_i (scanner,
+ &scanner->next_token,
+ &scanner->next_value,
+ &scanner->next_line,
+ &scanner->next_position);
+ }
+
+ return scanner->next_token;
+}
+
+GTokenType
+json_scanner_get_next_token (JsonScanner *scanner)
+{
+ g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
+
+ if (scanner->next_token != G_TOKEN_NONE)
+ {
+ json_scanner_free_value (&scanner->token, &scanner->value);
+
+ scanner->token = scanner->next_token;
+ scanner->value = scanner->next_value;
+ scanner->line = scanner->next_line;
+ scanner->position = scanner->next_position;
+ scanner->next_token = G_TOKEN_NONE;
+ }
+ else
+ json_scanner_get_token_i (scanner,
+ &scanner->token,
+ &scanner->value,
+ &scanner->line,
+ &scanner->position);
+
+ return scanner->token;
+}
+
+GTokenType
+json_scanner_cur_token (JsonScanner *scanner)
+{
+ g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
+
+ return scanner->token;
+}
+
+GTokenValue
+json_scanner_cur_value (JsonScanner *scanner)
+{
+ GTokenValue v;
+
+ v.v_int64 = 0;
+
+ g_return_val_if_fail (scanner != NULL, v);
+
+ /* MSC isn't capable of handling return scanner->value; ? */
+
+ v = scanner->value;
+
+ return v;
+}
+
+guint
+json_scanner_cur_line (JsonScanner *scanner)
+{
+ g_return_val_if_fail (scanner != NULL, 0);
+
+ return scanner->line;
+}
+
+guint
+json_scanner_cur_position (JsonScanner *scanner)
+{
+ g_return_val_if_fail (scanner != NULL, 0);
+
+ return scanner->position;
+}
+
+gboolean
+json_scanner_eof (JsonScanner *scanner)
+{
+ g_return_val_if_fail (scanner != NULL, TRUE);
+
+ return scanner->token == G_TOKEN_EOF || scanner->token == G_TOKEN_ERROR;
+}
+
+void
+json_scanner_input_file (JsonScanner *scanner,
+ gint input_fd)
+{
+ g_return_if_fail (scanner != NULL);
+ g_return_if_fail (input_fd >= 0);
+
+ if (scanner->input_fd >= 0)
+ json_scanner_sync_file_offset (scanner);
+
+ scanner->token = G_TOKEN_NONE;
+ scanner->value.v_int64 = 0;
+ scanner->line = 1;
+ scanner->position = 0;
+ scanner->next_token = G_TOKEN_NONE;
+
+ scanner->input_fd = input_fd;
+ scanner->text = NULL;
+ scanner->text_end = NULL;
+
+ if (!scanner->buffer)
+ scanner->buffer = g_new (gchar, READ_BUFFER_SIZE + 1);
+}
+
+void
+json_scanner_input_text (JsonScanner *scanner,
+ const gchar *text,
+ guint text_len)
+{
+ g_return_if_fail (scanner != NULL);
+ if (text_len)
+ g_return_if_fail (text != NULL);
+ else
+ text = NULL;
+
+ if (scanner->input_fd >= 0)
+ json_scanner_sync_file_offset (scanner);
+
+ scanner->token = G_TOKEN_NONE;
+ scanner->value.v_int64 = 0;
+ scanner->line = 1;
+ scanner->position = 0;
+ scanner->next_token = G_TOKEN_NONE;
+
+ scanner->input_fd = -1;
+ scanner->text = text;
+ scanner->text_end = text + text_len;
+
+ if (scanner->buffer)
+ {
+ g_free (scanner->buffer);
+ scanner->buffer = NULL;
+ }
+}
+
+static guchar
+json_scanner_peek_next_char (JsonScanner *scanner)
+{
+ if (scanner->text < scanner->text_end)
+ return *scanner->text;
+ else if (scanner->input_fd >= 0)
+ {
+ gint count;
+ gchar *buffer;
+
+ buffer = scanner->buffer;
+ do
+ {
+ count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE);
+ }
+ while (count == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (count < 1)
+ {
+ scanner->input_fd = -1;
+
+ return 0;
+ }
+ else
+ {
+ scanner->text = buffer;
+ scanner->text_end = buffer + count;
+
+ return *buffer;
+ }
+ }
+ else
+ return 0;
+}
+
+void
+json_scanner_sync_file_offset (JsonScanner *scanner)
+{
+ g_return_if_fail (scanner != NULL);
+
+ /* for file input, rewind the filedescriptor to the current
+ * buffer position and blow the file read ahead buffer. useful
+ * for third party uses of our file descriptor, which hooks
+ * onto the current scanning position.
+ */
+
+ if (scanner->input_fd >= 0 && scanner->text_end > scanner->text)
+ {
+ gint buffered;
+
+ buffered = scanner->text_end - scanner->text;
+ if (lseek (scanner->input_fd, - buffered, SEEK_CUR) >= 0)
+ {
+ /* we succeeded, blow our buffer's contents now */
+ scanner->text = NULL;
+ scanner->text_end = NULL;
+ }
+ else
+ errno = 0;
+ }
+}
+
+static guchar
+json_scanner_get_char (JsonScanner *scanner,
+ guint *line_p,
+ guint *position_p)
+{
+ guchar fchar;
+
+ if (scanner->text < scanner->text_end)
+ fchar = *(scanner->text++);
+ else if (scanner->input_fd >= 0)
+ {
+ gint count;
+ gchar *buffer;
+
+ buffer = scanner->buffer;
+ do
+ {
+ count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE);
+ }
+ while (count == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (count < 1)
+ {
+ scanner->input_fd = -1;
+ fchar = 0;
+ }
+ else
+ {
+ scanner->text = buffer + 1;
+ scanner->text_end = buffer + count;
+ fchar = *buffer;
+ if (!fchar)
+ {
+ json_scanner_sync_file_offset (scanner);
+ scanner->text_end = scanner->text;
+ scanner->input_fd = -1;
+ }
+ }
+ }
+ else
+ fchar = 0;
+
+ if (fchar == '\n')
+ {
+ (*position_p) = 0;
+ (*line_p)++;
+ }
+ else if (fchar)
+ {
+ (*position_p)++;
+ }
+
+ return fchar;
+}
+
+#define is_hex_digit(c) (((c) >= '0' && (c) <= '9') || \
+ ((c) >= 'a' && (c) <= 'f') || \
+ ((c) >= 'A' && (c) <= 'F'))
+#define to_hex_digit(c) (((c) <= '9') ? (c) - '0' : ((c) & 7) + 9)
+
+static gunichar
+json_scanner_get_unichar (JsonScanner *scanner,
+ guint *line_p,
+ guint *position_p)
+{
+ gunichar uchar;
+ gchar ch;
+ gint i;
+
+ uchar = 0;
+ for (i = 0; i < 4; i++)
+ {
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+
+ if (is_hex_digit (ch))
+ uchar += ((gunichar) to_hex_digit (ch) << ((3 - i) * 4));
+ else
+ break;
+ }
+
+ g_assert (g_unichar_validate (uchar) || g_unichar_type (uchar) == G_UNICODE_SURROGATE);
+
+ return uchar;
+}
+
+void
+json_scanner_unexp_token (JsonScanner *scanner,
+ GTokenType expected_token,
+ const gchar *identifier_spec,
+ const gchar *symbol_spec,
+ const gchar *symbol_name,
+ const gchar *message,
+ gint is_error)
+{
+ gchar *token_string;
+ guint token_string_len;
+ gchar *expected_string;
+ guint expected_string_len;
+ gchar *message_prefix;
+ gboolean print_unexp;
+ void (*msg_handler) (JsonScanner*, const gchar*, ...);
+
+ g_return_if_fail (scanner != NULL);
+
+ if (is_error)
+ msg_handler = json_scanner_error;
+ else
+ msg_handler = json_scanner_warn;
+
+ if (!identifier_spec)
+ identifier_spec = "identifier";
+ if (!symbol_spec)
+ symbol_spec = "symbol";
+
+ token_string_len = 56;
+ token_string = g_new (gchar, token_string_len + 1);
+ expected_string_len = 64;
+ expected_string = g_new (gchar, expected_string_len + 1);
+ print_unexp = TRUE;
+
+ switch (scanner->token)
+ {
+ case G_TOKEN_EOF:
+ g_snprintf (token_string, token_string_len, "end of file");
+ break;
+
+ default:
+ if (scanner->token >= 1 && scanner->token <= 255)
+ {
+ if ((scanner->token >= ' ' && scanner->token <= '~') ||
+ strchr (scanner->config->cset_identifier_first, scanner->token) ||
+ strchr (scanner->config->cset_identifier_nth, scanner->token))
+ g_snprintf (token_string, token_string_len, "character `%c'", scanner->token);
+ else
+ g_snprintf (token_string, token_string_len, "character `\\%o'", scanner->token);
+ break;
+ }
+ else if (!scanner->config->symbol_2_token)
+ {
+ g_snprintf (token_string, token_string_len, "(unknown) token <%d>", scanner->token);
+ break;
+ }
+ /* fall through */
+ case G_TOKEN_SYMBOL:
+ if (expected_token == G_TOKEN_SYMBOL ||
+ (scanner->config->symbol_2_token &&
+ expected_token > G_TOKEN_LAST))
+ print_unexp = FALSE;
+ if (symbol_name)
+ g_snprintf (token_string, token_string_len,
+ "%s%s `%s'",
+ print_unexp ? "" : "invalid ",
+ symbol_spec,
+ symbol_name);
+ else
+ g_snprintf (token_string, token_string_len,
+ "%s%s",
+ print_unexp ? "" : "invalid ",
+ symbol_spec);
+ break;
+
+ case G_TOKEN_ERROR:
+ print_unexp = FALSE;
+ expected_token = G_TOKEN_NONE;
+ switch (scanner->value.v_error)
+ {
+ case G_ERR_UNEXP_EOF:
+ g_snprintf (token_string, token_string_len, "scanner: unexpected end of file");
+ break;
+
+ case G_ERR_UNEXP_EOF_IN_STRING:
+ g_snprintf (token_string, token_string_len, "scanner: unterminated string constant");
+ break;
+
+ case G_ERR_UNEXP_EOF_IN_COMMENT:
+ g_snprintf (token_string, token_string_len, "scanner: unterminated comment");
+ break;
+
+ case G_ERR_NON_DIGIT_IN_CONST:
+ g_snprintf (token_string, token_string_len, "scanner: non digit in constant");
+ break;
+
+ case G_ERR_FLOAT_RADIX:
+ g_snprintf (token_string, token_string_len, "scanner: invalid radix for floating constant");
+ break;
+
+ case G_ERR_FLOAT_MALFORMED:
+ g_snprintf (token_string, token_string_len, "scanner: malformed floating constant");
+ break;
+
+ case G_ERR_DIGIT_RADIX:
+ g_snprintf (token_string, token_string_len, "scanner: digit is beyond radix");
+ break;
+
+ case G_ERR_UNKNOWN:
+ default:
+ g_snprintf (token_string, token_string_len, "scanner: unknown error");
+ break;
+ }
+ break;
+
+ case G_TOKEN_CHAR:
+ g_snprintf (token_string, token_string_len, "character `%c'", scanner->value.v_char);
+ break;
+
+ case G_TOKEN_IDENTIFIER:
+ case G_TOKEN_IDENTIFIER_NULL:
+ if (expected_token == G_TOKEN_IDENTIFIER ||
+ expected_token == G_TOKEN_IDENTIFIER_NULL)
+ print_unexp = FALSE;
+ g_snprintf (token_string, token_string_len,
+ "%s%s `%s'",
+ print_unexp ? "" : "invalid ",
+ identifier_spec,
+ scanner->token == G_TOKEN_IDENTIFIER ? scanner->value.v_string : "null");
+ break;
+
+ case G_TOKEN_BINARY:
+ case G_TOKEN_OCTAL:
+ case G_TOKEN_INT:
+ case G_TOKEN_HEX:
+ if (scanner->config->store_int64)
+ g_snprintf (token_string, token_string_len, "number `%" G_GUINT64_FORMAT "'", scanner->value.v_int64);
+ else
+ g_snprintf (token_string, token_string_len, "number `%lu'", scanner->value.v_int);
+ break;
+
+ case G_TOKEN_FLOAT:
+ g_snprintf (token_string, token_string_len, "number `%.3f'", scanner->value.v_float);
+ break;
+
+ case G_TOKEN_STRING:
+ if (expected_token == G_TOKEN_STRING)
+ print_unexp = FALSE;
+ g_snprintf (token_string, token_string_len,
+ "%s%sstring constant \"%s\"",
+ print_unexp ? "" : "invalid ",
+ scanner->value.v_string[0] == 0 ? "empty " : "",
+ scanner->value.v_string);
+ token_string[token_string_len - 2] = '"';
+ token_string[token_string_len - 1] = 0;
+ break;
+
+ case G_TOKEN_COMMENT_SINGLE:
+ case G_TOKEN_COMMENT_MULTI:
+ g_snprintf (token_string, token_string_len, "comment");
+ break;
+
+ case G_TOKEN_NONE:
+ /* somehow the user's parsing code is screwed, there isn't much
+ * we can do about it.
+ * Note, a common case to trigger this is
+ * json_scanner_peek_next_token(); json_scanner_unexp_token();
+ * without an intermediate json_scanner_get_next_token().
+ */
+ g_assert_not_reached ();
+ break;
+ }
+
+
+ switch (expected_token)
+ {
+ gboolean need_valid;
+ gchar *tstring;
+ case G_TOKEN_EOF:
+ g_snprintf (expected_string, expected_string_len, "end of file");
+ break;
+ default:
+ if (expected_token >= 1 && expected_token <= 255)
+ {
+ if ((expected_token >= ' ' && expected_token <= '~') ||
+ strchr (scanner->config->cset_identifier_first, expected_token) ||
+ strchr (scanner->config->cset_identifier_nth, expected_token))
+ g_snprintf (expected_string, expected_string_len, "character `%c'", expected_token);
+ else
+ g_snprintf (expected_string, expected_string_len, "character `\\%o'", expected_token);
+ break;
+ }
+ else if (!scanner->config->symbol_2_token)
+ {
+ g_snprintf (expected_string, expected_string_len, "(unknown) token <%d>", expected_token);
+ break;
+ }
+ /* fall through */
+ case G_TOKEN_SYMBOL:
+ need_valid = (scanner->token == G_TOKEN_SYMBOL ||
+ (scanner->config->symbol_2_token &&
+ scanner->token > G_TOKEN_LAST));
+ g_snprintf (expected_string, expected_string_len,
+ "%s%s",
+ need_valid ? "valid " : "",
+ symbol_spec);
+ /* FIXME: should we attempt to lookup the symbol_name for symbol_2_token? */
+ break;
+ case G_TOKEN_CHAR:
+ g_snprintf (expected_string, expected_string_len, "%scharacter",
+ scanner->token == G_TOKEN_CHAR ? "valid " : "");
+ break;
+ case G_TOKEN_BINARY:
+ tstring = "binary";
+ g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_OCTAL:
+ tstring = "octal";
+ g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_INT:
+ tstring = "integer";
+ g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_HEX:
+ tstring = "hexadecimal";
+ g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_FLOAT:
+ tstring = "float";
+ g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_STRING:
+ g_snprintf (expected_string,
+ expected_string_len,
+ "%sstring constant",
+ scanner->token == G_TOKEN_STRING ? "valid " : "");
+ break;
+ case G_TOKEN_IDENTIFIER:
+ case G_TOKEN_IDENTIFIER_NULL:
+ need_valid = (scanner->token == G_TOKEN_IDENTIFIER_NULL ||
+ scanner->token == G_TOKEN_IDENTIFIER);
+ g_snprintf (expected_string,
+ expected_string_len,
+ "%s%s",
+ need_valid ? "valid " : "",
+ identifier_spec);
+ break;
+ case G_TOKEN_COMMENT_SINGLE:
+ tstring = "single-line";
+ g_snprintf (expected_string, expected_string_len, "%scomment (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_COMMENT_MULTI:
+ tstring = "multi-line";
+ g_snprintf (expected_string, expected_string_len, "%scomment (%s)",
+ scanner->token == expected_token ? "valid " : "", tstring);
+ break;
+ case G_TOKEN_NONE:
+ case G_TOKEN_ERROR:
+ /* this is handled upon printout */
+ break;
+ }
+
+ if (message && message[0] != 0)
+ message_prefix = " - ";
+ else
+ {
+ message_prefix = "";
+ message = "";
+ }
+ if (expected_token == G_TOKEN_ERROR)
+ {
+ msg_handler (scanner,
+ "failure around %s%s%s",
+ token_string,
+ message_prefix,
+ message);
+ }
+ else if (expected_token == G_TOKEN_NONE)
+ {
+ if (print_unexp)
+ msg_handler (scanner,
+ "unexpected %s%s%s",
+ token_string,
+ message_prefix,
+ message);
+ else
+ msg_handler (scanner,
+ "%s%s%s",
+ token_string,
+ message_prefix,
+ message);
+ }
+ else
+ {
+ if (print_unexp)
+ msg_handler (scanner,
+ "unexpected %s, expected %s%s%s",
+ token_string,
+ expected_string,
+ message_prefix,
+ message);
+ else
+ msg_handler (scanner,
+ "%s, expected %s%s%s",
+ token_string,
+ expected_string,
+ message_prefix,
+ message);
+ }
+
+ g_free (token_string);
+ g_free (expected_string);
+}
+
+static void
+json_scanner_get_token_i (JsonScanner *scanner,
+ GTokenType *token_p,
+ GTokenValue *value_p,
+ guint *line_p,
+ guint *position_p)
+{
+ do
+ {
+ json_scanner_free_value (token_p, value_p);
+ json_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p);
+ }
+ while (((*token_p > 0 && *token_p < 256) &&
+ strchr (scanner->config->cset_skip_characters, *token_p)) ||
+ (*token_p == G_TOKEN_CHAR &&
+ strchr (scanner->config->cset_skip_characters, value_p->v_char)) ||
+ (*token_p == G_TOKEN_COMMENT_MULTI &&
+ scanner->config->skip_comment_multi) ||
+ (*token_p == G_TOKEN_COMMENT_SINGLE &&
+ scanner->config->skip_comment_single));
+
+ switch (*token_p)
+ {
+ case G_TOKEN_IDENTIFIER:
+ if (scanner->config->identifier_2_string)
+ *token_p = G_TOKEN_STRING;
+ break;
+
+ case G_TOKEN_SYMBOL:
+ if (scanner->config->symbol_2_token)
+ *token_p = (GTokenType) value_p->v_symbol;
+ break;
+
+ case G_TOKEN_BINARY:
+ case G_TOKEN_OCTAL:
+ case G_TOKEN_HEX:
+ if (scanner->config->numbers_2_int)
+ *token_p = G_TOKEN_INT;
+ break;
+
+ default:
+ break;
+ }
+
+ if (*token_p == G_TOKEN_INT &&
+ scanner->config->int_2_float)
+ {
+ *token_p = G_TOKEN_FLOAT;
+ if (scanner->config->store_int64)
+ {
+#ifdef _MSC_VER
+ /* work around error C2520, see gvaluetransform.c */
+ value_p->v_float = (__int64)value_p->v_int64;
+#else
+ value_p->v_float = value_p->v_int64;
+#endif
+ }
+ else
+ value_p->v_float = value_p->v_int;
+ }
+
+ errno = 0;
+}
+
+static void
+json_scanner_get_token_ll (JsonScanner *scanner,
+ GTokenType *token_p,
+ GTokenValue *value_p,
+ guint *line_p,
+ guint *position_p)
+{
+ JsonScannerConfig *config;
+ GTokenType token;
+ gboolean in_comment_multi;
+ gboolean in_comment_single;
+ gboolean in_string_sq;
+ gboolean in_string_dq;
+ GString *gstring;
+ GTokenValue value;
+ guchar ch;
+
+ config = scanner->config;
+ (*value_p).v_int64 = 0;
+
+ if ((scanner->text >= scanner->text_end && scanner->input_fd < 0) ||
+ scanner->token == G_TOKEN_EOF)
+ {
+ *token_p = G_TOKEN_EOF;
+ return;
+ }
+
+ in_comment_multi = FALSE;
+ in_comment_single = FALSE;
+ in_string_sq = FALSE;
+ in_string_dq = FALSE;
+ gstring = NULL;
+
+ do /* while (ch != 0) */
+ {
+ gboolean dotted_float = FALSE;
+
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+
+ value.v_int64 = 0;
+ token = G_TOKEN_NONE;
+
+ /* this is *evil*, but needed ;(
+ * we first check for identifier first character, because it
+ * might interfere with other key chars like slashes or numbers
+ */
+ if (config->scan_identifier &&
+ ch && strchr (config->cset_identifier_first, ch))
+ goto identifier_precedence;
+
+ switch (ch)
+ {
+ case 0:
+ token = G_TOKEN_EOF;
+ (*position_p)++;
+ /* ch = 0; */
+ break;
+
+ case '/':
+ if (!config->scan_comment_multi ||
+ json_scanner_peek_next_char (scanner) != '*')
+ goto default_case;
+ json_scanner_get_char (scanner, line_p, position_p);
+ token = G_TOKEN_COMMENT_MULTI;
+ in_comment_multi = TRUE;
+ gstring = g_string_new (NULL);
+ while ((ch = json_scanner_get_char (scanner, line_p, position_p)) != 0)
+ {
+ if (ch == '*' && json_scanner_peek_next_char (scanner) == '/')
+ {
+ json_scanner_get_char (scanner, line_p, position_p);
+ in_comment_multi = FALSE;
+ break;
+ }
+ else
+ gstring = g_string_append_c (gstring, ch);
+ }
+ ch = 0;
+ break;
+
+ case '\'':
+ if (!config->scan_string_sq)
+ goto default_case;
+ token = G_TOKEN_STRING;
+ in_string_sq = TRUE;
+ gstring = g_string_new (NULL);
+ while ((ch = json_scanner_get_char (scanner, line_p, position_p)) != 0)
+ {
+ if (ch == '\'')
+ {
+ in_string_sq = FALSE;
+ break;
+ }
+ else
+ gstring = g_string_append_c (gstring, ch);
+ }
+ ch = 0;
+ break;
+
+ case '"':
+ if (!config->scan_string_dq)
+ goto default_case;
+ token = G_TOKEN_STRING;
+ in_string_dq = TRUE;
+ gstring = g_string_new (NULL);
+ while ((ch = json_scanner_get_char (scanner, line_p, position_p)) != 0)
+ {
+ if (ch == '"')
+ {
+ in_string_dq = FALSE;
+ break;
+ }
+ else
+ {
+ if (ch == '\\')
+ {
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ switch (ch)
+ {
+ guint i;
+ guint fchar;
+
+ case 0:
+ break;
+
+ case '\\':
+ gstring = g_string_append_c (gstring, '\\');
+ break;
+
+ case 'n':
+ gstring = g_string_append_c (gstring, '\n');
+ break;
+
+ case 't':
+ gstring = g_string_append_c (gstring, '\t');
+ break;
+
+ case 'r':
+ gstring = g_string_append_c (gstring, '\r');
+ break;
+
+ case 'b':
+ gstring = g_string_append_c (gstring, '\b');
+ break;
+
+ case 'f':
+ gstring = g_string_append_c (gstring, '\f');
+ break;
+
+ case 'u':
+ fchar = json_scanner_peek_next_char (scanner);
+ if (is_hex_digit (fchar))
+ {
+ gunichar ucs;
+
+ ucs = json_scanner_get_unichar (scanner, line_p, position_p);
+
+ if (g_unichar_type (ucs) == G_UNICODE_SURROGATE)
+ {
+ /* read next surrogate */
+ if ('\\' == json_scanner_get_char (scanner, line_p, position_p)
+ && 'u' == json_scanner_get_char (scanner, line_p, position_p))
+ {
+ gunichar ucs_lo = json_scanner_get_unichar (scanner, line_p, position_p);
+ g_assert (g_unichar_type (ucs_lo) == G_UNICODE_SURROGATE);
+ ucs = (((ucs & 0x3ff) << 10) | (ucs_lo & 0x3ff)) + 0x10000;
+ }
+ }
+
+ g_assert (g_unichar_validate (ucs));
+ gstring = g_string_append_unichar (gstring, ucs);
+ }
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ i = ch - '0';
+ fchar = json_scanner_peek_next_char (scanner);
+ if (fchar >= '0' && fchar <= '7')
+ {
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ i = i * 8 + ch - '0';
+ fchar = json_scanner_peek_next_char (scanner);
+ if (fchar >= '0' && fchar <= '7')
+ {
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ i = i * 8 + ch - '0';
+ }
+ }
+ gstring = g_string_append_c (gstring, i);
+ break;
+
+ default:
+ gstring = g_string_append_c (gstring, ch);
+ break;
+ }
+ }
+ else
+ gstring = g_string_append_c (gstring, ch);
+ }
+ }
+ ch = 0;
+ break;
+
+ case '.':
+ if (!config->scan_float)
+ goto default_case;
+ token = G_TOKEN_FLOAT;
+ dotted_float = TRUE;
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ goto number_parsing;
+
+ case '$':
+ if (!config->scan_hex_dollar)
+ goto default_case;
+ token = G_TOKEN_HEX;
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ goto number_parsing;
+
+ case '0':
+ if (config->scan_octal)
+ token = G_TOKEN_OCTAL;
+ else
+ token = G_TOKEN_INT;
+ ch = json_scanner_peek_next_char (scanner);
+ if (config->scan_hex && (ch == 'x' || ch == 'X'))
+ {
+ token = G_TOKEN_HEX;
+ json_scanner_get_char (scanner, line_p, position_p);
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ if (ch == 0)
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_UNEXP_EOF;
+ (*position_p)++;
+ break;
+ }
+ if (json_scanner_char_2_num (ch, 16) < 0)
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_DIGIT_RADIX;
+ ch = 0;
+ break;
+ }
+ }
+ else if (config->scan_binary && (ch == 'b' || ch == 'B'))
+ {
+ token = G_TOKEN_BINARY;
+ json_scanner_get_char (scanner, line_p, position_p);
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ if (ch == 0)
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_UNEXP_EOF;
+ (*position_p)++;
+ break;
+ }
+ if (json_scanner_char_2_num (ch, 10) < 0)
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_NON_DIGIT_IN_CONST;
+ ch = 0;
+ break;
+ }
+ }
+ else
+ ch = '0';
+ /* fall through */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ number_parsing:
+ {
+ gboolean in_number = TRUE;
+ gchar *endptr;
+
+ if (token == G_TOKEN_NONE)
+ token = G_TOKEN_INT;
+
+ gstring = g_string_new (dotted_float ? "0." : "");
+ gstring = g_string_append_c (gstring, ch);
+
+ do /* while (in_number) */
+ {
+ gboolean is_E;
+
+ is_E = token == G_TOKEN_FLOAT && (ch == 'e' || ch == 'E');
+
+ ch = json_scanner_peek_next_char (scanner);
+
+ if (json_scanner_char_2_num (ch, 36) >= 0 ||
+ (config->scan_float && ch == '.') ||
+ (is_E && (ch == '+' || ch == '-')))
+ {
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+
+ switch (ch)
+ {
+ case '.':
+ if (token != G_TOKEN_INT && token != G_TOKEN_OCTAL)
+ {
+ value.v_error = token == G_TOKEN_FLOAT ? G_ERR_FLOAT_MALFORMED : G_ERR_FLOAT_RADIX;
+ token = G_TOKEN_ERROR;
+ in_number = FALSE;
+ }
+ else
+ {
+ token = G_TOKEN_FLOAT;
+ gstring = g_string_append_c (gstring, ch);
+ }
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ gstring = g_string_append_c (gstring, ch);
+ break;
+
+ case '-':
+ case '+':
+ if (token != G_TOKEN_FLOAT)
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_NON_DIGIT_IN_CONST;
+ in_number = FALSE;
+ }
+ else
+ gstring = g_string_append_c (gstring, ch);
+ break;
+
+ case 'e':
+ case 'E':
+ if ((token != G_TOKEN_HEX && !config->scan_float) ||
+ (token != G_TOKEN_HEX &&
+ token != G_TOKEN_OCTAL &&
+ token != G_TOKEN_FLOAT &&
+ token != G_TOKEN_INT))
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_NON_DIGIT_IN_CONST;
+ in_number = FALSE;
+ }
+ else
+ {
+ if (token != G_TOKEN_HEX)
+ token = G_TOKEN_FLOAT;
+ gstring = g_string_append_c (gstring, ch);
+ }
+ break;
+
+ default:
+ if (token != G_TOKEN_HEX)
+ {
+ token = G_TOKEN_ERROR;
+ value.v_error = G_ERR_NON_DIGIT_IN_CONST;
+ in_number = FALSE;
+ }
+ else
+ gstring = g_string_append_c (gstring, ch);
+ break;
+ }
+ }
+ else
+ in_number = FALSE;
+ }
+ while (in_number);
+
+ endptr = NULL;
+ if (token == G_TOKEN_FLOAT)
+ value.v_float = g_strtod (gstring->str, &endptr);
+ else
+ {
+ guint64 ui64 = 0;
+ switch (token)
+ {
+ case G_TOKEN_BINARY:
+ ui64 = g_ascii_strtoull (gstring->str, &endptr, 2);
+ break;
+ case G_TOKEN_OCTAL:
+ ui64 = g_ascii_strtoull (gstring->str, &endptr, 8);
+ break;
+ case G_TOKEN_INT:
+ ui64 = g_ascii_strtoull (gstring->str, &endptr, 10);
+ break;
+ case G_TOKEN_HEX:
+ ui64 = g_ascii_strtoull (gstring->str, &endptr, 16);
+ break;
+ default: ;
+ }
+ if (scanner->config->store_int64)
+ value.v_int64 = ui64;
+ else
+ value.v_int = ui64;
+ }
+ if (endptr && *endptr)
+ {
+ token = G_TOKEN_ERROR;
+ if (*endptr == 'e' || *endptr == 'E')
+ value.v_error = G_ERR_NON_DIGIT_IN_CONST;
+ else
+ value.v_error = G_ERR_DIGIT_RADIX;
+ }
+ g_string_free (gstring, TRUE);
+ gstring = NULL;
+ ch = 0;
+ } /* number_parsing:... */
+ break;
+
+ default:
+ default_case:
+ {
+ if (config->cpair_comment_single &&
+ ch == config->cpair_comment_single[0])
+ {
+ token = G_TOKEN_COMMENT_SINGLE;
+ in_comment_single = TRUE;
+ gstring = g_string_new (NULL);
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ while (ch != 0)
+ {
+ if (ch == config->cpair_comment_single[1])
+ {
+ in_comment_single = FALSE;
+ ch = 0;
+ break;
+ }
+
+ gstring = g_string_append_c (gstring, ch);
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ }
+ /* ignore a missing newline at EOF for single line comments */
+ if (in_comment_single &&
+ config->cpair_comment_single[1] == '\n')
+ in_comment_single = FALSE;
+ }
+ else if (config->scan_identifier && ch &&
+ strchr (config->cset_identifier_first, ch))
+ {
+ identifier_precedence:
+
+ if (config->cset_identifier_nth && ch &&
+ strchr (config->cset_identifier_nth,
+ json_scanner_peek_next_char (scanner)))
+ {
+ token = G_TOKEN_IDENTIFIER;
+ gstring = g_string_new (NULL);
+ gstring = g_string_append_c (gstring, ch);
+ do
+ {
+ ch = json_scanner_get_char (scanner, line_p, position_p);
+ gstring = g_string_append_c (gstring, ch);
+ ch = json_scanner_peek_next_char (scanner);
+ }
+ while (ch && strchr (config->cset_identifier_nth, ch));
+ ch = 0;
+ }
+ else if (config->scan_identifier_1char)
+ {
+ token = G_TOKEN_IDENTIFIER;
+ value.v_identifier = g_new0 (gchar, 2);
+ value.v_identifier[0] = ch;
+ ch = 0;
+ }
+ }
+ if (ch)
+ {
+ if (config->char_2_token)
+ token = ch;
+ else
+ {
+ token = G_TOKEN_CHAR;
+ value.v_char = ch;
+ }
+ ch = 0;
+ }
+ } /* default_case:... */
+ break;
+ }
+ g_assert (ch == 0 && token != G_TOKEN_NONE); /* paranoid */
+ }
+ while (ch != 0);
+
+ if (in_comment_multi || in_comment_single ||
+ in_string_sq || in_string_dq)
+ {
+ token = G_TOKEN_ERROR;
+ if (gstring)
+ {
+ g_string_free (gstring, TRUE);
+ gstring = NULL;
+ }
+ (*position_p)++;
+ if (in_comment_multi || in_comment_single)
+ value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT;
+ else /* (in_string_sq || in_string_dq) */
+ value.v_error = G_ERR_UNEXP_EOF_IN_STRING;
+ }
+
+ if (gstring)
+ {
+ value.v_string = g_string_free (gstring, FALSE);
+ gstring = NULL;
+ }
+
+ if (token == G_TOKEN_IDENTIFIER)
+ {
+ if (config->scan_symbols)
+ {
+ JsonScannerKey *key;
+ guint scope_id;
+
+ scope_id = scanner->scope_id;
+ key = json_scanner_lookup_internal (scanner, scope_id, value.v_identifier);
+ if (!key && scope_id && scanner->config->scope_0_fallback)
+ key = json_scanner_lookup_internal (scanner, 0, value.v_identifier);
+
+ if (key)
+ {
+ g_free (value.v_identifier);
+ token = G_TOKEN_SYMBOL;
+ value.v_symbol = key->value;
+ }
+ }
+
+ if (token == G_TOKEN_IDENTIFIER &&
+ config->scan_identifier_NULL &&
+ strlen (value.v_identifier) == 4)
+ {
+ gchar *null_upper = "NULL";
+ gchar *null_lower = "null";
+
+ if (scanner->config->case_sensitive)
+ {
+ if (value.v_identifier[0] == null_upper[0] &&
+ value.v_identifier[1] == null_upper[1] &&
+ value.v_identifier[2] == null_upper[2] &&
+ value.v_identifier[3] == null_upper[3])
+ token = G_TOKEN_IDENTIFIER_NULL;
+ }
+ else
+ {
+ if ((value.v_identifier[0] == null_upper[0] ||
+ value.v_identifier[0] == null_lower[0]) &&
+ (value.v_identifier[1] == null_upper[1] ||
+ value.v_identifier[1] == null_lower[1]) &&
+ (value.v_identifier[2] == null_upper[2] ||
+ value.v_identifier[2] == null_lower[2]) &&
+ (value.v_identifier[3] == null_upper[3] ||
+ value.v_identifier[3] == null_lower[3]))
+ token = G_TOKEN_IDENTIFIER_NULL;
+ }
+ }
+ }
+
+ *token_p = token;
+ *value_p = value;
+}
diff --git a/src/glib-jsonrpc/json-glib/json-scanner.h b/src/glib-jsonrpc/json-glib/json-scanner.h
new file mode 100644
index 0000000..49d7b1e
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-scanner.h
@@ -0,0 +1,171 @@
+/* json-scanner.h: Tokenizer for JSON
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * JsonScanner is a specialized tokenizer for JSON adapted from
+ * the GScanner tokenizer in GLib; GScanner came with this notice:
+ *
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ *
+ * JsonScanner: modified by Emmanuele Bassi <ebassi openedhand com>
+ */
+
+#ifndef __JSON_SCANNER_H__
+#define __JSON_SCANNER_H__
+
+#include <glib/gdataset.h>
+#include <glib/ghash.h>
+#include <glib/gscanner.h>
+
+G_BEGIN_DECLS
+
+typedef struct _JsonScanner JsonScanner;
+typedef struct _JsonScannerConfig JsonScannerConfig;
+
+typedef void (* JsonScannerMsgFunc) (JsonScanner *scanner,
+ gchar *message,
+ gboolean is_error);
+
+/**
+ * JsonTokenType:
+ * @JSON_TOKEN_INVALID: marker
+ * @JSON_TOKEN_TRUE: symbol for 'true' bareword
+ * @JSON_TOKEN_FALSE: symbol for 'false' bareword
+ * @JSON_TOKEN_NULL: symbol for 'null' bareword
+ * @JSON_TOKEN_VAR: symbol for 'var' bareword
+ * @JSON_TOKEN_LAST: marker
+ *
+ * Tokens for JsonScanner-based parser, extending #GTokenType.
+ */
+typedef enum {
+ JSON_TOKEN_INVALID = G_TOKEN_LAST,
+
+ JSON_TOKEN_TRUE,
+ JSON_TOKEN_FALSE,
+ JSON_TOKEN_NULL,
+ JSON_TOKEN_VAR,
+
+ JSON_TOKEN_LAST
+} JsonTokenType;
+
+/**
+ * JsonScanner:
+ *
+ * Tokenizer scanner for JSON. See #GScanner
+ *
+ * Since: 0.6
+ */
+struct _JsonScanner
+{
+ /*< private >*/
+ /* unused fields */
+ gpointer user_data;
+ guint max_parse_errors;
+
+ /* json_scanner_error() increments this field */
+ guint parse_errors;
+
+ /* name of input stream, featured by the default message handler */
+ const gchar *input_name;
+
+ /* quarked data */
+ GData *qdata;
+
+ /* link into the scanner configuration */
+ JsonScannerConfig *config;
+
+ /* fields filled in after json_scanner_get_next_token() */
+ GTokenType token;
+ GTokenValue value;
+ guint line;
+ guint position;
+
+ /* fields filled in after json_scanner_peek_next_token() */
+ GTokenType next_token;
+ GTokenValue next_value;
+ guint next_line;
+ guint next_position;
+
+ /* to be considered private */
+ GHashTable *symbol_table;
+ gint input_fd;
+ const gchar *text;
+ const gchar *text_end;
+ gchar *buffer;
+ guint scope_id;
+
+ /* handler function for _warn and _error */
+ JsonScannerMsgFunc msg_handler;
+};
+
+JsonScanner *json_scanner_new (void);
+void json_scanner_destroy (JsonScanner *scanner);
+void json_scanner_input_file (JsonScanner *scanner,
+ gint input_fd);
+void json_scanner_sync_file_offset (JsonScanner *scanner);
+void json_scanner_input_text (JsonScanner *scanner,
+ const gchar *text,
+ guint text_len);
+GTokenType json_scanner_get_next_token (JsonScanner *scanner);
+GTokenType json_scanner_peek_next_token (JsonScanner *scanner);
+GTokenType json_scanner_cur_token (JsonScanner *scanner);
+GTokenValue json_scanner_cur_value (JsonScanner *scanner);
+guint json_scanner_cur_line (JsonScanner *scanner);
+guint json_scanner_cur_position (JsonScanner *scanner);
+gboolean json_scanner_eof (JsonScanner *scanner);
+guint json_scanner_set_scope (JsonScanner *scanner,
+ guint scope_id);
+void json_scanner_scope_add_symbol (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol,
+ gpointer value);
+void json_scanner_scope_remove_symbol (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol);
+gpointer json_scanner_scope_lookup_symbol (JsonScanner *scanner,
+ guint scope_id,
+ const gchar *symbol);
+void json_scanner_scope_foreach_symbol (JsonScanner *scanner,
+ guint scope_id,
+ GHFunc func,
+ gpointer user_data);
+gpointer json_scanner_lookup_symbol (JsonScanner *scanner,
+ const gchar *symbol);
+void json_scanner_unexp_token (JsonScanner *scanner,
+ GTokenType expected_token,
+ const gchar *identifier_spec,
+ const gchar *symbol_spec,
+ const gchar *symbol_name,
+ const gchar *message,
+ gint is_error);
+void json_scanner_error (JsonScanner *scanner,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2,3);
+void json_scanner_warn (JsonScanner *scanner,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2,3);
+
+G_END_DECLS
+
+#endif /* __JSON_SCANNER_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-serializable.c b/src/glib-jsonrpc/json-glib/json-serializable.c
new file mode 100644
index 0000000..e49ccb1
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-serializable.c
@@ -0,0 +1,341 @@
+/* json-gobject.c - JSON GObject integration
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ *
+ * 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 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.
+ *
+ * Author:
+ * Emmanuele Bassi <ebassi openedhand com>
+ */
+
+/**
+ * SECTION:json-serializable
+ * @short_description: Interface for serialize and deserialize special GObjects
+ *
+ * #JsonSerializable is an interface for #GObject classes that
+ * allows controlling how the class is going to be serialized
+ * or deserialized by json_construct_gobject() and
+ * json_serialize_gobject() respectively.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "json-types-private.h"
+#include "json-gobject-private.h"
+#include "json-debug.h"
+
+/**
+ * json_serializable_serialize_property:
+ * @serializable: a #JsonSerializable object
+ * @property_name: the name of the property
+ * @value: the value of the property
+ * @pspec: a #GParamSpec
+ *
+ * Asks a #JsonSerializable implementation to serialize a #GObject
+ * property into a #JsonNode object.
+ *
+ * Return value: a #JsonNode containing the serialized property
+ */
+JsonNode *
+json_serializable_serialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ JsonSerializableIface *iface;
+
+ g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+ g_return_val_if_fail (pspec != NULL, NULL);
+
+ iface = JSON_SERIALIZABLE_GET_IFACE (serializable);
+
+ return iface->serialize_property (serializable, property_name, value, pspec);
+}
+
+/**
+ * json_serializable_deserialize_property:
+ * @serializable: a #JsonSerializable
+ * @property_name: the name of the property
+ * @value: (out): a pointer to an uninitialized #GValue
+ * @pspec: a #GParamSpec
+ * @property_node: a #JsonNode containing the serialized property
+ *
+ * Asks a #JsonSerializable implementation to deserialize the
+ * property contained inside @property_node into @value.
+ *
+ * Return value: %TRUE if the property was successfully deserialized.
+ */
+gboolean
+json_serializable_deserialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *property_node)
+{
+ JsonSerializableIface *iface;
+
+ g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), FALSE);
+ g_return_val_if_fail (property_name != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+ g_return_val_if_fail (pspec != NULL, FALSE);
+ g_return_val_if_fail (property_node != NULL, FALSE);
+
+ iface = JSON_SERIALIZABLE_GET_IFACE (serializable);
+
+ return iface->deserialize_property (serializable,
+ property_name,
+ value,
+ pspec,
+ property_node);
+}
+
+static gboolean
+json_serializable_real_deserialize (JsonSerializable *serializable,
+ const gchar *name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *node)
+{
+ JSON_NOTE (GOBJECT, "Default deserialization for property '%s'", pspec->name);
+ return json_deserialize_pspec (value, pspec, node);
+}
+
+static JsonNode *
+json_serializable_real_serialize (JsonSerializable *serializable,
+ const gchar *name,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ JSON_NOTE (GOBJECT, "Default serialization for property '%s'", pspec->name);
+
+ if (g_param_value_defaults (pspec, (GValue *)value))
+ return NULL;
+
+ return json_serialize_pspec (value, pspec);
+}
+
+static GParamSpec *
+json_serializable_real_find_property (JsonSerializable *serializable,
+ const char *name)
+{
+ return g_object_class_find_property (G_OBJECT_GET_CLASS (serializable), name);
+}
+
+static GParamSpec **
+json_serializable_real_list_properties (JsonSerializable *serializable,
+ guint *n_pspecs)
+{
+ return g_object_class_list_properties (G_OBJECT_GET_CLASS (serializable), n_pspecs);
+}
+
+static void
+json_serializable_real_set_property (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ const GValue *value)
+{
+ g_object_set_property (G_OBJECT (serializable), pspec->name, value);
+}
+
+static void
+json_serializable_real_get_property (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ GValue *value)
+{
+ g_object_get_property (G_OBJECT (serializable), pspec->name, value);
+}
+
+/* typedef to satisfy G_DEFINE_INTERFACE's naming */
+typedef JsonSerializableIface JsonSerializableInterface;
+
+static void
+json_serializable_default_init (JsonSerializableInterface *iface)
+{
+ iface->serialize_property = json_serializable_real_serialize;
+ iface->deserialize_property = json_serializable_real_deserialize;
+ iface->find_property = json_serializable_real_find_property;
+ iface->list_properties = json_serializable_real_list_properties;
+ iface->set_property = json_serializable_real_set_property;
+ iface->get_property = json_serializable_real_get_property;
+}
+
+G_DEFINE_INTERFACE (JsonSerializable, json_serializable, G_TYPE_OBJECT);
+
+/**
+ * json_serializable_default_serialize_property:
+ * @serializable: a #JsonSerializable object
+ * @property_name: the name of the property
+ * @value: the value of the property
+ * @pspec: a #GParamSpec
+ *
+ * Calls the default implementation of the #JsonSerializable
+ * serialize_property() virtual function
+ *
+ * This function can be used inside a custom implementation
+ * of the serialize_property() virtual function in lieu of:
+ *
+ * |[
+ * JsonSerializable *iface;
+ * JsonNode *node;
+ *
+ * iface = g_type_default_interface_peek (JSON_TYPE_SERIALIZABLE);
+ * node = iface->serialize_property (serializable, property_name,
+ * value,
+ * pspec);
+ * ]|
+ *
+ * Return value: (transfer full): a #JsonNode containing the serialized
+ * property
+ *
+ * Since: 0.10
+ */
+JsonNode *
+json_serializable_default_serialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+ g_return_val_if_fail (pspec != NULL, NULL);
+
+ return json_serializable_real_serialize (serializable,
+ property_name,
+ value, pspec);
+}
+
+/**
+ * json_serializable_default_deserialize_property:
+ * @serializable: a #JsonSerializable
+ * @property_name: the name of the property
+ * @value: a pointer to an uninitialized #GValue
+ * @pspec: a #GParamSpec
+ * @property_node: a #JsonNode containing the serialized property
+ *
+ * Calls the default implementation of the #JsonSerializable
+ * deserialize_property() virtual function
+ *
+ * This function can be used inside a custom implementation
+ * of the deserialize_property() virtual function in lieu of:
+ *
+ * |[
+ * JsonSerializable *iface;
+ * gboolean res;
+ *
+ * iface = g_type_default_interface_peek (JSON_TYPE_SERIALIZABLE);
+ * res = iface->deserialize_property (serializable, property_name,
+ * value,
+ * pspec,
+ * property_node);
+ * ]|
+ *
+ * Return value: %TRUE if the property was successfully deserialized.
+ *
+ * Since: 0.10
+ */
+gboolean
+json_serializable_default_deserialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *property_node)
+{
+ g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), FALSE);
+ g_return_val_if_fail (property_name != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+ g_return_val_if_fail (pspec != NULL, FALSE);
+ g_return_val_if_fail (property_node != NULL, FALSE);
+
+ return json_serializable_real_deserialize (serializable,
+ property_name,
+ value, pspec,
+ property_node);
+}
+
+/**
+ * json_serializable_find_property:
+ * @serializable: a #JsonSerializable
+ * @name: the name of the property
+ *
+ * FIXME
+ *
+ * Return value: (transfer none): the #GParamSpec for the property
+ * or %NULL if no property was found
+ *
+ * Since: 0.14
+ */
+GParamSpec *
+json_serializable_find_property (JsonSerializable *serializable,
+ const char *name)
+{
+ g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return JSON_SERIALIZABLE_GET_IFACE (serializable)->find_property (serializable, name);
+}
+
+/**
+ * json_serializable_list_properties:
+ * @serializable: a #JsonSerializable
+ * @n_pspecs: (out): return location for the length of the array
+ * of #GParamSpec returned by the function
+ *
+ * FIXME
+ *
+ * Return value: (array length=n_pspecs) (transfer container): an array
+ * of #GParamSpec. Use g_free() to free the array when done.
+ *
+ * Since: 0.14
+ */
+GParamSpec **
+json_serializable_list_properties (JsonSerializable *serializable,
+ guint *n_pspecs)
+{
+ g_return_val_if_fail (JSON_IS_SERIALIZABLE (serializable), NULL);
+
+ return JSON_SERIALIZABLE_GET_IFACE (serializable)->list_properties (serializable, n_pspecs);
+}
+
+void
+json_serializable_set_property (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ const GValue *value)
+{
+ g_return_if_fail (JSON_IS_SERIALIZABLE (serializable));
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+ g_return_if_fail (value != NULL);
+
+ JSON_SERIALIZABLE_GET_IFACE (serializable)->set_property (serializable,
+ pspec,
+ value);
+}
+
+void
+json_serializable_get_property (JsonSerializable *serializable,
+ GParamSpec *pspec,
+ GValue *value)
+{
+ g_return_if_fail (JSON_IS_SERIALIZABLE (serializable));
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+ g_return_if_fail (value != NULL);
+
+ JSON_SERIALIZABLE_GET_IFACE (serializable)->get_property (serializable,
+ pspec,
+ value);
+}
diff --git a/src/glib-jsonrpc/json-glib/json-types-private.h b/src/glib-jsonrpc/json-glib/json-types-private.h
new file mode 100644
index 0000000..e7f73f2
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-types-private.h
@@ -0,0 +1,66 @@
+/* json-types-private.h - JSON data types private header
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#ifndef __JSON_TYPES_PRIVATE_H__
+#define __JSON_TYPES_PRIVATE_H__
+
+#include "json-types.h"
+
+G_BEGIN_DECLS
+
+struct _JsonNode
+{
+ /*< private >*/
+ JsonNodeType type;
+
+ union {
+ JsonObject *object;
+ JsonArray *array;
+ GValue value;
+ } data;
+
+ JsonNode *parent;
+};
+
+struct _JsonArray
+{
+ GPtrArray *elements;
+
+ volatile gint ref_count;
+};
+
+struct _JsonObject
+{
+ GHashTable *members;
+
+ /* the members of the object, ordered in reverse */
+ GList *members_ordered;
+
+ volatile gint ref_count;
+};
+
+const gchar *json_node_type_get_name (JsonNodeType node_type);
+
+G_END_DECLS
+
+#endif /* __JSON_TYPES_PRIVATE_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-types.h b/src/glib-jsonrpc/json-glib/json-types.h
new file mode 100644
index 0000000..ecbf198
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-types.h
@@ -0,0 +1,334 @@
+/* json-types.h - JSON data types
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_TYPES_H__
+#define __JSON_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/**
+ * JSON_NODE_TYPE:
+ * @node: a #JsonNode
+ *
+ * Evaluates to the #JsonNodeType contained by @node
+ */
+#define JSON_NODE_TYPE(node) (json_node_get_node_type ((node)))
+
+/**
+ * JSON_NODE_HOLDS:
+ * @node: a #JsonNode
+ * @t: a #JsonNodeType
+ *
+ * Evaluates to %TRUE if the @node holds type @t
+ *
+ * Since: 0.10
+ */
+#define JSON_NODE_HOLDS(node,t) (json_node_get_node_type ((node)) == (t))
+
+/**
+ * JSON_NODE_HOLDS_VALUE:
+ * @node: a #JsonNode
+ *
+ * Evaluates to %TRUE if @node holds a %JSON_NODE_VALUE
+ *
+ * Since: 0.10
+ */
+#define JSON_NODE_HOLDS_VALUE(node) (JSON_NODE_HOLDS ((node), JSON_NODE_VALUE))
+
+/**
+ * JSON_NODE_HOLDS_OBJECT:
+ * @node: a #JsonNode
+ *
+ * Evaluates to %TRUE if @node holds a %JSON_NODE_OBJECT
+ *
+ * Since: 0.10
+ */
+#define JSON_NODE_HOLDS_OBJECT(node) (JSON_NODE_HOLDS ((node), JSON_NODE_OBJECT))
+
+/**
+ * JSON_NODE_HOLDS_ARRAY:
+ * @node: a #JsonNode
+ *
+ * Evaluates to %TRUE if @node holds a %JSON_NODE_ARRAY
+ *
+ * Since: 0.10
+ */
+#define JSON_NODE_HOLDS_ARRAY(node) (JSON_NODE_HOLDS ((node), JSON_NODE_ARRAY))
+
+/**
+ * JSON_NODE_HOLDS_NULL:
+ * @node: a #JsonNode
+ *
+ * Evaluates to %TRUE if @node holds a %JSON_NODE_NULL
+ *
+ * Since: 0.10
+ */
+#define JSON_NODE_HOLDS_NULL(node) (JSON_NODE_HOLDS ((node), JSON_NODE_NULL))
+
+#define JSON_TYPE_NODE (json_node_get_type ())
+#define JSON_TYPE_OBJECT (json_object_get_type ())
+#define JSON_TYPE_ARRAY (json_array_get_type ())
+
+/**
+ * JsonNode:
+ *
+ * A generic container of JSON data types. The contents of the #JsonNode
+ * structure are private and should only be accessed via the provided
+ * functions and never directly.
+ */
+typedef struct _JsonNode JsonNode;
+
+/**
+ * JsonObject:
+ *
+ * A JSON object type. The contents of the #JsonObject structure are private
+ * and should only be accessed by the provided API
+ */
+typedef struct _JsonObject JsonObject;
+
+/**
+ * JsonArray:
+ *
+ * A JSON array type. The contents of the #JsonArray structure are private
+ * and should only be accessed by the provided API
+ */
+typedef struct _JsonArray JsonArray;
+
+/**
+ * JsonNodeType:
+ * @JSON_NODE_OBJECT: The node contains a #JsonObject
+ * @JSON_NODE_ARRAY: The node contains a #JsonArray
+ * @JSON_NODE_VALUE: The node contains a fundamental type
+ * @JSON_NODE_NULL: Special type, for nodes containing null
+ *
+ * Indicates the content of a #JsonNode.
+ */
+typedef enum {
+ JSON_NODE_OBJECT,
+ JSON_NODE_ARRAY,
+ JSON_NODE_VALUE,
+ JSON_NODE_NULL
+} JsonNodeType;
+
+/**
+ * JsonObjectForeach:
+ * @object: the iterated #JsonObject
+ * @member_name: the name of the member
+ * @member_node: a #JsonNode containing the @member_name value
+ * @user_data: data passed to the function
+ *
+ * The function to be passed to json_object_foreach_member(). You
+ * should not add or remove members to and from @object within
+ * this function. It is safe to change the value of @member_node.
+ *
+ * Since: 0.8
+ */
+typedef void (* JsonObjectForeach) (JsonObject *object,
+ const gchar *member_name,
+ JsonNode *member_node,
+ gpointer user_data);
+
+/**
+ * JsonArrayForeach:
+ * @array: the iterated #JsonArray
+ * @index_: the index of the element
+ * @element_node: a #JsonNode containing the value at @index_
+ * @user_data: data passed to the function
+ *
+ * The function to be passed to json_array_foreach_element(). You
+ * should not add or remove elements to and from @array within
+ * this function. It is safe to change the value of @element_node.
+ *
+ * Since: 0.8
+ */
+typedef void (* JsonArrayForeach) (JsonArray *array,
+ guint index_,
+ JsonNode *element_node,
+ gpointer user_data);
+
+/*
+ * JsonNode
+ */
+GType json_node_get_type (void) G_GNUC_CONST;
+JsonNode * json_node_new (JsonNodeType type);
+JsonNode * json_node_copy (JsonNode *node);
+void json_node_free (JsonNode *node);
+JsonNodeType json_node_get_node_type (JsonNode *node);
+GType json_node_get_value_type (JsonNode *node);
+void json_node_set_parent (JsonNode *node,
+ JsonNode *parent);
+JsonNode * json_node_get_parent (JsonNode *node);
+const gchar * json_node_type_name (JsonNode *node);
+
+void json_node_set_object (JsonNode *node,
+ JsonObject *object);
+void json_node_take_object (JsonNode *node,
+ JsonObject *object);
+JsonObject * json_node_get_object (JsonNode *node);
+JsonObject * json_node_dup_object (JsonNode *node);
+void json_node_set_array (JsonNode *node,
+ JsonArray *array);
+void json_node_take_array (JsonNode *node,
+ JsonArray *array);
+JsonArray * json_node_get_array (JsonNode *node);
+JsonArray * json_node_dup_array (JsonNode *node);
+void json_node_set_value (JsonNode *node,
+ const GValue *value);
+void json_node_get_value (JsonNode *node,
+ GValue *value);
+void json_node_set_string (JsonNode *node,
+ const gchar *value);
+const gchar * json_node_get_string (JsonNode *node);
+gchar * json_node_dup_string (JsonNode *node);
+void json_node_set_int (JsonNode *node,
+ gint64 value);
+gint64 json_node_get_int (JsonNode *node);
+void json_node_set_double (JsonNode *node,
+ gdouble value);
+gdouble json_node_get_double (JsonNode *node);
+void json_node_set_boolean (JsonNode *node,
+ gboolean value);
+gboolean json_node_get_boolean (JsonNode *node);
+gboolean json_node_is_null (JsonNode *node);
+
+/*
+ * JsonObject
+ */
+GType json_object_get_type (void) G_GNUC_CONST;
+JsonObject * json_object_new (void);
+JsonObject * json_object_ref (JsonObject *object);
+void json_object_unref (JsonObject *object);
+
+#ifndef JSON_DISABLE_DEPRECATED
+void json_object_add_member (JsonObject *object,
+ const gchar *member_name,
+ JsonNode *node) G_GNUC_DEPRECATED;
+#endif /* JSON_DISABLE_DEPRECATED */
+
+void json_object_set_member (JsonObject *object,
+ const gchar *member_name,
+ JsonNode *node);
+void json_object_set_int_member (JsonObject *object,
+ const gchar *member_name,
+ gint64 value);
+void json_object_set_double_member (JsonObject *object,
+ const gchar *member_name,
+ gdouble value);
+void json_object_set_boolean_member (JsonObject *object,
+ const gchar *member_name,
+ gboolean value);
+void json_object_set_string_member (JsonObject *object,
+ const gchar *member_name,
+ const gchar *value);
+void json_object_set_null_member (JsonObject *object,
+ const gchar *member_name);
+void json_object_set_array_member (JsonObject *object,
+ const gchar *member_name,
+ JsonArray *value);
+void json_object_set_object_member (JsonObject *object,
+ const gchar *member_name,
+ JsonObject *value);
+GList * json_object_get_members (JsonObject *object);
+JsonNode * json_object_get_member (JsonObject *object,
+ const gchar *member_name);
+JsonNode * json_object_dup_member (JsonObject *object,
+ const gchar *member_name);
+gint64 json_object_get_int_member (JsonObject *object,
+ const gchar *member_name);
+gdouble json_object_get_double_member (JsonObject *object,
+ const gchar *member_name);
+gboolean json_object_get_boolean_member (JsonObject *object,
+ const gchar *member_name);
+const gchar * json_object_get_string_member (JsonObject *object,
+ const gchar *member_name);
+gboolean json_object_get_null_member (JsonObject *object,
+ const gchar *member_name);
+JsonArray * json_object_get_array_member (JsonObject *object,
+ const gchar *member_name);
+JsonObject * json_object_get_object_member (JsonObject *object,
+ const gchar *member_name);
+gboolean json_object_has_member (JsonObject *object,
+ const gchar *member_name);
+void json_object_remove_member (JsonObject *object,
+ const gchar *member_name);
+GList * json_object_get_values (JsonObject *object);
+guint json_object_get_size (JsonObject *object);
+void json_object_foreach_member (JsonObject *object,
+ JsonObjectForeach func,
+ gpointer data);
+
+GType json_array_get_type (void) G_GNUC_CONST;
+JsonArray * json_array_new (void);
+JsonArray * json_array_sized_new (guint n_elements);
+JsonArray * json_array_ref (JsonArray *array);
+void json_array_unref (JsonArray *array);
+void json_array_add_element (JsonArray *array,
+ JsonNode *node);
+void json_array_add_int_element (JsonArray *array,
+ gint64 value);
+void json_array_add_double_element (JsonArray *array,
+ gdouble value);
+void json_array_add_boolean_element (JsonArray *array,
+ gboolean value);
+void json_array_add_string_element (JsonArray *array,
+ const gchar *value);
+void json_array_add_null_element (JsonArray *array);
+void json_array_add_array_element (JsonArray *array,
+ JsonArray *value);
+void json_array_add_object_element (JsonArray *array,
+ JsonObject *value);
+GList * json_array_get_elements (JsonArray *array);
+JsonNode * json_array_get_element (JsonArray *array,
+ guint index_);
+gint64 json_array_get_int_element (JsonArray *array,
+ guint index_);
+gdouble json_array_get_double_element (JsonArray *array,
+ guint index_);
+gboolean json_array_get_boolean_element (JsonArray *array,
+ guint index_);
+const gchar * json_array_get_string_element (JsonArray *array,
+ guint index_);
+gboolean json_array_get_null_element (JsonArray *array,
+ guint index_);
+JsonArray * json_array_get_array_element (JsonArray *array,
+ guint index_);
+JsonObject * json_array_get_object_element (JsonArray *array,
+ guint index_);
+JsonNode * json_array_dup_element (JsonArray *array,
+ guint index_);
+void json_array_remove_element (JsonArray *array,
+ guint index_);
+guint json_array_get_length (JsonArray *array);
+void json_array_foreach_element (JsonArray *array,
+ JsonArrayForeach func,
+ gpointer data);
+
+G_END_DECLS
+
+#endif /* __JSON_TYPES_H__ */
diff --git a/src/glib-jsonrpc/json-glib/json-version.h b/src/glib-jsonrpc/json-glib/json-version.h
new file mode 100644
index 0000000..cfda093
--- /dev/null
+++ b/src/glib-jsonrpc/json-glib/json-version.h
@@ -0,0 +1,100 @@
+/* json-version.h - JSON-GLib versioning information
+ *
+ * This file is part of JSON-GLib
+ * Copyright (C) 2007 OpenedHand Ltd.
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * 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:
+ * Emmanuele Bassi <ebassi linux intel com>
+ */
+
+#if !defined(__JSON_GLIB_INSIDE__) && !defined(JSON_COMPILATION)
+#error "Only <json-glib/json-glib.h> can be included directly."
+#endif
+
+#ifndef __JSON_VERSION_H__
+#define __JSON_VERSION_H__
+
+/**
+ * SECTION:json-version
+ * @short_description: JSON-GLib version checking
+ *
+ * JSON-GLib provides macros to check the version of the library
+ * at compile-time
+ */
+
+/**
+ * JSON_MAJOR_VERSION:
+ *
+ * Json major version component (e.g. 1 if %JSON_VERSION is 1.2.3)
+ */
+#define JSON_MAJOR_VERSION (0)
+
+/**
+ * JSON_MINOR_VERSION:
+ *
+ * Json minor version component (e.g. 2 if %JSON_VERSION is 1.2.3)
+ */
+#define JSON_MINOR_VERSION (14)
+
+/**
+ * JSON_MICRO_VERSION:
+ *
+ * Json micro version component (e.g. 3 if %JSON_VERSION is 1.2.3)
+ */
+#define JSON_MICRO_VERSION (0)
+
+/**
+ * JSON_VERSION
+ *
+ * Json version.
+ */
+#define JSON_VERSION (0.14.0)
+
+/**
+ * JSON_VERSION_S:
+ *
+ * Json version, encoded as a string, useful for printing and
+ * concatenation.
+ */
+#define JSON_VERSION_S "0.14.0"
+
+/**
+ * JSON_VERSION_HEX:
+ *
+ * Json version, encoded as an hexadecimal number, useful for
+ * integer comparisons.
+ */
+#define JSON_VERSION_HEX (JSON_MAJOR_VERSION << 24 | \
+ JSON_MINOR_VERSION << 16 | \
+ JSON_MICRO_VERSION << 8)
+
+/**
+ * JSON_CHECK_VERSION:
+ * @major: required major version
+ * @minor: required minor version
+ * @micro: required micro version
+ *
+ * Compile-time version checking. Evaluates to %TRUE if the version
+ * of Json is greater than the required one.
+ */
+#define JSON_CHECK_VERSION(major,minor,micro) \
+ (JSON_MAJOR_VERSION > (major) || \
+ (JSON_MAJOR_VERSION == (major) && JSON_MINOR_VERSION > (minor)) || \
+ (JSON_MAJOR_VERSION == (major) && JSON_MINOR_VERSION == (minor) && \
+ JSON_MICRO_VERSION >= (micro)))
+
+#endif /* __JSON_VERSION_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]