2007-10-08 15:03:22 +00:00
|
|
|
/* json-object.c - JSON object implementation
|
|
|
|
*
|
|
|
|
* This file is part of JSON-GLib
|
|
|
|
* Copyright (C) 2007 OpenedHand Ltd.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Author:
|
|
|
|
* Emmanuele Bassi <ebassi@openedhand.com>
|
|
|
|
*/
|
|
|
|
|
2007-10-12 08:17:00 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2007-10-08 15:03:22 +00:00
|
|
|
#include "config.h"
|
2007-10-12 08:17:00 +00:00
|
|
|
#endif
|
2007-10-08 15:03:22 +00:00
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include "json-types.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:json-object
|
|
|
|
* @short_description: a JSON object representation
|
|
|
|
*
|
|
|
|
* #JsonArray is the representation of the object type inside JSON. It contains
|
|
|
|
* #JsonNode<!-- -->s, which may contain fundamental types, arrays or other
|
|
|
|
* objects. Each member of an object is accessed using its name.
|
|
|
|
*
|
|
|
|
* Since objects can be expensive, they are reference counted. You can control
|
|
|
|
* the lifetime of a #JsonObject using json_object_ref() and json_object_unref().
|
|
|
|
*
|
2007-10-10 12:51:51 +00:00
|
|
|
* To add a member with a given name, use json_object_add_member().
|
2007-10-08 15:03:22 +00:00
|
|
|
* To extract a member with a given name, use json_object_get_member().
|
|
|
|
* To retrieve the list of members, use json_object_get_members().
|
|
|
|
* To retrieve the size of the object (that is, the number of members it has), use
|
|
|
|
* json_object_get_size().
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct _JsonObject
|
|
|
|
{
|
|
|
|
GHashTable *members;
|
|
|
|
|
|
|
|
volatile gint ref_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
GType
|
|
|
|
json_object_get_type (void)
|
|
|
|
{
|
|
|
|
static GType object_type = 0;
|
|
|
|
|
|
|
|
if (G_UNLIKELY (!object_type))
|
|
|
|
object_type = g_boxed_type_register_static ("JsonObject",
|
|
|
|
(GBoxedCopyFunc) json_object_ref,
|
|
|
|
(GBoxedFreeFunc) json_object_unref);
|
|
|
|
|
|
|
|
return object_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_new:
|
|
|
|
*
|
|
|
|
* Creates a new #JsonObject, an JSON object type representation.
|
|
|
|
*
|
|
|
|
* Return value: the newly created #JsonObject
|
|
|
|
*/
|
|
|
|
JsonObject *
|
|
|
|
json_object_new (void)
|
|
|
|
{
|
|
|
|
JsonObject *object;
|
|
|
|
|
|
|
|
object = g_slice_new (JsonObject);
|
|
|
|
|
|
|
|
object->ref_count = 1;
|
|
|
|
object->members = g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
|
|
g_free,
|
|
|
|
(GDestroyNotify) json_node_free);
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_ref:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
*
|
|
|
|
* Increase by one the reference count of a #JsonObject.
|
|
|
|
*
|
|
|
|
* Return value: the passed #JsonObject, with the reference count
|
|
|
|
* increased by one.
|
|
|
|
*/
|
|
|
|
JsonObject *
|
|
|
|
json_object_ref (JsonObject *object)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (object != NULL, NULL);
|
|
|
|
g_return_val_if_fail (object->ref_count > 0, NULL);
|
|
|
|
|
|
|
|
g_atomic_int_exchange_and_add (&object->ref_count, 1);
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_unref:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
*
|
|
|
|
* Decreases by one the reference count of a #JsonObject. If the
|
|
|
|
* reference count reaches zero, the object is destroyed and all
|
|
|
|
* its allocated resources are freed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
json_object_unref (JsonObject *object)
|
|
|
|
{
|
|
|
|
gint old_ref;
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
g_return_if_fail (object->ref_count > 0);
|
|
|
|
|
|
|
|
old_ref = g_atomic_int_get (&object->ref_count);
|
|
|
|
if (old_ref > 1)
|
|
|
|
g_atomic_int_compare_and_exchange (&object->ref_count, old_ref, old_ref - 1);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_hash_table_destroy (object->members);
|
|
|
|
object->members = NULL;
|
|
|
|
|
|
|
|
g_slice_free (JsonObject, object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_add_member:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
* @member_name: the name of the member
|
|
|
|
* @node: the value of the member
|
|
|
|
*
|
|
|
|
* Adds a member named @member_name and containing @node into a #JsonObject.
|
2007-10-10 12:51:51 +00:00
|
|
|
* The object will take ownership of the #JsonNode.
|
2007-10-08 15:03:22 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
json_object_add_member (JsonObject *object,
|
|
|
|
const gchar *member_name,
|
|
|
|
JsonNode *node)
|
|
|
|
{
|
2007-10-16 14:40:00 +00:00
|
|
|
gchar *name;
|
|
|
|
|
2007-10-08 15:03:22 +00:00
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
g_return_if_fail (member_name != NULL);
|
|
|
|
g_return_if_fail (node != NULL);
|
|
|
|
|
|
|
|
if (json_object_has_member (object, member_name))
|
|
|
|
{
|
|
|
|
g_warning ("JsonObject already has a `%s' member of type `%s'",
|
|
|
|
member_name,
|
|
|
|
json_node_type_name (node));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-16 14:40:00 +00:00
|
|
|
name = g_strdelimit (g_strdup (member_name), G_STR_DELIMITERS, '_');
|
|
|
|
g_hash_table_replace (object->members, name, node);
|
2007-10-08 15:03:22 +00:00
|
|
|
}
|
|
|
|
|
2007-10-10 12:51:51 +00:00
|
|
|
/* FIXME: yuck. we really need to depend on GLib 2.14 */
|
|
|
|
#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 14
|
2007-10-08 15:18:31 +00:00
|
|
|
static void
|
|
|
|
get_keys (gpointer key,
|
|
|
|
gpointer value,
|
2007-10-10 12:51:51 +00:00
|
|
|
gpointer user_data)
|
2007-10-08 15:18:31 +00:00
|
|
|
{
|
2007-10-10 12:51:51 +00:00
|
|
|
GList **keys = user_data;
|
2007-10-08 15:18:31 +00:00
|
|
|
|
2007-10-10 12:51:51 +00:00
|
|
|
*keys = g_list_prepend (*keys, key);
|
2007-10-08 15:18:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GList *
|
|
|
|
g_hash_table_get_keys (GHashTable *hash_table)
|
|
|
|
{
|
2007-10-10 12:51:51 +00:00
|
|
|
GList *retval = NULL;
|
2007-10-08 15:18:31 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (hash_table != NULL, NULL);
|
|
|
|
|
|
|
|
g_hash_table_foreach (hash_table, get_keys, &retval);
|
|
|
|
|
2007-10-10 12:51:51 +00:00
|
|
|
return retval;
|
2007-10-08 15:18:31 +00:00
|
|
|
}
|
2007-10-10 12:51:51 +00:00
|
|
|
#endif /* GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 14 */
|
2007-10-08 15:18:31 +00:00
|
|
|
|
2007-10-08 15:03:22 +00:00
|
|
|
/**
|
|
|
|
* json_object_get_members:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
*
|
|
|
|
* Retrieves all the names of the members of a #JsonObject. You can
|
|
|
|
* obtain the value for each member using json_object_get_member().
|
|
|
|
*
|
2009-02-17 00:25:20 +00:00
|
|
|
* Return value: (transfer container) (element-type utf8): a #GList of
|
|
|
|
* member names. The content of the list is owned by the #JsonObject
|
|
|
|
* and should never be modified or freed. When you have finished using
|
|
|
|
* the returned list, use g_list_free() to free the resources it has
|
|
|
|
* allocated.
|
2007-10-08 15:03:22 +00:00
|
|
|
*/
|
|
|
|
GList *
|
|
|
|
json_object_get_members (JsonObject *object)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (object != NULL, NULL);
|
|
|
|
|
|
|
|
return g_hash_table_get_keys (object->members);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_get_member:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
* @member_name: the name of the JSON object member to access
|
|
|
|
*
|
2007-10-10 12:51:51 +00:00
|
|
|
* Retrieves the #JsonNode containing the value of @member_name inside
|
|
|
|
* a #JsonObject.
|
2007-10-08 15:03:22 +00:00
|
|
|
*
|
2009-02-17 00:25:20 +00:00
|
|
|
* Return value: (transfer none): a pointer to the node for the requested object
|
2007-10-08 15:03:22 +00:00
|
|
|
* member, or %NULL
|
|
|
|
*/
|
|
|
|
JsonNode *
|
|
|
|
json_object_get_member (JsonObject *object,
|
|
|
|
const gchar *member_name)
|
|
|
|
{
|
2007-10-16 14:40:00 +00:00
|
|
|
gchar *name;
|
|
|
|
JsonNode *retval;
|
|
|
|
|
2007-10-08 15:03:22 +00:00
|
|
|
g_return_val_if_fail (object != NULL, NULL);
|
|
|
|
g_return_val_if_fail (member_name != NULL, NULL);
|
|
|
|
|
2007-10-16 14:40:00 +00:00
|
|
|
name = g_strdelimit (g_strdup (member_name), G_STR_DELIMITERS, '_');
|
|
|
|
retval = g_hash_table_lookup (object->members, name);
|
|
|
|
g_free (name);
|
|
|
|
|
|
|
|
return retval;
|
2007-10-08 15:03:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_has_member:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
* @member_name: the name of a JSON object member
|
|
|
|
*
|
|
|
|
* Checks whether @object has a member named @member_name.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the JSON object has the requested member
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
json_object_has_member (JsonObject *object,
|
|
|
|
const gchar *member_name)
|
|
|
|
{
|
2007-10-16 14:40:00 +00:00
|
|
|
gchar *name;
|
|
|
|
gboolean retval;
|
|
|
|
|
2007-10-08 15:03:22 +00:00
|
|
|
g_return_val_if_fail (object != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (member_name != NULL, FALSE);
|
2007-10-16 14:40:00 +00:00
|
|
|
|
|
|
|
name = g_strdelimit (g_strdup (member_name), G_STR_DELIMITERS, '_');
|
|
|
|
retval = (g_hash_table_lookup (object->members, name) != NULL);
|
|
|
|
g_free (name);
|
|
|
|
|
|
|
|
return retval;
|
2007-10-08 15:03:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_get_size:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
*
|
2007-10-10 12:51:51 +00:00
|
|
|
* Retrieves the number of members of a #JsonObject.
|
2007-10-08 15:03:22 +00:00
|
|
|
*
|
2007-10-10 12:51:51 +00:00
|
|
|
* Return value: the number of members
|
2007-10-08 15:03:22 +00:00
|
|
|
*/
|
|
|
|
guint
|
|
|
|
json_object_get_size (JsonObject *object)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (object != NULL, 0);
|
|
|
|
|
|
|
|
return g_hash_table_size (object->members);
|
|
|
|
}
|
2007-10-10 12:51:51 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* json_object_remove_member:
|
|
|
|
* @object: a #JsonObject
|
|
|
|
* @member_name: the name of the member to remove
|
|
|
|
*
|
|
|
|
* Removes @member_name from @object, freeing its allocated resources.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
json_object_remove_member (JsonObject *object,
|
|
|
|
const gchar *member_name)
|
|
|
|
{
|
2007-10-16 14:40:00 +00:00
|
|
|
gchar *name;
|
|
|
|
|
2007-10-10 12:51:51 +00:00
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
g_return_if_fail (member_name != NULL);
|
|
|
|
|
2007-10-16 14:40:00 +00:00
|
|
|
name = g_strdelimit (g_strdup (member_name), G_STR_DELIMITERS, '_');
|
|
|
|
g_hash_table_remove (object->members, name);
|
|
|
|
g_free (name);
|
2007-10-10 12:51:51 +00:00
|
|
|
}
|