Coverage Report

Created: 2025-08-29 06:14

/src/tinysparql/subprojects/json-glib-1.10.6/json-glib/json-object.c
Line
Count
Source (jump to first uncovered line)
1
/* json-object.c - JSON object implementation
2
 * 
3
 * This file is part of JSON-GLib
4
 *
5
 * SPDX-FileCopyrightText: 2007  OpenedHand Ltd.
6
 * SPDX-FileCopyrightText: 2009  Intel Corp.
7
 * SPDX-License-Identifier: LGPL-2.1-or-later
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 * Author:
23
 *   Emmanuele Bassi  <ebassi@linux.intel.com>
24
 */
25
26
#include "config.h"
27
28
#include <string.h>
29
#include <glib.h>
30
31
#include "json-types-private.h"
32
33
/**
34
 * JsonObject:
35
 *
36
 * `JsonObject` is the representation of the object type inside JSON.
37
 *
38
 * A `JsonObject` contains [struct@Json.Node] "members", which may contain
39
 * fundamental types, arrays or other objects; each member of an object is
40
 * accessed using a unique string, or "name".
41
 *
42
 * Since objects can be arbitrarily big, copying them can be expensive; for
43
 * this reason they are reference counted. You can control the lifetime of
44
 * a `JsonObject` using [method@Json.Object.ref] and [method@Json.Object.unref].
45
 *
46
 * To add or overwrite a member with a given name, use [method@Json.Object.set_member].
47
 *
48
 * To extract a member with a given name, use [method@Json.Object.get_member].
49
 *
50
 * To retrieve the list of members, use [method@Json.Object.get_members].
51
 *
52
 * To retrieve the size of the object (that is, the number of members it has),
53
 * use [method@Json.Object.get_size].
54
 */
55
56
G_DEFINE_BOXED_TYPE (JsonObject, json_object, json_object_ref, json_object_unref);
57
58
/**
59
 * json_object_new: (constructor)
60
 * 
61
 * Creates a new object.
62
 *
63
 * Returns: (transfer full): the newly created object
64
 */
65
JsonObject *
66
json_object_new (void)
67
0
{
68
0
  JsonObject *object;
69
70
0
  object = g_new0 (JsonObject, 1);
71
72
0
  g_ref_count_init (&object->ref_count);
73
74
0
  object->age = 0;
75
0
  object->members = g_hash_table_new_full (g_str_hash, g_str_equal,
76
0
                                           g_free,
77
0
                                           (GDestroyNotify) json_node_unref);
78
0
  g_queue_init (&object->members_ordered);
79
80
0
  return object;
81
0
}
82
83
/**
84
 * json_object_ref:
85
 * @object: a JSON object
86
 *
87
 * Acquires a reference on the given object.
88
 *
89
 * Returns: (transfer none): the given object, with the reference count
90
 *   increased by one.
91
 */
92
JsonObject *
93
json_object_ref (JsonObject *object)
94
0
{
95
0
  g_return_val_if_fail (object != NULL, NULL);
96
97
0
  g_ref_count_inc (&object->ref_count);
98
99
0
  return object;
100
0
}
101
102
/**
103
 * json_object_unref:
104
 * @object: a JSON object
105
 *
106
 * Releases a reference on the given object.
107
 *
108
 * If the reference count reaches zero, the object is destroyed and
109
 * all its resources are freed.
110
 */
111
void
112
json_object_unref (JsonObject *object)
113
0
{
114
0
  g_return_if_fail (object != NULL);
115
116
0
  if (g_ref_count_dec (&object->ref_count))
117
0
    {
118
0
      g_queue_clear (&object->members_ordered);
119
0
      g_hash_table_destroy (object->members);
120
0
      object->members = NULL;
121
122
0
      g_free (object);
123
0
    }
124
0
}
125
126
/**
127
 * json_object_seal:
128
 * @object: a JSON object
129
 *
130
 * Seals the object, making it immutable to further changes.
131
 *
132
 * This function will recursively seal all members of the object too.
133
 *
134
 * If the object is already immutable, this is a no-op.
135
 *
136
 * Since: 1.2
137
 */
138
void
139
json_object_seal (JsonObject *object)
140
0
{
141
0
  JsonObjectIter iter;
142
0
  JsonNode *node;
143
144
0
  g_return_if_fail (object != NULL);
145
146
0
  if (object->immutable)
147
0
    return;
148
149
  /* Propagate to all members. */
150
0
  json_object_iter_init (&iter, object);
151
152
0
  while (json_object_iter_next (&iter, NULL, &node))
153
0
    json_node_seal (node);
154
155
0
  object->immutable_hash = json_object_hash (object);
156
0
  object->immutable = TRUE;
157
0
}
158
159
/**
160
 * json_object_is_immutable:
161
 * @object: a JSON object
162
 *
163
 * Checks whether the given object has been marked as immutable by calling
164
 * [method@Json.Object.seal] on it.
165
 *
166
 * Since: 1.2
167
 * Returns: `TRUE` if the object is immutable
168
 */
169
gboolean
170
json_object_is_immutable (JsonObject *object)
171
0
{
172
0
  g_return_val_if_fail (object != NULL, FALSE);
173
174
0
  return object->immutable;
175
0
}
176
177
static inline void
178
object_set_member_internal (JsonObject  *object,
179
                            const gchar *member_name,
180
                            JsonNode    *node)
