mirror of
https://github.com/DaveGamble/cJSON.git
synced 2026-11-14 19:03:32 +00:00
Compare commits
50
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08738673be | ||
|
|
1b001ab047 | ||
|
|
409c2aaea7 | ||
|
|
e8f56bd194 | ||
|
|
064eec8208 | ||
|
|
050f982608 | ||
|
|
d2d19127d3 | ||
|
|
691a83a479 | ||
|
|
ae9dc3e7db | ||
|
|
eeaaaac63e | ||
|
|
78b5bed9a0 | ||
|
|
1a8f732749 | ||
|
|
88c39fa2e4 | ||
|
|
9d801d64ea | ||
|
|
877fac0f90 | ||
|
|
98e0b586ca | ||
|
|
dd1ba72ce2 | ||
|
|
515d11f55a | ||
|
|
ba8fe0f479 | ||
|
|
f02f79ecbb | ||
|
|
d4e81cfe57 | ||
|
|
7030dc7c5b | ||
|
|
27977adc93 | ||
|
|
677f0cb1bb | ||
|
|
3ebc06196a | ||
|
|
fd5281bdd8 | ||
|
|
1f4044a707 | ||
|
|
08a2ad3c59 | ||
|
|
b06fb10f94 | ||
|
|
ce5f31ac47 | ||
|
|
0715259635 | ||
|
|
f4cc4d7c63 | ||
|
|
952b1017ab | ||
|
|
0914640d79 | ||
|
|
5ed383a0d1 | ||
|
|
3e2c29528a | ||
|
|
b2bbc11d44 | ||
|
|
06f4152008 | ||
|
|
0e0c463491 | ||
|
|
2336a0348d | ||
|
|
5d50f4efe1 | ||
|
|
8abf110750 | ||
|
|
d26a42af8d | ||
|
|
6f264b5d0c | ||
|
|
5da9edc8b1 | ||
|
|
22a7d04fa0 | ||
|
|
a559eac472 | ||
|
|
d514bb866e | ||
|
|
27caa364b0 | ||
|
|
f47271f455 |
No files matched your search
@@ -14,3 +14,5 @@ libcjson.so.*
|
|||||||
libcjson_utils.so.*
|
libcjson_utils.so.*
|
||||||
*.orig
|
*.orig
|
||||||
.vscode
|
.vscode
|
||||||
|
.idea
|
||||||
|
cmake-build-debug
|
||||||
@@ -1,3 +1,27 @@
|
|||||||
|
1.7.5
|
||||||
|
=====
|
||||||
|
Fixes:
|
||||||
|
------
|
||||||
|
* Fix a bug in the JSON Patch implementation of `cJSON Utils` (see #251), thanks @bobkocisko.
|
||||||
|
|
||||||
|
1.7.4
|
||||||
|
=====
|
||||||
|
Fixes:
|
||||||
|
------
|
||||||
|
* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added (#248). Thanks @hhallen for reporting.
|
||||||
|
|
||||||
|
1.7.3
|
||||||
|
=====
|
||||||
|
Fixes:
|
||||||
|
------
|
||||||
|
* Fix potential double free, thanks @projectgus for reporting (see #241)
|
||||||
|
|
||||||
|
1.7.2
|
||||||
|
=====
|
||||||
|
Fixes:
|
||||||
|
------
|
||||||
|
* Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting (see #240)
|
||||||
|
|
||||||
1.7.1
|
1.7.1
|
||||||
=====
|
=====
|
||||||
Fixes:
|
Fixes:
|
||||||
|
|||||||
+12
-18
@@ -7,7 +7,7 @@ include(GNUInstallDirs)
|
|||||||
|
|
||||||
set(PROJECT_VERSION_MAJOR 1)
|
set(PROJECT_VERSION_MAJOR 1)
|
||||||
set(PROJECT_VERSION_MINOR 7)
|
set(PROJECT_VERSION_MINOR 7)
|
||||||
set(PROJECT_VERSION_PATCH 1)
|
set(PROJECT_VERSION_PATCH 5)
|
||||||
set(CJSON_VERSION_SO 1)
|
set(CJSON_VERSION_SO 1)
|
||||||
set(CJSON_UTILS_VERSION_SO 1)
|
set(CJSON_UTILS_VERSION_SO 1)
|
||||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||||
@@ -106,12 +106,6 @@ endforeach()
|
|||||||
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}")
|
||||||
|
|
||||||
#variables for pkg-config
|
|
||||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
|
||||||
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
|
||||||
set(version "${PROJECT_VERSION}")
|
|
||||||
set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
|
|
||||||
|
|
||||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
option(ENABLE_TARGET_EXPORT "Enable exporting of CMake targets. Disable when it causes problems!" ON)
|
option(ENABLE_TARGET_EXPORT "Enable exporting of CMake targets. Disable when it causes problems!" ON)
|
||||||
|
|
||||||
@@ -148,15 +142,15 @@ endif()
|
|||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in"
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" @ONLY)
|
"${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" @ONLY)
|
||||||
|
|
||||||
install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
|
install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
|
||||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
|
||||||
install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_LIB}")
|
install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_LIB}")
|
||||||
if (BUILD_SHARED_AND_STATIC_LIBS)
|
if (BUILD_SHARED_AND_STATIC_LIBS)
|
||||||
install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}")
|
||||||
endif()
|
endif()
|
||||||
if(ENABLE_TARGET_EXPORT)
|
if(ENABLE_TARGET_EXPORT)
|
||||||
# export library information for CMake projects
|
# export library information for CMake projects
|
||||||
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties("${CJSON_LIB}"
|
set_target_properties("${CJSON_LIB}"
|
||||||
@@ -187,15 +181,15 @@ if(ENABLE_CJSON_UTILS)
|
|||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in"
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY)
|
"${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY)
|
||||||
|
|
||||||
install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}")
|
install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}")
|
||||||
if (BUILD_SHARED_AND_STATIC_LIBS)
|
if (BUILD_SHARED_AND_STATIC_LIBS)
|
||||||
install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}")
|
||||||
endif()
|
endif()
|
||||||
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
|
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
|
||||||
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
|
||||||
if(ENABLE_TARGET_EXPORT)
|
if(ENABLE_TARGET_EXPORT)
|
||||||
# export library information for CMake projects
|
# export library information for CMake projects
|
||||||
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties("${CJSON_UTILS_LIB}"
|
set_target_properties("${CJSON_UTILS_LIB}"
|
||||||
@@ -215,7 +209,7 @@ configure_file(
|
|||||||
# Install package config files
|
# Install package config files
|
||||||
install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
|
install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
|
||||||
${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake
|
${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake
|
||||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
|
DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
|
||||||
|
|
||||||
option(ENABLE_CJSON_TEST "Enable building cJSON test" ON)
|
option(ENABLE_CJSON_TEST "Enable building cJSON test" ON)
|
||||||
if(ENABLE_CJSON_TEST)
|
if(ENABLE_CJSON_TEST)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
|
|||||||
* [Ajay Bhargav](https://github.com/ajaybhargav)
|
* [Ajay Bhargav](https://github.com/ajaybhargav)
|
||||||
* [Alper Akcan](https://github.com/alperakcan)
|
* [Alper Akcan](https://github.com/alperakcan)
|
||||||
* [Anton Sergeev](https://github.com/anton-sergeev)
|
* [Anton Sergeev](https://github.com/anton-sergeev)
|
||||||
|
* [Bob Kocisko](https://github.com/bobkocisko)
|
||||||
* [Christian Schulze](https://github.com/ChristianSch)
|
* [Christian Schulze](https://github.com/ChristianSch)
|
||||||
* [Casperinous](https://github.com/Casperinous)
|
* [Casperinous](https://github.com/Casperinous)
|
||||||
* [Debora Grosse](https://github.com/DeboraG)
|
* [Debora Grosse](https://github.com/DeboraG)
|
||||||
@@ -42,3 +43,5 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
|
|||||||
* [yangfl](https://github.com/yangfl)
|
* [yangfl](https://github.com/yangfl)
|
||||||
|
|
||||||
And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0)
|
And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0)
|
||||||
|
|
||||||
|
Also thanks to all the people who reported bugs and suggested new features.
|
||||||
@@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c
|
|||||||
|
|
||||||
LDLIBS = -lm
|
LDLIBS = -lm
|
||||||
|
|
||||||
LIBVERSION = 1.7.1
|
LIBVERSION = 1.7.5
|
||||||
CJSON_SOVERSION = 1
|
CJSON_SOVERSION = 1
|
||||||
UTILS_SOVERSION = 1
|
UTILS_SOVERSION = 1
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <float.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
|
/* 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 != 1)
|
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 5)
|
||||||
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -121,12 +119,13 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned
|
|||||||
typedef struct internal_context
|
typedef struct internal_context
|
||||||
{
|
{
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
|
size_t end_position;
|
||||||
|
void *userdata;
|
||||||
|
cJSON_Allocators allocators;
|
||||||
cJSON_bool format;
|
cJSON_bool format;
|
||||||
cJSON_bool allow_data_after_json;
|
cJSON_bool allow_data_after_json;
|
||||||
cJSON_bool case_sensitive;
|
cJSON_bool case_sensitive;
|
||||||
cJSON_Allocators allocators;
|
cJSON_bool duplicate_recursive;
|
||||||
void *userdata;
|
|
||||||
size_t end_position;
|
|
||||||
} internal_context;
|
} internal_context;
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
@@ -195,16 +194,17 @@ static void deallocate(const internal_context * const context, void *pointer)
|
|||||||
|
|
||||||
#define default_context {\
|
#define default_context {\
|
||||||
256, /* default buffer size */\
|
256, /* default buffer size */\
|
||||||
true, /* enable formatting by default */\
|
0, /* default end position */\
|
||||||
true, /* allow data after the JSON by default */\
|
NULL, /* no userdata */\
|
||||||
true, /* case sensitive by default */\
|
|
||||||
{\
|
{\
|
||||||
malloc_wrapper,\
|
malloc_wrapper,\
|
||||||
free_wrapper,\
|
free_wrapper,\
|
||||||
realloc_wrapper\
|
realloc_wrapper\
|
||||||
},\
|
},\
|
||||||
NULL, /* no userdata */\
|
true, /* enable formatting by default */\
|
||||||
0 /* default end position */\
|
true, /* allow data after the JSON by default */\
|
||||||
|
true, /* case sensitive by default */\
|
||||||
|
true /* Do cJSON_Duplicate recursively by default */\
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is necessary to assign the default context after initialization */
|
/* this is necessary to assign the default context after initialization */
|
||||||
@@ -340,9 +340,9 @@ typedef struct
|
|||||||
} parse_buffer;
|
} parse_buffer;
|
||||||
|
|
||||||
/* check if the given size is left to read in a given parse buffer (starting with 1) */
|
/* check if the given size is left to read in a given parse buffer (starting with 1) */
|
||||||
#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
|
#define can_read(buffer, size) (((buffer)->offset + (size)) <= (buffer)->length)
|
||||||
/* check if the buffer can be accessed at the given index (starting with 0) */
|
/* check if the buffer can be accessed at the given index (starting with 0) */
|
||||||
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
|
#define can_access_at_index(buffer, index) (((buffer)->offset + (index)) < (buffer)->length)
|
||||||
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
|
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
|
||||||
/* get a pointer to the buffer at the position */
|
/* get a pointer to the buffer at the position */
|
||||||
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
|
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
|
||||||
@@ -529,8 +529,8 @@ static void update_offset(printbuffer * const buffer)
|
|||||||
buffer->offset += strlen((const char*)buffer_pointer);
|
buffer->offset += strlen((const char*)buffer_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define is_nan(number) (number != number)
|
#define is_nan(number) ((number) != (number))
|
||||||
#define is_infinity(number) (!is_nan(number) && (number * 0) != 0)
|
#define is_infinity(number) (!is_nan(number) && ((number) * 0) != 0)
|
||||||
|
|
||||||
/* Render the number nicely from the given item into a string. */
|
/* Render the number nicely from the given item into a string. */
|
||||||
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
|
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
|
||||||
@@ -1038,6 +1038,7 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
|
|||||||
buffer->offset++;
|
buffer->offset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* step back if we went over the end */
|
||||||
if (buffer->offset == buffer->length)
|
if (buffer->offset == buffer->length)
|
||||||
{
|
{
|
||||||
buffer->offset--;
|
buffer->offset--;
|
||||||
@@ -1063,7 +1064,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse an object - create a new root, and populate. */
|
/* Parse an object - create a new root, and populate. */
|
||||||
static cJSON *parse(const char * const json, internal_context * const context)
|
static cJSON *parse(const char * const json, const size_t length, internal_context * const context)
|
||||||
{
|
{
|
||||||
parse_buffer buffer = { 0, 0, 0, 0, default_context };
|
parse_buffer buffer = { 0, 0, 0, 0, default_context };
|
||||||
cJSON *item = NULL;
|
cJSON *item = NULL;
|
||||||
@@ -1078,7 +1079,7 @@ static cJSON *parse(const char * const json, internal_context * const context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer.content = (const unsigned char*)json;
|
buffer.content = (const unsigned char*)json;
|
||||||
buffer.length = strlen((const char*)json) + sizeof("");
|
buffer.length = length;
|
||||||
buffer.offset = 0;
|
buffer.offset = 0;
|
||||||
buffer.context = *context;
|
buffer.context = *context;
|
||||||
|
|
||||||
@@ -1113,7 +1114,6 @@ fail:
|
|||||||
delete_item(item, context);
|
delete_item(item, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json != NULL)
|
|
||||||
{
|
{
|
||||||
error local_error;
|
error local_error;
|
||||||
local_error.json = (const unsigned char*)json;
|
local_error.json = (const unsigned char*)json;
|
||||||
@@ -1141,8 +1141,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_
|
|||||||
internal_context context = global_context;
|
internal_context context = global_context;
|
||||||
cJSON *item = NULL;
|
cJSON *item = NULL;
|
||||||
|
|
||||||
|
if (json == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
context.allow_data_after_json = !require_null_terminated;
|
context.allow_data_after_json = !require_null_terminated;
|
||||||
item = parse(json, &context);
|
item = parse(json, strlen((const char*)json) + sizeof(""), &context);
|
||||||
|
|
||||||
if (return_parse_end != NULL)
|
if (return_parse_end != NULL)
|
||||||
{
|
{
|
||||||
@@ -1155,10 +1160,15 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_
|
|||||||
/* Default options for cJSON_Parse */
|
/* Default options for cJSON_Parse */
|
||||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json)
|
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json)
|
||||||
{
|
{
|
||||||
return parse(json, &global_context);
|
if (json == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(json, strlen((const char*)json) + sizeof(""), &global_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define cjson_min(a, b) ((a < b) ? a : b)
|
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
static unsigned char *print(const cJSON * const item, const internal_context * const context)
|
static unsigned char *print(const cJSON * const item, const internal_context * const context)
|
||||||
{
|
{
|
||||||
@@ -1397,10 +1407,6 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
|
|||||||
size_t raw_length = 0;
|
size_t raw_length = 0;
|
||||||
if (item->valuestring == NULL)
|
if (item->valuestring == NULL)
|
||||||
{
|
{
|
||||||
if (!output_buffer->noalloc)
|
|
||||||
{
|
|
||||||
deallocate(&output_buffer->context, output_buffer->buffer);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2000,32 +2006,37 @@ static void* cast_away_const(const void* string)
|
|||||||
|
|
||||||
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_context * const context, const cJSON_bool constant_key)
|
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_context * const context, const cJSON_bool constant_key)
|
||||||
{
|
{
|
||||||
|
char *new_key = NULL;
|
||||||
|
int new_type = cJSON_Invalid;
|
||||||
|
|
||||||
if ((object == NULL) || (string == NULL) || (item == NULL))
|
if ((object == NULL) || (string == NULL) || (item == NULL))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (constant_key)
|
||||||
|
{
|
||||||
|
new_key = (char*)cast_away_const(string);
|
||||||
|
new_type = item->type | cJSON_StringIsConst;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_key = (char*)custom_strdup((const unsigned char*)string, context);
|
||||||
|
if (new_key == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_type = item->type & ~cJSON_StringIsConst;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
||||||
{
|
{
|
||||||
deallocate(context, item->string);
|
deallocate(context, item->string);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constant_key)
|
item->string = new_key;
|
||||||
{
|
item->type = new_type;
|
||||||
item->string = (char*)cast_away_const(string);
|
|
||||||
item->type |= cJSON_StringIsConst;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *key = (char*)custom_strdup((const unsigned char*)string, context);
|
|
||||||
if (key == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->string = key;
|
|
||||||
item->type &= ~cJSON_StringIsConst;
|
|
||||||
}
|
|
||||||
|
|
||||||
return add_item_to_array(object, item);
|
return add_item_to_array(object, item);
|
||||||
}
|
}
|
||||||
@@ -2638,56 +2649,60 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Duplication */
|
static cJSON *duplicate_json(const cJSON *item, const internal_context * const context)
|
||||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
|
|
||||||
{
|
{
|
||||||
cJSON *newitem = NULL;
|
cJSON *newitem = NULL;
|
||||||
cJSON *child = NULL;
|
cJSON *child = NULL;
|
||||||
cJSON *next = NULL;
|
cJSON *next = NULL;
|
||||||
cJSON *newchild = NULL;
|
cJSON *newchild = NULL;
|
||||||
|
|
||||||
/* Bail on bad ptr */
|
if (item == NULL)
|
||||||
if (!item)
|
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/* Create new item */
|
|
||||||
newitem = create_item(&global_context);
|
newitem = create_item(context);
|
||||||
if (!newitem)
|
if (newitem == NULL)
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy over all vars */
|
/* Copy over all vars */
|
||||||
newitem->type = item->type & (~cJSON_IsReference);
|
newitem->type = item->type & (~cJSON_IsReference);
|
||||||
newitem->valueint = item->valueint;
|
newitem->valueint = item->valueint;
|
||||||
newitem->valuedouble = item->valuedouble;
|
newitem->valuedouble = item->valuedouble;
|
||||||
if (item->valuestring)
|
|
||||||
|
if (item->valuestring != NULL)
|
||||||
{
|
{
|
||||||
newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_context);
|
newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, context);
|
||||||
if (!newitem->valuestring)
|
if (newitem->valuestring == NULL)
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item->string)
|
|
||||||
|
if (item->string != NULL)
|
||||||
{
|
{
|
||||||
newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, &global_context);
|
newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, context);
|
||||||
if (!newitem->string)
|
if (!newitem->string)
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If non-recursive, then we're done! */
|
/* If non-recursive, then we're done! */
|
||||||
if (!recurse)
|
if (!context->duplicate_recursive)
|
||||||
{
|
{
|
||||||
return newitem;
|
return newitem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Walk the ->next chain for the child. */
|
/* Walk the ->next chain for the child. */
|
||||||
child = item->child;
|
child = item->child;
|
||||||
while (child != NULL)
|
while (child != NULL)
|
||||||
{
|
{
|
||||||
newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
|
/* Each item in the ->next chain */
|
||||||
if (!newchild)
|
newchild = duplicate_json(child, context);
|
||||||
|
if (newchild == NULL)
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2712,12 +2727,19 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
|
|||||||
fail:
|
fail:
|
||||||
if (newitem != NULL)
|
if (newitem != NULL)
|
||||||
{
|
{
|
||||||
delete_item(newitem, &global_context);
|
delete_item(newitem, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
|
||||||
|
{
|
||||||
|
internal_context context = global_context;
|
||||||
|
context.duplicate_recursive = recurse;
|
||||||
|
return duplicate_json(item, &context);
|
||||||
|
}
|
||||||
|
|
||||||
CJSON_PUBLIC(void) cJSON_Minify(char *json)
|
CJSON_PUBLIC(void) cJSON_Minify(char *json)
|
||||||
{
|
{
|
||||||
unsigned char *into = (unsigned char*)json;
|
unsigned char *into = (unsigned char*)json;
|
||||||
@@ -3011,6 +3033,17 @@ CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSO
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CJSON_PUBLIC(cJSON_Context) cJSON_MakeDuplicateRecursive(cJSON_Context context, cJSON_bool recursive)
|
||||||
|
{
|
||||||
|
if (context == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
((internal_context*)context)->duplicate_recursive = recursive;
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_context * const context)
|
static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_context * const context)
|
||||||
{
|
{
|
||||||
if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
|
if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern "C"
|
|||||||
/* project version */
|
/* project version */
|
||||||
#define CJSON_VERSION_MAJOR 1
|
#define CJSON_VERSION_MAJOR 1
|
||||||
#define CJSON_VERSION_MINOR 7
|
#define CJSON_VERSION_MINOR 7
|
||||||
#define CJSON_VERSION_PATCH 1
|
#define CJSON_VERSION_PATCH 5
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -174,6 +174,8 @@ CJSON_PUBLIC(cJSON_Context) cJSON_SetFormat(cJSON_Context context, cJSON_Format
|
|||||||
CJSON_PUBLIC(cJSON_Context) cJSON_MakeCaseSensitive(cJSON_Context context, cJSON_bool case_sensitive);
|
CJSON_PUBLIC(cJSON_Context) cJSON_MakeCaseSensitive(cJSON_Context context, cJSON_bool case_sensitive);
|
||||||
/* Change if data is allowed after the JSON */
|
/* Change if data is allowed after the JSON */
|
||||||
CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSON_bool allow_data_after_json);
|
CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSON_bool allow_data_after_json);
|
||||||
|
/* Change if cJSON_Duplicate copies recursively */
|
||||||
|
CJSON_PUBLIC(cJSON_Context) cJSON_MakeDuplicateRecursive(cJSON_Context context, cJSON_bool recursive);
|
||||||
|
|
||||||
/* Supply malloc and free functions to cJSON globally */
|
/* Supply malloc and free functions to cJSON globally */
|
||||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||||
|
|||||||
@@ -988,6 +988,12 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_
|
|||||||
cJSON_AddItemToObject(parent, (char*)child_pointer, value);
|
cJSON_AddItemToObject(parent, (char*)child_pointer, value);
|
||||||
value = NULL;
|
value = NULL;
|
||||||
}
|
}
|
||||||
|
else /* parent is not an object */
|
||||||
|
{
|
||||||
|
/* Couldn't find object to add to. */
|
||||||
|
status = 9;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (value != NULL)
|
if (value != NULL)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
set(CJSON_UTILS_FOUND @ENABLE_CJSON_UTILS@)
|
set(CJSON_UTILS_FOUND @ENABLE_CJSON_UTILS@)
|
||||||
|
|
||||||
# The include directories used by cJSON
|
# The include directories used by cJSON
|
||||||
set(CJSON_INCLUDE_DIRS "@prefix@/@includedir@")
|
set(CJSON_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||||
set(CJSON_INCLUDE_DIR "@prefix@/@includedir@")
|
set(CJSON_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||||
|
|
||||||
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
prefix=@prefix@
|
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||||
libdir=${prefix}/@libdir@
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
includedir=${prefix}/@includedir@
|
|
||||||
|
|
||||||
Name: libcjson
|
Name: libcjson
|
||||||
Version: @version@
|
Version: @PROJECT_VERSION@
|
||||||
Description: Ultralightweight JSON parser in ANSI C
|
Description: Ultralightweight JSON parser in ANSI C
|
||||||
URL: https://github.com/DaveGamble/cJSON
|
URL: https://github.com/DaveGamble/cJSON
|
||||||
Libs: -L${libdir} -lcjson
|
Libs: -L${libdir} -lcjson
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
prefix=@prefix@
|
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||||
libdir=${prefix}/@libdir@
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
includedir=${prefix}/@includedir@
|
|
||||||
|
|
||||||
Name: libcjson_utils
|
Name: libcjson_utils
|
||||||
Version: @version@
|
Version: @PROJECT_VERSION@
|
||||||
Description: An implementation of JSON Pointer, Patch and Merge Patch based on cJSON.
|
Description: An implementation of JSON Pointer, Patch and Merge Patch based on cJSON.
|
||||||
URL: https://github.com/DaveGamble/cJSON
|
URL: https://github.com/DaveGamble/cJSON
|
||||||
Libs: -L${libdir} -lcjson_utils
|
Libs: -L${libdir} -lcjson_utils
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ static void create_context_should_create_a_context(void)
|
|||||||
TEST_ASSERT_TRUE_MESSAGE(context->case_sensitive, "case_sensitive has an incorrect value.");
|
TEST_ASSERT_TRUE_MESSAGE(context->case_sensitive, "case_sensitive has an incorrect value.");
|
||||||
TEST_ASSERT_TRUE_MESSAGE(context->allow_data_after_json, "allow_data_after_json has an incorrect value.");
|
TEST_ASSERT_TRUE_MESSAGE(context->allow_data_after_json, "allow_data_after_json has an incorrect value.");
|
||||||
TEST_ASSERT_NULL_MESSAGE(context->userdata, "Userdata should be NULL");
|
TEST_ASSERT_NULL_MESSAGE(context->userdata, "Userdata should be NULL");
|
||||||
|
TEST_ASSERT_TRUE_MESSAGE(context->duplicate_recursive, "Duplicating is not recursive.");
|
||||||
TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == context->allocators.allocate, "Wrong malloc.");
|
TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == context->allocators.allocate, "Wrong malloc.");
|
||||||
TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc.");
|
TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc.");
|
||||||
TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free.");
|
TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free.");
|
||||||
@@ -240,6 +241,18 @@ static void allow_data_after_json_should_change_allow_data_after_json(void)
|
|||||||
free(context);
|
free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void make_duplicate_recursive_should_make_duplicate_recursive(void)
|
||||||
|
{
|
||||||
|
internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL);
|
||||||
|
TEST_ASSERT_NOT_NULL(context);
|
||||||
|
|
||||||
|
context = (internal_context*)cJSON_MakeDuplicateRecursive(context, false);
|
||||||
|
TEST_ASSERT_NOT_NULL(context);
|
||||||
|
TEST_ASSERT_FALSE_MESSAGE(context->duplicate_recursive, "Duplicating is not set correctly.");
|
||||||
|
|
||||||
|
free(context);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
@@ -259,6 +272,7 @@ int main(void)
|
|||||||
RUN_TEST(set_format_should_set_format);
|
RUN_TEST(set_format_should_set_format);
|
||||||
RUN_TEST(make_case_sensitive_should_change_case_sensitivity);
|
RUN_TEST(make_case_sensitive_should_change_case_sensitivity);
|
||||||
RUN_TEST(allow_data_after_json_should_change_allow_data_after_json);
|
RUN_TEST(allow_data_after_json_should_change_allow_data_after_json);
|
||||||
|
RUN_TEST(make_duplicate_recursive_should_make_duplicate_recursive);
|
||||||
|
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
@@ -80,5 +80,12 @@
|
|||||||
"doc": { "foo": ["bar"] },
|
"doc": { "foo": ["bar"] },
|
||||||
"patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
|
"patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
|
||||||
"expected": {"foo": ["bar", ["abc", "def"]] }
|
"expected": {"foo": ["bar", ["abc", "def"]] }
|
||||||
}
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"comment": "15",
|
||||||
|
"doc": {"foo": {"bar": 1}},
|
||||||
|
"patch": [{"op": "add", "path": "/foo/bar/baz", "value": "5"}],
|
||||||
|
"error": "attempting to add to subfield of non-object"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
+22
-3
@@ -10,8 +10,7 @@
|
|||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
@@ -420,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata)
|
|||||||
|
|
||||||
static void ensure_should_fail_on_failed_realloc(void)
|
static void ensure_should_fail_on_failed_realloc(void)
|
||||||
{
|
{
|
||||||
printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } };
|
printbuffer buffer = {NULL, 10, 0, 0, false, {256, 0, NULL, {malloc_wrapper, free_wrapper, failing_realloc}, false, true, true, true} };
|
||||||
buffer.context.userdata = &buffer;
|
buffer.context.userdata = &buffer;
|
||||||
buffer.buffer = (unsigned char*)malloc(100);
|
buffer.buffer = (unsigned char*)malloc(100);
|
||||||
TEST_ASSERT_NOT_NULL(buffer.buffer);
|
TEST_ASSERT_NOT_NULL(buffer.buffer);
|
||||||
@@ -510,6 +509,25 @@ static void cjson_create_array_reference_should_create_an_array_reference(void)
|
|||||||
cJSON_Delete(number_reference);
|
cJSON_Delete(number_reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased(void)
|
||||||
|
{
|
||||||
|
cJSON *object = cJSON_CreateObject();
|
||||||
|
cJSON *number = cJSON_CreateNumber(42);
|
||||||
|
char *name = (char*)custom_strdup((const unsigned char*)"number", &global_context);
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_NULL(object);
|
||||||
|
TEST_ASSERT_NOT_NULL(number);
|
||||||
|
TEST_ASSERT_NOT_NULL(name);
|
||||||
|
|
||||||
|
number->string = name;
|
||||||
|
|
||||||
|
/* The following should not have a use after free
|
||||||
|
* that would show up in valgrind or with AddressSanitizer */
|
||||||
|
cJSON_AddItemToObject(object, number->string, number);
|
||||||
|
|
||||||
|
cJSON_Delete(object);
|
||||||
|
}
|
||||||
|
|
||||||
static void is_nan_should_detect_nan(void)
|
static void is_nan_should_detect_nan(void)
|
||||||
{
|
{
|
||||||
double nan = 0.0/0.0;
|
double nan = 0.0/0.0;
|
||||||
@@ -550,6 +568,7 @@ int main(void)
|
|||||||
RUN_TEST(cjson_create_string_reference_should_create_a_string_reference);
|
RUN_TEST(cjson_create_string_reference_should_create_a_string_reference);
|
||||||
RUN_TEST(cjson_create_object_reference_should_create_an_object_reference);
|
RUN_TEST(cjson_create_object_reference_should_create_an_object_reference);
|
||||||
RUN_TEST(cjson_create_array_reference_should_create_an_array_reference);
|
RUN_TEST(cjson_create_array_reference_should_create_an_array_reference);
|
||||||
|
RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
|
||||||
RUN_TEST(is_nan_should_detect_nan);
|
RUN_TEST(is_nan_should_detect_nan);
|
||||||
RUN_TEST(is_infinity_should_detect_infinity);
|
RUN_TEST(is_infinity_should_detect_infinity);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user