diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | json-glib/Makefile.am | 2 | ||||
-rw-r--r-- | json-glib/json-glib.h | 3 | ||||
-rw-r--r-- | json-glib/json-reader.c | 779 | ||||
-rw-r--r-- | json-glib/json-reader.h | 142 | ||||
-rw-r--r-- | json-glib/tests/Makefile.am | 10 | ||||
-rw-r--r-- | json-glib/tests/reader-test.c | 101 |
7 files changed, 1035 insertions, 3 deletions
@@ -41,6 +41,7 @@ json-glib.pc /json-glib/tests/object-test /json-glib/tests/node-test /json-glib/tests/parser-test +/json-glib/tests/reader-test libtool ltmain.sh missing diff --git a/json-glib/Makefile.am b/json-glib/Makefile.am index e4d24e1..6340cbf 100644 --- a/json-glib/Makefile.am +++ b/json-glib/Makefile.am @@ -34,6 +34,7 @@ source_h = \ $(top_srcdir)/json-glib/json-generator.h \ $(top_srcdir)/json-glib/json-gobject.h \ $(top_srcdir)/json-glib/json-parser.h \ + $(top_srcdir)/json-glib/json-reader.h \ $(top_srcdir)/json-glib/json-types.h \ $(NULL) @@ -54,6 +55,7 @@ source_c = \ $(srcdir)/json-node.c \ $(srcdir)/json-object.c \ $(srcdir)/json-parser.c \ + $(srcdir)/json-reader.c \ $(srcdir)/json-scanner.c \ $(srcdir)/json-serializable.c \ $(NULL) diff --git a/json-glib/json-glib.h b/json-glib/json-glib.h index 9c3d6f0..7a4d783 100644 --- a/json-glib/json-glib.h +++ b/json-glib/json-glib.h @@ -27,10 +27,13 @@ #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-reader.h> #include <json-glib/json-version.h> + #include <json-glib/json-enum-types.h> #include <json-glib/json-gobject.h> diff --git a/json-glib/json-reader.c b/json-glib/json-reader.c new file mode 100644 index 0000000..adc859e --- /dev/null +++ b/json-glib/json-reader.c @@ -0,0 +1,779 @@ +/* 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_value_string (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 (error); + * 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> + +#include "json-reader.h" + +#include "json-types-private.h" + +#include "json-debug.h" +#include "json-parser.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 +{ + JsonParser *parser; + + JsonNode *root; + + JsonNode *current_node; + JsonNode *previous_node; + + GError *error; +}; + +G_DEFINE_TYPE (JsonReader, json_reader, G_TYPE_OBJECT); + +static void +json_reader_dispose (GObject *gobject) +{ + JsonReaderPrivate *priv = JSON_READER (gobject)->priv; + + if (priv->parser != NULL) + { + g_object_unref (priv->parser); + + priv->parser = NULL; + priv->root = NULL; + priv->current_node = NULL; + priv->previous_node = NULL; + } + + if (priv->error != NULL) + g_clear_error (&priv->error); + + G_OBJECT_CLASS (json_reader_parent_class)->dispose (gobject); +} + +static void +json_reader_class_init (JsonReaderClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (JsonReaderPrivate)); + + gobject_class->dispose = json_reader_dispose; +} + +static void +json_reader_init (JsonReader *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, JSON_TYPE_READER, + JsonReaderPrivate); + + self->priv->parser = json_parser_new (); +} + +GQuark +json_reader_error_quark (void) +{ + return g_quark_from_static_string ("json-reader-error"); +} + +/** + * json_reader_new: + * + * Creates a new #JsonReader instance + * + * Return value: the newly created #JsonReader. Use g_object_unref() to + * release the allocated resources when done + * + * Since: 0.12 + */ +JsonReader * +json_reader_new (void) +{ + return g_object_new (JSON_TYPE_READER, NULL); +} + +/** + * json_reader_load_from_data: + * @reader: a #JsonReader + * @data: the data to be parsed + * @length: the length of @data, or -1 + * @error: return location for a #GError, or %NULL + * + * Loads a JSON string and parses it. + * + * If @reader already contained a JSON DOM, it will be reset. + * + * Return value: %TRUE if the data was successfully parsed, and %FALSE + * otherwise. In case of failure, the #GError will be set accordingly + * + * Since: 0.12 + */ +gboolean +json_reader_load_from_data (JsonReader *reader, + const gchar *data, + gssize length, + GError **error) +{ + JsonReaderPrivate *priv; + GError *internal_error; + gboolean retval; + + g_return_val_if_fail (JSON_IS_READER (reader), FALSE); + + priv = reader->priv; + + if (priv->root != NULL) + { + priv->root = NULL; + + priv->current_node = NULL; + priv->previous_node = NULL; + } + + if (priv->error != NULL) + g_clear_error (&priv->error); + + internal_error = NULL; + retval = json_parser_load_from_data (priv->parser, data, length, &internal_error); + if (retval) + { + priv->root = json_parser_get_root (priv->parser); + + priv->current_node = priv->root; + priv->previous_node = NULL; + + priv->error = NULL; + } + else + { + priv->error = g_error_copy (internal_error); + g_propagate_error (error, internal_error); + } + + return retval; +} + +/* + * 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_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 + */ +G_CONST_RETURN 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 array 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_value_int (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_value_string (reader); + * json_reader_end_element (reader); + * + * json_reader_read_element (reader, 2); + * str_value = json_reader_get_value_string (reader); + * json_reader_end_element (reader); + * ]| + * + * If @reader is not currently on an array, or if the @index_ is bigger than + * the size of the array, 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; + JsonArray *array; + + 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)) + return json_reader_set_error (reader, JSON_READER_ERROR_NO_ARRAY, + "The current node is of type '%s', but " + "an array was expected.", + json_node_type_name (priv->current_node)); + + 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_); + + 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; + + 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) + return -1; + + if (!JSON_NODE_HOLDS_ARRAY (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_value_int (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_value_string (reader); + * json_reader_end_element (reader); + * + * json_reader_read_element (reader, "title"); + * title = json_reader_get_value_string (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); + + priv->previous_node = priv->current_node; + priv->current_node = json_object_get_member (object, 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; + + priv->current_node = priv->previous_node; + priv->previous_node = tmp; +} + +/** + * 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) + return -1; + + if (!JSON_NODE_HOLDS_OBJECT (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) +{ + 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) + return NULL; + + if (!JSON_NODE_HOLDS_VALUE (reader->priv->current_node)) + return NULL; + + return reader->priv->current_node; +} + +/** + * json_reader_get_value_int: + * @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_value_int (JsonReader *reader) +{ + 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) + return 0; + + if (!JSON_NODE_HOLDS_VALUE (reader->priv->current_node)) + return 0; + + return json_node_get_int (reader->priv->current_node); +} + +/** + * json_reader_get_value_double: + * @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_value_double (JsonReader *reader) +{ + 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) + return 0.0; + + if (!JSON_NODE_HOLDS_VALUE (reader->priv->current_node)) + return 0.0; + + return json_node_get_double (reader->priv->current_node); +} + +/** + * json_reader_get_value_string: + * @reader: a #JsonReader + * + * Retrieves the string value of the current position of @reader + * + * Return value: the string value + * + * Since: 0.12 + */ +G_CONST_RETURN gchar * +json_reader_get_value_string (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) + return NULL; + + if (!JSON_NODE_HOLDS_VALUE (reader->priv->current_node)) + return NULL; + + return json_node_get_string (reader->priv->current_node); +} + +/** + * json_reader_get_value_boolean: + * @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_value_boolean (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; + + if (!JSON_NODE_HOLDS_VALUE (reader->priv->current_node)) + return FALSE; + + return json_node_get_boolean (reader->priv->current_node); +} + +/** + * json_reader_get_value_null: + * @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_value_null (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_NULL (reader->priv->current_node); +} diff --git a/json-glib/json-reader.h b/json-glib/json-reader.h new file mode 100644 index 0000000..a4fb239 --- /dev/null +++ b/json-glib/json-reader.h @@ -0,0 +1,142 @@ +/* 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 + * + * 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 +} 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 (void); + +gboolean json_reader_load_from_data (JsonReader *reader, + const gchar *data, + gssize length, + GError **error); + +G_CONST_RETURN 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); + +gboolean json_reader_is_value (JsonReader *reader); +JsonNode * json_reader_get_value (JsonReader *reader); +gint64 json_reader_get_value_int (JsonReader *reader); +gdouble json_reader_get_value_double (JsonReader *reader); +G_CONST_RETURN gchar * json_reader_get_value_string (JsonReader *reader); +gboolean json_reader_get_value_boolean (JsonReader *reader); +gboolean json_reader_get_value_null (JsonReader *reader); + +G_END_DECLS + +#endif /* __JSON_READER_H__ */ diff --git a/json-glib/tests/Makefile.am b/json-glib/tests/Makefile.am index 917b0de..74b7ba0 100644 --- a/json-glib/tests/Makefile.am +++ b/json-glib/tests/Makefile.am @@ -37,6 +37,10 @@ TEST_PROGS += generator-test generator_test_SOURCES = generator-test.c generator_test_LDADD = $(progs_ldadd) -TEST_PROGS += builder-test -builder_test_SOURCES = builder-test.c -builder_test_LDADD = $(progs_ldadd) +TEST_PROGS += builder-test +builder_test_SOURCES = builder-test.c +builder_test_LDADD = $(progs_ldadd) + +TEST_PROGS += reader-test +reader_test_SOURCES = reader-test.c +reader_test_LDADD = $(progs_ldadd) diff --git a/json-glib/tests/reader-test.c b/json-glib/tests/reader-test.c new file mode 100644 index 0000000..ebd5381 --- /dev/null +++ b/json-glib/tests/reader-test.c @@ -0,0 +1,101 @@ +#include <stdlib.h> +#include <stdio.h> + +#include <glib.h> + +#include <json-glib/json-glib.h> + +static const gchar *test_base_array_data = +"[ 0, true, null, \"foo\", 3.14, [ false ], { \"bar\" : 42 } ]"; + +static const gchar *test_base_object_data = +"{ \"text\" : \"hello, world!\", \"foo\" : \"bar\", \"blah\" : 47 }"; + +static void +test_base_object (void) +{ + JsonReader *reader = json_reader_new (); + GError *error = NULL; + + json_reader_load_from_data (reader, test_base_object_data, -1, &error); + g_assert (error == NULL); + + g_assert (json_reader_is_object (reader)); + g_assert_cmpint (json_reader_count_members (reader), ==, 3); + + g_assert (json_reader_read_member (reader, "foo")); + g_assert (json_reader_is_value (reader)); + g_assert_cmpstr (json_reader_get_value_string (reader), ==, "bar"); + json_reader_end_member (reader); + + g_assert (!json_reader_read_member (reader, "bar")); + g_assert (json_reader_get_error (reader) != NULL); + g_assert_error ((GError *) json_reader_get_error (reader), + JSON_READER_ERROR, + JSON_READER_ERROR_INVALID_MEMBER); + json_reader_end_member (reader); + g_assert (json_reader_get_error (reader) == NULL); + + g_object_unref (reader); +} + +static void +test_base_array (void) +{ + JsonReader *reader = json_reader_new (); + GError *error = NULL; + + json_reader_load_from_data (reader, test_base_array_data, -1, &error); + g_assert (error == NULL); + + g_assert (json_reader_is_array (reader)); + g_assert_cmpint (json_reader_count_elements (reader), ==, 7); + + json_reader_read_element (reader, 0); + g_assert (json_reader_is_value (reader)); + g_assert_cmpint (json_reader_get_value_int (reader), ==, 0); + json_reader_end_element (reader); + + json_reader_read_element (reader, 3); + g_assert (json_reader_is_value (reader)); + g_assert_cmpstr (json_reader_get_value_string (reader), ==, "foo"); + json_reader_end_element (reader); + + json_reader_read_element (reader, 5); + g_assert (!json_reader_is_value (reader)); + g_assert (json_reader_is_array (reader)); + json_reader_end_element (reader); + + json_reader_read_element (reader, 6); + g_assert (json_reader_is_object (reader)); + + json_reader_read_member (reader, "bar"); + g_assert (json_reader_is_value (reader)); + g_assert_cmpint (json_reader_get_value_int (reader), ==, 42); + json_reader_end_member (reader); + + json_reader_end_element (reader); + + g_assert (!json_reader_read_element (reader, 7)); + g_assert_error ((GError *) json_reader_get_error (reader), + JSON_READER_ERROR, + JSON_READER_ERROR_INVALID_INDEX); + json_reader_end_element (reader); + g_assert (json_reader_get_error (reader) == NULL); + + g_object_unref (reader); +} + +int +main (int argc, + char *argv[]) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id="); + + g_test_add_func ("/reader/base-array", test_base_array); + g_test_add_func ("/reader/base-object", test_base_object); + + return g_test_run (); +} |