181
0
{
182
0
  gchar *name = g_strdup (member_name);
183
184
0
  if (g_hash_table_lookup (object->members, name) == NULL)
185
0
    {
186
0
      g_queue_push_tail (&object->members_ordered, name);
187
0
      object->age += 1;
188
0
    }
189
0
  else
190
0
    {
191
0
      GList *l;
192
193
      /* if the member already exists then we need to replace the
194
       * pointer to its name, to avoid keeping invalid pointers
195
       * once we replace the key in the hash table
196
       */
197
0
      l = g_queue_find_custom (&object->members_ordered, name, (GCompareFunc) strcmp);
198
0
      if (l != NULL)
199
0
        l->data = name;
200
0
    }
201
202
0
  g_hash_table_replace (object->members, name, node);
203
0
}
204
205
/**
206
 * json_object_add_member:
207
 * @object: a JSON object
208
 * @member_name: the name of the member
209
 * @node: (transfer full): the value of the member
210
 *
211
 * Adds a new member for the given name and value into an object.
212
 *
213
 * This function will return if the object already contains a member
214
 * with the same name.
215
 *
216
 * Deprecated: 0.8: Use [method@Json.Object.set_member] instead
217
 */
218
void
219
json_object_add_member (JsonObject  *object,
220
                        const gchar *member_name,
221
                        JsonNode    *node)
222
0
{
223
0
  g_return_if_fail (object != NULL);
224
0
  g_return_if_fail (member_name != NULL);
225
0
  g_return_if_fail (node != NULL);
226
227
0
  if (json_object_has_member (object, member_name))
228
0
    {
229
0
      g_warning ("JsonObject already has a `%s' member of type `%s'",
230
0
                 member_name,
231
0
                 json_node_type_name (node));
232
0
      return;
233
0
    }
234
235
0
  object_set_member_internal (object, member_name, node);
236
0
}
237
238
/**
239
 * json_object_set_member:
240
 * @object: a JSON object
241
 * @member_name: the name of the member
242
 * @node: (transfer full): the value of the member
243
 *
244
 * Sets the value of a member inside an object.
245
 *
246
 * If the object does not have a member with the given name, a new member
247
 * is created.
248
 *
249
 * If the object already has a member with the given name, the current
250
 * value is overwritten with the new.
251
 *
252
 * Since: 0.8
253
 */
254
void
255
json_object_set_member (JsonObject  *object,
256
                        const gchar *member_name,
257
                        JsonNode    *node)
258
0
{
259
0
  JsonNode *old_node;
260
261
0
  g_return_if_fail (object != NULL);
262
0
  g_return_if_fail (member_name != NULL);
263
0
  g_return_if_fail (node != NULL);
264
265
0
  old_node = g_hash_table_lookup (object->members, member_name);
266
0
  if (old_node == NULL)
267
0
    goto set_member;
268
269
0
  if (old_node == node)
270
0
    return;
271
272
0
set_member:
273
0
  object_set_member_internal (object, member_name, node);
274
0
}
275
276
/**
277
 * json_object_set_int_member:
278
 * @object: a JSON object
279
 * @member_name: the name of the member
280
 * @value: the value of the member
281
 *
282
 * Convenience function for setting an object member with an integer value.
283
 *
284
 * See also: [method@Json.Object.set_member], [method@Json.Node.init_int]
285
 *
286
 * Since: 0.8
287
 */
288
void
289
json_object_set_int_member (JsonObject  *object,
290
                            const gchar *member_name,
291
                            gint64       value)
292
0
{
293
0
  g_return_if_fail (object != NULL);
294
0
  g_return_if_fail (member_name != NULL);
295
296
0
  object_set_member_internal (object, member_name, json_node_init_int (json_node_alloc (), value));
297
0
}
298
299
/**
300
 * json_object_set_double_member:
301
 * @object: a JSON object
302
 * @member_name: the name of the member
303
 * @value: the value of the member
304
 *
305
 * Convenience function for setting an object member with a floating point value.
306
 *
307
 * See also: [method@Json.Object.set_member], [method@Json.Node.init_double]
308
 *
309
 * Since: 0.8
310
 */
311
void
312
json_object_set_double_member (JsonObject  *object,
313
                               const gchar *member_name,
314
                               gdouble      value)
315
0
{
316
0
  g_return_if_fail (object != NULL);
317
0
  g_return_if_fail (member_name != NULL);
318
319
0
  object_set_member_internal (object, member_name, json_node_init_double (json_node_alloc (), value));
320
0
}
321
322
/**
323
 * json_object_set_boolean_member:
324
 * @object: a JSON object
325
 * @member_name: the name of the member
326
 * @value: the value of the member
327
 *
328
 * Convenience function for setting an object member with a boolean value.
329
 *
330
 * See also: [method@Json.Object.set_member], [method@Json.Node.init_boolean]
331
 *
332
 * Since: 0.8
333
 */
334
void
335
json_object_set_boolean_member (JsonObject  *object,
336
                                const gchar *member_name,
337
                                gboolean     value)
338
0
{
339
0
  g_return_if_fail (object != NULL);
340
0
  g_return_if_fail (member_name != NULL);
341
342
0
  object_set_member_internal (object, member_name, json_node_init_boolean (json_node_alloc (), value));
343
0
}
344
345
/**
346
 * json_object_set_string_member:
347
 * @object: a JSON object
348
 * @member_name: the name of the member
349
 * @value: the value of the member
350
 *
351
 * Convenience function for setting an object member with a string value.
352
 *
353
 * See also: [method@Json.Object.set_member], [method@Json.Node.init_string]
354
 *
355
 * Since: 0.8
356
 */
