mirror of
https://github.com/json-c/json-c.git
synced 2026-04-10 15:59:07 +08:00
Merge pull request #234 from NeoRaider/userdata
Add public API to use userdata independently of custom serializer
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
|
json_object_set_userdata(jso, userdata, user_delete);
|
||||||
if (jso->_user_delete)
|
|
||||||
{
|
|
||||||
jso->_user_delete(jso, jso->_userdata);
|
|
||||||
}
|
|
||||||
jso->_userdata = NULL;
|
|
||||||
jso->_user_delete = NULL;
|
|
||||||
|
|
||||||
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,
|
static int json_object_double_to_json_string_format(struct json_object* jso,
|
||||||
struct printbuf *pb,
|
struct printbuf *pb,
|
||||||
int level,
|
int level,
|
||||||
int flags)
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,18 +223,20 @@ 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
|
* Returns the userdata set by json_object_set_userdata() or
|
||||||
* is converted to a string by json_object_to_json_string.
|
* json_object_set_serializer()
|
||||||
*
|
*
|
||||||
* If a custom serializer is already set on this object, any existing
|
* @param jso the object to return the userdata for
|
||||||
* user_delete function is called before the new one is set.
|
*/
|
||||||
|
extern void* json_object_get_userdata(json_object *jso);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an opaque userdata value for an object
|
||||||
*
|
*
|
||||||
* If to_string_func is NULL, the other parameters are ignored
|
* The userdata can be retrieved using json_object_get_userdata().
|
||||||
* and the default behaviour is reset.
|
|
||||||
*
|
*
|
||||||
* The userdata parameter is optional and may be passed as NULL. If provided,
|
* If custom userdata is already set on this object, any existing user_delete
|
||||||
* it is passed to to_string_func as-is. This parameter may be NULL even
|
* function is called before the new one is set.
|
||||||
* 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 +245,44 @@ 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: 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 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 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. 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
|
||||||
|
* 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 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
|
* Notes:
|
||||||
* an exact re-serialization of a parsed object.
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
|||||||
31
tests/test_double_serializer.c
Normal file
31
tests/test_double_serializer.c
Normal file
@@ -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);
|
||||||
|
}
|
||||||
8
tests/test_double_serializer.expected
Normal file
8
tests/test_double_serializer.expected
Normal file
@@ -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
|
||||||
12
tests/test_double_serializer.test
Executable file
12
tests/test_double_serializer.test
Executable file
@@ -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 $?
|
||||||
Reference in New Issue
Block a user