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