]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
Add a json_set_serializer() function to allow the string output of a json_object...
authorEric Haszlakiewicz <erh+git@nimenees.com>
Sun, 2 Sep 2012 20:21:56 +0000 (15:21 -0500)
committerEric Haszlakiewicz <erh+git@nimenees.com>
Sun, 2 Sep 2012 20:21:56 +0000 (15:21 -0500)
.gitignore
json_object.c
json_object.h
json_object_private.h
tests/Makefile.am
tests/test_set_serializer.c [new file with mode: 0644]
tests/test_set_serializer.expected [new file with mode: 0644]
tests/test_set_serializer.test [new file with mode: 0755]

index a5034a990adb62d45cffcbb05df7ea8be8c84ef5..843fb3c837e7816590e20bc2bc71147ce10f570c 100644 (file)
@@ -35,6 +35,7 @@
 /tests/test_cast
 /tests/test_null
 /tests/test_printbuf
+/tests/test_set_serializer
 /Debug
 /Release
 *.lo
index 8dd13b0d665c94fab860c785aeba4844a10fcc51..d11efc52189d75da271eb1442c77fbc802f6e75f 100644 (file)
@@ -46,6 +46,13 @@ const char *json_hex_chars = "0123456789abcdefABCDEF";
 static void json_object_generic_delete(struct json_object* jso);
 static struct json_object* json_object_new(enum json_type o_type);
 
+static json_object_to_json_string_fn json_object_object_to_json_string;
+static json_object_to_json_string_fn json_object_boolean_to_json_string;
+static json_object_to_json_string_fn json_object_int_to_json_string;
+static json_object_to_json_string_fn json_object_double_to_json_string;
+static json_object_to_json_string_fn json_object_string_to_json_string;
+static json_object_to_json_string_fn json_object_array_to_json_string;
+
 
 /* ref count debugging */
 
@@ -134,10 +141,16 @@ extern struct json_object* json_object_get(struct json_object *jso)
 
 extern void json_object_put(struct json_object *jso)
 {
-  if(jso) {
-    jso->_ref_count--;
-    if(!jso->_ref_count) jso->_delete(jso);
-  }
+       if(jso)
+       {
+               jso->_ref_count--;
+               if(!jso->_ref_count)
+               {
+                       if (jso->_user_delete)
+                               jso->_user_delete(jso, jso->_userdata);
+                       jso->_delete(jso);
+               }
+       }
 }
 
 
@@ -187,6 +200,57 @@ enum json_type json_object_get_type(struct json_object *jso)
   return jso->o_type;
 }
 
+/* set a custom conversion to string */
+
+void json_object_set_serializer(json_object *jso,
+       json_object_to_json_string_fn to_string_func,
+       void *userdata,
+       json_object_delete_fn *user_delete)
+{
+       // First, clean up any previously existing user info
+       if (jso->_user_delete)
+       {
+               jso->_user_delete(jso, jso->_userdata);
+       }
+       jso->_userdata = NULL;
+       jso->_user_delete = NULL;
+
+       if (to_string_func == NULL)
+       {
+               // Reset to the standard serialization function
+               switch(jso->o_type)
+               {
+               case json_type_null:
+                       jso->_to_json_string = NULL;
+                       break;
+               case json_type_boolean:
+                       jso->_to_json_string = &json_object_boolean_to_json_string;
+                       break;
+               case json_type_double:
+                       jso->_to_json_string = &json_object_double_to_json_string;
+                       break;
+               case json_type_int:
+                       jso->_to_json_string = &json_object_int_to_json_string;
+                       break;
+               case json_type_object:
+                       jso->_to_json_string = &json_object_object_to_json_string;
+                       break;
+               case json_type_array:
+                       jso->_to_json_string = &json_object_array_to_json_string;
+                       break;
+               case json_type_string:
+                       jso->_to_json_string = &json_object_string_to_json_string;
+                       break;
+               }
+               return;
+       }
+
+       jso->_to_json_string = to_string_func;
+       jso->_userdata = userdata;
+       jso->_user_delete = user_delete;
+}
+
+
 /* extended conversion to string */
 
 const char* json_object_to_json_string_ext(struct json_object *jso, int flags)
index 6520a9a7dbeb7fd9a805f195b42df1e47d017e80..f264629c1a7ef6f41c2cc0de726f2e926d3842e1 100644 (file)
@@ -70,6 +70,19 @@ typedef struct json_object json_object;
 typedef struct json_object_iter json_object_iter;
 typedef struct json_tokener json_tokener;
 