357
void
358
json_object_set_string_member (JsonObject  *object,
359
                               const gchar *member_name,
360
                               const gchar *value)
361
0
{
362
0
  JsonNode *node;
363
364
0
  g_return_if_fail (object != NULL);
365
0
  g_return_if_fail (member_name != NULL);
366
367
0
  node = json_node_alloc ();
368
369
0
  if (value != NULL)
370
0
    json_node_init_string (node, value);
371
0
  else
372
0
    json_node_init_null (node);
373
374
0
  object_set_member_internal (object, member_name, node);
375
0
}
376
377
/**
378
 * json_object_set_null_member:
379
 * @object: a JSON object
380
 * @member_name: the name of the member
381
 *
382
 * Convenience function for setting an object member with a `null` value.
383
 *
384
 * See also: [method@Json.Object.set_member], [method@Json.Node.init_null]
385
 *
386
 * Since: 0.8
387
 */
388
void
389
json_object_set_null_member (JsonObject  *object,
390
                             const gchar *member_name)
391
0
{
392
0
  g_return_if_fail (object != NULL);
393
0
  g_return_if_fail (member_name != NULL);
394
395
0
  object_set_member_internal (object, member_name, json_node_init_null (json_node_alloc ()));
396
0
}
397
398
/**
399
 * json_object_set_array_member:
400
 * @object: a JSON object
401
 * @member_name: the name of the member
402
 * @value: (transfer full): the value of the member
403
 *
404
 * Convenience function for setting an object member with an array value.
405
 *
406
 * See also: [method@Json.Object.set_member], [method@Json.Node.take_array]
407
 *
408
 * Since: 0.8
409
 */
410
void
411
json_object_set_array_member (JsonObject  *object,
412
                              const gchar *member_name,
413
                              JsonArray   *value)
414
0
{
415
0
  JsonNode *node;
416
417
0
  g_return_if_fail (object != NULL);
418
0
  g_return_if_fail (member_name != NULL);
419
420
0
  node = json_node_alloc ();
421
422
0
  if (value != NULL)
423
0
    {
424
0
      json_node_init_array (node, value);
425
0
      json_array_unref (value);
426
0
    }
427
0
  else
428
0
    json_node_init_null (node);
429
430
0
  object_set_member_internal (object, member_name, node);
431
0
}
432
433
/**
434
 * json_object_set_object_member:
435
 * @object: a JSON object
436
 * @member_name: the name of the member
437
 * @value: (transfer full): the value of the member
438
 *
439
 * Convenience function for setting an object member with an object value.
440
 *
441
 * See also: [method@Json.Object.set_member], [method@Json.Node.take_object]
442
 *
443
 * Since: 0.8
444
 */
445
void
446
json_object_set_object_member (JsonObject  *object,
447
                               const gchar *member_name,
448
                               JsonObject  *value)
449
0
{
450
0
  JsonNode *node;
451
452
0
  g_return_if_fail (object != NULL);
453
0
  g_return_if_fail (member_name != NULL);
454
455
0
  node = json_node_alloc ();
456
457
0
  if (value != NULL)
458
0
    {
459
0
      json_node_init_object (node, value);
460
0
      json_object_unref (value);
461
0
    }
462
0
  else
463
0
    json_node_init_null (node);
464
465
0
  object_set_member_internal (object, member_name, node);
466
0
}
467
468
/**
469
 * json_object_get_members:
470
 * @object: a JSON object
471
 *
472
 * Retrieves all the names of the members of an object.
473
 *
474
 * You can obtain the value for each member by iterating the returned list
475
 * and calling [method@Json.Object.get_member].
476
 *
477
 * Returns: (element-type utf8) (transfer container) (nullable): the
478
 *   member names of the object
479
 */
480
GList *
481
json_object_get_members (JsonObject *object)
482
0
{
483
0
  g_return_val_if_fail (object != NULL, NULL);
484
485
0
  return g_list_copy (object->members_ordered.head);
486
0
}
487
488
489
GQueue *
490
json_object_get_members_internal (JsonObject *object)
491
0
{
492
0
  g_return_val_if_fail (object != NULL, NULL);
493
494
0
  return &object->members_ordered;
495
0
}
496
497
/**
498
 * json_object_get_values:
499
 * @object: a JSON object
500
 *
501
 * Retrieves all the values of the members of an object.
502
 *
503
 * Returns: (element-type JsonNode) (transfer container) (nullable): the
504
 *   member values of the object
505
 */
506
GList *
507
json_object_get_values (JsonObject *object)
508
0
{
509
0
  GList *values, *l;
510
511
0
  g_return_val_if_fail (object != NULL, NULL);
512
513
0
  values = NULL;
514
0
  for (l = object->members_ordered.tail; l != NULL; l = l->prev)
515
0
    values = g_list_prepend (values, g_hash_table_lookup (object->members, l->data));
516
517
0
  return values;
518
0
}
519
520
/**
521
 * json_object_dup_member:
522
 * @object: a JSON object
523
 * @member_name: the name of the JSON object member to access
524
 *
525
 * Retrieves a copy of the value of the given member inside an object.
526
 *
527
 * Returns: (transfer full) (nullable): a copy of the value for the
528
 *   requested object member
529
 *
530
 * Since: 0.6
531
 */
532
JsonNode *
533
json_object_dup_member (JsonObject  *object,
534
                        const gchar *member_name)
