1 /* json-reader.h - JSON cursor parser
2  *
3  * This file is part of JSON-GLib
4  * Copyright (C) 2010  Intel Corp.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Author:
20  *   Emmanuele Bassi  <ebassi@linux.intel.com>
21  */
22 
23 /**
24  * SECTION:json-reader
25  * @Title: JsonReader
26  * @short_description: A cursor-based parser
27  *
28  * #JsonReader provides a simple, cursor-based API for parsing a JSON DOM. It
29  * is similar, in spirit, to the XML Reader API.
30  *
31  * In case of error, #JsonReader will be set in an error state; all subsequent
32  * calls will simply be ignored until a function that resets the error state is
33  * called, e.g.:
34  *
35  * |[
36  * // ask for the 7th element; if the element does not exist, the
37  * // reader will be put in an error state
38  * json_reader_read_element (reader, 6);
39  *
40  * // in case of error, this will return NULL, otherwise it will
41  * // return the value of the element
42  * str = json_reader_get_string_value (value);
43  *
44  * // this function resets the error state if any was set
45  * json_reader_end_element (reader);
46  * ]|
47  *
48  * If you want to detect the error state as soon as possible, you can use
49  * json_reader_get_error():
50  *
51  * |[<!-- language="C" -->
52  * // like the example above, but in this case we print out the
53  * // error immediately
54  * if (!json_reader_read_element (reader, 6))
55  *   {
56  *     const GError *error = json_reader_get_error (reader);
57  *     g_print ("Unable to read the element: %s", error->message);
58  *   }
59  * ]|
60  *
61  * #JsonReader is available since JSON-GLib 0.12.
62  */
63 
64 #include "config.h"
65 
66 #include <string.h>
67 
68 #include <glib/gi18n-lib.h>
69 
70 #include "json-reader.h"
71 #include "json-types-private.h"
72 #include "json-debug.h"
73 
74 #define json_reader_return_if_error_set(r)      G_STMT_START {  \
75         if (((JsonReader *) (r))->priv->error != NULL)          \
76           return;                               } G_STMT_END
77 
78 #define json_reader_return_val_if_error_set(r,v) G_STMT_START {  \
79         if (((JsonReader *) (r))->priv->error != NULL)           \
80           return (v);                           } G_STMT_END
81 
82 struct _JsonReaderPrivate
83 {
84   JsonNode *root;
85 
86   JsonNode *current_node;
87   JsonNode *previous_node;
88 
89   /* Stack of member names. */
90   GPtrArray *members;
91 
92   GError *error;
93 };
94 
95 enum
96 {
97   PROP_0,
98 
99   PROP_ROOT,
100 
101   PROP_LAST
102 };
103 
104 static GParamSpec *reader_properties[PROP_LAST] = { NULL, };
105 
G_DEFINE_TYPE_WITH_PRIVATE(JsonReader,json_reader,G_TYPE_OBJECT)106 G_DEFINE_TYPE_WITH_PRIVATE (JsonReader, json_reader, G_TYPE_OBJECT)
107 
108 G_DEFINE_QUARK (json-reader-error-quark, json_reader_error)
109 
110 static void
111 json_reader_finalize (GObject *gobject)
112 {
113   JsonReaderPrivate *priv = JSON_READER (gobject)->priv;
114 
115   if (priv->root != NULL)
116     json_node_unref (priv->root);
117 
118   if (priv->error != NULL)
119     g_clear_error (&priv->error);
120 
121   if (priv->members != NULL)
122     g_ptr_array_unref (priv->members);
123 
124   G_OBJECT_CLASS (json_reader_parent_class)->finalize (gobject);
125 }
126 
127 static void
json_reader_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)128 json_reader_set_property (GObject      *gobject,
129                           guint         prop_id,
130                           const GValue *value,
131                           GParamSpec   *pspec)
132 {
133   switch (prop_id)
134     {
135     case PROP_ROOT:
136       json_reader_set_root (JSON_READER (gobject), g_value_get_boxed (value));
137       break;
138 
139     default:
140       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
141       break;
142     }
143 }
144 
145 static void
json_reader_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)146 json_reader_get_property (GObject    *gobject,
147                           guint       prop_id,
148                           GValue     *value,
149                           GParamSpec *pspec)
150 {
151   switch (prop_id)
152     {
153     case PROP_ROOT:
154       g_value_set_boxed (value, JSON_READER (gobject)->priv->root);
155       break;
156 
157     default:
158       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
159       break;
160     }
161 }
162 
163 static void
json_reader_class_init(JsonReaderClass * klass)164 json_reader_class_init (JsonReaderClass *klass)
165 {
166   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
167 
168   /**
169    * JsonReader:root:
170    *
171    * The root of the JSON tree that the #JsonReader should read.
172    *
173    * Since: 0.12
174    */
175   reader_properties[PROP_ROOT] =
176     g_param_spec_boxed ("root",
177                         "Root Node",
178                         "The root of the tree to read",
179                         JSON_TYPE_NODE,
180                         G_PARAM_READWRITE |
181                         G_PARAM_CONSTRUCT |
182                         G_PARAM_STATIC_STRINGS);
183 
184   gobject_class->finalize = json_reader_finalize;
185   gobject_class->set_property = json_reader_set_property;
186   gobject_class->get_property = json_reader_get_property;
187   g_object_class_install_properties (gobject_class, PROP_LAST, reader_properties);
188 }
189 
190 static void
json_reader_init(JsonReader * self)191 json_reader_init (JsonReader *self)
192 {
193   self->priv = json_reader_get_instance_private (self);
194   self->priv->members = g_ptr_array_new_with_free_func (g_free);
195 }
196 
197 /**
198  * json_reader_new:
199  * @node: (allow-none): a #JsonNode, or %NULL
200  *
201  * Creates a new #JsonReader. You can use this object to read the contents of
202  * the JSON tree starting from @node
203  *
204  * Return value: the newly created #JsonReader. Use g_object_unref() to
205  *   release the allocated resources when done
206  *
207  * Since: 0.12
208  */
209 JsonReader *
json_reader_new(JsonNode * node)210 json_reader_new (JsonNode *node)
211 {
212   return g_object_new (JSON_TYPE_READER, "root", node, NULL);
213 }
214 
215 /*
216  * json_reader_unset_error:
217  * @reader: a #JsonReader
218  *
219  * Unsets the error state of @reader, if set
220  *
221  * Return value: TRUE if an error was set.
222  */
223 static inline gboolean
json_reader_unset_error(JsonReader * reader)224 json_reader_unset_error (JsonReader *reader)
225 {
226   if (reader->priv->error != NULL)
227     {
228       g_clear_error (&(reader->priv->error));
229       return TRUE;
230     }
231   return FALSE;
232 }
233 
234 /**
235  * json_reader_set_root:
236  * @reader: a #JsonReader
237  * @root: (allow-none): a #JsonNode
238  *
239  * Sets the root #JsonNode to be read by @reader. The @reader will take
240  * a copy of @root
241  *
242  * If another #JsonNode is currently set as root, it will be replaced.
243  *
244  * Since: 0.12
245  */
246 void
json_reader_set_root(JsonReader * reader,JsonNode * root)247 json_reader_set_root (JsonReader *reader,
248                       JsonNode   *root)
249 {
250   JsonReaderPrivate *priv;
251 
252   g_return_if_fail (JSON_IS_READER (reader));
253 
254   priv = reader->priv;
255 
256   if (priv->root == root)
257     return;
258 
259   if (priv->root != NULL)
260     {
261       json_node_unref (priv->root);
262       priv->root = NULL;
263       priv->current_node = NULL;
264       priv->previous_node = NULL;
265     }
266 
267   if (root != NULL)
268     {
269       priv->root = json_node_copy (root);
270       priv->current_node = priv->root;
271       priv->previous_node = NULL;
272     }
273 
274   g_object_notify_by_pspec (G_OBJECT (reader), reader_properties[PROP_ROOT]);
275 }
276 
277 /*
278  * json_reader_ser_error:
279  * @reader: a #JsonReader
280  * @error_code: the #JsonReaderError code for the error
281  * @error_fmt: format string
282  * @Varargs: list of arguments for the @error_fmt string
283  *
284  * Sets the error state of @reader using the given error code
285  * and string
286  *
287  * Return value: %FALSE, to be used to return immediately from
288  *   the caller function
289  */
290 G_GNUC_PRINTF (3, 4)
291 static gboolean
json_reader_set_error(JsonReader * reader,JsonReaderError error_code,const gchar * error_fmt,...)292 json_reader_set_error (JsonReader      *reader,
293                        JsonReaderError  error_code,
294                        const gchar     *error_fmt,
295                        ...)
296 {
297   JsonReaderPrivate *priv = reader->priv;
298   va_list args;
299   gchar *error_msg;
300 
301   if (priv->error != NULL)
302     g_clear_error (&priv->error);
303 
304   va_start (args, error_fmt);
305   error_msg = g_strdup_vprintf (error_fmt, args);
306   va_end (args);
307 
308   g_set_error_literal (&priv->error, JSON_READER_ERROR,
309                        error_code,
310                        error_msg);
311 
312   g_free (error_msg);
313 
314   return FALSE;
315 }
316 
317 /**
318  * json_reader_get_error:
319  * @reader: a #JsonReader
320  *
321  * Retrieves the #GError currently set on @reader, if the #JsonReader
322  * is in error state
323  *
324  * Return value: (nullable) (transfer none): the pointer to the error, or %NULL
325  *
326  * Since: 0.12
327  */
328 const GError *
json_reader_get_error(JsonReader * reader)329 json_reader_get_error (JsonReader *reader)
330 {
331   g_return_val_if_fail (JSON_IS_READER (reader), NULL);
332 
333   return reader->priv->error;
334 }
335 
336 /**
337  * json_reader_is_array:
338  * @reader: a #JsonReader
339  *
340  * Checks whether the @reader is currently on an array
341  *
342  * Return value: %TRUE if the #JsonReader is on an array, and %FALSE
343  *   otherwise
344  *
345  * Since: 0.12
346  */
347 gboolean
json_reader_is_array(JsonReader * reader)348 json_reader_is_array (JsonReader *reader)
349 {
350   g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
351   json_reader_return_val_if_error_set (reader, FALSE);
352 
353   if (reader->priv->current_node == NULL)
354     return FALSE;
355 
356   return JSON_NODE_HOLDS_ARRAY (reader->priv->current_node);
357 }
358 
359 /**
360  * json_reader_is_object:
361  * @reader: a #JsonReader
362  *
363  * Checks whether the @reader is currently on an object
364  *
365  * Return value: %TRUE if the #JsonReader is on an object, and %FALSE
366  *   otherwise
367  *
368  * Since: 0.12
369  */
370 gboolean
json_reader_is_object(JsonReader * reader)371 json_reader_is_object (JsonReader *reader)
372 {
373   g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
374   json_reader_return_val_if_error_set (reader, FALSE);
375 
376   if (reader->priv->current_node == NULL)
377     return FALSE;
378 
379   return JSON_NODE_HOLDS_OBJECT (reader->priv->current_node);
380 }
381 
382 /**
383  * json_reader_is_value:
384  * @reader: a #JsonReader
385  *
386  * Checks whether the @reader is currently on a value
387  *
388  * Return value: %TRUE if the #JsonReader is on a value, and %FALSE
389  *   otherwise
390  *
391  * Since: 0.12
392  */
393 gboolean
json_reader_is_value(JsonReader * reader)394 json_reader_is_value (JsonReader *reader)
395 {
396   g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
397   json_reader_return_val_if_error_set (reader, FALSE);
398 
399   if (reader->priv->current_node == NULL)
400     return FALSE;
401 
402   return JSON_NODE_HOLDS_VALUE (reader->priv->current_node) ||
403          JSON_NODE_HOLDS_NULL (reader->priv->current_node);
404 }
405 
406 /**
407  * json_reader_read_element:
408  * @reader: a #JsonReader
409  * @index_: the index of the element
410  *
411  * Advances the cursor of @reader to the element @index_ of the array
412  * or the object at the current position.
413  *
414  * You can use the json_reader_get_value* family of functions to retrieve
415  * the value of the element; for instance:
416  *
417  * |[
418  * json_reader_read_element (reader, 0);
419  * int_value = json_reader_get_int_value (reader);
420  * ]|
421  *
422  * After reading the value, json_reader_end_element() should be called to
423  * reposition the cursor inside the #JsonReader, e.g.:
424  *
425  * |[
426  * json_reader_read_element (reader, 1);
427  * str_value = json_reader_get_string_value (reader);
428  * json_reader_end_element (reader);
429  *
430  * json_reader_read_element (reader, 2);
431  * str_value = json_reader_get_string_value (reader);
432  * json_reader_end_element (reader);
433  * ]|
434  *
435  * If @reader is not currently on an array or an object, or if the @index_ is
436  * bigger than the size of the array or the object, the #JsonReader will be
437  * put in an error state until json_reader_end_element() is called. This means
438  * that if used conditionally, json_reader_end_element() must be called on both
439  * code paths:
440  *
441  * |[
442  * if (!json_reader_read_element (reader, 1))
443  *   {
444  *     json_reader_end_element (reader);
445  *     g_set_error (error, …);
446  *     return FALSE;
447  *   }
448  *
449  * str_value = json_reader_get_string_value (reader);
450  * json_reader_end_element (reader);
451  * ]|
452  *
453  * Return value: %TRUE on success, and %FALSE otherwise
454  *
455  * Since: 0.12
456  */
457 gboolean
json_reader_read_element(JsonReader * reader,guint index_)458 json_reader_read_element (JsonReader *reader,
459                           guint       index_)
460 {
461   JsonReaderPrivate *priv;
462 
463   g_return_val_if_fail (JSON_READER (reader), FALSE);
464   json_reader_return_val_if_error_set (reader, FALSE);
465 
466   priv = reader->priv;
467 
468   if (priv->current_node == NULL)
469     priv->current_node = priv->root;
470 
471   if (!(JSON_NODE_HOLDS_ARRAY (priv->current_node) ||
472         JSON_NODE_HOLDS_OBJECT (priv->current_node)))
473     return json_reader_set_error (reader, JSON_READER_ERROR_NO_ARRAY,
474                                   _("The current node is of type “%s”, but "
475                                     "an array or an object was expected."),
476                                   json_node_type_name (priv->current_node));
477 
478   switch (json_node_get_node_type (priv->current_node))
479     {
480     case JSON_NODE_ARRAY:
481       {
482         JsonArray *array = json_node_get_array (priv->current_node);
483 
484         if (index_ >= json_array_get_length (array))
485           return json_reader_set_error (reader, JSON_READER_ERROR_INVALID_INDEX,
486                                         _("The index “%d” is greater than the size "
487                                           "of the array at the current position."),
488                                         index_);
489 
490         priv->previous_node = priv->current_node;
491         priv->current_node = json_array_get_element (array, index_);
492       }
493       break;
494 
495     case JSON_NODE_OBJECT:
496       {
497         JsonObject *object = json_node_get_object (priv->current_node);
498         GQueue *members;
499         const gchar *name;
500 
501         if (index_ >= json_object_get_size (object))
502           return json_reader_set_error (reader, JSON_READER_ERROR_INVALID_INDEX,
503                                         _("The index “%d” is greater than the size "
504                                           "of the object at the current position."),
505                                         index_);
506 
507         priv->previous_node = priv->current_node;
508 
509         members = json_object_get_members_internal (object);
510         name = g_queue_peek_nth (members, index_);
511 
512         priv->current_node = json_object_get_member (object, name);
513         g_ptr_array_add (priv->members, g_strdup (name));
514       }
515       break;
516 
517     default:
518       g_assert_not_reached ();
519       return FALSE;
520     }
521 
522   return TRUE;
523 }
524 
525 /**
526  * json_reader_end_element:
527  * @reader: a #JsonReader
528  *
529  * Moves the cursor back to the previous node after being positioned
530  * inside an array
531  *
532  * This function resets the error state of @reader, if any was set
533  *
534  * Since: 0.12
535  */
536 void
json_reader_end_element(JsonReader * reader)537 json_reader_end_element (JsonReader *reader)
538 {
539   JsonReaderPrivate *priv;
540   JsonNode *tmp;
541 
542   g_return_if_fail (JSON_IS_READER (reader));
543 
544   if (json_reader_unset_error (reader))
545     return;
546 
547   priv = reader->priv;
548 
549   if (priv->previous_node != NULL)
550     tmp = json_node_get_parent (priv->previous_node);
551   else
552     tmp = NULL;
553 
554   if (json_node_get_node_type (priv->previous_node) == JSON_NODE_OBJECT)
555     g_ptr_array_remove_index (priv->members, priv->members->len - 1);
556 
557   priv->current_node = priv->previous_node;
558   priv->previous_node = tmp;
559 }
560 
561 /**
562  * json_reader_count_elements:
563  * @reader: a #JsonReader
564  *
565  * Counts the elements of the current position, if @reader is
566  * positioned on an array
567  *
568  * Return value: the number of elements, or -1. In case of failure
569  *   the #JsonReader is set in an error state
570  *
571  * Since: 0.12
572  */
573 gint
json_reader_count_elements(JsonReader * reader)574 json_reader_count_elements (JsonReader *reader)
575 {
576   JsonReaderPrivate *priv;
577 
578   g_return_val_if_fail (JSON_IS_READER (reader), -1);
579 
580   priv = reader->priv;
581 
582   if (priv->current_node == NULL)
583     {
584       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
585                              _("No node available at the current position"));
586       return -1;
587     }
588 
589   if (!JSON_NODE_HOLDS_ARRAY (priv->current_node))
590     {
591       json_reader_set_error (reader, JSON_READER_ERROR_NO_ARRAY,
592                              _("The current position holds a “%s” and not an array"),
593                              json_node_type_get_name (JSON_NODE_TYPE (priv->current_node)));
594       return -1;
595     }
596 
597   return json_array_get_length (json_node_get_array (priv->current_node));
598 }
599 
600 /**
601  * json_reader_read_member:
602  * @reader: a #JsonReader
603  * @member_name: the name of the member to read
604  *
605  * Advances the cursor of @reader to the @member_name of the object at the
606  * current position.
607  *
608  * You can use the json_reader_get_value* family of functions to retrieve
609  * the value of the member; for instance:
610  *
611  * |[
612  * json_reader_read_member (reader, "width");
613  * width = json_reader_get_int_value (reader);
614  * ]|
615  *
616  * After reading the value, json_reader_end_member() should be called to
617  * reposition the cursor inside the #JsonReader, e.g.:
618  *
619  * |[
620  * json_reader_read_member (reader, "author");
621  * author = json_reader_get_string_value (reader);
622  * json_reader_end_member (reader);
623  *
624  * json_reader_read_member (reader, "title");
625  * title = json_reader_get_string_value (reader);
626  * json_reader_end_member (reader);
627  * ]|
628  *
629  * If @reader is not currently on an object, or if the @member_name is not
630  * defined in the object, the #JsonReader will be put in an error state until
631  * json_reader_end_member() is called. This means that if used conditionally,
632  * json_reader_end_member() must be called on both code paths:
633  *
634  * |[
635  * if (!json_reader_read_member (reader, "title"))
636  *   {
637  *     json_reader_end_member (reader);
638  *     g_set_error (error, …);
639  *     return FALSE;
640  *   }
641  *
642  * str_value = json_reader_get_string_value (reader);
643  * json_reader_end_member (reader);
644  * ]|
645  *
646  * Return value: %TRUE on success, and %FALSE otherwise
647  *
648  * Since: 0.12
649  */
650 gboolean
json_reader_read_member(JsonReader * reader,const gchar * member_name)651 json_reader_read_member (JsonReader  *reader,
652                          const gchar *member_name)
653 {
654   JsonReaderPrivate *priv;
655   JsonObject *object;
656 
657   g_return_val_if_fail (JSON_READER (reader), FALSE);
658   g_return_val_if_fail (member_name != NULL, FALSE);
659   json_reader_return_val_if_error_set (reader, FALSE);
660 
661   priv = reader->priv;
662 
663   if (priv->current_node == NULL)
664     priv->current_node = priv->root;
665 
666   if (!JSON_NODE_HOLDS_OBJECT (priv->current_node))
667     return json_reader_set_error (reader, JSON_READER_ERROR_NO_OBJECT,
668                                   _("The current node is of type “%s”, but "
669                                     "an object was expected."),
670                                   json_node_type_name (priv->current_node));
671 
672   object = json_node_get_object (priv->current_node);
673   if (!json_object_has_member (object, member_name))
674     return json_reader_set_error (reader, JSON_READER_ERROR_INVALID_MEMBER,
675                                   _("The member “%s” is not defined in the "
676                                     "object at the current position."),
677                                   member_name);
678 
679   priv->previous_node = priv->current_node;
680   priv->current_node = json_object_get_member (object, member_name);
681   g_ptr_array_add (priv->members, g_strdup (member_name));
682 
683   return TRUE;
684 }
685 
686 /**
687  * json_reader_end_member:
688  * @reader: a #JsonReader
689  *
690  * Moves the cursor back to the previous node after being positioned
691  * inside an object
692  *
693  * This function resets the error state of @reader, if any was set
694  *
695  * Since: 0.12
696  */
697 void
json_reader_end_member(JsonReader * reader)698 json_reader_end_member (JsonReader *reader)
699 {
700   JsonReaderPrivate *priv;
701   JsonNode *tmp;
702 
703   g_return_if_fail (JSON_IS_READER (reader));
704 
705   if (json_reader_unset_error (reader))
706     return;
707 
708   priv = reader->priv;
709 
710   if (priv->previous_node != NULL)
711     tmp = json_node_get_parent (priv->previous_node);
712   else
713     tmp = NULL;
714 
715   g_ptr_array_remove_index (priv->members, priv->members->len - 1);
716 
717   priv->current_node = priv->previous_node;
718   priv->previous_node = tmp;
719 }
720 
721 /**
722  * json_reader_list_members:
723  * @reader: a #JsonReader
724  *
725  * Retrieves a list of member names from the current position, if @reader
726  * is positioned on an object.
727  *
728  * Return value: (transfer full): a newly allocated, %NULL-terminated
729  *   array of strings holding the members name. Use g_strfreev() when
730  *   done.
731  *
732  * Since: 0.14
733  */
734 gchar **
json_reader_list_members(JsonReader * reader)735 json_reader_list_members (JsonReader *reader)
736 {
737   JsonReaderPrivate *priv;
738   JsonObject *object;
739   GQueue *members;
740   GList *l;
741   gchar **retval;
742   gint i;
743 
744   g_return_val_if_fail (JSON_IS_READER (reader), NULL);
745 
746   priv = reader->priv;
747 
748   if (priv->current_node == NULL)
749     {
750       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
751                              _("No node available at the current position"));
752       return NULL;
753     }
754 
755   if (!JSON_NODE_HOLDS_OBJECT (priv->current_node))
756     {
757       json_reader_set_error (reader, JSON_READER_ERROR_NO_OBJECT,
758                              _("The current position holds a “%s” and not an object"),
759                              json_node_type_get_name (JSON_NODE_TYPE (priv->current_node)));
760       return NULL;
761     }
762 
763   object = json_node_get_object (priv->current_node);
764   members = json_object_get_members_internal (object);
765 
766   retval = g_new (gchar*, g_queue_get_length (members) + 1);
767   for (l = members->head, i = 0; l != NULL; l = l->next, i += 1)
768     retval[i] = g_strdup (l->data);
769 
770   retval[i] = NULL;
771 
772   return retval;
773 }
774 
775 /**
776  * json_reader_count_members:
777  * @reader: a #JsonReader
778  *
779  * Counts the members of the current position, if @reader is
780  * positioned on an object
781  *
782  * Return value: the number of members, or -1. In case of failure
783  *   the #JsonReader is set in an error state
784  *
785  * Since: 0.12
786  */
787 gint
json_reader_count_members(JsonReader * reader)788 json_reader_count_members (JsonReader *reader)
789 {
790   JsonReaderPrivate *priv;
791 
792   g_return_val_if_fail (JSON_IS_READER (reader), -1);
793 
794   priv = reader->priv;
795 
796   if (priv->current_node == NULL)
797     {
798       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
799                              _("No node available at the current position"));
800       return -1;
801     }
802 
803   if (!JSON_NODE_HOLDS_OBJECT (priv->current_node))
804     {
805       json_reader_set_error (reader, JSON_READER_ERROR_NO_OBJECT,
806                              _("The current position holds a “%s” and not an object"),
807                              json_node_type_get_name (JSON_NODE_TYPE (priv->current_node)));
808       return -1;
809     }
810 
811   return json_object_get_size (json_node_get_object (priv->current_node));
812 }
813 
814 /**
815  * json_reader_get_value:
816  * @reader: a #JsonReader
817  *
818  * Retrieves the #JsonNode of the current position of @reader
819  *
820  * Return value: (nullable) (transfer none): a #JsonNode, or %NULL. The
821  * returned node is owned by the #JsonReader and it should not be
822  * modified or freed directly
823  *
824  * Since: 0.12
825  */
826 JsonNode *
json_reader_get_value(JsonReader * reader)827 json_reader_get_value (JsonReader *reader)
828 {
829   JsonNode *node;
830 
831   g_return_val_if_fail (JSON_IS_READER (reader), NULL);
832   json_reader_return_val_if_error_set (reader, NULL);
833 
834   if (reader->priv->current_node == NULL)
835     {
836       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
837                              _("No node available at the current position"));
838       return NULL;
839     }
840 
841   node = reader->priv->current_node;
842 
843   if (!JSON_NODE_HOLDS_VALUE (node) && !JSON_NODE_HOLDS_NULL (node))
844     {
845       json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
846                              _("The current position holds a “%s” and not a value"),
847                              json_node_type_get_name (JSON_NODE_TYPE (node)));
848       return NULL;
849     }
850 
851   return reader->priv->current_node;
852 }
853 
854 /**
855  * json_reader_get_int_value:
856  * @reader: a #JsonReader
857  *
858  * Retrieves the integer value of the current position of @reader
859  *
860  * Return value: the integer value
861  *
862  * Since: 0.12
863  */
864 gint64
json_reader_get_int_value(JsonReader * reader)865 json_reader_get_int_value (JsonReader *reader)
866 {
867   JsonNode *node;
868 
869   g_return_val_if_fail (JSON_IS_READER (reader), 0);
870   json_reader_return_val_if_error_set (reader, 0);
871 
872   if (reader->priv->current_node == NULL)
873     {
874       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
875                              _("No node available at the current position"));
876       return 0;
877     }
878 
879   node = reader->priv->current_node;
880 
881   if (!JSON_NODE_HOLDS_VALUE (node))
882     {
883       json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
884                              _("The current position holds a “%s” and not a value"),
885                              json_node_type_get_name (JSON_NODE_TYPE (node)));
886       return 0;
887     }
888 
889   return json_node_get_int (reader->priv->current_node);
890 }
891 
892 /**
893  * json_reader_get_double_value:
894  * @reader: a #JsonReader
895  *
896  * Retrieves the floating point value of the current position of @reader
897  *
898  * Return value: the floating point value
899  *
900  * Since: 0.12
901  */
902 gdouble
json_reader_get_double_value(JsonReader * reader)903 json_reader_get_double_value (JsonReader *reader)
904 {
905   JsonNode *node;
906 
907   g_return_val_if_fail (JSON_IS_READER (reader), 0.0);
908   json_reader_return_val_if_error_set (reader, 0.0);
909 
910   if (reader->priv->current_node == NULL)
911     {
912       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
913                              _("No node available at the current position"));
914       return 0.0;
915     }
916 
917   node = reader->priv->current_node;
918 
919   if (!JSON_NODE_HOLDS_VALUE (node))
920     {
921       json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
922                              _("The current position holds a “%s” and not a value"),
923                              json_node_type_get_name (JSON_NODE_TYPE (node)));
924       return 0.0;
925     }
926 
927   return json_node_get_double (reader->priv->current_node);
928 }
929 
930 /**
931  * json_reader_get_string_value:
932  * @reader: a #JsonReader
933  *
934  * Retrieves the string value of the current position of @reader
935  *
936  * Return value: the string value
937  *
938  * Since: 0.12
939  */
940 const gchar *
json_reader_get_string_value(JsonReader * reader)941 json_reader_get_string_value (JsonReader *reader)
942 {
943   JsonNode *node;
944 
945   g_return_val_if_fail (JSON_IS_READER (reader), NULL);
946   json_reader_return_val_if_error_set (reader, NULL);
947 
948   if (reader->priv->current_node == NULL)
949     {
950       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
951                              _("No node available at the current position"));
952       return NULL;
953     }
954 
955   node = reader->priv->current_node;
956 
957   if (!JSON_NODE_HOLDS_VALUE (node))
958     {
959       json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
960                              _("The current position holds a “%s” and not a value"),
961                              json_node_type_get_name (JSON_NODE_TYPE (node)));
962       return NULL;
963     }
964 
965   if (json_node_get_value_type (node) != G_TYPE_STRING)
966     {
967       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_TYPE,
968                              _("The current position does not hold a string type"));
969       return NULL;
970     }
971 
972   return json_node_get_string (reader->priv->current_node);
973 }
974 
975 /**
976  * json_reader_get_boolean_value:
977  * @reader: a #JsonReader
978  *
979  * Retrieves the boolean value of the current position of @reader
980  *
981  * Return value: the boolean value
982  *
983  * Since: 0.12
984  */
985 gboolean
json_reader_get_boolean_value(JsonReader * reader)986 json_reader_get_boolean_value (JsonReader *reader)
987 {
988   JsonNode *node;
989 
990   g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
991   json_reader_return_val_if_error_set (reader, FALSE);
992 
993   if (reader->priv->current_node == NULL)
994     {
995       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
996                              _("No node available at the current position"));
997       return FALSE;
998     }
999 
1000   node = reader->priv->current_node;
1001 
1002   if (!JSON_NODE_HOLDS_VALUE (node))
1003     {
1004       json_reader_set_error (reader, JSON_READER_ERROR_NO_VALUE,
1005                              _("The current position holds a “%s” and not a value"),
1006                              json_node_type_get_name (JSON_NODE_TYPE (node)));
1007       return FALSE;
1008     }
1009 
1010   return json_node_get_boolean (node);
1011 }
1012 
1013 /**
1014  * json_reader_get_null_value:
1015  * @reader: a #JsonReader
1016  *
1017  * Checks whether the value of the current position of @reader is 'null'
1018  *
1019  * Return value: %TRUE if 'null' is set, and %FALSE otherwise
1020  *
1021  * Since: 0.12
1022  */
1023 gboolean
json_reader_get_null_value(JsonReader * reader)1024 json_reader_get_null_value (JsonReader *reader)
1025 {
1026   g_return_val_if_fail (JSON_IS_READER (reader), FALSE);
1027   json_reader_return_val_if_error_set (reader, FALSE);
1028 
1029   if (reader->priv->current_node == NULL)
1030     {
1031       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
1032                              _("No node available at the current position"));
1033       return FALSE;
1034     }
1035 
1036   return JSON_NODE_HOLDS_NULL (reader->priv->current_node);
1037 }
1038 
1039 /**
1040  * json_reader_get_member_name:
1041  * @reader: a #JsonReader
1042  *
1043  * Retrieves the name of the current member.
1044  *
1045  * Return value: (nullable) (transfer none): the name of the member, or %NULL
1046  *
1047  * Since: 0.14
1048  */
1049 const gchar *
json_reader_get_member_name(JsonReader * reader)1050 json_reader_get_member_name (JsonReader *reader)
1051 {
1052   g_return_val_if_fail (JSON_IS_READER (reader), NULL);
1053   json_reader_return_val_if_error_set (reader, NULL);
1054 
1055   if (reader->priv->current_node == NULL)
1056     {
1057       json_reader_set_error (reader, JSON_READER_ERROR_INVALID_NODE,
1058                              _("No node available at the current position"));
1059       return NULL;
1060     }
1061 
1062   if (reader->priv->members->len == 0)
1063     return NULL;
1064 
1065   return g_ptr_array_index (reader->priv->members,
1066                             reader->priv->members->len - 1);
1067 }
1068