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.
37 #include "json-types-private.h"
39 #include "json-generator.h"
41 struct _JsonGeneratorPrivate
63 static gchar *dump_value (JsonGenerator *generator,
68 static gchar *dump_array (JsonGenerator *generator,
73 static gchar *dump_object (JsonGenerator *generator,
79 static GParamSpec *generator_props[PROP_LAST] = { NULL, };
81 G_DEFINE_TYPE_WITH_PRIVATE (JsonGenerator, json_generator, G_TYPE_OBJECT)
84 json_strescape (const gchar *str)
93 output = g_string_sized_new (len);
95 for (p = str; p < end; p++)
97 if (*p == '\\' || *p == '"')
99 g_string_append_c (output, '\\');
100 g_string_append_c (output, *p);
102 else if ((*p > 0 && *p < 0x1f) || *p == 0x7f)
107 g_string_append (output, "\\b");
110 g_string_append (output, "\\f");
113 g_string_append (output, "\\n");
116 g_string_append (output, "\\r");
119 g_string_append (output, "\\t");
122 g_string_append_printf (output, "\\u00%02x", (guint)*p);
128 g_string_append_c (output, *p);
132 return g_string_free (output, FALSE);
136 json_generator_finalize (GObject *gobject)
138 JsonGeneratorPrivate *priv;
140 priv = json_generator_get_instance_private ((JsonGenerator *) gobject);
141 if (priv->root != NULL)
142 json_node_unref (priv->root);
144 G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject);
148 json_generator_set_property (GObject *gobject,
153 JsonGenerator *generator = JSON_GENERATOR (gobject);
158 json_generator_set_pretty (generator, g_value_get_boolean (value));
162 json_generator_set_indent (generator, g_value_get_uint (value));
165 case PROP_INDENT_CHAR:
166 json_generator_set_indent_char (generator, g_value_get_uint (value));
170 json_generator_set_root (generator, g_value_get_boxed (value));
174 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
180 json_generator_get_property (GObject *gobject,
185 JsonGeneratorPrivate *priv = JSON_GENERATOR (gobject)->priv;
190 g_value_set_boolean (value, priv->pretty);
193 g_value_set_uint (value, priv->indent);
195 case PROP_INDENT_CHAR:
196 g_value_set_uint (value, priv->indent_char);
199 g_value_set_boxed (value, priv->root);
202 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
208 json_generator_class_init (JsonGeneratorClass *klass)
210 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
213 * JsonGenerator:pretty:
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
219 generator_props[PROP_PRETTY] =
220 g_param_spec_boolean ("pretty",
222 "Pretty-print the output",
227 * JsonGenerator:indent:
229 * Number of spaces to be used to indent when pretty printing.
231 generator_props[PROP_INDENT] =
232 g_param_spec_uint ("indent",
234 "Number of indentation spaces",
240 * JsonGenerator:root:
242 * The root #JsonNode to be used when constructing a JSON data
247 generator_props[PROP_ROOT] =
248 g_param_spec_boxed ("root",
250 "Root of the JSON data tree",
255 * JsonGenerator:indent-char:
257 * The character that should be used when indenting in pretty print.
261 generator_props[PROP_INDENT_CHAR] =
262 g_param_spec_unichar ("indent-char",
264 "Character that should be used when indenting",
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);
275 json_generator_init (JsonGenerator *generator)
277 JsonGeneratorPrivate *priv = json_generator_get_instance_private (generator);
279 generator->priv = priv;
281 priv->pretty = FALSE;
283 priv->indent_char = ' ';
287 dump_value (JsonGenerator *generator,
293 JsonGeneratorPrivate *priv = generator->priv;
294 gboolean pretty = priv->pretty;
295 guint indent = priv->indent;
296 const JsonValue *value;
299 buffer = g_string_new ("");
305 for (i = 0; i < (level * indent); i++)
306 g_string_append_c (buffer, priv->indent_char);
312 g_string_append_printf (buffer, "\"%s\" : ", name);
314 g_string_append_printf (buffer, "\"%s\":", name);
317 value = node->data.value;
322 g_string_append_printf (buffer, "%" G_GINT64_FORMAT, json_value_get_int (value));
325 case JSON_VALUE_STRING:
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, '"');
338 case JSON_VALUE_DOUBLE:
340 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
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)
348 g_string_append (buffer, ".0");
353 case JSON_VALUE_BOOLEAN:
354 g_string_append (buffer, json_value_get_boolean (value) ? "true" : "false");
357 case JSON_VALUE_NULL:
358 g_string_append (buffer, "null");
366 *length = buffer->len;
368 return g_string_free (buffer, FALSE);
372 dump_array (JsonGenerator *generator,
378 JsonGeneratorPrivate *priv = generator->priv;
379 guint array_len = json_array_get_length (array);
382 gboolean pretty = priv->pretty;
383 guint indent = priv->indent;
385 buffer = g_string_new ("");
389 for (i = 0; i < (level * indent); i++)
390 g_string_append_c (buffer, priv->indent_char);
396 g_string_append_printf (buffer, "\"%s\" : ", name);
398 g_string_append_printf (buffer, "\"%s\":", name);
401 g_string_append_c (buffer, '[');
404 g_string_append_c (buffer, '\n');
406 for (i = 0; i < array_len; i++)
408 JsonNode *cur = json_array_get_element (array, i);
409 guint sub_level = level + 1;
413 switch (JSON_NODE_TYPE (cur))
418 for (j = 0; j < (sub_level * indent); j++)
419 g_string_append_c (buffer, priv->indent_char);
421 g_string_append (buffer, "null");
424 case JSON_NODE_VALUE:
425 value = dump_value (generator, sub_level, NULL, cur, NULL);
426 g_string_append (buffer, value);
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);
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);
443 if ((i + 1) != array_len)
444 g_string_append_c (buffer, ',');
447 g_string_append_c (buffer, '\n');
452 for (i = 0; i < (level * indent); i++)
453 g_string_append_c (buffer, priv->indent_char);
456 g_string_append_c (buffer, ']');
459 *length = buffer->len;
461 return g_string_free (buffer, FALSE);
465 dump_object (JsonGenerator *generator,
471 JsonGeneratorPrivate *priv = generator->priv;
474 gboolean pretty = priv->pretty;
475 guint indent = priv->indent;
478 buffer = g_string_new ("");
482 for (i = 0; i < (level * indent); i++)
483 g_string_append_c (buffer, priv->indent_char);
489 g_string_append_printf (buffer, "\"%s\" : ", name);
491 g_string_append_printf (buffer, "\"%s\":", name);
494 g_string_append_c (buffer, '{');
497 g_string_append_c (buffer, '\n');
499 members = json_object_get_members (object);
501 for (l = members; l != NULL; l = l->next)
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;
510 switch (JSON_NODE_TYPE (cur))
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);
521 g_string_append_printf (buffer, "\"%s\":null", escaped_name);
525 case JSON_NODE_VALUE:
526 value = dump_value (generator, sub_level, escaped_name, cur, NULL);
527 g_string_append (buffer, value);
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);
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);
547 g_string_append_c (buffer, ',');
550 g_string_append_c (buffer, '\n');
552 g_free (escaped_name);
555 g_list_free (members);
559 for (i = 0; i < (level * indent); i++)
560 g_string_append_c (buffer, priv->indent_char);
563 g_string_append_c (buffer, '}');
566 *length = buffer->len;
568 return g_string_free (buffer, FALSE);
572 * json_generator_new:
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
578 * Return value: the newly created #JsonGenerator instance
581 json_generator_new (void)
583 return g_object_new (JSON_TYPE_GENERATOR, NULL);
587 * json_generator_to_data:
588 * @generator: a #JsonGenerator
589 * @length: (out): return location for the length of the returned
592 * Generates a JSON data stream from @generator and returns it as a
595 * Return value: a newly allocated buffer holding a JSON data stream.
596 * Use g_free() to free the allocated resources.
599 json_generator_to_data (JsonGenerator *generator,
603 gchar *retval = NULL;
605 g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
607 root = generator->priv->root;
616 switch (JSON_NODE_TYPE (root))
618 case JSON_NODE_ARRAY:
619 retval = dump_array (generator, 0, NULL, json_node_get_array (root), length);
622 case JSON_NODE_OBJECT:
623 retval = dump_object (generator, 0, NULL, json_node_get_object (root), length);
627 retval = g_strdup ("null");
632 case JSON_NODE_VALUE:
633 retval = dump_value (generator, 0, NULL, root, length);
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
646 * Creates a JSON data stream and puts it inside @filename, overwriting the
647 * current file contents. This operation is atomic.
649 * Return value: %TRUE if saving was successful.
652 json_generator_to_file (JsonGenerator *generator,
653 const gchar *filename,
660 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
661 g_return_val_if_fail (filename != NULL, FALSE);
663 buffer = json_generator_to_data (generator, &len);
664 retval = g_file_set_contents (filename, buffer, len, error);
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
677 * Outputs JSON data and streams it (synchronously) to @stream.
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
685 json_generator_to_stream (JsonGenerator *generator,
686 GOutputStream *stream,
687 GCancellable *cancellable,
694 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
695 g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
697 if (g_cancellable_set_error_if_cancelled (cancellable, error))
700 buffer = json_generator_to_data (generator, &len);
701 retval = g_output_stream_write (stream, buffer, len, cancellable, error);
708 * json_generator_set_root:
709 * @generator: a #JsonGenerator
712 * Sets @node as the root of the JSON data stream to be serialized by
713 * the #JsonGenerator.
715 * The passed @node is copied by the generator object, so it can be
716 * safely freed after calling this function.
719 json_generator_set_root (JsonGenerator *generator,
722 g_return_if_fail (JSON_IS_GENERATOR (generator));
724 if (generator->priv->root == node)
727 if (generator->priv->root != NULL)
729 json_node_unref (generator->priv->root);
730 generator->priv->root = NULL;
734 generator->priv->root = json_node_copy (node);
736 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]);
740 * json_generator_get_root:
741 * @generator: a #JsonGenerator
743 * Retrieves a pointer to the root #JsonNode set using
744 * json_generator_set_root().
746 * Return value: (transfer none): a #JsonNode, or %NULL. The returned node
747 * is owned by the #JsonGenerator and it should not be freed
752 json_generator_get_root (JsonGenerator *generator)
754 g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
756 return generator->priv->root;
760 * json_generator_set_pretty:
761 * @generator: a #JsonGenerator
762 * @is_pretty: whether the generated string should be pretty printed
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.
771 json_generator_set_pretty (JsonGenerator *generator,
774 JsonGeneratorPrivate *priv;
776 g_return_if_fail (JSON_IS_GENERATOR (generator));
778 priv = generator->priv;
780 is_pretty = !!is_pretty;
782 if (priv->pretty != is_pretty)
784 priv->pretty = is_pretty;
786 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_PRETTY]);
791 * json_generator_get_pretty:
792 * @generator: a #JsonGenerator
794 * Retrieves the value set using json_generator_set_pretty().
796 * Return value: %TRUE if the generated JSON should be pretty-printed, and
802 json_generator_get_pretty (JsonGenerator *generator)
804 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
806 return generator->priv->pretty;
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
815 * Sets the number of repetitions for each indentation level.
820 json_generator_set_indent (JsonGenerator *generator,
823 JsonGeneratorPrivate *priv;
825 g_return_if_fail (JSON_IS_GENERATOR (generator));
827 priv = generator->priv;
829 if (priv->indent != indent_level)
831 priv->indent = indent_level;
833 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT]);
838 * json_generator_get_indent:
839 * @generator: a #JsonGenerator
841 * Retrieves the value set using json_generator_set_indent().
843 * Return value: the number of repetitions per indentation level
848 json_generator_get_indent (JsonGenerator *generator)
850 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
852 return generator->priv->indent;
856 * json_generator_set_indent_char:
857 * @generator: a #JsonGenerator
858 * @indent_char: a Unicode character to be used when indenting
860 * Sets the character to be used when indenting
865 json_generator_set_indent_char (JsonGenerator *generator,
866 gunichar indent_char)
868 JsonGeneratorPrivate *priv;
870 g_return_if_fail (JSON_IS_GENERATOR (generator));
872 priv = generator->priv;
874 if (priv->indent_char != indent_char)
876 priv->indent_char = indent_char;
878 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT_CHAR]);
883 * json_generator_get_indent_char:
884 * @generator: a #JsonGenerator
886 * Retrieves the value set using json_generator_set_indent_char().
888 * Return value: the character to be used when indenting
893 json_generator_get_indent_char (JsonGenerator *generator)
895 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
897 return generator->priv->indent_char;