mirror of
https://github.com/DaveGamble/cJSON.git
synced 2025-09-15 12:58:50 +08:00
Compare commits
3 Commits
c756cae93f
...
4318635d48
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4318635d48 | ||
|
|
c859b25da0 | ||
|
|
6f9d1f7dd6 |
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,3 +1,15 @@
|
||||
1.7.19 (Sep 9, 2025)
|
||||
======
|
||||
Fixes:
|
||||
------
|
||||
* Fix indentation (should use spaces), see #814
|
||||
* Fix spelling errors found by CodeSpell, see #841
|
||||
* Check for NULL in cJSON_DetachItemViaPointer, fixes #882, see #886
|
||||
* Fix #881, check overlap before calling strcpy in cJSON_SetValuestring, see #885
|
||||
* Fix #880 Max recursion depth for cJSON_Duplicate to prevent stack exhaustion, see #888
|
||||
* Allocate memory for the temporary buffer when paring numbers, see #939
|
||||
* fix the incorrect check in decode_array_index_from_pointer, see #957
|
||||
|
||||
1.7.18 (May 13, 2024)
|
||||
======
|
||||
Fixes:
|
||||
|
||||
@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(cJSON
|
||||
VERSION 1.7.18
|
||||
VERSION 1.7.19
|
||||
LANGUAGES C)
|
||||
|
||||
cmake_policy(SET CMP0054 NEW) # set CMP0054 policy
|
||||
|
||||
@ -24,6 +24,7 @@ Contributors:
|
||||
* [Debora Grosse](https://github.com/DeboraG)
|
||||
* [dieyushi](https://github.com/dieyushi)
|
||||
* [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang)
|
||||
* [Dominik](https://github.com/DL6ER)
|
||||
* [Donough Liu](https://github.com/ldm0)
|
||||
* [Erez Oxman](https://github.com/erez-o)
|
||||
* Eswar Yaganti
|
||||
@ -80,6 +81,8 @@ Contributors:
|
||||
* [Stephan Gatzka](https://github.com/gatzka)
|
||||
* [Tony Langhammer](https://github.com/BigBrainAFK)
|
||||
* [Vemake](https://github.com/vemakereporter)
|
||||
* [vwvw](https://github.com/vwvw)
|
||||
* [warmsocks](https://github.com/warmsocks)
|
||||
* [Wei Tan](https://github.com/tan-wei)
|
||||
* [Weston Schmidt](https://github.com/schmidtw)
|
||||
* [xiaomianhehe](https://github.com/xiaomianhehe)
|
||||
|
||||
2
Makefile
2
Makefile
@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c
|
||||
|
||||
LDLIBS = -lm
|
||||
|
||||
LIBVERSION = 1.7.18
|
||||
LIBVERSION = 1.7.19
|
||||
CJSON_SOVERSION = 1
|
||||
UTILS_SOVERSION = 1
|
||||
|
||||
|
||||
106
cJSON.c
106
cJSON.c
@ -106,6 +106,20 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
|
||||
return item->valuestring;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValueWithLength(const cJSON * const item, size_t *length)
|
||||
{
|
||||
if (!cJSON_IsString(item))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(length != NULL)
|
||||
{
|
||||
*length = item->valuestringlen;
|
||||
}
|
||||
return item->valuestring;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
|
||||
{
|
||||
if (!cJSON_IsNumber(item))
|
||||
@ -117,7 +131,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
|
||||
}
|
||||
|
||||
/* 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 != 18)
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 19)
|
||||
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
||||
#endif
|
||||
|
||||
@ -206,6 +220,26 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h
|
||||
return copy;
|
||||
}
|
||||
|
||||
static unsigned char* cJSON_strndup(const unsigned char* string, size_t length, const internal_hooks * const hooks)
|
||||
{
|
||||
unsigned char *copy = NULL;
|
||||
|
||||
if (string == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length += sizeof("");
|
||||
copy = (unsigned char*)hooks->allocate(length);
|
||||
if (copy == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
memcpy(copy, string, length);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (hooks == NULL)
|
||||
@ -428,6 +462,15 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
|
||||
|
||||
/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
|
||||
{
|
||||
if (valuestring == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return cJSON_SetValuestringWithLength(object, valuestring, strlen(valuestring));
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestringWithLength(cJSON *object, const char *valuestring, size_t valuestringlen)
|
||||
{
|
||||
char *copy = NULL;
|
||||
size_t v1_len;
|
||||
@ -443,20 +486,18 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v1_len = strlen(valuestring);
|
||||
v2_len = strlen(object->valuestring);
|
||||
v1_len = valuestringlen;
|
||||
v2_len = object->valuestringlen;
|
||||
|
||||
if (v1_len <= v2_len)
|
||||
{
|
||||
/* strcpy does not handle overlapping string: [X1, X2] [Y1, Y2] => X2 < Y1 or Y2 < X1 */
|
||||
if (!( valuestring + v1_len < object->valuestring || object->valuestring + v2_len < valuestring ))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
strcpy(object->valuestring, valuestring);
|
||||
/* memmove does handle overlapping string */
|
||||
memmove(object->valuestring, valuestring, valuestringlen);
|
||||
object->valuestring[valuestringlen] = '\0';
|
||||
object->valuestringlen = valuestringlen;
|
||||
return object->valuestring;
|
||||
}
|
||||
copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
|
||||
copy = (char*) cJSON_strndup((const unsigned char*)valuestring, valuestringlen, &global_hooks);
|
||||
if (copy == NULL)
|
||||
{
|
||||
return NULL;
|
||||
@ -466,6 +507,7 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
|
||||
cJSON_free(object->valuestring);
|
||||
}
|
||||
object->valuestring = copy;
|
||||
object->valuestringlen = valuestringlen;
|
||||
|
||||
return copy;
|
||||
}
|
||||
@ -924,6 +966,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
|
||||
|
||||
item->type = cJSON_String;
|
||||
item->valuestring = (char*)output;
|
||||
item->valuestringlen = (size_t) (output_pointer - output);
|
||||
|
||||
input_buffer->offset = (size_t) (input_end - input_buffer->content);
|
||||
input_buffer->offset++;
|
||||
@ -945,10 +988,10 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Render the cstring provided to an escaped version that can be printed. */
|
||||
static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
|
||||
static cJSON_bool print_string_len(const unsigned char * const input, const size_t input_length, printbuffer * const output_buffer)
|
||||
{
|
||||
const unsigned char *input_pointer = NULL;
|
||||
const unsigned char * const input_end = input + input_length;
|
||||
unsigned char *output = NULL;
|
||||
unsigned char *output_pointer = NULL;
|
||||
size_t output_length = 0;
|
||||
@ -974,7 +1017,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
|
||||
}
|
||||
|
||||
/* set "flag" to 1 if something needs to be escaped */
|
||||
for (input_pointer = input; *input_pointer; input_pointer++)
|
||||
for (input_pointer = input; input_pointer < input_end; input_pointer++)
|
||||
{
|
||||
switch (*input_pointer)
|
||||
{
|
||||
@ -1019,7 +1062,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
|
||||
output[0] = '\"';
|
||||
output_pointer = output + 1;
|
||||
/* copy the string */
|
||||
for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
|
||||
for (input_pointer = input; input_pointer < input_end; (void)input_pointer++, output_pointer++)
|
||||
{
|
||||
if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
|
||||
{
|
||||
@ -1067,10 +1110,16 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Invoke print_string_ptr (which is useful) on an item. */
|
||||
/* Render the cstring provided to an escaped version that can be printed. */
|
||||
static cJSON_bool print_string_ptr(const char * const input, printbuffer * const output_buffer)
|
||||
{
|
||||
return print_string_len((const unsigned char*)input, input ? strlen(input) : 0, output_buffer);
|
||||
}
|
||||
|
||||
/* Invoke print_string_len (which is useful) on an item. */
|
||||
static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
|
||||
{
|
||||
return print_string_ptr((unsigned char*)item->valuestring, p);
|
||||
return print_string_len((unsigned char*)item->valuestring, item->valuestringlen, p);
|
||||
}
|
||||
|
||||
/* Predeclare these prototypes. */
|
||||
@ -1464,7 +1513,7 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
|
||||
return false;
|
||||
}
|
||||
|
||||
raw_length = strlen(item->valuestring) + sizeof("");
|
||||
raw_length = item->valuestringlen + sizeof("");
|
||||
output = ensure(output_buffer, raw_length);
|
||||
if (output == NULL)
|
||||
{
|
||||
@ -1812,7 +1861,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
|
||||
}
|
||||
|
||||
/* print key */
|
||||
if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
|
||||
if (!print_string_ptr(current_item->string, output_buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2514,12 +2563,18 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
|
||||
{
|
||||
return cJSON_CreateStringWithLength(string, string ? strlen(string) : 0);
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, size_t length)
|
||||
{
|
||||
cJSON *item = cJSON_New_Item(&global_hooks);
|
||||
if(item)
|
||||
{
|
||||
item->type = cJSON_String;
|
||||
item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
|
||||
item->valuestringlen = length;
|
||||
item->valuestring = (char*)cJSON_strndup((const unsigned char*)string, length, &global_hooks);
|
||||
if(!item->valuestring)
|
||||
{
|
||||
cJSON_Delete(item);
|
||||
@ -2537,6 +2592,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
|
||||
{
|
||||
item->type = cJSON_String | cJSON_IsReference;
|
||||
item->valuestring = (char*)cast_away_const(string);
|
||||
item->valuestringlen = strlen(string);
|
||||
}
|
||||
|
||||
return item;
|
||||
@ -2569,7 +2625,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
|
||||
if(item)
|
||||
{
|
||||
item->type = cJSON_Raw;
|
||||
item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
|
||||
item->valuestringlen = raw ? strlen(raw) : 0;
|
||||
item->valuestring = (char*)cJSON_strndup((const unsigned char*)raw, item->valuestringlen, &global_hooks);
|
||||
if(!item->valuestring)
|
||||
{
|
||||
cJSON_Delete(item);
|
||||
@ -2795,7 +2852,8 @@ cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
|
||||
newitem->valuedouble = item->valuedouble;
|
||||
if (item->valuestring)
|
||||
{
|
||||
newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
|
||||
newitem->valuestringlen = item->valuestringlen;
|
||||
newitem->valuestring = (char*)cJSON_strndup((unsigned char*)item->valuestring, item->valuestringlen, &global_hooks);
|
||||
if (!newitem->valuestring)
|
||||
{
|
||||
goto fail;
|
||||
@ -3105,7 +3163,11 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (strcmp(a->valuestring, b->valuestring) == 0)
|
||||
if (a->valuestringlen != b->valuestringlen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (memcmp(a->valuestring, b->valuestring, a->valuestringlen) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
7
cJSON.h
7
cJSON.h
@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
#define CJSON_VERSION_PATCH 19
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@ -113,6 +113,8 @@ typedef struct cJSON
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* Length of the item's string, useful for handling "\u0000" in string */
|
||||
size_t valuestringlen;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
@ -183,6 +185,7 @@ 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(char *) cJSON_GetStringValueWithLength(const cJSON * const item, size_t *length);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
@ -204,6 +207,7 @@ 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_CreateString(const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, size_t length);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
@ -284,6 +288,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)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);
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestringWithLength(cJSON *object, const char *valuestring, size_t valuestringlen);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
|
||||
@ -238,7 +238,7 @@ static void cjson_should_not_follow_too_deep_circular_references(void)
|
||||
|
||||
static void cjson_set_number_value_should_set_numbers(void)
|
||||
{
|
||||
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}};
|
||||
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, 0, NULL}};
|
||||
|
||||
cJSON_SetNumberValue(number, 1.5);
|
||||
TEST_ASSERT_EQUAL(1, number->valueint);
|
||||
@ -360,7 +360,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void)
|
||||
|
||||
static void cjson_replace_item_in_object_should_preserve_name(void)
|
||||
{
|
||||
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, NULL}};
|
||||
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL}};
|
||||
cJSON *child = NULL;
|
||||
cJSON *replacement = NULL;
|
||||
cJSON_bool flag = false;
|
||||
@ -498,11 +498,10 @@ static void cjson_set_valuestring_should_return_null_if_strings_overlap(void)
|
||||
|
||||
str = cJSON_SetValuestring(obj, "abcde");
|
||||
str += 1;
|
||||
/* The string passed to strcpy overlap which is not allowed.*/
|
||||
/* The string passed to strcpy overlap which is correctly copied.*/
|
||||
str2 = cJSON_SetValuestring(obj, str);
|
||||
/* If it overlaps, the string will be messed up.*/
|
||||
TEST_ASSERT_TRUE(strcmp(str, "bcde") == 0);
|
||||
TEST_ASSERT_NULL(str2);
|
||||
/* If it overlaps, the string will not be messed up.*/
|
||||
TEST_ASSERT_TRUE(strncmp(str2, "bcde", 4) == 0);
|
||||
cJSON_Delete(obj);
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ static void assert_print_string(const char *expected, const char *input)
|
||||
buffer.noalloc = true;
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string.");
|
||||
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr(input, &buffer), "Failed to print string.");
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected.");
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user