Imported Upstream version 1.2.4
[platform/upstream/json-glib.git] / json-glib / json-generator.c
1 /* json-generator.c - JSON streams generator
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 /**
25  * SECTION:json-generator
26  * @short_description: Generates JSON data streams
27  *
28  * #JsonGenerator provides an object for generating a JSON data stream and
29  * put it into a buffer or a file.
30  */
31
32 #include "config.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "json-types-private.h"
38
39 #include "json-generator.h"
40
41 struct _JsonGeneratorPrivate
42 {
43   JsonNode *root;
44
45   guint indent;
46   gunichar indent_char;
47
48   guint pretty : 1;
49 };
50
51 enum
52 {
53   PROP_0,
54
55   PROP_PRETTY,
56   PROP_INDENT,
57   PROP_ROOT,
58   PROP_INDENT_CHAR,
59
60   PROP_LAST
61 };
62
63 static gchar *dump_value  (JsonGenerator *generator,
64                            gint           level,
65                            const gchar   *name,
66                            JsonNode      *node,
67                            gsize         *length);
68 static gchar *dump_array  (JsonGenerator *generator,
69                            gint           level,
70                            const gchar   *name,
71                            JsonArray     *array,
72                            gsize         *length);
73 static gchar *dump_object (JsonGenerator *generator,
74                            gint           level,
75                            const gchar   *name,
76                            JsonObject    *object,
77                            gsize         *length);
78
79 static GParamSpec *generator_props[PROP_LAST] = { NULL, };
80
81 G_DEFINE_TYPE_WITH_PRIVATE (JsonGenerator, json_generator, G_TYPE_OBJECT)
82
83 static gchar *
84 json_strescape (const gchar *str)
85 {
86   const gchar *p;
87   const gchar *end;
88   GString *output;
89   gsize len;
90
91   len = strlen (str);
92   end = str + len;
93   output = g_string_sized_new (len);
94
95   for (p = str; p < end; p++)
96     {
97       if (*p == '\\' || *p == '"')
98         {
99           g_string_append_c (output, '\\');
100           g_string_append_c (output, *p);
101         }
102       else if ((*p > 0 && *p < 0x1f) || *p == 0x7f)
103         {
104           switch (*p)
105             {
106             case '\b':
107               g_string_append (output, "\\b");
108               break;
109             case '\f':
110               g_string_append (output, "\\f");
111               break;
112             case '\n':
113               g_string_append (output, "\\n");
114               break;
115             case '\r':
116               g_string_append (output, "\\r");
117               break;
118             case '\t':
119               g_string_append (output, "\\t");
120               break;
121             default:
122               g_string_append_printf (output, "\\u00%02x", (guint)*p);
123               break;
124             }
125         }
126       else
127         {
128           g_string_append_c (output, *p);
129         }
130     }
131
132   return g_string_free (output, FALSE);
133 }
134
135 static void
136 json_generator_finalize (GObject *gobject)
137 {
138   JsonGeneratorPrivate *priv;
139
140   priv = json_generator_get_instance_private ((JsonGenerator *) gobject);
141   if (priv->root != NULL)
142     json_node_unref (priv->root);
143
144   G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject);
145 }
146
147 static void
148 json_generator_set_property (GObject      *gobject,
149                              guint         prop_id,
150                              const GValue *value,
151                              GParamSpec   *pspec)
152 {
153   JsonGenerator *generator = JSON_GENERATOR (gobject);
154
155   switch (prop_id)
156     {
157     case PROP_PRETTY:
158       json_generator_set_pretty (generator, g_value_get_boolean (value));
159       break;
160
161     case PROP_INDENT:
162       json_generator_set_indent (generator, g_value_get_uint (value));
163       break;
164
165     case PROP_INDENT_CHAR:
166       json_generator_set_indent_char (generator, g_value_get_uint (value));
167       break;
168
169     case PROP_ROOT:
170       json_generator_set_root (generator, g_value_get_boxed (value));
171       break;
172
173     default:
174       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
175       break;
176     }
177 }
178
179 static void
180 json_generator_get_property (GObject    *gobject,
181                              guint       prop_id,
182                              GValue     *value,
183                              GParamSpec *pspec)
184 {
185   JsonGeneratorPrivate *priv = JSON_GENERATOR (gobject)->priv;
186
187   switch (prop_id)
188     {
189     case PROP_PRETTY:
190       g_value_set_boolean (value, priv->pretty);
191       break;
192     case PROP_INDENT:
193       g_value_set_uint (value, priv->indent);
194       break;
195     case PROP_INDENT_CHAR:
196       g_value_set_uint (value, priv->indent_char);
197       break;
198     case PROP_ROOT:
199       g_value_set_boxed (value, priv->root);
200       break;
201     default:
202       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
203       break;
204     }
205 }
206
207 static void
208 json_generator_class_init (JsonGeneratorClass *klass)
209 {
210   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
211
212   /**
213    * JsonGenerator:pretty:
214    *
215    * Whether the output should be "pretty-printed", with indentation and
216    * newlines. The indentation level can be controlled by using the
217    * JsonGenerator:indent property
218    */
219   generator_props[PROP_PRETTY] =
220     g_param_spec_boolean ("pretty",
221                           "Pretty",
222                           "Pretty-print the output",
223                           FALSE,
224                           G_PARAM_READWRITE);
225
226   /**
227    * JsonGenerator:indent:
228    *
229    * Number of spaces to be used to indent when pretty printing.
230    */
231   generator_props[PROP_INDENT] =
232     g_param_spec_uint ("indent",
233                        "Indent",
234                        "Number of indentation spaces",
235                        0, G_MAXUINT,
236                        2,
237                        G_PARAM_READWRITE);
238
239   /**
240    * JsonGenerator:root:
241    *
242    * The root #JsonNode to be used when constructing a JSON data
243    * stream.
244    *
245    * Since: 0.4
246    */
247   generator_props[PROP_ROOT] =
248     g_param_spec_boxed ("root",
249                         "Root",
250                         "Root of the JSON data tree",
251                         JSON_TYPE_NODE,
252                         G_PARAM_READWRITE);
253
254   /**
255    * JsonGenerator:indent-char:
256    *
257    * The character that should be used when indenting in pretty print.
258    *
259    * Since: 0.6
260    */
261   generator_props[PROP_INDENT_CHAR] =
262     g_param_spec_unichar ("indent-char",
263                           "Indent Char",
264                           "Character that should be used when indenting",
265                           ' ',
266                           G_PARAM_READWRITE);
267
268   gobject_class->set_property = json_generator_set_property;
269   gobject_class->get_property = json_generator_get_property;
270   gobject_class->finalize = json_generator_finalize;
271   g_object_class_install_properties (gobject_class, PROP_LAST, generator_props);
272 }
273
274 static void
275 json_generator_init (JsonGenerator *generator)
276 {
277   JsonGeneratorPrivate *priv = json_generator_get_instance_private (generator);
278
279   generator->priv = priv;
280
281   priv->pretty = FALSE;
282   priv->indent = 2;
283   priv->indent_char = ' ';
284 }
285
286 static gchar *
287 dump_value (JsonGenerator *generator,
288             gint           level,
289             const gchar   *name,
290             JsonNode      *node,
291             gsize         *length)
292 {
293   JsonGeneratorPrivate *priv = generator->priv;
294   gboolean pretty = priv->pretty;
295   guint indent = priv->indent;
296   const JsonValue *value;
297   GString *buffer;
298
299   buffer = g_string_new ("");
300
301   if (pretty)
302     {
303       guint i;
304
305       for (i = 0; i < (level * indent); i++)
306         g_string_append_c (buffer, priv->indent_char);
307     }
308
309   if (name)
310     {
311       if (pretty)
312         g_string_append_printf (buffer, "\"%s\" : ", name);
313       else
314         g_string_append_printf (buffer, "\"%s\":", name);
315     }
316
317   value = node->data.value;
318
319   switch (value->type)
320     {
321     case JSON_VALUE_INT:
322       g_string_append_printf (buffer, "%" G_GINT64_FORMAT, json_value_get_int (value));
323       break;
324
325     case JSON_VALUE_STRING:
326       {
327         gchar *tmp;
328
329         tmp = json_strescape (json_value_get_string (value));
330         g_string_append_c (buffer, '"');
331         g_string_append (buffer, tmp);
332         g_string_append_c (buffer, '"');
333
334         g_free (tmp);
335       }
336       break;
337
338     case JSON_VALUE_DOUBLE:
339       {
340         gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
341
342         g_string_append (buffer,
343                          g_ascii_dtostr (buf, sizeof (buf),
344                                          json_value_get_double (value)));
345         /* ensure doubles don't become ints */
346         if (g_strstr_len (buf, G_ASCII_DTOSTR_BUF_SIZE, ".") == NULL)
347           {
348             g_string_append (buffer, ".0");
349           }
350       }
351       break;
352
353     case JSON_VALUE_BOOLEAN:
354       g_string_append (buffer, json_value_get_boolean (value) ? "true" : "false");
355       break;
356
357     case JSON_VALUE_NULL:
358       g_string_append (buffer, "null");
359       break;
360
361     default:
362       break;
363     }
364
365   if (length)
366     *length = buffer->len;
367
368   return g_string_free (buffer, FALSE);
369 }
370
371 static gchar *
372 dump_array (JsonGenerator *generator,
373             gint           level,
374             const gchar   *name,
375             JsonArray     *array,
376             gsize         *length)
377 {
378   JsonGeneratorPrivate *priv = generator->priv;
379   guint array_len = json_array_get_length (array);
380   guint i;
381   GString *buffer;
382   gboolean pretty = priv->pretty;
383   guint indent = priv->indent;
384
385   buffer = g_string_new ("");
386
387   if (pretty)
388     {
389       for (i = 0; i < (level * indent); i++)
390         g_string_append_c (buffer, priv->indent_char);
391     }
392
393   if (name)
394     {
395       if (pretty)
396         g_string_append_printf (buffer, "\"%s\" : ", name);
397       else
398         g_string_append_printf (buffer, "\"%s\":", name);
399     }
400
401   g_string_append_c (buffer, '[');
402
403   if (pretty)
404     g_string_append_c (buffer, '\n');
405
406   for (i = 0; i < array_len; i++)
407     {
408       JsonNode *cur = json_array_get_element (array, i);
409       guint sub_level = level + 1;
410       guint j;
411       gchar *value; 
412
413       switch (JSON_NODE_TYPE (cur))
414         {
415         case JSON_NODE_NULL:
416           if (pretty)
417             {
418               for (j = 0; j < (sub_level * indent); j++)
419                 g_string_append_c (buffer, priv->indent_char);
420             }
421           g_string_append (buffer, "null");
422           break;
423
424         case JSON_NODE_VALUE:
425           value = dump_value (generator, sub_level, NULL, cur, NULL);
426           g_string_append (buffer, value);
427           g_free (value);
428           break;
429
430         case JSON_NODE_ARRAY:
431           value = dump_array (generator, sub_level, NULL, json_node_get_array (cur), NULL);
432           g_string_append (buffer, value);
433           g_free (value);
434           break;
435
436         case JSON_NODE_OBJECT:
437           value = dump_object (generator, sub_level, NULL, json_node_get_object (cur), NULL);
438           g_string_append (buffer, value);
439           g_free (value);
440           break;
441         }
442
443       if ((i + 1) != array_len)
444         g_string_append_c (buffer, ',');
445
446       if (pretty)
447         g_string_append_c (buffer, '\n');
448     }
449
450   if (pretty)
451     {
452       for (i = 0; i < (level * indent); i++)
453         g_string_append_c (buffer, priv->indent_char);
454     }
455
456   g_string_append_c (buffer, ']');
457
458   if (length)
459     *length = buffer->len;
460
461   return g_string_free (buffer, FALSE);
462 }
463
464 static gchar *
465 dump_object (JsonGenerator *generator,
466              gint           level,
467              const gchar   *name,
468              JsonObject    *object,
469              gsize         *length)
470 {
471   JsonGeneratorPrivate *priv = generator->priv;
472   GList *members, *l;
473   GString *buffer;
474   gboolean pretty = priv->pretty;
475   guint indent = priv->indent;
476   guint i;
477
478   buffer = g_string_new ("");
479
480   if (pretty)
481     {
482       for (i = 0; i < (level * indent); i++)
483         g_string_append_c (buffer, priv->indent_char);
484     }
485
486   if (name)
487     {
488       if (pretty)
489         g_string_append_printf (buffer, "\"%s\" : ", name);
490       else
491         g_string_append_printf (buffer, "\"%s\":", name);
492     }
493
494   g_string_append_c (buffer, '{');
495
496   if (pretty)
497     g_string_append_c (buffer, '\n');
498
499   members = json_object_get_members (object);
500
501   for (l = members; l != NULL; l = l->next)
502     {
503       const gchar *member_name = l->data;
504       gchar *escaped_name = json_strescape (member_name);
505       JsonNode *cur = json_object_get_member (object, member_name);
506       guint sub_level = level + 1;
507       guint j;
508       gchar *value;
509
510       switch (JSON_NODE_TYPE (cur))
511         {
512         case JSON_NODE_NULL:
513           if (pretty)
514             {
515               for (j = 0; j < (sub_level * indent); j++)
516                 g_string_append_c (buffer, priv->indent_char);
517               g_string_append_printf (buffer, "\"%s\" : null", escaped_name);
518             }
519           else
520             {
521               g_string_append_printf (buffer, "\"%s\":null", escaped_name);
522             }
523           break;
524
525         case JSON_NODE_VALUE:
526           value = dump_value (generator, sub_level, escaped_name, cur, NULL);
527           g_string_append (buffer, value);
528           g_free (value);
529           break;
530
531         case JSON_NODE_ARRAY:
532           value = dump_array (generator, sub_level, escaped_name,
533                               json_node_get_array (cur), NULL);
534           g_string_append (buffer, value);
535           g_free (value);
536           break;
537
538         case JSON_NODE_OBJECT:
539           value = dump_object (generator, sub_level, escaped_name,
540                                json_node_get_object (cur), NULL);
541           g_string_append (buffer, value);
542           g_free (value);
543           break;
544         }
545
546       if (l->next != NULL)
547         g_string_append_c (buffer, ',');
548
549       if (pretty)
550         g_string_append_c (buffer, '\n');
551
552       g_free (escaped_name);
553     }
554
555   g_list_free (members);
556
557   if (pretty)
558     {
559       for (i = 0; i < (level * indent); i++)
560         g_string_append_c (buffer, priv->indent_char);
561     }
562
563   g_string_append_c (buffer, '}');
564
565   if (length)
566     *length = buffer->len;
567
568   return g_string_free (buffer, FALSE);
569 }
570
571 /**
572  * json_generator_new:
573  * 
574  * Creates a new #JsonGenerator. You can use this object to generate a
575  * JSON data stream starting from a data object model composed by
576  * #JsonNodes.
577  *
578  * Return value: the newly created #JsonGenerator instance
579  */
580 JsonGenerator *
581 json_generator_new (void)
582 {
583   return g_object_new (JSON_TYPE_GENERATOR, NULL);
584 }
585
586 /**
587  * json_generator_to_data:
588  * @generator: a #JsonGenerator
589  * @length: (out): return location for the length of the returned
590  *   buffer, or %NULL
591  *
592  * Generates a JSON data stream from @generator and returns it as a
593  * buffer.
594  *
595  * Return value: a newly allocated buffer holding a JSON data stream.
596  *   Use g_free() to free the allocated resources.
597  */
598 gchar *
599 json_generator_to_data (JsonGenerator *generator,
600                         gsize         *length)
601 {
602   JsonNode *root;
603   gchar *retval = NULL;
604
605   g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
606
607   root = generator->priv->root;
608   if (!root)
609     {
610       if (length)
611         *length = 0;
612
613       return NULL;
614     }
615
616   switch (JSON_NODE_TYPE (root))
617     {
618     case JSON_NODE_ARRAY:
619       retval = dump_array (generator, 0, NULL, json_node_get_array (root), length);
620       break;
621
622     case JSON_NODE_OBJECT:
623       retval = dump_object (generator, 0, NULL, json_node_get_object (root), length);
624       break;
625
626     case JSON_NODE_NULL:
627       retval = g_strdup ("null");
628       if (length)
629         *length = 4;
630       break;
631
632     case JSON_NODE_VALUE:
633       retval = dump_value (generator, 0, NULL, root, length);
634       break;
635     }
636
637   return retval;
638 }
639
640 /**
641  * json_generator_to_file:
642  * @generator: a #JsonGenerator
643  * @filename: path to the target file
644  * @error: return location for a #GError, or %NULL
645  *
646  * Creates a JSON data stream and puts it inside @filename, overwriting the
647  * current file contents. This operation is atomic.
648  *
649  * Return value: %TRUE if saving was successful.
650  */
651 gboolean
652 json_generator_to_file (JsonGenerator  *generator,
653                         const gchar    *filename,
654                         GError        **error)
655 {
656   gchar *buffer;
657   gsize len;
658   gboolean retval;
659
660   g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
661   g_return_val_if_fail (filename != NULL, FALSE);
662
663   buffer = json_generator_to_data (generator, &len);
664   retval = g_file_set_contents (filename, buffer, len, error);
665   g_free (buffer);
666
667   return retval;
668 }
669
670 /**
671  * json_generator_to_stream:
672  * @generator: a #JsonGenerator
673  * @stream: a #GOutputStream
674  * @cancellable: (allow-none): a #GCancellable, or %NULL
675  * @error: return location for a #GError, or %NULL
676  *
677  * Outputs JSON data and streams it (synchronously) to @stream.
678  *
679  * Return value: %TRUE if the write operation was successful, and %FALSE
680  *   on failure. In case of error, the #GError will be filled accordingly
681  *
682  * Since: 0.12
683  */
684 gboolean
685 json_generator_to_stream (JsonGenerator  *generator,
686                           GOutputStream  *stream,
687                           GCancellable   *cancellable,
688                           GError        **error)
689 {
690   gboolean retval;
691   gchar *buffer;
692   gsize len;
693
694   g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
695   g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
696
697   if (g_cancellable_set_error_if_cancelled (cancellable, error))
698     return FALSE;
699
700   buffer = json_generator_to_data (generator, &len);
701   retval = g_output_stream_write (stream, buffer, len, cancellable, error);
702   g_free (buffer);
703
704   return retval;
705 }
706
707 /**
708  * json_generator_set_root:
709  * @generator: a #JsonGenerator
710  * @node: a #JsonNode
711  *
712  * Sets @node as the root of the JSON data stream to be serialized by
713  * the #JsonGenerator.
714  *
715  * The passed @node is copied by the generator object, so it can be
716  * safely freed after calling this function.
717  */
718 void
719 json_generator_set_root (JsonGenerator *generator,
720                          JsonNode      *node)
721 {
722   g_return_if_fail (JSON_IS_GENERATOR (generator));
723
724   if (generator->priv->root == node)
725     return;
726
727   if (generator->priv->root != NULL)
728     {
729       json_node_unref (generator->priv->root);
730       generator->priv->root = NULL;
731     }
732
733   if (node != NULL)
734     generator->priv->root = json_node_copy (node);
735
736   g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]);
737 }
738
739 /**
740  * json_generator_get_root:
741  * @generator: a #JsonGenerator
742  *
743  * Retrieves a pointer to the root #JsonNode set using
744  * json_generator_set_root().
745  *
746  * Return value: (transfer none): a #JsonNode, or %NULL. The returned node
747  *   is owned by the #JsonGenerator and it should not be freed
748  *
749  * Since: 0.14
750  */
751 JsonNode *
752 json_generator_get_root (JsonGenerator *generator)
753 {
754   g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
755
756   return generator->priv->root;
757 }
758
759 /**
760  * json_generator_set_pretty:
761  * @generator: a #JsonGenerator
762  * @is_pretty: whether the generated string should be pretty printed
763  *
764  * Sets whether the generated JSON should be pretty printed, using the
765  * indentation character specified in the #JsonGenerator:indent-char
766  * property and the spacing specified in #JsonGenerator:indent property.
767  *
768  * Since: 0.14
769  */
770 void
771 json_generator_set_pretty (JsonGenerator *generator,
772                            gboolean       is_pretty)
773 {
774   JsonGeneratorPrivate *priv;
775
776   g_return_if_fail (JSON_IS_GENERATOR (generator));
777
778   priv = generator->priv;
779
780   is_pretty = !!is_pretty;
781
782   if (priv->pretty != is_pretty)
783     {
784       priv->pretty = is_pretty;
785
786       g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_PRETTY]);
787     }
788 }
789
790 /**
791  * json_generator_get_pretty:
792  * @generator: a #JsonGenerator
793  *
794  * Retrieves the value set using json_generator_set_pretty().
795  *
796  * Return value: %TRUE if the generated JSON should be pretty-printed, and
797  *   %FALSE otherwise
798  *
799  * Since: 0.14
800  */
801 gboolean
802 json_generator_get_pretty (JsonGenerator *generator)
803 {
804   g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
805
806   return generator->priv->pretty;
807 }
808
809 /**
810  * json_generator_set_indent:
811  * @generator: a #JsonGenerator
812  * @indent_level: the number of repetitions of the indentation character
813  *   that should be applied when pretty printing
814  *
815  * Sets the number of repetitions for each indentation level.
816  *
817  * Since: 0.14
818  */
819 void
820 json_generator_set_indent (JsonGenerator *generator,
821                            guint          indent_level)
822 {
823   JsonGeneratorPrivate *priv;
824
825   g_return_if_fail (JSON_IS_GENERATOR (generator));
826
827   priv = generator->priv;
828
829   if (priv->indent != indent_level)
830     {
831       priv->indent = indent_level;
832
833       g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT]);
834     }
835 }
836
837 /**
838  * json_generator_get_indent:
839  * @generator: a #JsonGenerator
840  *
841  * Retrieves the value set using json_generator_set_indent().
842  *
843  * Return value: the number of repetitions per indentation level
844  *
845  * Since: 0.14
846  */
847 guint
848 json_generator_get_indent (JsonGenerator *generator)
849 {
850   g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
851
852   return generator->priv->indent;
853 }
854
855 /**
856  * json_generator_set_indent_char:
857  * @generator: a #JsonGenerator
858  * @indent_char: a Unicode character to be used when indenting
859  *
860  * Sets the character to be used when indenting
861  *
862  * Since: 0.14
863  */
864 void
865 json_generator_set_indent_char (JsonGenerator *generator,
866                                 gunichar       indent_char)
867 {
868   JsonGeneratorPrivate *priv;
869
870   g_return_if_fail (JSON_IS_GENERATOR (generator));
871
872   priv = generator->priv;
873
874   if (priv->indent_char != indent_char)
875     {
876       priv->indent_char = indent_char;
877
878       g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT_CHAR]);
879     }
880 }
881
882 /**
883  * json_generator_get_indent_char:
884  * @generator: a #JsonGenerator
885  *
886  * Retrieves the value set using json_generator_set_indent_char().
887  *
888  * Return value: the character to be used when indenting
889  *
890  * Since: 0.14
891  */
892 gunichar
893 json_generator_get_indent_char (JsonGenerator *generator)
894 {
895   g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
896
897   return generator->priv->indent_char;
898 }