| @@ -35,6 +35,7 @@ | |||
| /tests/test_cast | |||
| /tests/test_null | |||
| /tests/test_printbuf | |||
| /tests/test_set_serializer | |||
| /Debug | |||
| /Release | |||
| *.lo | |||
| @@ -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) | |||
| @@ -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 */ | |||
| @@ -16,16 +16,12 @@ | |||
| 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 | |||
| @@ -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) | |||
| @@ -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; | |||
| } | |||
| @@ -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 | |||
| @@ -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 $? | |||