535
0
{
536
0
  JsonNode *retval;
537
538
0
  g_return_val_if_fail (object != NULL, NULL);
539
0
  g_return_val_if_fail (member_name != NULL, NULL);
540
541
0
  retval = json_object_get_member (object, member_name);
542
0
  if (!retval)
543
0
    return NULL;
544
545
0
  return json_node_copy (retval);
546
0
}
547
548
static inline JsonNode *
549
object_get_member_internal (JsonObject  *object,
550
                            const gchar *member_name)
551
0
{
552
0
  return g_hash_table_lookup (object->members, member_name);
553
0
}
554
555
/**
556
 * json_object_get_member:
557
 * @object: a JSON object
558
 * @member_name: the name of the JSON object member to access
559
 *
560
 * Retrieves the value of the given member inside an object.
561
 *
562
 * Returns: (transfer none) (nullable): the value for the
563
 *   requested object member
564
 */
565
JsonNode *
566
json_object_get_member (JsonObject  *object,
567
                        const gchar *member_name)
568
0
{
569
0
  g_return_val_if_fail (object != NULL, NULL);
570
0
  g_return_val_if_fail (member_name != NULL, NULL);
571
572
0
  return object_get_member_internal (object, member_name);
573
0
}
574
575
#define JSON_OBJECT_GET(ret_type,type_name) \
576
ret_type \
577
json_object_get_ ##type_name## _member (JsonObject *object, \
578
0
                                        const char *member_name) \
579
0
{ \
580
0
  g_return_val_if_fail (object != NULL, (ret_type) 0); \
581
0
  g_return_val_if_fail (member_name != NULL, (ret_type) 0); \
582
0
\
583
0
  JsonNode *node = object_get_member_internal (object, member_name); \
584
0
  g_return_val_if_fail (node != NULL, (ret_type) 0); \
585
0
\
586
0
  if (JSON_NODE_HOLDS_NULL (node)) \
587
0
    return (ret_type) 0; \
588
0
\
589
0
  g_return_val_if_fail (JSON_NODE_TYPE (node) == JSON_NODE_VALUE, (ret_type) 0); \
590
0
\
591
0
  return json_node_get_ ##type_name (node); \
592
0
}
Unexecuted instantiation: json_object_get_int_member
Unexecuted instantiation: json_object_get_double_member
Unexecuted instantiation: json_object_get_boolean_member
Unexecuted instantiation: json_object_get_string_member
593
594
#define JSON_OBJECT_GET_DEFAULT(ret_type,type_name) \
595
ret_type \
596
json_object_get_ ##type_name## _member_with_default (JsonObject *object, \
597
                                                     const char *member_name, \
598
0
                                                     ret_type    default_value) \
599
0
{ \
600
0
  g_return_val_if_fail (object != NULL, default_value); \
601
0
  g_return_val_if_fail (member_name != NULL, default_value); \
602
0
\
603
0
  JsonNode *node = object_get_member_internal (object, member_name); \
604
0
  if (node == NULL) \
605
0
    return default_value; \
606
0
\
607
0
  if (JSON_NODE_HOLDS_NULL (node)) \
608
0
    return default_value; \
609
0
\
610
0
  if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE) \
611
0
    return default_value; \
612
0
\
613
0
  return json_node_get_ ##type_name (node); \
614
0
}
Unexecuted instantiation: json_object_get_int_member_with_default
Unexecuted instantiation: json_object_get_double_member_with_default
Unexecuted instantiation: json_object_get_boolean_member_with_default
Unexecuted instantiation: json_object_get_string_member_with_default
615
616
/**
617
 * json_object_get_int_member:
618
 * @object: a JSON object
619
 * @member_name: the name of the object member
620
 *
621
 * Convenience function that retrieves the integer value
622
 * stored in @member_name of @object. It is an error to specify a
623
 * @member_name which does not exist or which holds a non-scalar,
624
 * non-`null` value.
625
 *
626
 * See also: [method@Json.Object.get_int_member_with_default],
627
 *   [method@Json.Object.get_member], [method@Json.Object.has_member]
628
 *
629
 * Returns: the integer value of the object's member
630
 *
631
 * Since: 0.8
632
 */
633
JSON_OBJECT_GET (gint64, int)
634
635
/**
636
 * json_object_get_int_member_with_default:
637
 * @object: a JSON object
638
 * @member_name: the name of the object member
639
 * @default_value: the value to return if @member_name is not valid
640
 *
641
 * Convenience function that retrieves the integer value
642
 * stored in @member_name of @object.
643
 *
644
 * If @member_name does not exist, does not contain a scalar value,
645
 * or contains `null`, then @default_value is returned instead. If
646
 * @member_name contains a non-integer, non-`null` scalar value, then whatever
647
 * json_node_get_int() would return is returned.
648
 *
649
 * Returns: the integer value of the object's member, or the
650
 *   given default
651
 *
652
 * Since: 1.6
653
 */
654
JSON_OBJECT_GET_DEFAULT (gint64, int)
655
656
/**
657
 * json_object_get_double_member:
658
 * @object: a JSON object
659
 * @member_name: the name of the member
660
 *
661
 * Convenience function that retrieves the floating point value
662
 * stored in @member_name of @object. It is an error to specify a
663
 * @member_name which does not exist or which holds a non-scalar,
664
 * non-`null` value.
665
 *
666
 * See also: [method@Json.Object.get_double_member_with_default],
667
 *   [method@Json.Object.get_member], [method@Json.Object.has_member]
668
 *
669
 * Returns: the floating point value of the object's member
670
 *
671
 * Since: 0.8
672
 */
