Add public API to use userdata independently of custom serializertags/json-c-0.13-20171207
@@ -41,6 +41,7 @@ | |||||
/tests/test_parse | /tests/test_parse | ||||
/tests/test_cast | /tests/test_cast | ||||
/tests/test_charcase | /tests/test_charcase | ||||
/tests/test_double_serializer | |||||
/tests/test_locale | /tests/test_locale | ||||
/tests/test_null | /tests/test_null | ||||
/tests/test_printbuf | /tests/test_printbuf | ||||
@@ -54,6 +54,7 @@ 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_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_boolean_to_json_string; | ||||
static json_object_to_json_string_fn json_object_double_to_json_string_default; | |||||
static json_object_to_json_string_fn json_object_int_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_string_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; | static json_object_to_json_string_fn json_object_array_to_json_string; | ||||
@@ -234,6 +235,21 @@ enum json_type json_object_get_type(const struct json_object *jso) | |||||
return jso->o_type; | return jso->o_type; | ||||
} | } | ||||
void* json_object_get_userdata(json_object *jso) { | |||||
return jso->_userdata; | |||||
} | |||||
void json_object_set_userdata(json_object *jso, 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 = userdata; | |||||
jso->_user_delete = user_delete; | |||||
} | |||||
/* set a custom conversion to string */ | /* set a custom conversion to string */ | ||||
void json_object_set_serializer(json_object *jso, | void json_object_set_serializer(json_object *jso, | ||||
@@ -241,13 +257,7 @@ void json_object_set_serializer(json_object *jso, | |||||
void *userdata, | void *userdata, | ||||
json_object_delete_fn *user_delete) | 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; | |||||
json_object_set_userdata(jso, userdata, user_delete); | |||||
if (to_string_func == NULL) | if (to_string_func == NULL) | ||||
{ | { | ||||
@@ -261,7 +271,7 @@ void json_object_set_serializer(json_object *jso, | |||||
jso->_to_json_string = &json_object_boolean_to_json_string; | jso->_to_json_string = &json_object_boolean_to_json_string; | ||||
break; | break; | ||||
case json_type_double: | case json_type_double: | ||||
jso->_to_json_string = &json_object_double_to_json_string; | |||||
jso->_to_json_string = &json_object_double_to_json_string_default; | |||||
break; | break; | ||||
case json_type_int: | case json_type_int: | ||||
jso->_to_json_string = &json_object_int_to_json_string; | jso->_to_json_string = &json_object_int_to_json_string; | ||||
@@ -280,8 +290,6 @@ void json_object_set_serializer(json_object *jso, | |||||
} | } | ||||
jso->_to_json_string = to_string_func; | jso->_to_json_string = to_string_func; | ||||
jso->_userdata = userdata; | |||||
jso->_user_delete = user_delete; | |||||
} | } | ||||
@@ -643,10 +651,11 @@ int64_t json_object_get_int64(const struct json_object *jso) | |||||
/* json_object_double */ | /* json_object_double */ | ||||
int json_object_double_to_json_string(struct json_object* jso, | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
static int json_object_double_to_json_string_format(struct json_object* jso, | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags, | |||||
const char *format) | |||||
{ | { | ||||
char buf[128], *p, *q; | char buf[128], *p, *q; | ||||
int size; | int size; | ||||
@@ -663,7 +672,7 @@ int json_object_double_to_json_string(struct json_object* jso, | |||||
size = snprintf(buf, sizeof(buf), "-Infinity"); | size = snprintf(buf, sizeof(buf), "-Infinity"); | ||||
else | else | ||||
size = snprintf(buf, sizeof(buf), | size = snprintf(buf, sizeof(buf), | ||||
jso->_userdata ? (const char*) jso->_userdata : "%.17g", jso->o.c_double); | |||||
format ? format : "%.17g", jso->o.c_double); | |||||
p = strchr(buf, ','); | p = strchr(buf, ','); | ||||
if (p) { | if (p) { | ||||
@@ -685,12 +694,30 @@ int json_object_double_to_json_string(struct json_object* jso, | |||||
return size; | return size; | ||||
} | } | ||||
static int json_object_double_to_json_string_default(struct json_object* jso, | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | |||||
return json_object_double_to_json_string_format(jso, pb, level, flags, | |||||
NULL); | |||||
} | |||||
int json_object_double_to_json_string(struct json_object* jso, | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | |||||
return json_object_double_to_json_string_format(jso, pb, level, flags, | |||||
jso->_userdata); | |||||
} | |||||
struct json_object* json_object_new_double(double d) | struct json_object* json_object_new_double(double d) | ||||
{ | { | ||||
struct json_object *jso = json_object_new(json_type_double); | struct json_object *jso = json_object_new(json_type_double); | ||||
if (!jso) | if (!jso) | ||||
return NULL; | return NULL; | ||||
jso->_to_json_string = &json_object_double_to_json_string; | |||||
jso->_to_json_string = &json_object_double_to_json_string_default; | |||||
jso->o.c_double = d; | jso->o.c_double = d; | ||||
return jso; | return jso; | ||||
} | } | ||||
@@ -222,19 +222,55 @@ 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); | ||||
/** | |||||
* Returns the userdata set by json_object_set_userdata() or | |||||
* json_object_set_serializer() | |||||
* | |||||
* @param jso the object to return the userdata for | |||||
*/ | |||||
extern void* json_object_get_userdata(json_object *jso); | |||||
/** | |||||
* Set an opaque userdata value for an object | |||||
* | |||||
* The userdata can be retrieved using json_object_get_userdata(). | |||||
* | |||||
* If custom userdata is already set on this object, any existing user_delete | |||||
* function is called before the new one is set. | |||||
* | |||||
* 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) | |||||
* | |||||
* Note: Objects created by parsing strings may have custom serializers set | |||||
* which expect the userdata to contain specific data (due to use of | |||||
* json_object_new_double_s()). In this case, json_object_set_serialiser() with | |||||
* NULL as to_string_func should be used instead to set the userdata and reset | |||||
* the serializer to its default value. | |||||
* | |||||
* @param jso the object to set the userdata for | |||||
* @param userdata an optional opaque cookie | |||||
* @param user_delete an optional function from freeing userdata | |||||
*/ | |||||
extern void json_object_set_userdata(json_object *jso, void *userdata, | |||||
json_object_delete_fn *user_delete); | |||||
/** | /** | ||||
* Set a custom serialization function to be used when this particular object | * Set a custom serialization function to be used when this particular object | ||||
* is converted to a string by json_object_to_json_string. | * 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 custom userdata 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. | |||||
* If to_string_func is NULL the default behaviour is reset (but the userdata | |||||
* and user_delete fields are still set). | |||||
* | * | ||||
* 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 userdata parameter is optional and may be passed as NULL. It can be used | |||||
* to provide additional data for to_string_func to use. 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 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 | * the userdata parameter is non-NULL. It will be called just before the | ||||
@@ -243,6 +279,10 @@ flags); | |||||
* If this is not provided, it is up to the caller to free the userdata at | * 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) | * an appropriate time. (i.e. after the json_object is deleted) | ||||
* | * | ||||
* Note that the userdata is the same as set by json_object_set_userdata(), so | |||||
* care must be taken not to overwrite the value when both a custom serializer | |||||
* and json_object_set_userdata() are used. | |||||
* | |||||
* @param jso the object to customize | * @param jso the object to customize | ||||
* @param to_string_func the custom serialization function | * @param to_string_func the custom serialization function | ||||
* @param userdata an optional opaque cookie | * @param userdata an optional opaque cookie | ||||
@@ -634,8 +674,13 @@ extern struct json_object* json_object_new_double(double d); | |||||
* inefficiently (e.g. 12.3 => "12.300000000000001") to be | * inefficiently (e.g. 12.3 => "12.300000000000001") to be | ||||
* serialized with the more convenient form. | * serialized with the more convenient form. | ||||
* | * | ||||
* Note: this is used by json_tokener_parse_ex() to allow for | |||||
* an exact re-serialization of a parsed object. | |||||
* Notes: | |||||
* | |||||
* This is used by json_tokener_parse_ex() to allow for | |||||
* an exact re-serialization of a parsed object. | |||||
* | |||||
* The userdata field is used to store the string representation, so it | |||||
* can't be used for other data if this function is used. | |||||
* | * | ||||
* An equivalent sequence of calls is: | * An equivalent sequence of calls is: | ||||
* @code | * @code | ||||
@@ -11,6 +11,7 @@ TESTS+= testReplaceExisting.test | |||||
TESTS+= test_parse_int64.test | TESTS+= test_parse_int64.test | ||||
TESTS+= test_null.test | TESTS+= test_null.test | ||||
TESTS+= test_cast.test | TESTS+= test_cast.test | ||||
TESTS+= test_double_serializer.test | |||||
TESTS+= test_parse.test | TESTS+= test_parse.test | ||||
TESTS+= test_locale.test | TESTS+= test_locale.test | ||||
TESTS+= test_charcase.test | TESTS+= test_charcase.test | ||||
@@ -22,7 +23,7 @@ check_PROGRAMS= | |||||
check_PROGRAMS += $(TESTS:.test=) | check_PROGRAMS += $(TESTS:.test=) | ||||
# Note: handled by test1.test | # Note: handled by test1.test | ||||
check_PROGRAMS += test1Formatted | |||||
check_PROGRAMS += test1Formatted | |||||
test1Formatted_SOURCES = test1.c parse_flags.c | test1Formatted_SOURCES = test1.c parse_flags.c | ||||
test1Formatted_CPPFLAGS = -DTEST_FORMATTED | test1Formatted_CPPFLAGS = -DTEST_FORMATTED | ||||
@@ -0,0 +1,31 @@ | |||||
/* | |||||
* Tests if the format string for double serialization is handled correctly | |||||
*/ | |||||
#include <stdio.h> | |||||
#include "config.h" | |||||
#include "json_object.h" | |||||
#include "json_object_private.h" | |||||
int main() | |||||
{ | |||||
struct json_object *obj = json_object_new_double(0.5); | |||||
printf("Test default serializer:\n"); | |||||
printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); | |||||
printf("Test default serializer with custom userdata:\n"); | |||||
obj->_userdata = "test"; | |||||
printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); | |||||
printf("Test explicit serializer with custom userdata:\n"); | |||||
json_object_set_serializer(obj, json_object_double_to_json_string, "test", NULL); | |||||
printf("obj.to_string(custom)=%s\n", json_object_to_json_string(obj)); | |||||
printf("Test reset serializer:\n"); | |||||
json_object_set_serializer(obj, NULL, NULL, NULL); | |||||
printf("obj.to_string(reset)=%s\n", json_object_to_json_string(obj)); | |||||
json_object_put(obj); | |||||
} |
@@ -0,0 +1,8 @@ | |||||
Test default serializer: | |||||
obj.to_string(standard)=0.5 | |||||
Test default serializer with custom userdata: | |||||
obj.to_string(userdata)=0.5 | |||||
Test explicit serializer with custom userdata: | |||||
obj.to_string(custom)=test | |||||
Test reset serializer: | |||||
obj.to_string(reset)=0.5 |
@@ -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_double_serializer | |||||
exit $? |