Coverage Report

Created: 2025-11-11 06:06

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