Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a20692c18 | ||
|
|
2f65e80a34 | ||
|
|
ef34500693 | ||
|
|
b0dfcde04c | ||
|
|
1934059554 | ||
|
|
cc84a446be | ||
|
|
e58f7ec027 | ||
|
|
4bfb880093 | ||
|
|
b7ce06224b | ||
|
|
227d3398d6 | ||
|
|
466eb8e3f8 | ||
|
|
4ec6e76ea2 | ||
|
|
a1b37d0abe | ||
|
|
3d971db426 | ||
|
|
30e1e7af7c | ||
|
|
76e5296d0d | ||
|
|
c597601cf1 | ||
|
|
e3d5798896 | ||
|
|
cf1842dc6f |
@@ -1,7 +1,5 @@
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
subdirs(tests fuzzing)
|
||||
cmake_minimum_required(VERSION 2.8.5)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
@@ -9,7 +7,7 @@ project(cJSON C)
|
||||
|
||||
set(PROJECT_VERSION_MAJOR 1)
|
||||
set(PROJECT_VERSION_MINOR 4)
|
||||
set(PROJECT_VERSION_PATCH 0)
|
||||
set(PROJECT_VERSION_PATCH 5)
|
||||
set(CJSON_VERSION_SO 1)
|
||||
set(CJSON_UTILS_VERSION_SO 1)
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
@@ -78,10 +76,13 @@ foreach(compiler_flag ${custom_compiler_flags})
|
||||
|
||||
CHECK_C_COMPILER_FLAG(${compiler_flag} "FLAG_SUPPORTED_${current_variable}")
|
||||
if (FLAG_SUPPORTED_${current_variable})
|
||||
list(APPEND supported_compiler_flags)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${compiler_flag}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}")
|
||||
|
||||
#variables for pkg-config
|
||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
||||
@@ -167,9 +168,30 @@ if(ENABLE_CJSON_TEST)
|
||||
add_executable("${TEST_CJSON}" test.c)
|
||||
target_link_libraries("${TEST_CJSON}" "${CJSON_LIB}")
|
||||
|
||||
add_test(NAME ${TEST_CJSON} COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${TEST_CJSON}")
|
||||
|
||||
# Disable -fsanitize=float-divide-by-zero for cJSON_test
|
||||
if (FLAG_SUPPORTED_fsanitizefloatdividebyzero)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=float-divide-by-zero")
|
||||
else()
|
||||
target_compile_options(${TEST_CJSON} PRIVATE "-fno-sanitize=float-divide-by-zero")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_CJSON_UTILS)
|
||||
set(TEST_CJSON_UTILS cJSON_test_utils)
|
||||
add_executable("${TEST_CJSON_UTILS}" test_utils.c)
|
||||
target_link_libraries("${TEST_CJSON_UTILS}" "${CJSON_UTILS_LIB}")
|
||||
|
||||
add_test(NAME ${TEST_CJSON_UTILS} COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${TEST_CJSON_UTILS}")
|
||||
endif()
|
||||
|
||||
#"check" target that automatically builds everything and runs the tests
|
||||
add_custom_target(check
|
||||
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
|
||||
DEPENDS ${TEST_CJSON} ${TEST_CJSON_UTILS})
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(fuzzing)
|
||||
|
||||
2
Makefile
2
Makefile
@@ -10,7 +10,7 @@ UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
|
||||
|
||||
LDLIBS = -lm
|
||||
|
||||
LIBVERSION = 1.4.0
|
||||
LIBVERSION = 1.4.5
|
||||
CJSON_SOVERSION = 1
|
||||
UTILS_SOVERSION = 1
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ Because the entire library is only one C file and one header file, you can just
|
||||
cJSON is written in ANSI C (C89) in order to support as many platforms and compilers as possible.
|
||||
|
||||
#### CMake
|
||||
With CMake, cJSON supports a full blown build system. This way you get the most features. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it.
|
||||
With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 2.8.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it.
|
||||
|
||||
```
|
||||
mkdir build
|
||||
@@ -97,10 +97,8 @@ make
|
||||
make DESTDIR=$pkgdir install
|
||||
```
|
||||
|
||||
CMake supports a lot of different platforms, not only UNIX Makefiles, but only UNIX Makefiles have been tested. It works on GNU/Linux and has been confirmed to compile on some versions of macOS, Cygwin, FreeBSD, Solaris and OpenIndiana.
|
||||
|
||||
#### Makefile
|
||||
If you don't have CMake available, but still have make. You can use the makefile to build cJSON:
|
||||
If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON:
|
||||
|
||||
Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program.
|
||||
|
||||
|
||||
81
cJSON.c
81
cJSON.c
@@ -47,7 +47,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
|
||||
}
|
||||
|
||||
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 4) || (CJSON_VERSION_PATCH != 0)
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 4) || (CJSON_VERSION_PATCH != 5)
|
||||
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
||||
#endif
|
||||
|
||||
@@ -228,7 +228,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
|
||||
}
|
||||
else
|
||||
{
|
||||
object->valueint = cJSON_Number;
|
||||
object->valueint = (int)number;
|
||||
}
|
||||
|
||||
return object->valuedouble = number;
|
||||
@@ -253,13 +253,19 @@ static unsigned char* ensure(printbuffer * const p, size_t needed, const interna
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((p->length > 0) && (p->offset >= p->length))
|
||||
{
|
||||
/* make sure that offset is valid */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (needed > INT_MAX)
|
||||
{
|
||||
/* sizes bigger than INT_MAX are currently not supported */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
needed += p->offset;
|
||||
needed += p->offset + 1;
|
||||
if (needed <= p->length)
|
||||
{
|
||||
return p->buffer + p->offset;
|
||||
@@ -270,8 +276,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed, const interna
|
||||
}
|
||||
|
||||
/* calculate new buffer size */
|
||||
newsize = needed * 2;
|
||||
if (newsize > INT_MAX)
|
||||
if (newsize > (INT_MAX / 2))
|
||||
{
|
||||
/* overflow of int, use INT_MAX if possible */
|
||||
if (needed <= INT_MAX)
|
||||
@@ -283,6 +288,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed, const interna
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newsize = needed * 2;
|
||||
}
|
||||
|
||||
if (hooks->reallocate != NULL)
|
||||
{
|
||||
@@ -372,28 +381,30 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
|
||||
|
||||
/* This is a nice tradeoff. */
|
||||
output_pointer = ensure(output_buffer, 64, hooks);
|
||||
if (output_pointer != NULL)
|
||||
if (output_pointer == NULL)
|
||||
{
|
||||
/* This checks for NaN and Infinity */
|
||||
if ((d * 0) != 0)
|
||||
{
|
||||
length = sprintf((char*)output_pointer, "null");
|
||||
}
|
||||
else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
|
||||
{
|
||||
/* integer */
|
||||
length = sprintf((char*)output_pointer, "%.0f", d);
|
||||
trim_zeroes = false; /* don't remove zeroes for "big integers" */
|
||||
}
|
||||
else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
|
||||
{
|
||||
length = sprintf((char*)output_pointer, "%e", d);
|
||||
trim_zeroes = false; /* don't remove zeroes in engineering notation */
|
||||
}
|
||||
else
|
||||
{
|
||||
length = sprintf((char*)output_pointer, "%f", d);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This checks for NaN and Infinity */
|
||||
if ((d * 0) != 0)
|
||||
{
|
||||
length = sprintf((char*)output_pointer, "null");
|
||||
}
|
||||
else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
|
||||
{
|
||||
/* integer */
|
||||
length = sprintf((char*)output_pointer, "%.0f", d);
|
||||
trim_zeroes = false; /* don't remove zeroes for "big integers" */
|
||||
}
|
||||
else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
|
||||
{
|
||||
length = sprintf((char*)output_pointer, "%e", d);
|
||||
trim_zeroes = false; /* don't remove zeroes in engineering notation */
|
||||
}
|
||||
else
|
||||
{
|
||||
length = sprintf((char*)output_pointer, "%f", d);
|
||||
}
|
||||
|
||||
/* sprintf failed */
|
||||
@@ -1224,7 +1235,7 @@ static cJSON_bool print_array(const cJSON * const item, const size_t depth, cons
|
||||
update_offset(output_buffer);
|
||||
if (current_element->next)
|
||||
{
|
||||
length = format ? 2 : 1;
|
||||
length = (size_t) (format ? 2 : 1);
|
||||
output_pointer = ensure(output_buffer, length + 1, hooks);
|
||||
if (output_pointer == NULL)
|
||||
{
|
||||
@@ -1360,7 +1371,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con
|
||||
}
|
||||
|
||||
/* Compose the output: */
|
||||
length = format ? 2 : 1; /* fmt: {\n */
|
||||
length = (size_t) (format ? 2 : 1); /* fmt: {\n */
|
||||
output_pointer = ensure(output_buffer, length + 1, hooks);
|
||||
if (output_pointer == NULL)
|
||||
{
|
||||
@@ -1398,7 +1409,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con
|
||||
}
|
||||
update_offset(output_buffer);
|
||||
|
||||
length = format ? 2 : 1;
|
||||
length = (size_t) (format ? 2 : 1);
|
||||
output_pointer = ensure(output_buffer, length, hooks);
|
||||
if (output_pointer == NULL)
|
||||
{
|
||||
@@ -1419,7 +1430,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con
|
||||
update_offset(output_buffer);
|
||||
|
||||
/* print comma if not last */
|
||||
length = (size_t) (format ? 1 : 0) + (current_item->next ? 1 : 0);
|
||||
length = (size_t) ((format ? 1 : 0) + (current_item->next ? 1 : 0));
|
||||
output_pointer = ensure(output_buffer, length + 1, hooks);
|
||||
if (output_pointer == NULL)
|
||||
{
|
||||
@@ -1578,6 +1589,10 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO
|
||||
item->type &= ~cJSON_StringIsConst;
|
||||
}
|
||||
|
||||
#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
/* Add an item to an object with constant string as key */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
|
||||
{
|
||||
@@ -1589,13 +1604,13 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ
|
||||
{
|
||||
global_hooks.deallocate(item->string);
|
||||
}
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
item->string = (char*)string;
|
||||
#pragma GCC diagnostic pop
|
||||
item->type |= cJSON_StringIsConst;
|
||||
cJSON_AddItemToArray(object, item);
|
||||
}
|
||||
#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
|
||||
{
|
||||
|
||||
7
cJSON.h
7
cJSON.h
@@ -31,7 +31,7 @@ extern "C"
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 4
|
||||
#define CJSON_VERSION_PATCH 0
|
||||
#define CJSON_VERSION_PATCH 5
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -132,8 +132,9 @@ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: If you are printing numbers, the buffer hat to be 63 bytes bigger then the printed JSON (worst case) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
|
||||
|
||||
|
||||
@@ -230,11 +230,11 @@ static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
|
||||
|
||||
for (; *string; (void)s2++, string++)
|
||||
{
|
||||
*s2 = (*string != '~')
|
||||
*s2 = (unsigned char) ((*string != '~')
|
||||
? (*string)
|
||||
: ((*(++string) == '0')
|
||||
? '~'
|
||||
: '/');
|
||||
: '/'));
|
||||
}
|
||||
|
||||
*s2 = '\0';
|
||||
|
||||
@@ -2,14 +2,28 @@ if(ENABLE_CJSON_TEST)
|
||||
add_library(unity unity/src/unity.c)
|
||||
|
||||
# Disable -Werror for Unity
|
||||
list(FIND custom_compiler_flags "-Werror" werror_found)
|
||||
if (werror_found)
|
||||
target_compile_options(unity PRIVATE "-Wno-error")
|
||||
if (FLAG_SUPPORTED_Werror)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-Wno-error")
|
||||
endif()
|
||||
endif()
|
||||
# Disable -fvisibility=hidden for Unity
|
||||
list(FIND custom_compiler_flags "-fvisibility=hidden" visibility_found)
|
||||
if (visibility_found)
|
||||
target_compile_options(unity PRIVATE "-fvisibility=default")
|
||||
if (FLAG_SUPPORTED_fvisibilityhidden)
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=default")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-fvisibility=default")
|
||||
endif()
|
||||
endif()
|
||||
# Disable -fsanitize=float-divide-by-zero for Unity (GCC bug on x86 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097)
|
||||
if (FLAG_SUPPORTED_fsanitizefloatdividebyzero AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"))
|
||||
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=float-divide-by-zero")
|
||||
else()
|
||||
target_compile_options(unity PRIVATE "-fno-sanitize=float-divide-by-zero")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#copy test files
|
||||
@@ -46,20 +60,17 @@ if(ENABLE_CJSON_TEST)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#"check" target that automatically builds everything and runs the tests
|
||||
add_custom_target(check
|
||||
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
|
||||
DEPENDS ${unity_tests})
|
||||
|
||||
foreach(unity_test ${unity_tests})
|
||||
add_executable("${unity_test}" "${unity_test}.c")
|
||||
target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common)
|
||||
if(MEMORYCHECK_COMMAND)
|
||||
add_test(NAME "${unity_test}"
|
||||
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "./${unity_test}")
|
||||
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${unity_test}")
|
||||
else()
|
||||
add_test(NAME "${unity_test}"
|
||||
COMMAND "./${unity_test}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_dependencies(check ${unity_tests})
|
||||
endif()
|
||||
|
||||
@@ -50,7 +50,7 @@ static void print_number_should_print_negative_integers(void)
|
||||
{
|
||||
assert_print_number("-1", -1);
|
||||
assert_print_number("-32768", -32768);
|
||||
assert_print_number("-2147483648", -2147483648);
|
||||
assert_print_number("-2147483648", -2147483648.0);
|
||||
}
|
||||
|
||||
static void print_number_should_print_positive_integers(void)
|
||||
|
||||
Reference in New Issue
Block a user