673
JSON_OBJECT_GET (gdouble, double)
674
675
/**
676
 * json_object_get_double_member_with_default:
677
 * @object: a JSON object
678
 * @member_name: the name of the @object member
679
 * @default_value: the value to return if @member_name is not valid
680
 *
681
 * Convenience function that retrieves the floating point value
682
 * stored in @member_name of @object.
683
 *
684
 * If @member_name does not exist, does not contain a scalar value,
685
 * or contains `null`, then @default_value is returned instead. If
686
 * @member_name contains a non-double, non-`null` scalar value, then
687
 * whatever json_node_get_double() would return is returned.
688
 *
689
 * Returns: the floating point value of the object's member, or the
690
 *   given default
691
 *
692
 * Since: 1.6
693
 */
694
JSON_OBJECT_GET_DEFAULT (double, double)
695
696
/**
697
 * json_object_get_boolean_member:
698
 * @object: a JSON object
699
 * @member_name: the name of the member
700
 *
701
 * Convenience function that retrieves the boolean value
702
 * stored in @member_name of @object. It is an error to specify a
703
 * @member_name which does not exist or which holds a non-scalar,
704
 * non-`null` value.
705
 *
706
 * See also: [method@Json.Object.get_boolean_member_with_default],
707
 *   [method@Json.Object.get_member], [method@Json.Object.has_member]
708
 *
709
 * Returns: the boolean value of the object's member
710
 *
711
 * Since: 0.8
712
 */
713
JSON_OBJECT_GET (gboolean, boolean)
714
715
/**
716
 * json_object_get_boolean_member_with_default:
717
 * @object: a JSON object
718
 * @member_name: the name of the @object member
719
 * @default_value: the value to return if @member_name is not valid
720
 *
721
 * Convenience function that retrieves the boolean value
722
 * stored in @member_name of @object.
723
 *
724
 * If @member_name does not exist, does not contain a scalar value,
725
 * or contains `null`, then @default_value is returned instead. If
726
 * @member_name contains a non-boolean, non-`null` scalar value, then
727
 * whatever json_node_get_boolean() would return is returned.
728
 *
729
 * Returns: the boolean value of the object's member, or the
730
 *   given default
731
 *
732
 * Since: 1.6
733
 */
734
JSON_OBJECT_GET_DEFAULT (gboolean, boolean)
735
736
/**
737
 * json_object_get_string_member:
738
 * @object: a JSON object
739
 * @member_name: the name of the member
740
 *
741
 * Convenience function that retrieves the string value
742
 * stored in @member_name of @object. It is an error to specify a
743
 * @member_name that does not exist or which holds a non-scalar,
744
 * non-`null` value.
745
 *
746
 * See also: [method@Json.Object.get_string_member_with_default],
747
 *   [method@Json.Object.get_member], [method@Json.Object.has_member]
748
 *
749
 * Returns: the string value of the object's member
750
 *
751
 * Since: 0.8
752
 */
753
JSON_OBJECT_GET (const gchar *, string)
754
755
/**
756
 * json_object_get_string_member_with_default:
757
 * @object: a JSON object
758
 * @member_name: the name of the @object member
759
 * @default_value: the value to return if @member_name is not valid
760
 *
761
 * Convenience function that retrieves the string value
762
 * stored in @member_name of @object.
763
 *
764
 * If @member_name does not exist, does not contain a scalar value,
765
 * or contains `null`, then @default_value is returned instead. If
766
 * @member_name contains a non-string, non-`null` scalar value, then
767
 * %NULL is returned.
768
 *
769
 * Returns: the string value of the object's member, or the
770
 *   given default
771
 *
772
 * Since: 1.6
773
 */
774
JSON_OBJECT_GET_DEFAULT (const char *, string)
775
776
/**
777
 * json_object_get_null_member:
778
 * @object: a JSON object
779
 * @member_name: the name of the member
780
 *
781
 * Convenience function that checks whether the value
782
 * stored in @member_name of @object is null. It is an error to
783
 * specify a @member_name which does not exist.
784
 *
785
 * See also: [method@Json.Object.get_member], [method@Json.Object.has_member]
786
 *
787
 * Returns: `TRUE` if the value is `null`
788
 *
789
 * Since: 0.8
790
 */
791
gboolean
792
json_object_get_null_member (JsonObject  *object,
793
                             const gchar *member_name)
794
0
{
795
0
  JsonNode *node;
796
797
0
  g_return_val_if_fail (object != NULL, FALSE);
798
0
  g_return_val_if_fail (member_name != NULL, FALSE);
799
800
0
  node = object_get_member_internal (object, member_name);
801
0
  g_return_val_if_fail (node != NULL, FALSE);
802
803
0
  if (JSON_NODE_HOLDS_NULL (node))
804
0
    return TRUE;
805
806
0
  if (JSON_NODE_HOLDS_OBJECT (node))
807
0
    return json_node_get_object (node) == NULL;
808
809
0
  if (JSON_NODE_HOLDS_ARRAY (node))
810
0
    return json_node_get_array (node) == NULL;
811
812
0
  return FALSE;
813
0
}
814
815
/**
816
 * json_object_get_array_member:
817
 * @object: a JSON object
818
 * @member_name: the name of the member
819
 *
820
 * Convenience function that retrieves the array
821
 * stored in @member_name of @object. It is an error to specify a
822
 * @member_name which does not exist or which holds a non-`null`, non-array
823
 * value.
824
 *
825
 * If @member_name contains `null`, then this function will return `NULL`.
826
 *
827
 * See also: [method@Json.Object.get_member], [method@Json.Object.has_member]
828
 *
829
 * Returns: (transfer none) (nullable): the array inside the object's member
830
 *
831
 * Since: 0.8
832
 */
