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-marshal.h"
40 #include "json-generator.h"
42 struct _JsonGeneratorPrivate
64 static gchar *dump_value (JsonGenerator *generator,
69 static gchar *dump_array (JsonGenerator *generator,
74 static gchar *dump_object (JsonGenerator *generator,
80 static GParamSpec *generator_props[PROP_LAST] = { NULL, };
82 G_DEFINE_TYPE_WITH_PRIVATE (JsonGenerator, json_generator, G_TYPE_OBJECT)
85 json_strescape (const gchar *str)
94 output = g_string_sized_new (len);
96 for (p = str; p < end; p++)
98 if (*p == '\\' || *p == '"')
100 g_string_append_c (output, '\\');
101 g_string_append_c (output, *p);
103 else if ((*p > 0 && *p < 0x1f) || *p == 0x7f)
108 g_string_append (output, "\\b");
111 g_string_append (output, "\\f");
114 g_string_append (output, "\\n");
117 g_string_append (output, "\\r");
120 g_string_append (output, "\\t");
123 g_string_append_printf (output, "\\u00%02x", (guint)*p);
129 g_string_append_c (output, *p);
133 return g_string_free (output, FALSE);
137 json_generator_finalize (GObject *gobject)
139 JsonGeneratorPrivate *priv;
141 priv = json_generator_get_instance_private ((JsonGenerator *) gobject);
142 if (priv->root != NULL)
143 json_node_free (priv->root);
145 G_OBJECT_CLASS (json_generator_parent_class)->finalize (gobject);
149 json_generator_set_property (GObject *gobject,
154 JsonGenerator *generator = JSON_GENERATOR (gobject);
159 json_generator_set_pretty (generator, g_value_get_boolean (value));
163 json_generator_set_indent (generator, g_value_get_uint (value));
166 case PROP_INDENT_CHAR:
167 json_generator_set_indent_char (generator, g_value_get_uint (value));
171 json_generator_set_root (generator, g_value_get_boxed (value));
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
181 json_generator_get_property (GObject *gobject,
186 JsonGeneratorPrivate *priv = JSON_GENERATOR (gobject)->priv;
191 g_value_set_boolean (value, priv->pretty);
194 g_value_set_uint (value, priv->indent);
196 case PROP_INDENT_CHAR:
197 g_value_set_uint (value, priv->indent_char);
200 g_value_set_boxed (value, priv->root);
203 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
209 json_generator_class_init (JsonGeneratorClass *klass)
211 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
214 * JsonGenerator:pretty:
216 * Whether the output should be "pretty-printed", with indentation and
217 * newlines. The indentation level can be controlled by using the
218 * JsonGenerator:indent property
220 generator_props[PROP_PRETTY] =
221 g_param_spec_boolean ("pretty",
223 "Pretty-print the output",
228 * JsonGenerator:indent:
230 * Number of spaces to be used to indent when pretty printing.
232 generator_props[PROP_INDENT] =
233 g_param_spec_uint ("indent",
235 "Number of indentation spaces",
241 * JsonGenerator:root:
243 * The root #JsonNode to be used when constructing a JSON data
248 generator_props[PROP_ROOT] =
249 g_param_spec_boxed ("root",
251 "Root of the JSON data tree",
256 * JsonGenerator:indent-char:
258 * The character that should be used when indenting in pretty print.
262 generator_props[PROP_INDENT_CHAR] =
263 g_param_spec_unichar ("indent-char",
265 "Character that should be used when indenting",
269 gobject_class->set_property = json_generator_set_property;
270 gobject_class->get_property = json_generator_get_property;
271 gobject_class->finalize = json_generator_finalize;
272 g_object_class_install_properties (gobject_class, PROP_LAST, generator_props);
276 json_generator_init (JsonGenerator *generator)
278 JsonGeneratorPrivate *priv = json_generator_get_instance_private (generator);
280 generator->priv = priv;
282 priv->pretty = FALSE;
284 priv->indent_char = ' ';
288 dump_value (JsonGenerator *generator,
294 JsonGeneratorPrivate *priv = generator->priv;
295 gboolean pretty = priv->pretty;
296 guint indent = priv->indent;
297 const JsonValue *value;
300 buffer = g_string_new ("");
306 for (i = 0; i < (level * indent); i++)
307 g_string_append_c (buffer, priv->indent_char);
313 g_string_append_printf (buffer, "\"%s\" : ", name);
315 g_string_append_printf (buffer, "\"%s\":", name);
318 value = node->data.value;
323 g_string_append_printf (buffer, "%" G_GINT64_FORMAT, json_value_get_int (value));
326 case JSON_VALUE_STRING:
330 tmp = json_strescape (json_value_get_string (value));
331 g_string_append_c (buffer, '"');
332 g_string_append (buffer, tmp);
333 g_string_append_c (buffer, '"');
339 case JSON_VALUE_DOUBLE:
341 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
343 g_string_append (buffer,
344 g_ascii_dtostr (buf, sizeof (buf),
345 json_value_get_double (value)));
349 case JSON_VALUE_BOOLEAN:
350 g_string_append (buffer, json_value_get_boolean (value) ? "true" : "false");
353 case JSON_VALUE_NULL:
354 g_string_append (buffer, "null");
362 *length = buffer->len;
364 return g_string_free (buffer, FALSE);
368 dump_array (JsonGenerator *generator,
374 JsonGeneratorPrivate *priv = generator->priv;
375 guint array_len = json_array_get_length (array);
378 gboolean pretty = priv->pretty;
379 guint indent = priv->indent;
381 buffer = g_string_new ("");
385 for (i = 0; i < (level * indent); i++)
386 g_string_append_c (buffer, priv->indent_char);
392 g_string_append_printf (buffer, "\"%s\" : ", name);
394 g_string_append_printf (buffer, "\"%s\":", name);
397 g_string_append_c (buffer, '[');
400 g_string_append_c (buffer, '\n');
402 for (i = 0; i < array_len; i++)
404 JsonNode *cur = json_array_get_element (array, i);
405 guint sub_level = level + 1;
409 switch (JSON_NODE_TYPE (cur))
414 for (j = 0; j < (sub_level * indent); j++)
415 g_string_append_c (buffer, priv->indent_char);
417 g_string_append (buffer, "null");
420 case JSON_NODE_VALUE:
421 value = dump_value (generator, sub_level, NULL, cur, NULL);
422 g_string_append (buffer, value);
426 case JSON_NODE_ARRAY:
427 value = dump_array (generator, sub_level, NULL, json_node_get_array (cur), NULL);
428 g_string_append (buffer, value);
432 case JSON_NODE_OBJECT:
433 value = dump_object (generator, sub_level, NULL, json_node_get_object (cur), NULL);
434 g_string_append (buffer, value);
439 if ((i + 1) != array_len)
440 g_string_append_c (buffer, ',');
443 g_string_append_c (buffer, '\n');
448 for (i = 0; i < (level * indent); i++)
449 g_string_append_c (buffer, priv->indent_char);
452 g_string_append_c (buffer, ']');
455 *length = buffer->len;
457 return g_string_free (buffer, FALSE);
461 dump_object (JsonGenerator *generator,
467 JsonGeneratorPrivate *priv = generator->priv;
470 gboolean pretty = priv->pretty;
471 guint indent = priv->indent;
474 buffer = g_string_new ("");
478 for (i = 0; i < (level * indent); i++)
479 g_string_append_c (buffer, priv->indent_char);
485 g_string_append_printf (buffer, "\"%s\" : ", name);
487 g_string_append_printf (buffer, "\"%s\":", name);
490 g_string_append_c (buffer, '{');
493 g_string_append_c (buffer, '\n');
495 members = json_object_get_members (object);
497 for (l = members; l != NULL; l = l->next)
499 const gchar *member_name = l->data;
500 gchar *escaped_name = json_strescape (member_name);
501 JsonNode *cur = json_object_get_member (object, member_name);
502 guint sub_level = level + 1;
506 switch (JSON_NODE_TYPE (cur))
511 for (j = 0; j < (sub_level * indent); j++)
512 g_string_append_c (buffer, priv->indent_char);
513 g_string_append_printf (buffer, "\"%s\" : null", escaped_name);
517 g_string_append_printf (buffer, "\"%s\":null", escaped_name);
521 case JSON_NODE_VALUE:
522 value = dump_value (generator, sub_level, escaped_name, cur, NULL);
523 g_string_append (buffer, value);
527 case JSON_NODE_ARRAY:
528 value = dump_array (generator, sub_level, escaped_name,
529 json_node_get_array (cur), NULL);
530 g_string_append (buffer, value);
534 case JSON_NODE_OBJECT:
535 value = dump_object (generator, sub_level, escaped_name,
536 json_node_get_object (cur), NULL);
537 g_string_append (buffer, value);
543 g_string_append_c (buffer, ',');
546 g_string_append_c (buffer, '\n');
548 g_free (escaped_name);
551 g_list_free (members);
555 for (i = 0; i < (level * indent); i++)
556 g_string_append_c (buffer, priv->indent_char);
559 g_string_append_c (buffer, '}');
562 *length = buffer->len;
564 return g_string_free (buffer, FALSE);
568 * json_generator_new:
570 * Creates a new #JsonGenerator. You can use this object to generate a
571 * JSON data stream starting from a data object model composed by
574 * Return value: the newly created #JsonGenerator instance
577 json_generator_new (void)
579 return g_object_new (JSON_TYPE_GENERATOR, NULL);
583 * json_generator_to_data:
584 * @generator: a #JsonGenerator
585 * @length: (out): return location for the length of the returned
588 * Generates a JSON data stream from @generator and returns it as a
591 * Return value: a newly allocated buffer holding a JSON data stream.
592 * Use g_free() to free the allocated resources.
595 json_generator_to_data (JsonGenerator *generator,
599 gchar *retval = NULL;
601 g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
603 root = generator->priv->root;
612 switch (JSON_NODE_TYPE (root))
614 case JSON_NODE_ARRAY:
615 retval = dump_array (generator, 0, NULL, json_node_get_array (root), length);
618 case JSON_NODE_OBJECT:
619 retval = dump_object (generator, 0, NULL, json_node_get_object (root), length);
623 retval = g_strdup ("null");
628 case JSON_NODE_VALUE:
629 retval = dump_value (generator, 0, NULL, root, length);
637 * json_generator_to_file:
638 * @generator: a #JsonGenerator
639 * @filename: path to the target file
640 * @error: return location for a #GError, or %NULL
642 * Creates a JSON data stream and puts it inside @filename, overwriting the
643 * current file contents. This operation is atomic.
645 * Return value: %TRUE if saving was successful.
648 json_generator_to_file (JsonGenerator *generator,
649 const gchar *filename,
656 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
657 g_return_val_if_fail (filename != NULL, FALSE);
659 buffer = json_generator_to_data (generator, &len);
660 retval = g_file_set_contents (filename, buffer, len, error);
667 * json_generator_to_stream:
668 * @generator: a #JsonGenerator
669 * @stream: a #GOutputStream
670 * @cancellable: (allow-none): a #GCancellable, or %NULL
671 * @error: return location for a #GError, or %NULL
673 * Outputs JSON data and streams it (synchronously) to @stream.
675 * Return value: %TRUE if the write operation was successful, and %FALSE
676 * on failure. In case of error, the #GError will be filled accordingly
681 json_generator_to_stream (JsonGenerator *generator,
682 GOutputStream *stream,
683 GCancellable *cancellable,
690 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
691 g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
693 if (g_cancellable_set_error_if_cancelled (cancellable, error))
696 buffer = json_generator_to_data (generator, &len);
697 retval = g_output_stream_write (stream, buffer, len, cancellable, error);
704 * json_generator_set_root:
705 * @generator: a #JsonGenerator
708 * Sets @node as the root of the JSON data stream to be serialized by
709 * the #JsonGenerator.
711 * The passed @node is copied by the generator object, so it can be
712 * safely freed after calling this function.
715 json_generator_set_root (JsonGenerator *generator,
718 g_return_if_fail (JSON_IS_GENERATOR (generator));
720 if (generator->priv->root == node)
723 if (generator->priv->root != NULL)
725 json_node_free (generator->priv->root);
726 generator->priv->root = NULL;
730 generator->priv->root = json_node_copy (node);
732 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_ROOT]);
736 * json_generator_get_root:
737 * @generator: a #JsonGenerator
739 * Retrieves a pointer to the root #JsonNode set using
740 * json_generator_set_root().
742 * Return value: (transfer none): a #JsonNode, or %NULL. The returned node
743 * is owned by the #JsonGenerator and it should not be freed
748 json_generator_get_root (JsonGenerator *generator)
750 g_return_val_if_fail (JSON_IS_GENERATOR (generator), NULL);
752 return generator->priv->root;
756 * json_generator_set_pretty:
757 * @generator: a #JsonGenerator
758 * @is_pretty: whether the generated string should be pretty printed
760 * Sets whether the generated JSON should be pretty printed, using the
761 * indentation character specified in the #JsonGenerator:indent-char
762 * property and the spacing specified in #JsonGenerator:indent property.
767 json_generator_set_pretty (JsonGenerator *generator,
770 JsonGeneratorPrivate *priv;
772 g_return_if_fail (JSON_IS_GENERATOR (generator));
774 priv = generator->priv;
776 is_pretty = !!is_pretty;
778 if (priv->pretty != is_pretty)
780 priv->pretty = is_pretty;
782 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_PRETTY]);
787 * json_generator_get_pretty:
788 * @generator: a #JsonGenerator
790 * Retrieves the value set using json_generator_set_pretty().
792 * Return value: %TRUE if the generated JSON should be pretty-printed, and
798 json_generator_get_pretty (JsonGenerator *generator)
800 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
802 return generator->priv->pretty;
806 * json_generator_set_indent:
807 * @generator: a #JsonGenerator
808 * @indent_level: the number of repetitions of the indentation character
809 * that should be applied when pretty printing
811 * Sets the number of repetitions for each indentation level.
816 json_generator_set_indent (JsonGenerator *generator,
819 JsonGeneratorPrivate *priv;
821 g_return_if_fail (JSON_IS_GENERATOR (generator));
823 priv = generator->priv;
825 if (priv->indent != indent_level)
827 priv->indent = indent_level;
829 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT]);
834 * json_generator_get_indent:
835 * @generator: a #JsonGenerator
837 * Retrieves the value set using json_generator_set_indent().
839 * Return value: the number of repetitions per indentation level
844 json_generator_get_indent (JsonGenerator *generator)
846 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
848 return generator->priv->indent;
852 * json_generator_set_indent_char:
853 * @generator: a #JsonGenerator
854 * @indent_char: a Unicode character to be used when indenting
856 * Sets the character to be used when indenting
861 json_generator_set_indent_char (JsonGenerator *generator,
862 gunichar indent_char)
864 JsonGeneratorPrivate *priv;
866 g_return_if_fail (JSON_IS_GENERATOR (generator));
868 priv = generator->priv;
870 if (priv->indent_char != indent_char)
872 priv->indent_char = indent_char;
874 g_object_notify_by_pspec (G_OBJECT (generator), generator_props[PROP_INDENT_CHAR]);
879 * json_generator_get_indent_char:
880 * @generator: a #JsonGenerator
882 * Retrieves the value set using json_generator_set_indent_char().
884 * Return value: the character to be used when indenting
889 json_generator_get_indent_char (JsonGenerator *generator)
891 g_return_val_if_fail (JSON_IS_GENERATOR (generator), FALSE);
893 return generator->priv->indent_char;