Coverage Report

Created: 2025-07-11 06:31

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