@@ -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 $? |