| @@ -35,6 +35,7 @@ | |||||
| /tests/test_cast | /tests/test_cast | ||||
| /tests/test_null | /tests/test_null | ||||
| /tests/test_printbuf | /tests/test_printbuf | ||||
| /tests/test_set_serializer | |||||
| /Debug | /Debug | ||||
| /Release | /Release | ||||
| *.lo | *.lo | ||||
| @@ -46,6 +46,13 @@ const char *json_hex_chars = "0123456789abcdefABCDEF"; | |||||
| static void json_object_generic_delete(struct json_object* jso); | static void json_object_generic_delete(struct json_object* jso); | ||||
| static struct json_object* json_object_new(enum json_type o_type); | 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 */ | /* 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) | 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; | 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 */ | /* extended conversion to string */ | ||||
| const char* json_object_to_json_string_ext(struct json_object *jso, int flags) | 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_object_iter json_object_iter; | ||||
| typedef struct json_tokener json_tokener; | 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 */ | /* supported object types */ | ||||
| typedef enum json_type { | 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 | extern const char* json_object_to_json_string_ext(struct json_object *obj, int | ||||
| flags); | 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 */ | /* object type methods */ | ||||
| @@ -16,16 +16,12 @@ | |||||
| extern "C" { | extern "C" { | ||||
| #endif | #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 | struct json_object | ||||
| { | { | ||||
| enum json_type o_type; | 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; | json_object_to_json_string_fn *_to_json_string; | ||||
| int _ref_count; | int _ref_count; | ||||
| struct printbuf *_pb; | struct printbuf *_pb; | ||||
| @@ -40,6 +36,8 @@ struct json_object | |||||
| int len; | int len; | ||||
| } c_string; | } c_string; | ||||
| } o; | } o; | ||||
| json_object_delete_fn *_user_delete; | |||||
| void *_userdata; | |||||
| }; | }; | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| @@ -42,6 +42,10 @@ TESTS+= test_printbuf.test | |||||
| check_PROGRAMS+=test_printbuf | check_PROGRAMS+=test_printbuf | ||||
| test_printbuf_LDADD = $(LIBJSON_LA) | 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= | ||||
| EXTRA_DIST += $(TESTS) | 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 $? | |||||