+/**
+ * Type of custom user delete functions.  See json_object_set_serializer.
+ */
+typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata);
+
+/**
+ * Type of a custom serialization function.  See json_object_set_serializer.
+ */
+typedef int (json_object_to_json_string_fn)(struct json_object *jso,
+                                               struct printbuf *pb,
+                                               int level,
+                                               int flags);
+
 /* supported object types */
 
 typedef enum json_type {
@@ -149,6 +162,38 @@ extern const char* json_object_to_json_string(struct json_object *obj);
 extern const char* json_object_to_json_string_ext(struct json_object *obj, int
 flags);
 
+/**
+ * Set a custom serialization function to be used when this particular object
+ * is converted to a string by json_object_to_json_string.
+ *
+ * If a custom serializer is already set on this object, any existing 
+ * user_delete function is called before the new one is set.
+ *
+ * If to_string_func is NULL, the other parameters are ignored
+ * and the default behaviour is reset.
+ *
+ * The userdata parameter is optional and may be passed as NULL.  If provided,
+ * it is passed to to_string_func as-is.  This parameter may be NULL even
+ * if user_delete is non-NULL.
+ *
+ * The user_delete parameter is optional and may be passed as NULL, even if
+ * the userdata parameter is non-NULL.  It will be called just before the
+ * json_object is deleted, after it's reference count goes to zero
+ * (see json_object_put()).
+ * If this is not provided, it is up to the caller to free the userdata at
+ * an appropriate time. (i.e. after the json_object is deleted)
+ *
+ * @param jso the object to customize
+ * @param to_string_func the custom serialization function
+ * @param userdata an optional opaque cookie
+ * @param user_delete an optional function from freeing userdata
+ */
+void json_object_set_serializer(json_object *jso,
+       json_object_to_json_string_fn to_string_func,
+       void *userdata,
+       json_object_delete_fn *user_delete);
+
+
 
 /* object type methods */
 
index 597332b980699f91a2d91a87f38562edc8de45de..5ed791b58b3776ed00cedf760f8bf9a579bc79e5 100644 (file)
 extern "C" {
 #endif
 
-typedef void (json_object_delete_fn)(struct json_object *o);
-typedef int (json_object_to_json_string_fn)(struct json_object *o,
-                                               struct printbuf *pb,
-                                               int level,
-                                               int flags);
+typedef void (json_object_private_delete_fn)(struct json_object *o);
 
 struct json_object
 {
   enum json_type o_type;
-  json_object_delete_fn *_delete;
+  json_object_private_delete_fn *_delete;
   json_object_to_json_string_fn *_to_json_string;
   int _ref_count;
   struct printbuf *_pb;
@@ -40,6 +36,8 @@ struct json_object
         int len;
     } c_string;
   } o;
+  json_object_delete_fn *_user_delete;
+  void *_userdata;
 };
 
 #ifdef __cplusplus
index 635ce5583e7c3c17912b9c7a6496a093b8249df8..8057acdf51c8e8587d9ac021c70a55f4c0625c93 100644 (file)
@@ -42,6 +42,10 @@ TESTS+= test_printbuf.test
 check_PROGRAMS+=test_printbuf
 test_printbuf_LDADD = $(LIBJSON_LA)
 
+TESTS+= test_set_serializer.test
+check_PROGRAMS += test_set_serializer
+test_set_serializer_LDADD = $(LIBJSON_LA)
+
 EXTRA_DIST=
 EXTRA_DIST += $(TESTS)
 
diff --git a/tests/test_set_serializer.c b/tests/test_set_serializer.c
new file mode 100644 (file)
index 0000000..ae0121b
--- /dev/null
@@ -0,0 +1,71 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "json.h"
+#include "printbuf.h"
+
+struct myinfo {
+       int value;
+};
+
+static int freeit_was_called = 0;
+static void freeit(json_object *jso, void *userdata)
+{
+       struct myinfo *info = userdata;
+       printf("freeit, value=%d\n", info->value);
+       // Don't actually free anything here, the userdata is stack allocated.
+       freeit_was_called = 1;
+}
+static int custom_serializer(struct json_object *o,
+                                       struct printbuf *pb,
+                                       int level,
+                                       int flags)
+{
+       sprintbuf(pb, "Custom Output");
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       json_object *my_object;
+
+       MC_SET_DEBUG(1);
+
+       printf("Test setting, then resetting a custom serializer:\n");
+       my_object = json_object_new_object();
+       json_object_object_add(my_object, "abc", json_object_new_int(12));
+       json_object_object_add(my_object, "foo", json_object_new_string("bar"));
+
+       printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object));
+
+       struct myinfo userdata = { .value = 123 };
+       json_object_set_serializer(my_object, custom_serializer, &userdata, freeit);
+
+       printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object));
+
+       printf("Next line of output should be from the custom freeit function:\n");
+       freeit_was_called = 0;
+       json_object_set_serializer(my_object, NULL, NULL, NULL);
+       assert(freeit_was_called);
+
+       printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object));
+
+       json_object_put(my_object);
+
+       // ============================================
+
+       my_object = json_object_new_object();
+       printf("Check that the custom serializer isn't free'd until the last json_object_put:\n");
+       json_object_set_serializer(my_object, custom_serializer, &userdata, freeit);
+       json_object_get(my_object);
+       json_object_put(my_object);
+       printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object));
+       printf("Next line of output should be from the custom freeit function:\n");
+
+       freeit_was_called = 0;  
+       json_object_put(my_object);
+       assert(freeit_was_called);
+
+       return 0;
+}
diff --git a/tests/test_set_serializer.expected b/tests/test_set_serializer.expected
new file mode 100644 (file)
index 0000000..b91a081
--- /dev/null
@@ -0,0 +1,9 @@
+my_object.to_string(standard)={ "abc": 12, "foo": "bar" }
+my_object.to_string(custom serializer)=Custom Output
+Next line of output should be from the custom freeit function:
+freeit, value=123
+my_object.to_string(standard)={ "abc": 12, "foo": "bar" }
+Check that the custom serializer isn't free'd until the last json_object_put:
+my_object.to_string(custom serializer)=Custom Output
+Next line of output should be from the custom freeit function:
+freeit, value=123
diff --git a/tests/test_set_serializer.test b/tests/test_set_serializer.test
new file mode 100755 (executable)
index 0000000..728dfed
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# Common definitions
+if test -z "$srcdir"; then
+    srcdir="${0%/*}"
+    test "$srcdir" = "$0" && srcdir=.
+    test -z "$srcdir" && srcdir=.
+fi
+. "$srcdir/test-defs.sh"
+
+run_output_test test_set_serializer
+exit $?