/* 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 . * * Author: * Emmanuele Bassi */ /** * JsonReader: * * `JsonReader` provides a simple, cursor-based API for parsing a JSON DOM. * * It is similar, in spirit, to the XML Reader API. * * ## Using `JsonReader` * * ```c * g_autoptr(JsonParser) parser = json_parser_new (); * * // str is defined elsewhere * json_parser_load_from_data (parser, str, -1, NULL); * * g_autoptr(JsonReader) reader = json_reader_new (json_parser_get_root (parser)); * * json_reader_read_member (reader, "url"); * const char *url = json_reader_get_string_value (reader); * json_reader_end_member (reader); * * json_reader_read_member (reader, "size"); * json_reader_read_element (reader, 0); * int width = json_reader_get_int_value (reader); * json_reader_end_element (reader); * json_reader_read_element (reader, 1); * int height = json_reader_get_int_value (reader); * json_reader_end_element (reader); * json_reader_end_member (reader); * ``` * * ## Error handling * * 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.: * * ```c * // 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 * [method@Json.Reader.get_error]: * * ```c * // 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); * } * ``` * * Since: 0.12 */ #include "config.h" #include #include #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; /* Stack of member names. */ GPtrArray *members; GError *error; }; enum { PROP_0, PROP_ROOT, PROP_LAST }; static GParamSpec *reader_properties[PROP_LAST] = { NULL, }; G_DEFINE_TYPE_WITH_PRIVATE (JsonReader, json_reader, G_TYPE_OBJECT) G_DEFINE_QUARK (json-reader-error-quark, json_reader_error) static void json_reader_finalize (GObject *gobject) { JsonReaderPrivate *priv = JSON_READER (gobject)->priv; if (priv->root != NULL) json_node_unref (priv->root); if (priv->error != NULL) g_clear_error (&priv->error); if (priv->members != NULL) g_ptr_array_unref (priv->members); 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); /** * JsonReader:root: (attributes org.gtk.Property.set=json_reader_set_root) * * The root of the JSON tree that the reader 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 = json_reader_get_instance_private (self); self->priv->members = g_ptr_array_new_with_free_func (g_free); } /** * json_reader_new: * @node: (nullable): the root node * * Creates a new reader. * * You can use this object to read the contents of the JSON tree starting * from the given node. * * Return value: the newly created reader * * 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 reader * * Unsets the error state of @reader, if set * * Return value: TRUE if an error was set. */ static inline gboolean json_reader_unset_error (JsonReader *reader) { if (reader->priv->error != NULL) { g_clear_error (&(reader->priv->error)); return TRUE; } return FALSE; } /** * json_reader_set_root: (attributes org.gtk.Method.set_property=root) * @reader: a reader * @root: (nullable): the root node * * Sets the root node of the JSON tree to be read by @reader. * * The reader will take a copy of the node. * * 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_unref (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_set_error: * @reader: a reader * @error_code: the [error@Json.ReaderError] code for the error * @error_fmt: format string * @Varargs: list of arguments for the `error_fmt` string * * Sets the error state of the reader using the given error code * and string. * * Return value: `FALSE`, to be used to return immediately from * the caller function */ G_GNUC_PRINTF (3, 4) 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 reader * * Retrieves the error currently set on the reader. * * Return value: (nullable) (transfer none): the current error * * Since: 0.12 */ const GError * json_reader_get_error (JsonReader *reader) { g_return_val_if_fail (JSON_IS_READER (reader), NULL); return reader->priv->error; } /** * json_reader_is_array: * @reader: a reader * * Checks whether the reader is currently on an array. * * Return value: `TRUE` if the reader is on an array * * 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 reader * * Checks whether the reader is currently on an object. * * Return value: `TRUE` if the reader is on an object * * 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 reader * * Checks whether the reader is currently on a value. * * Return value: `TRUE` if the reader is on a value * * 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_NODE_HOLDS_NULL (reader->priv->current_node); } /** * json_reader_read_element: * @reader: a reader * @index_: the index of the element * * Advances the cursor of the reader to the element of the array or * the member of the object at the given position. * * You can use [method@Json.Reader.get_value] and its wrapper functions to * retrieve the value of the element; for instance, the following code will * read the first element of the array at the current cursor position: * * ```c * json_reader_read_element (reader, 0); * int_value = json_reader_get_int_value (reader); * ``` * * After reading the value, you should call [method@Json.Reader.end_element] * to reposition the cursor inside the reader, e.g.: * * ```c * const char *str_value = NULL; * * 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 the 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 reader will be * put in an error state until [method@Json.Reader.end_element] is called. This * means that, if used conditionally, [method@Json.Reader.end_element] must be * called on all branches: * * ```c * if (!json_reader_read_element (reader, 1)) * { * g_propagate_error (error, json_reader_get_error (reader)); * json_reader_end_element (reader); * return FALSE; * } * else * { * const char *str_value = json_reader_get_string_value (reader); * json_reader_end_element (reader); * * // use str_value * * return TRUE; * } * ```c * * 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); GQueue *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; members = json_object_get_members_internal (object); name = g_queue_peek_nth (members, index_); priv->current_node = json_object_get_member (object, name); g_ptr_array_add (priv->members, g_strdup (name)); } break; default: g_assert_not_reached (); return FALSE; } return TRUE; } /** * json_reader_end_element: * @reader: a reader * * Moves the cursor back to the previous node after being positioned * inside an array. * * This function resets the error state of the 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)); if (json_reader_unset_error (reader)) return; priv = reader->priv; if (priv->previous_node != NULL) tmp = json_node_get_parent (priv->previous_node); else tmp = NULL; if (json_node_get_node_type (priv->previous_node) == JSON_NODE_OBJECT) g_ptr_array_remove_index (priv->members, priv->members->len - 1); priv->current_node = priv->previous_node; priv->previous_node = tmp; } /** * json_reader_count_elements: * @reader: a reader * * Counts the elements of the current position, if the reader is * positioned on an array. * * In case of failure, the reader is set to an error state. * * Return value: the number of elements, or -1. * * 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 reader * @member_name: the name of the member to read * * Advances the cursor of the reader to the `member_name` of the object at * the current position. * * You can use [method@Json.Reader.get_value] and its wrapper functions to * retrieve the value of the member; for instance: * * ```c * 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 reader, e.g.: * * ```c * json_reader_read_member (reader, "author"); * author = json_reader_get_string_value (reader); * json_reader_end_member (reader); * * json_reader_read_member (reader, "title"); * title = json_reader_get_string_value (reader); * json_reader_end_member (reader); * ``` * * If the reader is not currently on an object, or if the `member_name` is not * defined in the object, the reader will be put in an error state until * [method@Json.Reader.end_member] is called. This means that if used * conditionally, [method@Json.Reader.end_member] must be called on all branches: * * ```c * if (!json_reader_read_member (reader, "title")) * { * g_propagate_error (error, json_reader_get_error (reader)); * json_reader_end_member (reader); * return FALSE; * } * else * { * const char *str_value = json_reader_get_string_value (reader); * json_reader_end_member (reader); * * // use str_value * * return TRUE; * } * ``` * * 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); g_ptr_array_add (priv->members, g_strdup (member_name)); return TRUE; } /** * json_reader_end_member: * @reader: a reader * * Moves the cursor back to the previous node after being positioned * inside an object. * * This function resets the error state of the 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)); if (json_reader_unset_error (reader)) return; priv = reader->priv; if (priv->previous_node != NULL) tmp = json_node_get_parent (priv->previous_node); else tmp = NULL; g_ptr_array_remove_index (priv->members, priv->members->len - 1); priv->current_node = priv->previous_node; priv->previous_node = tmp; } /** * json_reader_list_members: * @reader: a reader * * Retrieves a list of member names from the current position, if the reader * is positioned on an object. * * In case of failure, the reader is set to an error state. * * Return value: (transfer full) (array zero-terminated=1): the members of * the object * * Since: 0.14 */ gchar ** json_reader_list_members (JsonReader *reader) { JsonReaderPrivate *priv; JsonObject *object; GQueue *members; GList *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; } object = json_node_get_object (priv->current_node); members = json_object_get_members_internal (object); retval = g_new (gchar*, g_queue_get_length (members) + 1); for (l = members->head, i = 0; l != NULL; l = l->next, i += 1) retval[i] = g_strdup (l->data); retval[i] = NULL; return retval; } /** * json_reader_count_members: * @reader: a reader * * Counts the members of the current position, if the reader is * positioned on an object. * * In case of failure, the reader is set to an error state. * * Return value: the number of members, or -1 * * 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 reader * * Retrieves the value node at the current position of the reader. * * If the current position does not contain a scalar value, the reader * is set to an error state. * * Return value: (nullable) (transfer none): the current value node * * 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_NODE_HOLDS_NULL (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 reader * * Retrieves the integer value of the current position of the reader. * * See also: [method@Json.Reader.get_value] * * 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; } return json_node_get_int (reader->priv->current_node); } /** * json_reader_get_double_value: * @reader: a reader * * Retrieves the floating point value of the current position of the reader. * * See also: [method@Json.Reader.get_value] * * 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; } return json_node_get_double (reader->priv->current_node); } /** * json_reader_get_string_value: * @reader: a reader * * Retrieves the string value of the current position of the reader. * * See also: [method@Json.Reader.get_value] * * 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 reader * * Retrieves the boolean value of the current position of the reader. * * See also: [method@Json.Reader.get_value] * * 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; } return json_node_get_boolean (node); } /** * json_reader_get_null_value: * @reader: a reader * * Checks whether the value of the current position of the reader is `null`. * * See also: [method@Json.Reader.get_value] * * 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 reader * * Retrieves the name of the current member. * * In case of failure, the reader is set to an error state. * * Return value: (nullable) (transfer none): the name of the member * * 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 NULL; } if (reader->priv->members->len == 0) return NULL; return g_ptr_array_index (reader->priv->members, reader->priv->members->len - 1); } /** * json_reader_get_current_node: * @reader: a reader * * Retrieves the reader node at the current position. * * Return value: (nullable) (transfer none): the current node of the reader * * Since: 1.8 */ JsonNode * json_reader_get_current_node (JsonReader *reader) { g_return_val_if_fail (JSON_IS_READER (reader), NULL); json_reader_return_val_if_error_set (reader, NULL); return reader->priv->current_node; }