mirror of
https://github.com/DaveGamble/cJSON.git
synced 2023-08-10 21:13:26 +03:00
Merge c4429d580e
into cb8693b058
This commit is contained in:
commit
2a5797600c
30
README.md
30
README.md
@ -28,6 +28,7 @@ Ultralightweight JSON parser in ANSI C.
|
||||
* [Character Encoding](#character-encoding)
|
||||
* [C Standard](#c-standard)
|
||||
* [Floating Point Numbers](#floating-point-numbers)
|
||||
* [Integer numbers](#integer-numbers)
|
||||
* [Deep Nesting Of Arrays And Objects](#deep-nesting-of-arrays-and-objects)
|
||||
* [Thread Safety](#thread-safety)
|
||||
* [Case Sensitivity](#case-sensitivity)
|
||||
@ -197,9 +198,10 @@ typedef struct cJSON
|
||||
struct cJSON *child;
|
||||
int type;
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
double valuedouble;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetIntValue instead */
|
||||
cJSON_int valueint;
|
||||
/* writing to valuedouble is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
cJSON_float valuedouble;
|
||||
char *string;
|
||||
} cJSON;
|
||||
```
|
||||
@ -214,7 +216,8 @@ The type can be one of the following:
|
||||
* `cJSON_False` (check with `cJSON_IsFalse`): Represents a `false` boolean value. You can also check for boolean values in general with `cJSON_IsBool`.
|
||||
* `cJSON_True` (check with `cJSON_IsTrue`): Represents a `true` boolean value. You can also check for boolean values in general with `cJSON_IsBool`.
|
||||
* `cJSON_NULL` (check with `cJSON_IsNull`): Represents a `null` value.
|
||||
* `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value. The value is stored as a double in `valuedouble` and also in `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`.
|
||||
* `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value, which may be integer. The value is stored in `valuedouble`, and also in `valueint` with possibly some loss of precision. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`.
|
||||
* `cJSON_Number` with `cJSON_PreferInt` flag (check with `cJSON_IsInt`): Represents an integer number value that is within the range representable by `valueint`. The value is stored in `valueint`, and also in `valuedouble` with possibly some loss of precision.
|
||||
* `cJSON_String` (check with `cJSON_IsString`): Represents a string value. It is stored in the form of a zero terminated string in `valuestring`.
|
||||
* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev.next == NULL` and the last element `next == NULL`.
|
||||
* `cJSON_Object` (check with `cJSON_IsObject`): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in `string`.
|
||||
@ -237,7 +240,8 @@ it gets deleted as well. You also could use `cJSON_SetValuestring` to change a `
|
||||
|
||||
* **null** is created with `cJSON_CreateNull`
|
||||
* **booleans** are created with `cJSON_CreateTrue`, `cJSON_CreateFalse` or `cJSON_CreateBool`
|
||||
* **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`
|
||||
* (floating point) **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` will be used for `valueint`
|
||||
* **integer numbers** are created with `cJSON_CreateInt`. This will set both `valuedouble` and `valueint`, and will remember that the value represents an integer number.
|
||||
* **strings** are created with `cJSON_CreateString` (copies the string) or with `cJSON_CreateStringReference` (directly points to the string. This means that `valuestring` won't be deleted by `cJSON_Delete` and you are responsible for its lifetime, useful for constants)
|
||||
|
||||
#### Arrays
|
||||
@ -561,6 +565,22 @@ cJSON does not officially support any `double` implementations other than IEEE75
|
||||
|
||||
The maximum length of a floating point literal that cJSON supports is currently 63 characters.
|
||||
|
||||
The floating point type defaults to `double`, and can be switched to `float` by defining `CJSON_FLOAT_USE_FLOAT` in `cJSON.h`.
|
||||
|
||||
#### Integer numbers
|
||||
|
||||
While the JSON standard only specifies floating point numbers, cJSON also supports really-integer numbers when explicitly created as such. Also during parsing, integer numbers are recognized when a value does not contain a decimal digit or exponential notation, and is exactly representable by the integer data type. In some cases, the integer data type may be able to exactly represent larger integer values, where the floating point data type would lose precision.
|
||||
|
||||
cJSON number items can be accessed using either the floating point or the integer function calls. Especially **writing** to the `valuedouble` or `valueint` members is deprecated, since writing to either one will not update the other, and will not update the integer representation flag.
|
||||
|
||||
The integer type defaults to `int`, and can be switched to `long long` by defining `CJSON_INT_USE_LONGLONG` in `cJSON.h`. Since `long long` is not a C89 data type, a default cmake compile will fail. Either remove `-std=c89` from `CMakeLists.txt`, or force compiler flags e.g.:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
CFLAGS="-Wall -Werror" cmake -DENABLE_CUSTOM_COMPILER_FLAGS=Off ..
|
||||
```
|
||||
|
||||
#### Deep Nesting Of Arrays And Objects
|
||||
|
||||
cJSON doesn't support arrays and objects that are nested too deeply because this would result in a stack overflow. To prevent this cJSON limits the depth to `CJSON_NESTING_LIMIT` which is 1000 by default but can be changed at compile time.
|
||||
|
186
cJSON.c
186
cJSON.c
@ -69,6 +69,30 @@
|
||||
#endif
|
||||
#define false ((cJSON_bool)0)
|
||||
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
#define CJSON_INT_MAX LLONG_MAX
|
||||
#define CJSON_INT_MIN LLONG_MIN
|
||||
#define strtoint(s) strtoll((const char*)(s), NULL, 0)
|
||||
#define intfmt "%lld"
|
||||
#else
|
||||
#define CJSON_INT_MAX INT_MAX
|
||||
#define CJSON_INT_MIN INT_MIN
|
||||
#define strtoint(s) atoi((const char*)(s))
|
||||
#define intfmt "%d"
|
||||
#endif
|
||||
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
#define strtofloat strtof
|
||||
#define has_no_decimals(d) (d == floorf(d))
|
||||
#define floatfmt_shorter "%1.6g"
|
||||
#define floatfmt_longer "%1.9g"
|
||||
#else
|
||||
#define strtofloat strtod
|
||||
#define has_no_decimals(d) (d == floor(d))
|
||||
#define floatfmt_shorter "%1.15g"
|
||||
#define floatfmt_longer "%1.17g"
|
||||
#endif
|
||||
|
||||
/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
|
||||
#ifndef isinf
|
||||
#define isinf(d) (isnan((d - d)) && !isnan(d))
|
||||
@ -81,7 +105,7 @@
|
||||
#ifdef _WIN32
|
||||
#define NAN sqrt(-1.0)
|
||||
#else
|
||||
#define NAN 0.0/0.0
|
||||
#define NAN (0.0/0.0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -106,16 +130,26 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
|
||||
return item->valuestring;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
|
||||
CJSON_PUBLIC(cJSON_float) cJSON_GetNumberValue(const cJSON * const item)
|
||||
{
|
||||
if (!cJSON_IsNumber(item))
|
||||
{
|
||||
return (double) NAN;
|
||||
return (cJSON_float) NAN;
|
||||
}
|
||||
|
||||
return item->valuedouble;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON_int) cJSON_GetIntValue(const cJSON * const item)
|
||||
{
|
||||
if (!cJSON_IsNumber(item))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return item->valueint;
|
||||
}
|
||||
|
||||
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 16)
|
||||
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
||||
@ -304,7 +338,8 @@ typedef struct
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
|
||||
{
|
||||
double number = 0;
|
||||
cJSON_float number;
|
||||
cJSON_bool is_integer = cJSON_True;
|
||||
unsigned char *after_end = NULL;
|
||||
unsigned char number_c_string[64];
|
||||
unsigned char decimal_point = get_decimal_point();
|
||||
@ -334,12 +369,17 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu
|
||||
case '9':
|
||||
case '+':
|
||||
case '-':
|
||||
number_c_string[i] = buffer_at_offset(input_buffer)[i];
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
is_integer = cJSON_False;
|
||||
number_c_string[i] = buffer_at_offset(input_buffer)[i];
|
||||
break;
|
||||
|
||||
case '.':
|
||||
is_integer = cJSON_False;
|
||||
number_c_string[i] = decimal_point;
|
||||
break;
|
||||
|
||||
@ -350,50 +390,56 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu
|
||||
loop_end:
|
||||
number_c_string[i] = '\0';
|
||||
|
||||
number = strtod((const char*)number_c_string, (char**)&after_end);
|
||||
number = strtofloat((const char*)number_c_string, (char**)&after_end);
|
||||
if (number_c_string == after_end)
|
||||
{
|
||||
return false; /* parse_error */
|
||||
}
|
||||
|
||||
item->valuedouble = number;
|
||||
item->type = cJSON_Number;
|
||||
|
||||
/* use saturation in case of overflow */
|
||||
if (number >= INT_MAX)
|
||||
/* note that even float has range beyond long long (though inexactly) */
|
||||
if (number >= (cJSON_float)CJSON_INT_MAX)
|
||||
{
|
||||
item->valueint = INT_MAX;
|
||||
item->valueint = CJSON_INT_MAX;
|
||||
}
|
||||
else if (number <= (double)INT_MIN)
|
||||
else if (number <= (cJSON_float)CJSON_INT_MIN)
|
||||
{
|
||||
item->valueint = INT_MIN;
|
||||
item->valueint = CJSON_INT_MIN;
|
||||
}
|
||||
else if (is_integer == cJSON_True)
|
||||
{
|
||||
/* integer is in range, parse as integer to prevent float inexactness */
|
||||
item->valueint = strtoint(number_c_string);
|
||||
item->type |= cJSON_PreferInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->valueint = (int)number;
|
||||
item->valueint = (cJSON_int)number;
|
||||
}
|
||||
|
||||
item->type = cJSON_Number;
|
||||
|
||||
input_buffer->offset += (size_t)(after_end - number_c_string);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
|
||||
CJSON_PUBLIC(cJSON_float) cJSON_SetNumberHelper(cJSON *object, cJSON_float number)
|
||||
{
|
||||
if (number >= INT_MAX)
|
||||
if (number >= (cJSON_float)CJSON_INT_MAX)
|
||||
{
|
||||
object->valueint = INT_MAX;
|
||||
object->valueint = CJSON_INT_MAX;
|
||||
}
|
||||
else if (number <= (double)INT_MIN)
|
||||
else if (number <= (cJSON_float)CJSON_INT_MIN)
|
||||
{
|
||||
object->valueint = INT_MIN;
|
||||
object->valueint = CJSON_INT_MIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->valueint = (int)number;
|
||||
object->valueint = (cJSON_int)number;
|
||||
}
|
||||
|
||||
object->type &= ~cJSON_PreferInt;
|
||||
return object->valuedouble = number;
|
||||
}
|
||||
|
||||
@ -535,47 +581,57 @@ static void update_offset(printbuffer * const buffer)
|
||||
}
|
||||
|
||||
/* securely comparison of floating-point variables */
|
||||
static cJSON_bool compare_double(double a, double b)
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
static cJSON_bool compare_cJSON_float(cJSON_float a, cJSON_float b)
|
||||
{
|
||||
double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
|
||||
cJSON_float maxVal = fabsf(a) > fabsf(b) ? fabsf(a) : fabsf(b);
|
||||
return (fabsf(a - b) <= maxVal * FLT_EPSILON);
|
||||
}
|
||||
#else
|
||||
static cJSON_bool compare_cJSON_float(cJSON_float a, cJSON_float b)
|
||||
{
|
||||
cJSON_float maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
|
||||
return (fabs(a - b) <= maxVal * DBL_EPSILON);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
|
||||
{
|
||||
unsigned char *output_pointer = NULL;
|
||||
double d = item->valuedouble;
|
||||
cJSON_float d = item->valuedouble;
|
||||
int length = 0;
|
||||
size_t i = 0;
|
||||
unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
|
||||
unsigned char decimal_point = get_decimal_point();
|
||||
double test = 0.0;
|
||||
cJSON_float test;
|
||||
char *test_endptr = NULL;
|
||||
|
||||
if (output_buffer == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This checks for NaN and Infinity */
|
||||
if (isnan(d) || isinf(d))
|
||||
if (item->type & cJSON_PreferInt)
|
||||
{
|
||||
length = sprintf((char*)number_buffer, intfmt, item->valueint);
|
||||
}
|
||||
else if (isnan(d) || isinf(d))
|
||||
/* note that isnan/isinf will never work when compiling with -ffast-math */
|
||||
{
|
||||
length = sprintf((char*)number_buffer, "null");
|
||||
}
|
||||
else if(d == (double)item->valueint)
|
||||
{
|
||||
length = sprintf((char*)number_buffer, "%d", item->valueint);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
|
||||
length = sprintf((char*)number_buffer, "%1.15g", d);
|
||||
/* Try 15 (6) decimal places of precision to avoid nonsignificant nonzero digits */
|
||||
length = sprintf((char*)number_buffer, floatfmt_shorter, d);
|
||||
|
||||
/* Check whether the original double can be recovered */
|
||||
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
|
||||
/* Check whether the original value can be recovered */
|
||||
test = strtofloat((char*)number_buffer, &test_endptr);
|
||||
if (test_endptr == NULL || test_endptr == (char *)number_buffer || *test_endptr != '\0' || !compare_cJSON_float((cJSON_float)test, d))
|
||||
{
|
||||
/* If not, print with 17 decimal places of precision */
|
||||
length = sprintf((char*)number_buffer, "%1.17g", d);
|
||||
/* If not, print with 17 (9) decimal places of precision */
|
||||
length = sprintf((char*)number_buffer, floatfmt_longer, d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2124,7 +2180,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * co
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const cJSON_float number)
|
||||
{
|
||||
cJSON *number_item = cJSON_CreateNumber(number);
|
||||
if (add_item_to_object(object, name, number_item, &global_hooks, false))
|
||||
@ -2136,6 +2192,18 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddIntToObject(cJSON * const object, const char * const name, const cJSON_int number)
|
||||
{
|
||||
cJSON *number_item = cJSON_CreateInt(number);
|
||||
if (add_item_to_object(object, name, number_item, &global_hooks, false))
|
||||
{
|
||||
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);
|
||||
@ -2426,27 +2494,25 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
|
||||
return item;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(cJSON_float num)
|
||||
{
|
||||
cJSON *item = cJSON_New_Item(&global_hooks);
|
||||
if(item)
|
||||
{
|
||||
item->type = cJSON_Number;
|
||||
item->valuedouble = num;
|
||||
cJSON_SetNumberValue(item, num);
|
||||
}
|
||||
|
||||
/* use saturation in case of overflow */
|
||||
if (num >= INT_MAX)
|
||||
{
|
||||
item->valueint = INT_MAX;
|
||||
}
|
||||
else if (num <= (double)INT_MIN)
|
||||
{
|
||||
item->valueint = INT_MIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->valueint = (int)num;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateInt(cJSON_int num)
|
||||
{
|
||||
cJSON *item = cJSON_New_Item(&global_hooks);
|
||||
if(item)
|
||||
{
|
||||
item->type = cJSON_Number;
|
||||
cJSON_SetIntValue(item, num);
|
||||
}
|
||||
|
||||
return item;
|
||||
@ -2558,7 +2624,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
|
||||
|
||||
for(i = 0; a && (i < (size_t)count); i++)
|
||||
{
|
||||
n = cJSON_CreateNumber(numbers[i]);
|
||||
n = cJSON_CreateInt(numbers[i]);
|
||||
if (!n)
|
||||
{
|
||||
cJSON_Delete(a);
|
||||
@ -2598,7 +2664,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
|
||||
|
||||
for(i = 0; a && (i < (size_t)count); i++)
|
||||
{
|
||||
n = cJSON_CreateNumber((double)numbers[i]);
|
||||
n = cJSON_CreateNumber((cJSON_float)numbers[i]);
|
||||
if(!n)
|
||||
{
|
||||
cJSON_Delete(a);
|
||||
@ -2638,7 +2704,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
|
||||
|
||||
for(i = 0; a && (i < (size_t)count); i++)
|
||||
{
|
||||
n = cJSON_CreateNumber(numbers[i]);
|
||||
n = cJSON_CreateNumber((cJSON_float)numbers[i]);
|
||||
if(!n)
|
||||
{
|
||||
cJSON_Delete(a);
|
||||
@ -2943,6 +3009,16 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
|
||||
return (item->type & 0xFF) == cJSON_Number;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInt(const cJSON * const item)
|
||||
{
|
||||
if (item == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((item->type & 0xFF) == cJSON_Number) && (item->type & cJSON_PreferInt);
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
|
||||
{
|
||||
if (item == NULL)
|
||||
@ -3022,7 +3098,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
|
||||
return true;
|
||||
|
||||
case cJSON_Number:
|
||||
if (compare_double(a->valuedouble, b->valuedouble))
|
||||
if ((a->valueint == b->valueint) && compare_cJSON_float(a->valuedouble, b->valuedouble))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
49
cJSON.h
49
cJSON.h
@ -28,6 +28,19 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* CJSON_INT_USE_LONGLONG
|
||||
Compile-time option to use "long long" instead of default "int".
|
||||
Note: Default cmake rules will force C89 and prevent long long.
|
||||
To use long long, delete build tree, then run:
|
||||
CFLAGS="-Wall -Werror" cmake -DENABLE_CUSTOM_COMPILER_FLAGS=Off <sourcedir>
|
||||
*/
|
||||
#define notCJSON_INT_USE_LONGLONG
|
||||
|
||||
/* CJSON_FLOAT_USE_FLOAT
|
||||
Compile-time option to use "float" instead of default "double".
|
||||
*/
|
||||
#define notCJSON_FLOAT_USE_FLOAT
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
@ -98,6 +111,19 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
#define cJSON_PreferInt 1024
|
||||
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
typedef long long cJSON_int;
|
||||
#else
|
||||
typedef int cJSON_int;
|
||||
#endif
|
||||
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
typedef float cJSON_float;
|
||||
#else
|
||||
typedef double cJSON_float;
|
||||
#endif
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
@ -113,10 +139,11 @@ typedef struct cJSON
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetIntValue instead */
|
||||
cJSON_int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
/* writing to valuedouble is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
cJSON_float valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
@ -177,7 +204,8 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_float) cJSON_GetNumberValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_int) cJSON_GetIntValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
@ -186,6 +214,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInt(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
@ -196,7 +225,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(cJSON_float num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateInt(cJSON_int num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
@ -265,17 +295,18 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * co
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
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_AddNumberToObject(cJSON * const object, const char * const name, const cJSON_float number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddIntToObject(cJSON * const object, const char * const name, const cJSON_int number);
|
||||
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);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
#define cJSON_SetIntValue(object, number) ((object != NULL) ? ((object)->valuedouble = (number), (object)->type |= cJSON_PreferInt, (object)->valueint = (number)) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
CJSON_PUBLIC(cJSON_float) cJSON_SetNumberHelper(cJSON *object, cJSON_float number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (cJSON_float)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
|
@ -109,12 +109,19 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st
|
||||
}
|
||||
|
||||
/* securely comparison of floating-point variables */
|
||||
static cJSON_bool compare_double(double a, double b)
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
static cJSON_bool compare_cJSON_float(cJSON_float a, cJSON_float b)
|
||||
{
|
||||
double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
|
||||
cJSON_float maxVal = fabsf(a) > fabsf(b) ? fabsf(a) : fabsf(b);
|
||||
return (fabsf(a - b) <= maxVal * FLT_EPSILON);
|
||||
}
|
||||
#else
|
||||
static cJSON_bool compare_cJSON_float(cJSON_float a, cJSON_float b)
|
||||
{
|
||||
cJSON_float maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
|
||||
return (fabs(a - b) <= maxVal * DBL_EPSILON);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */
|
||||
static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive)
|
||||
@ -612,7 +619,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti
|
||||
{
|
||||
case cJSON_Number:
|
||||
/* numeric mismatch. */
|
||||
if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble)))
|
||||
if ((a->valueint != b->valueint) || (!compare_cJSON_float(a->valuedouble, b->valuedouble)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1154,7 +1161,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa
|
||||
switch (from->type & 0xFF)
|
||||
{
|
||||
case cJSON_Number:
|
||||
if ((from->valueint != to->valueint) || !compare_double(from->valuedouble, to->valuedouble))
|
||||
if ((from->valueint != to->valueint) || !compare_cJSON_float(from->valuedouble, to->valuedouble))
|
||||
{
|
||||
compose_patch(patches, (const unsigned char*)"replace", path, NULL, to);
|
||||
}
|
||||
|
@ -278,6 +278,45 @@ static void cjson_add_number_should_fail_on_allocation_failure(void)
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_int_should_add_integer(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON *number = NULL;
|
||||
|
||||
cJSON_AddIntToObject(root, "number", 42);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(number = cJSON_GetObjectItemCaseSensitive(root, "number"));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(number->type, cJSON_Number | cJSON_PreferInt);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(number->valuedouble, 42);
|
||||
TEST_ASSERT_EQUAL_INT(number->valueint, 42);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_int_should_fail_with_null_pointers(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddIntToObject(NULL, "number", 42));
|
||||
TEST_ASSERT_NULL(cJSON_AddIntToObject(root, NULL, 42));
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_int_should_fail_on_allocation_failure(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
cJSON_InitHooks(&failing_hooks);
|
||||
|
||||
TEST_ASSERT_NULL(cJSON_AddIntToObject(root, "number", 42));
|
||||
|
||||
cJSON_InitHooks(NULL);
|
||||
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
static void cjson_add_string_should_add_string(void)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
@ -451,6 +490,10 @@ int CJSON_CDECL main(void)
|
||||
RUN_TEST(cjson_add_number_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_number_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_int_should_add_integer);
|
||||
RUN_TEST(cjson_add_int_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_int_should_fail_on_allocation_failure);
|
||||
|
||||
RUN_TEST(cjson_add_string_should_add_string);
|
||||
RUN_TEST(cjson_add_string_should_fail_with_null_pointers);
|
||||
RUN_TEST(cjson_add_string_should_fail_on_allocation_failure);
|
||||
|
@ -64,9 +64,14 @@ static void cjson_compare_should_compare_numbers(void)
|
||||
TEST_ASSERT_TRUE(compare_from_string("1", "1", false));
|
||||
TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", true));
|
||||
TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", false));
|
||||
TEST_ASSERT_TRUE(compare_from_string("1E100", "10E99", false));
|
||||
|
||||
TEST_ASSERT_TRUE(compare_from_string("1E20", "10E19", false));
|
||||
TEST_ASSERT_FALSE(compare_from_string("0.5E-20", "0.5E-21", false));
|
||||
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
TEST_ASSERT_TRUE(compare_from_string("1E100", "10E99", false));
|
||||
TEST_ASSERT_FALSE(compare_from_string("0.5E-100", "0.5E-101", false));
|
||||
#endif
|
||||
|
||||
TEST_ASSERT_FALSE(compare_from_string("1", "2", true));
|
||||
TEST_ASSERT_FALSE(compare_from_string("1", "2", false));
|
||||
|
22
tests/inputs/test7float
Normal file
22
tests/inputs/test7float
Normal file
@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.7668,
|
||||
"Longitude": -122.395,
|
||||
"Address": "",
|
||||
"City": "SAN FRANCISCO",
|
||||
"State": "CA",
|
||||
"Zip": "94107",
|
||||
"Country": "US"
|
||||
},
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.3719,
|
||||
"Longitude": -122.0260,
|
||||
"Address": "",
|
||||
"City": "SUNNYVALE",
|
||||
"State": "CA",
|
||||
"Zip": "94085",
|
||||
"Country": "US"
|
||||
}
|
||||
]
|
19
tests/inputs/test7float.expected
Normal file
19
tests/inputs/test7float.expected
Normal file
@ -0,0 +1,19 @@
|
||||
[{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.7668,
|
||||
"Longitude": -122.395,
|
||||
"Address": "",
|
||||
"City": "SAN FRANCISCO",
|
||||
"State": "CA",
|
||||
"Zip": "94107",
|
||||
"Country": "US"
|
||||
}, {
|
||||
"precision": "zip",
|
||||
"Latitude": 37.3719,
|
||||
"Longitude": -122.026,
|
||||
"Address": "",
|
||||
"City": "SUNNYVALE",
|
||||
"State": "CA",
|
||||
"Zip": "94085",
|
||||
"Country": "US"
|
||||
}]
|
@ -28,6 +28,11 @@
|
||||
#include "unity/src/unity.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
#undef TEST_ASSERT_EQUAL_DOUBLE
|
||||
#define TEST_ASSERT_EQUAL_DOUBLE TEST_ASSERT_EQUAL_FLOAT
|
||||
#endif
|
||||
|
||||
static void cjson_array_foreach_should_loop_over_arrays(void)
|
||||
{
|
||||
cJSON array[1];
|
||||
@ -183,6 +188,12 @@ static void typecheck_functions_should_check_type(void)
|
||||
TEST_ASSERT_FALSE(cJSON_IsNumber(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsNumber(invalid));
|
||||
TEST_ASSERT_TRUE(cJSON_IsNumber(item));
|
||||
TEST_ASSERT_FALSE(cJSON_IsInt(item));
|
||||
|
||||
item->type = cJSON_Number | cJSON_StringIsConst | cJSON_PreferInt;
|
||||
TEST_ASSERT_FALSE(cJSON_IsInt(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsInt(invalid));
|
||||
TEST_ASSERT_TRUE(cJSON_IsInt(item));
|
||||
|
||||
item->type = cJSON_String | cJSON_StringIsConst;
|
||||
TEST_ASSERT_FALSE(cJSON_IsString(NULL));
|
||||
@ -231,13 +242,13 @@ static void cjson_set_number_value_should_set_numbers(void)
|
||||
TEST_ASSERT_EQUAL(-1, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(-1.5, number->valuedouble);
|
||||
|
||||
cJSON_SetNumberValue(number, 1 + (double)INT_MAX);
|
||||
TEST_ASSERT_EQUAL(INT_MAX, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(1 + (double)INT_MAX, number->valuedouble);
|
||||
cJSON_SetNumberValue(number, 1.0 + (double)CJSON_INT_MAX);
|
||||
TEST_ASSERT_EQUAL(CJSON_INT_MAX, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(1.0 + (double)CJSON_INT_MAX, number->valuedouble);
|
||||
|
||||
cJSON_SetNumberValue(number, -1 + (double)INT_MIN);
|
||||
TEST_ASSERT_EQUAL(INT_MIN, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(-1 + (double)INT_MIN, number->valuedouble);
|
||||
cJSON_SetNumberValue(number, -1.0 + (double)CJSON_INT_MIN);
|
||||
TEST_ASSERT_EQUAL(CJSON_INT_MIN, number->valueint);
|
||||
TEST_ASSERT_EQUAL_DOUBLE(-1.0 + (double)CJSON_INT_MIN, number->valuedouble);
|
||||
}
|
||||
|
||||
static void cjson_detach_item_via_pointer_should_detach_items(void)
|
||||
@ -376,6 +387,7 @@ static void cjson_functions_should_not_crash_with_null_pointers(void)
|
||||
TEST_ASSERT_FALSE(cJSON_IsBool(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsNull(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsNumber(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsInt(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsString(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsArray(NULL));
|
||||
TEST_ASSERT_FALSE(cJSON_IsObject(NULL));
|
||||
|
@ -156,7 +156,11 @@ static void file_test6_should_not_be_parsed(void)
|
||||
|
||||
static void file_test7_should_be_parsed_and_printed(void)
|
||||
{
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
do_test("test7float");
|
||||
#else
|
||||
do_test("test7");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void file_test8_should_be_parsed_and_printed(void)
|
||||
|
@ -43,7 +43,7 @@ static void assert_is_number(cJSON *number_item)
|
||||
assert_has_no_string(number_item);
|
||||
}
|
||||
|
||||
static void assert_parse_number(const char *string, int integer, double real)
|
||||
static void assert_parse_number(const char *string, cJSON_int integer, cJSON_float real)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.content = (const unsigned char*)string;
|
||||
@ -51,8 +51,16 @@ static void assert_parse_number(const char *string, int integer, double real)
|
||||
|
||||
TEST_ASSERT_TRUE(parse_number(item, &buffer));
|
||||
assert_is_number(item);
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
TEST_ASSERT_EQUAL_INT64(integer, item->valueint);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_INT(integer, item->valueint);
|
||||
#endif
|
||||
#ifdef CJSON_FLOAT_USE_FLOAT
|
||||
TEST_ASSERT_EQUAL_FLOAT(real, item->valuedouble);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_number_should_parse_zero(void)
|
||||
@ -65,15 +73,33 @@ static void parse_number_should_parse_zero(void)
|
||||
static void parse_number_should_parse_negative_integers(void)
|
||||
{
|
||||
assert_parse_number("-1", -1, -1);
|
||||
assert_parse_number("-32768", -32768, -32768.0);
|
||||
assert_parse_number("-2147483648", (int)-2147483648.0, -2147483648.0);
|
||||
|
||||
/* not -32768: C allows int as 15bit + signbit, or one's complement */
|
||||
assert_parse_number("-32767", -32767, -32767.0);
|
||||
|
||||
if (sizeof(cJSON_int) >= 4)
|
||||
assert_parse_number("-2147483648", -2147483648, -2147483648.0);
|
||||
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
assert_parse_number("-8765432101234567", -8765432101234567LL, -8765432101234567.0);
|
||||
#else
|
||||
assert_parse_number("-8765432101234567", CJSON_INT_MIN, -8765432101234567.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_number_should_parse_positive_integers(void)
|
||||
{
|
||||
assert_parse_number("1", 1, 1);
|
||||
assert_parse_number("32767", 32767, 32767.0);
|
||||
assert_parse_number("2147483647", (int)2147483647.0, 2147483647.0);
|
||||
|
||||
if (sizeof(cJSON_int) >= 4)
|
||||
assert_parse_number("2147483647", 2147483647, 2147483647.0);
|
||||
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
assert_parse_number("8765432101234567", 8765432101234567LL, 8765432101234567.0);
|
||||
#else
|
||||
assert_parse_number("8765432101234567", CJSON_INT_MAX, 8765432101234567.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_number_should_parse_positive_reals(void)
|
||||
@ -81,9 +107,16 @@ static void parse_number_should_parse_positive_reals(void)
|
||||
assert_parse_number("0.001", 0, 0.001);
|
||||
assert_parse_number("10e-10", 0, 10e-10);
|
||||
assert_parse_number("10E-10", 0, 10e-10);
|
||||
assert_parse_number("10e10", INT_MAX, 10e10);
|
||||
assert_parse_number("123e+127", INT_MAX, 123e127);
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_parse_number("10e10", 100000000000LL, 10e10);
|
||||
#endif
|
||||
#endif
|
||||
assert_parse_number("10e20", CJSON_INT_MAX, 10e20);
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_parse_number("123e+127", CJSON_INT_MAX, 123e127);
|
||||
assert_parse_number("123e-128", 0, 123e-128);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_number_should_parse_negative_reals(void)
|
||||
@ -91,9 +124,16 @@ static void parse_number_should_parse_negative_reals(void)
|
||||
assert_parse_number("-0.001", 0, -0.001);
|
||||
assert_parse_number("-10e-10", 0, -10e-10);
|
||||
assert_parse_number("-10E-10", 0, -10e-10);
|
||||
assert_parse_number("-10e20", INT_MIN, -10e20);
|
||||
assert_parse_number("-123e+127", INT_MIN, -123e127);
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_parse_number("-10e10", -100000000000LL, -10e10);
|
||||
#endif
|
||||
#endif
|
||||
assert_parse_number("-10e20", CJSON_INT_MIN, -10e20);
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_parse_number("-123e+127", CJSON_INT_MIN, -123e127);
|
||||
assert_parse_number("-123e-128", 0, -123e-128);
|
||||
#endif
|
||||
}
|
||||
|
||||
int CJSON_CDECL main(void)
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "unity/src/unity.h"
|
||||
#include "common.h"
|
||||
|
||||
static void assert_print_number(const char *expected, double input)
|
||||
static void assert_print_number(const char *expected, cJSON_float input)
|
||||
{
|
||||
unsigned char printed[1024];
|
||||
unsigned char new_buffer[26];
|
||||
@ -62,33 +62,93 @@ static void assert_print_number(const char *expected, double input)
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected.");
|
||||
}
|
||||
|
||||
static void assert_print_integer(const char *expected, cJSON_int input)
|
||||
{
|
||||
unsigned char printed[1024];
|
||||
unsigned char new_buffer[26];
|
||||
cJSON item[1];
|
||||
printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
buffer.buffer = printed;
|
||||
buffer.length = sizeof(printed);
|
||||
buffer.offset = 0;
|
||||
buffer.noalloc = true;
|
||||
buffer.hooks = global_hooks;
|
||||
buffer.buffer = new_buffer;
|
||||
|
||||
memset(item, 0, sizeof(item));
|
||||
memset(new_buffer, 0, sizeof(new_buffer));
|
||||
cJSON_SetIntValue(item, input);
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer), "Failed to print integer.");
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed integer is not as expected.");
|
||||
}
|
||||
|
||||
static void print_number_should_print_zero(void)
|
||||
{
|
||||
assert_print_number("0", 0);
|
||||
assert_print_integer("0", 0);
|
||||
}
|
||||
|
||||
static void print_number_should_print_negative_integers(void)
|
||||
{
|
||||
assert_print_number("-1", -1.0);
|
||||
assert_print_number("-32768", -32768.0);
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_print_number("-2147483648", -2147483648.0);
|
||||
assert_print_number("-2147483649", -2147483649.0);
|
||||
assert_print_number("-4294967296", -4294967296.0);
|
||||
assert_print_number("-4294967297", -4294967297.0);
|
||||
/* Approx lowest integer exactly representable in double */
|
||||
assert_print_number("-8765432101234567", -8765432101234567.0);
|
||||
#endif
|
||||
|
||||
assert_print_integer("-1", -1);
|
||||
|
||||
/* not -32768: C allows int as 15bit + signbit, or one's complement */
|
||||
assert_print_integer("-32767", -32767);
|
||||
|
||||
if (sizeof(cJSON_int) >= 4)
|
||||
assert_print_integer("-2147483647", -2147483647);
|
||||
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
assert_print_integer("-9223372036854775807", -9223372036854775807LL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_number_should_print_positive_integers(void)
|
||||
{
|
||||
assert_print_number("1", 1.0);
|
||||
assert_print_number("32767", 32767.0);
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_print_number("2147483647", 2147483647.0);
|
||||
assert_print_number("2147483648", 2147483648.0);
|
||||
assert_print_number("4294967295", 4294967295.0);
|
||||
assert_print_number("4294967296", 4294967296.0);
|
||||
/* Approx highest integer exactly representable in double */
|
||||
assert_print_number("8765432101234567", 8765432101234567.0);
|
||||
#endif
|
||||
|
||||
assert_print_integer("1", 1);
|
||||
assert_print_integer("32767", 32767);
|
||||
|
||||
if (sizeof(cJSON_int) >= 4)
|
||||
assert_print_integer("2147483647", 2147483647);
|
||||
|
||||
#ifdef CJSON_INT_USE_LONGLONG
|
||||
assert_print_integer("9223372036854775807", 9223372036854775807LL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_number_should_print_positive_reals(void)
|
||||
{
|
||||
assert_print_number("0.123", 0.123);
|
||||
assert_print_number("1e-09", 10e-10);
|
||||
assert_print_number("1e+21", 10e20);
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_print_number("1000000000000", 10e11);
|
||||
assert_print_number("1.23e+129", 123e+127);
|
||||
assert_print_number("1.23e-126", 123e-128);
|
||||
assert_print_number("3.1415926535897931", 3.1415926535897931);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_number_should_print_negative_reals(void)
|
||||
@ -96,17 +156,18 @@ static void print_number_should_print_negative_reals(void)
|
||||
assert_print_number("-0.0123", -0.0123);
|
||||
assert_print_number("-1e-09", -10e-10);
|
||||
assert_print_number("-1e+21", -10e20);
|
||||
#ifndef CJSON_FLOAT_USE_FLOAT
|
||||
assert_print_number("-1.23e+129", -123e+127);
|
||||
assert_print_number("-1.23e-126", -123e-128);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_number_should_print_non_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
/* FIXME: Cannot test this easily in C89! */
|
||||
/* assert_print_number("null", NaN); */
|
||||
/* assert_print_number("null", INFTY); */
|
||||
/* assert_print_number("null", -INFTY); */
|
||||
assert_print_number("null", 0.0/0.0);
|
||||
assert_print_number("null", -(0.0/0.0));
|
||||
assert_print_number("null", 1.0/0.0);
|
||||
assert_print_number("null", (-1.0)/0.0);
|
||||
}
|
||||
|
||||
int CJSON_CDECL main(void)
|
||||
|
@ -202,7 +202,7 @@ static int supports_full_hd(const char * const monitor)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (compare_double(width->valuedouble, 1920) && compare_double(height->valuedouble, 1080))
|
||||
if (compare_cJSON_float(width->valuedouble, 1920) && compare_cJSON_float(height->valuedouble, 1080))
|
||||
{
|
||||
status = 1;
|
||||
goto end;
|
||||
|
Loading…
Reference in New Issue
Block a user