Add public API to use userdata independently of custom serializertags/json-c-0.13-20171207
@@ -41,6 +41,7 @@ | |||
/tests/test_parse | |||
/tests/test_cast | |||
/tests/test_charcase | |||
/tests/test_double_serializer | |||
/tests/test_locale | |||
/tests/test_null | |||
/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_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_string_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; | |||
} | |||
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 */ | |||
void json_object_set_serializer(json_object *jso, | |||
@@ -241,13 +257,7 @@ void json_object_set_serializer(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 = NULL; | |||
jso->_user_delete = NULL; | |||
json_object_set_userdata(jso, userdata, user_delete); | |||
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; | |||
break; | |||
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; | |||
case json_type_int: | |||
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->_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 */ | |||
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; | |||
int size; | |||
@@ -663,7 +672,7 @@ int json_object_double_to_json_string(struct json_object* jso, | |||
size = snprintf(buf, sizeof(buf), "-Infinity"); | |||
else | |||
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, ','); | |||
if (p) { | |||
@@ -685,12 +694,30 @@ int json_object_double_to_json_string(struct json_object* jso, | |||
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 *jso = json_object_new(json_type_double); | |||
if (!jso) | |||
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; | |||
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 | |||
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 | |||
* 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 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 | |||
* 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 to_string_func the custom serialization function | |||
* @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 | |||
* 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: | |||
* @code | |||
@@ -11,6 +11,7 @@ TESTS+= testReplaceExisting.test | |||
TESTS+= test_parse_int64.test | |||
TESTS+= test_null.test | |||
TESTS+= test_cast.test | |||
TESTS+= test_double_serializer.test | |||
TESTS+= test_parse.test | |||
TESTS+= test_locale.test | |||
TESTS+= test_charcase.test | |||
@@ -22,7 +23,7 @@ check_PROGRAMS= | |||
check_PROGRAMS += $(TESTS:.test=) | |||
# Note: handled by test1.test | |||
check_PROGRAMS += test1Formatted | |||
check_PROGRAMS += test1Formatted | |||
test1Formatted_SOURCES = test1.c parse_flags.c | |||
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 $? |