833
JsonArray *
834
json_object_get_array_member (JsonObject  *object,
835
                              const gchar *member_name)
836
0
{
837
0
  JsonNode *node;
838
839
0
  g_return_val_if_fail (object != NULL, NULL);
840
0
  g_return_val_if_fail (member_name != NULL, NULL);
841
842
0
  node = object_get_member_internal (object, member_name);
843
0
  g_return_val_if_fail (node != NULL, NULL);
844
0
  g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (node) || JSON_NODE_HOLDS_NULL (node), NULL);
845
846
0
  if (JSON_NODE_HOLDS_NULL (node))
847
0
    return NULL;
848
849
0
  return json_node_get_array (node);
850
0
}
851
852
/**
853
 * json_object_get_object_member:
854
 * @object: a JSON object
855
 * @member_name: the name of the member
856
 *
857
 * Convenience function that retrieves the object
858
 * stored in @member_name of @object. It is an error to specify a @member_name
859
 * which does not exist or which holds a non-`null`, non-object value.
860
 *
861
 * If @member_name contains `null`, then this function will return `NULL`.
862
 *
863
 * See also: [method@Json.Object.get_member], [method@Json.Object.has_member]
864
 *
865
 * Returns: (transfer none) (nullable): the object inside the object's member
866
 *
867
 * Since: 0.8
868
 */
869
JsonObject *
870
json_object_get_object_member (JsonObject  *object,
871
                               const gchar *member_name)
872
0
{
873
0
  JsonNode *node;
874
875
0
  g_return_val_if_fail (object != NULL, NULL);
876
0
  g_return_val_if_fail (member_name != NULL, NULL);
877
878
0
  node = object_get_member_internal (object, member_name);
879
0
  g_return_val_if_fail (node != NULL, NULL);
880
0
  g_return_val_if_fail (JSON_NODE_HOLDS_OBJECT (node) || JSON_NODE_HOLDS_NULL (node), NULL);
881
882
0
  if (JSON_NODE_HOLDS_NULL (node))
883
0
    return NULL;
884
885
0
  return json_node_get_object (node);
886
0
}
887
888
/**
889
 * json_object_has_member:
890
 * @object: a JSON object
891
 * @member_name: the name of a JSON object member
892
 *
893
 * Checks whether @object has a member named @member_name.
894
 *
895
 * Returns: `TRUE` if the JSON object has the requested member
896
 */
897
gboolean
898
json_object_has_member (JsonObject *object,
899
                        const gchar *member_name)
900
0
{
901
0
  g_return_val_if_fail (object != NULL, FALSE);
902
0
  g_return_val_if_fail (member_name != NULL, FALSE);
903
904
0
  return (g_hash_table_lookup (object->members, member_name) != NULL);
905
0
}
906
907
/**
908
 * json_object_get_size:
909
 * @object: a JSON object
910
 *
911
 * Retrieves the number of members of a JSON object.
912
 *
913
 * Returns: the number of members
914
 */
915
guint
916
json_object_get_size (JsonObject *object)
917
0
{
918
0
  g_return_val_if_fail (object != NULL, 0);
919
920
0
  return g_hash_table_size (object->members);
921
0
}
922
923
/**
924
 * json_object_remove_member:
925
 * @object: a JSON object
926
 * @member_name: the name of the member to remove
927
 *
928
 * Removes @member_name from @object, freeing its allocated resources.
929
 */
930
void
931
json_object_remove_member (JsonObject  *object,
932
                           const gchar *member_name)
933
0
{
934
0
  GList *l;
935
936
0
  g_return_if_fail (object != NULL);
937
0
  g_return_if_fail (member_name != NULL);
938
939
0
  for (l = object->members_ordered.head; l != NULL; l = l->next)
940
0
    {
941
0
      const gchar *name = l->data;
942
943
0
      if (g_strcmp0 (name, member_name) == 0)
944
0
        {
945
0
          g_queue_delete_link (&object->members_ordered, l);
946
0
          break;
947
0
        }
948
0
    }
949
950
0
  g_hash_table_remove (object->members, member_name);
951
0
}
952
953
/**
954
 * json_object_foreach_member:
955
 * @object: a JSON object
956
 * @func: (scope call) (closure data): the function to be called on each member
957
 * @data: data to be passed to the function
958
 *
959
 * Iterates over all members of @object and calls @func on
960
 * each one of them.
961
 *
962
 * It is safe to change the value of a member of the oobject
963
 * from within the iterator function, but it is not safe to add or
964
 * remove members from the object.
965
 *
966
 * The order in which the object members are iterated is the
967
 * insertion order.
968
 *
969
 * Since: 0.8
970
 */
971
void
972
json_object_foreach_member (JsonObject        *object,
973
                            JsonObjectForeach  func,
974
                            gpointer           data)
975
0
{
976
0
  GList *l;
977
0
  int age;
978
979
0
  g_return_if_fail (object != NULL);
980
0
  g_return_if_fail (func != NULL);
981
982
0
  age = object->age;
983
984
0
  for (l = object->members_ordered.head; l != NULL; l = l->next)
985
0
    {
986
0
      const gchar *member_name = l->data;
987
0
      JsonNode *member_node = g_hash_table_lookup (object->members, member_name);
988
989
0
      func (object, member_name, member_node, data);
990
991
0
      g_assert (object->age == age);
992
0
    }
993
0
}
994
995
/**
996
 * json_object_hash:
997
 * @key: (type JsonObject): a JSON object to hash
998
 *
999
 * Calculate a hash value for the given @key (a JSON object).
1000
 *
1001
 * The hash is calculated over the object and all its members, recursively. If
1002
 * the object is immutable, this is a fast operation; otherwise, it scales
1003
 * proportionally with the number of members in the object.
1004
 *
1005
 * Returns: hash value for @key
1006
 * Since: 1.2
1007
 */
