From 295bc517f8a8789b335c7d8d7643cee8519b0ce3 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 19 Mar 2010 10:40:12 +0000 Subject: [PATCH] json: Update the internal copy of JsonGenerator The JsonGenerator we have inside Clutter as a fallback for a missing system copy of JSON-GLib is way out of date. --- clutter/json/json-generator.c | 177 +++++++++++++++++++++++++++------- 1 file changed, 143 insertions(+), 34 deletions(-) diff --git a/clutter/json/json-generator.c b/clutter/json/json-generator.c index d1c8717dc..c77830e61 100644 --- a/clutter/json/json-generator.c +++ b/clutter/json/json-generator.c @@ -2,19 +2,23 @@ * * This file is part of JSON-GLib * Copyright (C) 2007 OpenedHand Ltd. + * Copyright (C) 2009 Intel Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * * Author: - * Emmanuele Bassi + * Emmanuele Bassi */ /** @@ -34,8 +38,8 @@ #include "json-types-private.h" -#include "json-generator.h" #include "json-marshal.h" +#include "json-generator.h" #define JSON_GENERATOR_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), JSON_TYPE_GENERATOR, JsonGeneratorPrivate)) @@ -45,6 +49,7 @@ struct _JsonGeneratorPrivate JsonNode *root; guint indent; + gunichar indent_char; guint pretty : 1; }; @@ -54,7 +59,9 @@ enum PROP_0, PROP_PRETTY, - PROP_INDENT + PROP_INDENT, + PROP_ROOT, + PROP_INDENT_CHAR }; static gchar *dump_value (JsonGenerator *generator, @@ -72,8 +79,39 @@ static gchar *dump_object (JsonGenerator *generator, JsonObject *object, gsize *length); +/* non-ASCII characters can't be escaped, otherwise UTF-8 + * chars will break, so we just pregenerate this table of + * high characters and then we feed it to g_strescape() + */ +static const char json_exceptions[] = { + 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, + 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, + 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, + 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, + 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, + 0xff, + '\0' /* g_strescape() expects a NUL-terminated string */ +}; + G_DEFINE_TYPE (JsonGenerator, json_generator, G_TYPE_OBJECT); +static gchar * +json_strescape (const gchar *str) +{ + return g_strescape (str, json_exceptions); +} + static void json_generator_finalize (GObject *gobject) { @@ -101,6 +139,13 @@ json_generator_set_property (GObject *gobject, case PROP_INDENT: priv->indent = g_value_get_uint (value); break; + case PROP_INDENT_CHAR: + priv->indent_char = g_value_get_uint (value); + break; + case PROP_ROOT: + json_generator_set_root (JSON_GENERATOR (gobject), + g_value_get_boxed (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; @@ -123,6 +168,12 @@ json_generator_get_property (GObject *gobject, case PROP_INDENT: g_value_set_uint (value, priv->indent); break; + case PROP_INDENT_CHAR: + g_value_set_uint (value, priv->indent_char); + break; + case PROP_ROOT: + g_value_set_boxed (value, priv->root); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; @@ -167,6 +218,35 @@ json_generator_class_init (JsonGeneratorClass *klass) 0, G_MAXUINT, 2, G_PARAM_READWRITE)); + /** + * JsonGenerator:root: + * + * The root #JsonNode to be used when constructing a JSON data + * stream. + * + * Since: 0.4 + */ + g_object_class_install_property (gobject_class, + PROP_ROOT, + g_param_spec_boxed ("root", + "Root", + "Root of the JSON data tree", + JSON_TYPE_NODE, + G_PARAM_READWRITE)); + /** + * JsonGenerator:indent-char: + * + * The character that should be used when indenting in pretty print. + * + * Since: 0.6 + */ + g_object_class_install_property (gobject_class, + PROP_INDENT_CHAR, + g_param_spec_unichar ("indent-char", + "Indent Char", + "Character that should be used when indenting", + ' ', + G_PARAM_READWRITE)); } static void @@ -178,6 +258,7 @@ json_generator_init (JsonGenerator *generator) priv->pretty = FALSE; priv->indent = 2; + priv->indent_char = ' '; } static gchar * @@ -186,18 +267,20 @@ dump_value (JsonGenerator *generator, const gchar *name, JsonNode *node) { - gboolean pretty = generator->priv->pretty; - guint indent = generator->priv->indent; + JsonGeneratorPrivate *priv = generator->priv; + gboolean pretty = priv->pretty; + guint indent = priv->indent; GValue value = { 0, }; GString *buffer; - gint i; buffer = g_string_new (""); if (pretty) { + guint i; + for (i = 0; i < (level * indent); i++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } if (name && name[0] != '\0') @@ -207,16 +290,28 @@ dump_value (JsonGenerator *generator, switch (G_VALUE_TYPE (&value)) { - case G_TYPE_INT: - g_string_append_printf (buffer, "%d", g_value_get_int (&value)); + case G_TYPE_INT64: + g_string_append_printf (buffer, "%" G_GINT64_FORMAT, g_value_get_int64 (&value)); break; case G_TYPE_STRING: - g_string_append_printf (buffer, "\"%s\"", g_value_get_string (&value)); + { + gchar *tmp; + + tmp = json_strescape (g_value_get_string (&value)); + g_string_append_printf (buffer, "\"%s\"", tmp); + + g_free (tmp); + } break; - case G_TYPE_FLOAT: - g_string_append_printf (buffer, "%f", g_value_get_float (&value)); + case G_TYPE_DOUBLE: + { + gchar buf[65]; + + g_ascii_formatd (buf, 65, "%g", g_value_get_double (&value)); + g_string_append (buffer, buf); + } break; case G_TYPE_BOOLEAN: @@ -240,18 +335,19 @@ dump_array (JsonGenerator *generator, JsonArray *array, gsize *length) { - gint array_len = json_array_get_length (array); - gint i; + JsonGeneratorPrivate *priv = generator->priv; + guint array_len = json_array_get_length (array); + guint i; GString *buffer; - gboolean pretty = generator->priv->pretty; - guint indent = generator->priv->indent; + gboolean pretty = priv->pretty; + guint indent = priv->indent; buffer = g_string_new (""); if (pretty) { for (i = 0; i < (level * indent); i++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } if (name && name[0] != '\0') @@ -268,7 +364,7 @@ dump_array (JsonGenerator *generator, { JsonNode *cur = json_array_get_element (array, i); guint sub_level = level + 1; - gint j; + guint j; gchar *value; switch (JSON_NODE_TYPE (cur)) @@ -277,7 +373,7 @@ dump_array (JsonGenerator *generator, if (pretty) { for (j = 0; j < (sub_level * indent); j++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } g_string_append (buffer, "null"); break; @@ -285,16 +381,19 @@ dump_array (JsonGenerator *generator, case JSON_NODE_VALUE: value = dump_value (generator, sub_level, NULL, cur); g_string_append (buffer, value); + g_free (value); break; case JSON_NODE_ARRAY: value = dump_array (generator, sub_level, NULL, json_node_get_array (cur), NULL); g_string_append (buffer, value); + g_free (value); break; case JSON_NODE_OBJECT: value = dump_object (generator, sub_level, NULL, json_node_get_object (cur), NULL); g_string_append (buffer, value); + g_free (value); break; } @@ -310,7 +409,7 @@ dump_array (JsonGenerator *generator, if (pretty) { for (i = 0; i < (level * indent); i++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } g_string_append_c (buffer, ']'); @@ -328,18 +427,19 @@ dump_object (JsonGenerator *generator, JsonObject *object, gsize *length) { + JsonGeneratorPrivate *priv = generator->priv; GList *members, *l; GString *buffer; - gboolean pretty = generator->priv->pretty; - guint indent = generator->priv->indent; - gint i; + gboolean pretty = priv->pretty; + guint indent = priv->indent; + guint i; buffer = g_string_new (""); if (pretty) { for (i = 0; i < (level * indent); i++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } if (name && name[0] != '\0') @@ -359,7 +459,7 @@ dump_object (JsonGenerator *generator, const gchar *member_name = l->data; JsonNode *cur = json_object_get_member (object, member_name); guint sub_level = level + 1; - gint j; + guint j; gchar *value; switch (JSON_NODE_TYPE (cur)) @@ -368,7 +468,7 @@ dump_object (JsonGenerator *generator, if (pretty) { for (j = 0; j < (sub_level * indent); j++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } g_string_append_printf (buffer, "\"%s\" : null", member_name); break; @@ -376,16 +476,21 @@ dump_object (JsonGenerator *generator, case JSON_NODE_VALUE: value = dump_value (generator, sub_level, member_name, cur); g_string_append (buffer, value); + g_free (value); break; case JSON_NODE_ARRAY: - value = dump_array (generator, sub_level, member_name, json_node_get_array (cur), NULL); + value = dump_array (generator, sub_level, member_name, + json_node_get_array (cur), NULL); g_string_append (buffer, value); + g_free (value); break; case JSON_NODE_OBJECT: - value = dump_object (generator, sub_level, member_name, json_node_get_object (cur), NULL); + value = dump_object (generator, sub_level, member_name, + json_node_get_object (cur), NULL); g_string_append (buffer, value); + g_free (value); break; } @@ -403,7 +508,7 @@ dump_object (JsonGenerator *generator, if (pretty) { for (i = 0; i < (level * indent); i++) - g_string_append_c (buffer, ' '); + g_string_append_c (buffer, priv->indent_char); } g_string_append_c (buffer, '}'); @@ -432,13 +537,14 @@ json_generator_new (void) /** * json_generator_to_data: * @generator: a #JsonGenerator - * @length: return location for the length of the returned buffer, or %NULL + * @length: (out): return location for the length of the returned + * buffer, or %NULL * * Generates a JSON data stream from @generator and returns it as a * buffer. * - * Return value: a newly allocated buffer holding a JSON data stream. Use - * g_free() to free the allocated resources. + * Return value: a newly allocated buffer holding a JSON data stream. + * Use g_free() to free the allocated resources. */ gchar * json_generator_to_data (JsonGenerator *generator, @@ -519,6 +625,9 @@ json_generator_to_file (JsonGenerator *generator, * * Sets @node as the root of the JSON data stream to be serialized by * the #JsonGenerator. + * + * The node is copied by the generator object, so it can be safely + * freed after calling this function. */ void json_generator_set_root (JsonGenerator *generator, @@ -533,5 +642,5 @@ json_generator_set_root (JsonGenerator *generator, } if (node) - generator->priv->root = node; + generator->priv->root = json_node_copy (node); }