1 /* json-generator.c - JSON streams generator
3 * This file is part of JSON-GLib
4 * Copyright (C) 2007 OpenedHand Ltd.
5 * Copyright (C) 2009 Intel Corp.
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.
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.
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/>.
21 * Emmanuele Bassi <ebassi@linux.intel.com>
25 * SECTION:json-generator
26 * @short_description: Generates JSON data streams
28 * #JsonGenerator provides an object for generating a JSON data stream and
29 * put it into a buffer or a file.
39 #include "json-types-private.h"
41 #include "json-marshal.h"
42 #include "json-generator.h"
44 #define JSON_GENERATOR_GET_PRIVATE(obj) \
45 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), JSON_TYPE_GENERATOR, JsonGeneratorPrivate))
47 struct _JsonGeneratorPrivate
69 static gchar *dump_value (JsonGenerator *generator,
74 static gchar *dump_array (JsonGenerator *generator,
79 static gchar *dump_object (JsonGenerator *generator,
85 /* non-ASCII characters can't be escaped, otherwise UTF-8
86 * chars will break, so we just pregenerate this table of
87 * high characters and then we feed it to g_strescape()
89 static const char json_exceptions[] = {
90 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
91 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
92 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
93 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
94 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
95 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
96 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
97 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe,
98 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
99 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
100 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
101 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
102 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
103 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee,
104 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
105 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
107 '\0' /* g_strescape() expects a NUL-terminated string */
110 static GParamSpec *generator_props[PROP_LAST] = { NULL, };
112 G_DEFINE_TYPE (JsonGenerator, json_generator, G_TYPE_OBJECT);
115 json_strescape (const gchar *str)
117 return g_strescape (str, json_exceptions);
121 json_generator_finalize (GObject *gobject)
123 JsonGeneratorPrivate *priv = JSON_GENERATOR_GET_PRIVATE (gobject);
126 json_node_free (priv->root);
128 G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject);
132 json_generator_set_property (GObject *gobject,
137 JsonGenerator *generator = JSON_GENERATOR (gobject);
142 json_generator_set_pretty (generator, g_value_get_boolean (value));
146 json_generator_set_indent (generator, g_value_get_uint (value));
149 case PROP_INDENT_CHAR:
150 json_generator_set_indent_char (generator, g_value_get_uint (value));
154 json_generator_set_root (generator, g_value_get_boxed (value));
158 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
164 json_generator_get_property (GObject *gobject,
169 JsonGeneratorPrivate *priv = JSON_GENERATOR (gobject)->priv;
174 g_value_set_boolean (value, priv->pretty);
177 g_value_set_uint (value, priv->indent);
179 case PROP_INDENT_CHAR:
180 g_value_set_uint (value, priv->indent_char);
183 g_value_set_boxed (value, priv->root);
186 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
192 json_generator_class_init (JsonGeneratorClass *klass)
194 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
196 g_type_class_add_private (klass, sizeof (JsonGeneratorPrivate));
199 * JsonGenerator:pretty:
201 * Whether the output should be "pretty-printed", with indentation and
202 * newlines. The indentation level can be controlled by using the
203 * JsonGenerator:indent property
205 generator_props[PROP_PRETTY] =
206 g_param_spec_boolean ("pretty",
208 "Pretty-print the output",
213 * JsonGenerator:indent:
215 * Number of spaces to be used to indent when pretty printing.
217 generator_props[PROP_INDENT] =
218 g_param_spec_uint ("indent",
220 "Number of indentation spaces",
226 * JsonGenerator:root:
228 * The root #JsonNode to be used when constructing a JSON data
233 generator_props[PROP_ROOT] =
234 g_param_spec_boxed ("root",
236 "Root of the JSON data tree",
241 * JsonGenerator:indent-char:
243 * The character that should be used when indenting in pretty print.
247 generator_props[PROP_INDENT_CHAR] =
248 g_param_spec_unichar ("indent-char",
250 "Character that should be used when indenting",
254 gobject_class->set_property = json_generator_set_property;
255 gobject_class->get_property = json_generator_get_property;
256 gobject_class->finalize = json_generator_finalize;
257 g_object_class_install_properties (gobject_class, PROP_LAST, generator_props);
261 json_generator_init (JsonGenerator *generator)
263 JsonGeneratorPrivate *priv;
265 generator->priv = priv = JSON_GENERATOR_GET_PRIVATE (generator);
267 priv->pretty = FALSE;
269 priv->indent_char = ' ';
273 dump_value (JsonGenerator *generator,
279 JsonGeneratorPrivate *priv = generator->priv;
280 gboolean pretty = priv->pretty;
281 guint indent = priv->indent;
282 GValue value = { 0, };
285 buffer = g_string_new ("");
291 for (i = 0; i < (level * indent); i++)
292 g_string_append_c (buffer, priv->indent_char);
295 if (name && name[0] != '\0')
298 g_string_append_printf (buffer, "\"%s\" : ", name);
300 g_string_append_printf (buffer, "\"%s\":", name);
303 json_node_get_value (node, &value);
305 switch (G_VALUE_TYPE (&value))
308 g_string_append_printf (buffer, "%" G_GINT64_FORMAT, g_value_get_int64 (&value));
315 tmp = json_strescape (g_value_get_string (&value));
316 g_string_append_printf (buffer, "\"%s\"", tmp);
324 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
326 g_string_append (buffer,
327 g_ascii_dtostr (buf, sizeof (buf),
328 g_value_get_double (&value)));
333 g_string_append_printf (buffer, "%s",
334 g_value_get_boolean (&value) ? "true" : "false");
341 g_value_unset (&value);
344 *length = buffer->len;
346 return g_string_free (buffer, FALSE);
350 dump_array (JsonGenerator *generator,
356 JsonGeneratorPrivate *priv = generator->priv;
357 guint array_len = json_array_get_length (array);
360 gboolean pretty = priv->pretty;
361 guint indent = priv->indent;
363 buffer = g_string_new ("");
367 for (i = 0; i < (level * indent); i++)
368 g_string_append_c (buffer, priv->indent_char);
371 if (name && name[0] != '\0')
374 g_string_append_printf (buffer, "\"%s\" : ", name);
376 g_string_append_printf (buffer, "\"%s\":", name);
379 g_string_append_c (buffer, '[');
382 g_string_append_c (buffer, '\n');
384 for (i = 0; i < array_len; i++)
386 JsonNode *cur = json_array_get_element (array, i);
387 guint sub_level = level + 1;
391 switch (JSON_NODE_TYPE (cur))
396 for (j = 0; j < (sub_level * indent); j++)
397 g_string_append_c (buffer, priv->indent_char);
399 g_string_append (buffer, "null");
402 case JSON_NODE_VALUE:
403 value = dump_value (generator, sub_level, NULL, cur, NULL);
404 g_string_append (buffer, value);
408 case JSON_NODE_ARRAY:
409 value = dump_array (generator, sub_level, NULL, json_node_get_array (cur), NULL);
410 g_string_append (buffer, value);
414 case JSON_NODE_OBJECT:
415 value = dump_object (generator, sub_level, NULL, json_node_get_object (cur), NULL);
416 g_string_append (buffer, value);
421 if ((i + 1) != array_len)
422 g_string_append_c (buffer, ',');
425 g_string_append_c (buffer, '\n');
430 for (i = 0; i < (level * indent); i++)
431 g_string_append_c (buffer, priv->indent_char);
434 g_string_append_c (buffer, ']');
437 *length = buffer->len;
439 return g_string_free (buffer, FALSE);
443 dump_object (JsonGenerator *generator,
449 JsonGeneratorPrivate *priv = generator->priv;
452 gboolean pretty = priv->pretty;
453 guint indent = priv->indent;
456 buffer = g_string_new ("");
460 for (i = 0; i < (level * indent); i++)
461 g_string_append_c (buffer, priv->indent_char);
464 if (name && name[0] != '\0')
467 g_string_append_printf (buffer, "\"%s\" : ", name);
469 g_string_append_printf (buffer, "\"%s\":", name);
472 g_string_append_c (buffer, '{');
475 g_string_append_c (buffer, '\n');
477 members = json_object_get_members (object);
479 for (l = members; l != NULL; l = l->next)
481 const gchar *member_name = l->data;
482 JsonNode *cur = json_object_get_member (object, member_name);
483 guint sub_level = level + 1;
487 switch (JSON_NODE_TYPE (cur))
492 for (j = 0; j < (sub_level * indent); j++)
493 g_string_append_c (buffer, priv->indent_char);
494 g_string_append_printf (buffer, "\"%s\" : null", member_name);
498 g_string_append_printf (buffer, "\"%s\":null", member_name);
502 case JSON_NODE_VALUE:
503 value = dump_value (generator, sub_level, member_name, cur, NULL);
504 g_string_append (buffer, value);
508 case JSON_NODE_ARRAY:
509 value = dump_array (generator, sub_level, member_name,
510 json_node_get_array (cur), NULL);
511 g_string_append (buffer, value);
515 case JSON_NODE_OBJECT:
516 value = dump_object (generator, sub_level, member_name,
517 json_node_get_object (cur), NULL);
518 g_string_append (buffer, value);
524 g_string_append_c (buffer, ',');
527 g_string_append_c (buffer, '\n');
530 g_list_free (members);
534 for (i = 0; i < (level * indent); i++)
535 g_string_append_c (buffer, priv->indent_char);
538 g_string_append_c (buffer, '}');
541 *length = buffer->len;
543 return g_string_free (buffer, FALSE);
547 * json_generator_new:
549 * Creates a new #JsonGenerator. You can use this object to generate a
550 * JSON data stream starting from a data object model composed by
551 * #JsonNode<!-- -->s.
553 * Return value: the newly created #JsonGenerator instance
556 json_generator_new (void)
558 return g_object_new (JSON_TYPE_GENERATOR, NULL);
562 * json_generator_to_data:
563 * @generator: a #JsonGenerator
564 * @length: (out): return location for the length of the returned
567 * Generates a JSON data stream from @generator and returns it as a
570 * Return value: a newly allocated buffer holding a JSON data stream.
571 * Use g_free() to free the allocated resources.
574 json_generator_to_data (JsonGenerator *generator,
578 gchar *retval = NULL;
580 g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
582 root = generator->priv->root;
591 switch (JSON_NODE_TYPE (root))
593 case JSON_NODE_ARRAY:
594 retval = dump_array (generator, 0, NULL, json_node_get_array (root), length);
597 case JSON_NODE_OBJECT:
598 retval = dump_object (generator, 0, NULL, json_node_get_object (root), length);
602 retval = g_strdup ("null");
607 case JSON_NODE_VALUE:
608 retval = dump_value (generator, 0, NULL, root, length);
616 * json_generator_to_file:
617 * @generator: a #JsonGenerator
618 * @filename: path to the target file
619 * @error: return location for a #GError, or %NULL
621 * Creates a JSON data stream and puts it inside @filename, overwriting the
622 * current file contents. This operation is atomic.
624 * Return value: %TRUE if saving was successful.
627 json_generator_to_file (JsonGenerator *generator,
628 const gchar *filename,
635 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
636 g_return_val_if_fail (filename != NULL, FALSE);
638 buffer = json_generator_to_data (generator, &len);
639 retval = g_file_set_contents (filename, buffer, len, error);
646 * json_generator_to_stream:
647 * @generator: a #JsonGenerator
648 * @stream: a #GOutputStream
649 * @cancellable: (allow-none): a #GCancellable, or %NULL
650 * @error: return location for a #GError, or %NULL
652 * Outputs JSON data and streams it (synchronously) to @stream.
654 * Return value: %TRUE if the write operation was successful, and %FALSE
655 * on failure. In case of error, the #GError will be filled accordingly
660 json_generator_to_stream (JsonGenerator *generator,
661 GOutputStream *stream,
662 GCancellable *cancellable,
669 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
670 g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
672 if (g_cancellable_set_error_if_cancelled (cancellable, error))
675 buffer = json_generator_to_data (generator, &len);
676 retval = g_output_stream_write (stream, buffer, len, cancellable, error);
683 * json_generator_set_root:
684 * @generator: a #JsonGenerator
687 * Sets @node as the root of the JSON data stream to be serialized by
688 * the #JsonGenerator.
690 * <note>The node is copied by the generator object, so it can be safely
691 * freed after calling this function.</note>
694 json_generator_set_root (JsonGenerator *generator,
697 g_return_if_fail (JSON_IS_GENERATOR (generator));
699 if (generator->priv->root != NULL)
701 json_node_free (generator->priv->root);
702 generator->priv->root = NULL;
706 generator->priv->root = json_node_copy (node);
708 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]);
712 * json_generator_get_root:
713 * @generator: a #JsonGenerator
715 * Retrieves a pointer to the root #JsonNode set using
716 * json_generator_set_root().
718 * Return value: (transfer none): a #JsonNode, or %NULL. The returned node
719 * is owned by the #JsonGenerator and it should not be freed
724 json_generator_get_root (JsonGenerator *generator)
726 g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
728 return generator->priv->root;
732 * json_generator_set_pretty:
733 * @generator: a #JsonGenerator
734 * @is_pretty: whether the generated string should be pretty printed
736 * Sets whether the generated JSON should be pretty printed, using the
737 * indentation character specified in the #JsonGenerator:indent-char
738 * property and the spacing specified in #JsonGenerator:indent property.
743 json_generator_set_pretty (JsonGenerator *generator,
746 JsonGeneratorPrivate *priv;
748 g_return_if_fail (JSON_IS_GENERATOR (generator));
750 priv = generator->priv;
752 is_pretty = !!is_pretty;
754 if (priv->pretty != is_pretty)
756 priv->pretty = is_pretty;
758 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_PRETTY]);
763 * json_generator_get_pretty:
764 * @generator: a #JsonGenerator
766 * Retrieves the value set using json_generator_set_pretty().
768 * Return value: %TRUE if the generated JSON should be pretty-printed, and
774 json_generator_get_pretty (JsonGenerator *generator)
776 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
778 return generator->priv->pretty;
782 * json_generator_set_indent:
783 * @generator: a #JsonGenerator
784 * @indent_level: the number of repetitions of the indentation character
785 * that should be applied when pretty printing
787 * Sets the number of repetitions for each indentation level.
792 json_generator_set_indent (JsonGenerator *generator,
795 JsonGeneratorPrivate *priv;
797 g_return_if_fail (JSON_IS_GENERATOR (generator));
799 priv = generator->priv;
801 if (priv->indent != indent_level)
803 priv->indent = indent_level;
805 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT]);
810 * json_generator_get_indent:
811 * @generator: a #JsonGenerator
813 * Retrieves the value set using json_generator_set_indent().
815 * Return value: the number of repetitions per indentation level
820 json_generator_get_indent (JsonGenerator *generator)
822 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
824 return generator->priv->indent;
828 * json_generator_set_indent_char:
829 * @generator: a #JsonGenerator
830 * @indent_char: a Unicode character to be used when indenting
832 * Sets the character to be used when indenting
837 json_generator_set_indent_char (JsonGenerator *generator,
838 gunichar indent_char)
840 JsonGeneratorPrivate *priv;
842 g_return_if_fail (JSON_IS_GENERATOR (generator));
844 priv = generator->priv;
846 if (priv->indent_char != indent_char)
848 priv->indent_char = indent_char;
850 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT_CHAR]);
855 * json_generator_get_indent_char:
856 * @generator: a #JsonGenerator
858 * Retrieves the value set using json_generator_set_indent_char().
860 * Return value: the character to be used when indenting
865 json_generator_get_indent_char (JsonGenerator *generator)
867 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
869 return generator->priv->indent_char;