1008
guint
1009
json_object_hash (gconstpointer key)
1010
0
{
1011
0
  JsonObject *object = (JsonObject *) key;
1012
0
  guint hash = 0;
1013
0
  JsonObjectIter iter;
1014
0
  const gchar *member_name;
1015
0
  JsonNode *node;
1016
1017
0
  g_return_val_if_fail (object != NULL, 0);
1018
1019
  /* If the object is immutable, use the cached hash. */
1020
0
  if (object->immutable)
1021
0
    return object->immutable_hash;
1022
1023
  /* Otherwise, calculate from scratch. */
1024
0
  json_object_iter_init (&iter, object);
1025
1026
0
  while (json_object_iter_next (&iter, &member_name, &node))
1027
0
    hash ^= (json_string_hash (member_name) ^ json_node_hash (node));
1028
1029
0
  return hash;
1030
0
}
1031
1032
/**
1033
 * json_object_equal:
1034
 * @a: (type JsonObject): a JSON object
1035
 * @b: (type JsonObject): another JSON object
1036
 *
1037
 * Check whether @a and @b are equal objects, meaning they have the same
1038
 * set of members, and the values of corresponding members are equal.
1039
 *
1040
 * Returns: `TRUE` if @a and @b are equal, and `FALSE` otherwise
1041
 * Since: 1.2
1042
 */
1043
gboolean
1044
json_object_equal (gconstpointer  a,
1045
                   gconstpointer  b)
1046
0
{
1047
0
  JsonObject *object_a, *object_b;
1048
0
  guint size_a, size_b;
1049
0
  JsonObjectIter iter_a;
1050
0
  JsonNode *child_a, *child_b;  /* unowned */
1051
0
  const gchar *member_name;
1052
1053
0
  object_a = (JsonObject *) a;
1054
0
  object_b = (JsonObject *) b;
1055
1056
  /* Identity comparison. */
1057
0
  if (object_a == object_b)
1058
0
    return TRUE;
1059
1060
  /* Check sizes. */
1061
0
  size_a = json_object_get_size (object_a);
1062
0
  size_b = json_object_get_size (object_b);
1063
1064
0
  if (size_a != size_b)
1065
0
    return FALSE;
1066
1067
  /* Check member names and values. Check the member names first
1068
   * to avoid expensive recursive value comparisons which might
1069
   * be unnecessary. */
1070
0
  json_object_iter_init (&iter_a, object_a);
1071
1072
0
  while (json_object_iter_next (&iter_a, &member_name, NULL))
1073
0
    {
1074
0
      if (!json_object_has_member (object_b, member_name))
1075
0
        return FALSE;
1076
0
    }
1077
1078
0
  json_object_iter_init (&iter_a, object_a);
1079
1080
0
  while (json_object_iter_next (&iter_a, &member_name, &child_a))
1081
0
    {
1082
0
      child_b = json_object_get_member (object_b, member_name);
1083
1084
0
      if (!json_node_equal (child_a, child_b))
1085
0
        return FALSE;
1086
0
    }
1087
1088
0
  return TRUE;
1089
0
}
1090
1091
/**
1092
 * json_object_iter_init:
1093
 * @iter: an uninitialised JSON object iterator
1094
 * @object: the JSON object to iterate over
1095
 *
1096
 * Initialises the @iter and associate it with @object.
1097
 *
1098
 * ```c
1099
 * JsonObjectIter iter;
1100
 * const gchar *member_name;
1101
 * JsonNode *member_node;
1102
 *
1103
 * json_object_iter_init (&iter, some_object);
1104
 * while (json_object_iter_next (&iter, &member_name, &member_node))
1105
 *   {
1106
 *     // Do something with @member_name and @member_node.
1107
 *   }
1108
 * ```
1109
 *
1110
 * The iterator initialized with this function will iterate the
1111
 * members of the object in an undefined order.
1112
 *
1113
 * See also: [method@Json.ObjectIter.init_ordered]
1114
 *
1115
 * Since: 1.2
1116
 */
1117
void
1118
json_object_iter_init (JsonObjectIter  *iter,
1119
                       JsonObject      *object)
1120
0
{
1121
0
  JsonObjectIterReal *iter_real = (JsonObjectIterReal *) iter;;
1122
1123
0
  g_return_if_fail (iter != NULL);
1124
0
  g_return_if_fail (object != NULL);
1125
1126
0
  iter_real->object = object;
1127
0
  g_hash_table_iter_init (&iter_real->members_iter, object->members);
1128
0
}
1129
1130
/**
1131
 * json_object_iter_next:
1132
 * @iter: a JSON object iterator
1133
 * @member_name: (out callee-allocates) (transfer none) (optional): return
1134
 *    location for the member name, or %NULL to ignore
1135
 * @member_node: (out callee-allocates) (transfer none) (optional): return
1136
 *    location for the member value, or %NULL to ignore
1137
 *
1138
 * Advances the iterator and retrieves the next member in the object.
1139
 *
1140
 * If the end of the object is reached, `FALSE` is returned and @member_name
1141
 * and @member_node are set to invalid values. After that point, the @iter
1142
 * is invalid.
1143
 *
1144
 * The order in which members are returned by the iterator is undefined. The
1145
 * iterator is invalidated if the object is modified during iteration.
1146
 *
1147
 * You must use this function with an iterator initialized with
1148
 * [method@Json.ObjectIter.init]; using this function with an iterator
1149
 * initialized with [method@Json.ObjectIter.init_ordered] yields undefined
1150
 * behavior.
1151
 *
1152
 * See also: [method@Json.ObjectIter.next_ordered]
1153
 *
1154
 * Returns: `TRUE` if @member_name and @member_node are valid; `FALSE` if
1155
 *   there are no more members
1156
 *
1157
 * Since: 1.2
1158
 */
