Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,14 +619,20 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
}
else
{
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
length = sprintf((char*)number_buffer, "%1.15g", d);

/* Check whether the original double can be recovered */
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
{
/* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d);
/* If decimal places are present and value is not an integer type */
if (item->decimal_places && (ceil(d) != d)) {
/* Then convert it to string */
length = sprintf((char*) number_buffer, "%.*f", item->decimal_places, d);
} else {
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
length = sprintf((char*)number_buffer, "%1.15g", d);

/* Check whether the original double can be recovered */
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
{
/* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d);
}
}
}

Expand Down Expand Up @@ -2207,6 +2213,27 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char *
return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddNumberWithPrecisionToObject(cJSON * const object, const char * const name, const double n, int decimal_places)
{
cJSON *number_item;

if (decimal_places <= 0 || decimal_places > 14)
{
return NULL;
}

number_item = cJSON_CreateNumber(n);

if (add_item_to_object(object, name, number_item, &global_hooks, false))
{
number_item->decimal_places = decimal_places;
return number_item;
}

cJSON_Delete(number_item);
return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
{
cJSON *string_item = cJSON_CreateString(string);
Expand Down
3 changes: 3 additions & 0 deletions cJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ typedef struct cJSON
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* Decimal places */
int decimal_places;

/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
Expand Down Expand Up @@ -272,6 +274,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * co
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberWithPrecisionToObject(cJSON * const object, const char * const name, const double n, int decimal_places);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
Expand Down
2 changes: 1 addition & 1 deletion cJSON_Utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_
{
if (opcode == REMOVE)
{
static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL};
static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, 0, NULL};

overwrite_item(object, invalid);

Expand Down
39 changes: 39 additions & 0 deletions tests/cjson_add.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,43 @@ static void cjson_add_number_should_add_number(void)
cJSON_Delete(root);
}

static void assert_add_number_with_precision_prints(const char *expected, double number, int decimal_places)
{
cJSON *root = cJSON_CreateObject();
char *printed = NULL;

TEST_ASSERT_NOT_NULL(cJSON_AddNumberWithPrecisionToObject(root, "number", number, decimal_places));

printed = cJSON_PrintUnformatted(root);
TEST_ASSERT_EQUAL_STRING(expected, printed);

cJSON_free(printed);
cJSON_Delete(root);
}

static void cjson_add_number_with_precision_should_format_output(void)
{
assert_add_number_with_precision_prints("{\"number\":1.20}", 1.2, 2);
assert_add_number_with_precision_prints("{\"number\":1.24}", 1.236, 2);
assert_add_number_with_precision_prints("{\"number\":-1.200}", -1.2, 3);
assert_add_number_with_precision_prints("{\"number\":0.12345678901234}", 0.12345678901234, 14);
}

static void cjson_add_number_with_precision_should_reject_invalid_precision(void)
{
cJSON *root = cJSON_CreateObject();
char *printed = NULL;

TEST_ASSERT_NULL(cJSON_AddNumberWithPrecisionToObject(root, "number", 1.2, 0));
TEST_ASSERT_NULL(cJSON_AddNumberWithPrecisionToObject(root, "number", 1.2, 15));

printed = cJSON_PrintUnformatted(root);
TEST_ASSERT_EQUAL_STRING("{}", printed);

cJSON_free(printed);
cJSON_Delete(root);
}

static void cjson_add_number_should_fail_with_null_pointers(void)
{
cJSON *root = cJSON_CreateObject();
Expand Down Expand Up @@ -448,6 +485,8 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_add_bool_should_fail_on_allocation_failure);

RUN_TEST(cjson_add_number_should_add_number);
RUN_TEST(cjson_add_number_with_precision_should_format_output);
RUN_TEST(cjson_add_number_with_precision_should_reject_invalid_precision);
RUN_TEST(cjson_add_number_should_fail_with_null_pointers);
RUN_TEST(cjson_add_number_should_fail_on_allocation_failure);

Expand Down
4 changes: 2 additions & 2 deletions tests/misc_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ static void cjson_should_not_follow_too_deep_circular_references(void)

static void cjson_set_number_value_should_set_numbers(void)
{
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}};
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, 0, NULL}};

cJSON_SetNumberValue(number, 1.5);
TEST_ASSERT_EQUAL(1, number->valueint);
Expand Down Expand Up @@ -361,7 +361,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void)

static void cjson_replace_item_in_object_should_preserve_name(void)
{
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, NULL}};
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL}};
cJSON *child = NULL;
cJSON *replacement = NULL;
cJSON_bool flag = false;
Expand Down