1159
gboolean
1160
json_object_iter_next (JsonObjectIter  *iter,
1161
                       const gchar    **member_name,
1162
                       JsonNode       **member_node)
1163
0
{
1164
0
  JsonObjectIterReal *iter_real = (JsonObjectIterReal *) iter;
1165
1166
0
  g_return_val_if_fail (iter != NULL, FALSE);
1167
0
  g_return_val_if_fail (iter_real->object != NULL, FALSE);
1168
1169
0
  return g_hash_table_iter_next (&iter_real->members_iter,
1170
0
                                 (gpointer *) member_name,
1171
0
                                 (gpointer *) member_node);
1172
0
}
1173
1174
/**
1175
 * json_object_iter_init_ordered:
1176
 * @iter: an uninitialised iterator
1177
 * @object: the JSON object to iterate over
1178
 *
1179
 * Initialises the @iter and associate it with @object.
1180
 *
1181
 * ```c
1182
 * JsonObjectIter iter;
1183
 * const gchar *member_name;
1184
 * JsonNode *member_node;
1185
 *
1186
 * json_object_iter_init_ordered (&iter, some_object);
1187
 * while (json_object_iter_next_ordered (&iter, &member_name, &member_node))
1188
 *   {
1189
 *     // Do something with @member_name and @member_node.
1190
 *   }
1191
 * ```
1192
 *
1193
 * See also: [method@Json.ObjectIter.init]
1194
 *
1195
 * Since: 1.6
1196
 */
1197
void
1198
json_object_iter_init_ordered (JsonObjectIter  *iter,
1199
                               JsonObject      *object)
1200
0
{
1201
0
  JsonObjectOrderedIterReal *iter_real = (JsonObjectOrderedIterReal *) iter;
1202
1203
0
  g_return_if_fail (iter != NULL);
1204
0
  g_return_if_fail (object != NULL);
1205
1206
0
  iter_real->object = object;
1207
0
  iter_real->cur_member = NULL;
1208
0
  iter_real->next_member = NULL;
1209
0
  iter_real->age = iter_real->object->age;
1210
0
}
1211
1212
/**
1213
 * json_object_iter_next_ordered:
1214
 * @iter: an ordered JSON object iterator
1215
 * @member_name: (out callee-allocates) (transfer none) (optional): return
1216
 *    location for the member name, or %NULL to ignore
1217
 * @member_node: (out callee-allocates) (transfer none) (optional): return
1218
 *    location for the member value, or %NULL to ignore
1219
 *
1220
 * Advances the iterator and retrieves the next member in the object.
1221
 *
1222
 * If the end of the object is reached, `FALSE` is returned and @member_name and
1223
 * @member_node are set to invalid values. After that point, the @iter is invalid.
1224
 *
1225
 * The order in which members are returned by the iterator is the same order in
1226
 * which the members were added to the `JsonObject`. The iterator is invalidated
1227
 * if its `JsonObject` is modified during iteration.
1228
 *
1229
 * You must use this function with an iterator initialized with
1230
 * [method@Json.ObjectIter.init_ordered]; using this function with an iterator
1231
 * initialized with [method@Json.ObjectIter.init] yields undefined behavior.
1232
 *
1233
 * See also: [method@Json.ObjectIter.next]
1234
 *
1235
 * Returns: `TRUE `if @member_name and @member_node are valid; `FALSE` if the end
1236
 *    of the object has been reached
1237
 *
1238
 * Since: 1.6
1239
 */
1240
gboolean
1241
json_object_iter_next_ordered (JsonObjectIter  *iter,
1242
                               const gchar    **member_name,
1243
                               JsonNode       **member_node)
1244
0
{
1245
0
  JsonObjectOrderedIterReal *iter_real = (JsonObjectOrderedIterReal *) iter;
1246
0
  const char *name = NULL;
1247
1248
0
  g_return_val_if_fail (iter != NULL, FALSE);
1249
0
  g_return_val_if_fail (iter_real->object != NULL, FALSE);
1250
0
  g_return_val_if_fail (iter_real->age == iter_real->object->age, FALSE);
1251
1252
0
  if (iter_real->cur_member == NULL)
1253
0
    iter_real->cur_member = iter_real->object->members_ordered.head;
1254
0
  else
1255
0
    iter_real->cur_member = iter_real->cur_member->next;
1256
1257
0
  name = iter_real->cur_member != NULL ? iter_real->cur_member->data : NULL;
1258
1259
0
  if (member_name != NULL)
1260
0
    *member_name = name;
1261
0
  if (member_node != NULL)
1262
0
    {
1263
0
      if (name != NULL)
1264
0
        *member_node = g_hash_table_lookup (iter_real->object->members, name);
1265
0
      else
1266
0
        *member_node = NULL;
1267
0
    }
1268
1269
0
  return iter_real->cur_member != NULL;
1270
0
}