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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 122 additions & 29 deletions src/cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,12 @@
#endif

#ifndef NAN
#ifdef _WIN32
#define NAN sqrt(-1.0)
#else
#define NAN 0.0 / 0.0
#endif
#endif

typedef struct {
const unsigned char *json;
Expand Down Expand Up @@ -111,7 +115,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 != 14)
(CJSON_VERSION_PATCH != 19)
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif

Expand Down Expand Up @@ -243,10 +247,12 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) {
if (!(item->type & cJSON_IsReference) &&
(item->valuestring != NULL)) {
global_hooks.deallocate(item->valuestring);
item->valuestring = NULL;
}
if (!(item->type & cJSON_StringIsConst) &&
(item->string != NULL)) {
global_hooks.deallocate(item->string);
item->string = NULL;
}
global_hooks.deallocate(item);
item = next;
Expand Down Expand Up @@ -290,21 +296,21 @@ static cJSON_bool parse_number(cJSON *const item,
parse_buffer *const input_buffer) {
double number = 0;
unsigned char *after_end = NULL;
unsigned char number_c_string[64];
unsigned char decimal_point = get_decimal_point();
size_t i = 0;
unsigned char *number_c_string;
unsigned char decimal_point = get_decimal_point();
size_t i = 0;
size_t number_string_length = 0;
cJSON_bool has_decimal_point = false;

if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
return false;
}

/* copy the number into a temporary buffer and replace '.' with the
* decimal point of the current locale (for strtod)
* This also takes care of '\0' not necessarily being available for
* marking the end of the input */
for (i = 0; (i < (sizeof(number_c_string) - 1)) &&
can_access_at_index(input_buffer, i);
i++) {
* decimal point of the current locale (for strtod) This also takes care
* of '\0' not necessarily being available for marking the end of the
* input */
for (i = 0; can_access_at_index(input_buffer, i); i++) {
switch (buffer_at_offset(input_buffer)[i]) {
case '0':
case '1':
Expand All @@ -320,22 +326,44 @@ static cJSON_bool parse_number(cJSON *const item,
case '-':
case 'e':
case 'E':
number_c_string[i] = buffer_at_offset(input_buffer)[i];
number_string_length++;
break;

case '.':
number_c_string[i] = decimal_point;
number_string_length++;
has_decimal_point = true;
break;

default:
goto loop_end;
}
}
loop_end:
number_c_string[i] = '\0';
/* malloc for temporary buffer, add 1 for '\0' */
number_c_string = (unsigned char *)input_buffer->hooks.allocate(
number_string_length + 1);
if (number_c_string == NULL) {
return false; /* allocation failure */
}

memcpy(number_c_string, buffer_at_offset(input_buffer),
number_string_length);
number_c_string[number_string_length] = '\0';

if (has_decimal_point) {
for (i = 0; i < number_string_length; i++) {
if (number_c_string[i] == '.') {
/* replace '.' with the decimal point of the
* current locale (for strtod) */
number_c_string[i] = decimal_point;
}
}
}

number = strtod((const char *)number_c_string, (char **)&after_end);
if (number_c_string == after_end) {
/* free the temporary buffer */
input_buffer->hooks.deallocate(number_c_string);
return false; /* parse_error */
}

Expand All @@ -353,6 +381,8 @@ static cJSON_bool parse_number(cJSON *const item,
item->type = cJSON_Number;

input_buffer->offset += (size_t)(after_end - number_c_string);
/* free the temporary buffer */
input_buffer->hooks.deallocate(number_c_string);
return true;
}

Expand All @@ -370,16 +400,34 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) {
return object->valuedouble = 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) {
char *copy = NULL;
size_t v1_len;
size_t v2_len;
/* if object's type is not cJSON_String or is cJSON_IsReference, it
* should not set valuestring */
if (!(object->type & cJSON_String) ||
if ((object == NULL) || !(object->type & cJSON_String) ||
(object->type & cJSON_IsReference)) {
return NULL;
}
if (strlen(valuestring) <= strlen(object->valuestring)) {
/* return NULL if the object is corrupted or valuestring is NULL */
if (object->valuestring == NULL || valuestring == NULL) {
return NULL;
}

v1_len = strlen(valuestring);
v2_len = strlen(object->valuestring);

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);
return object->valuestring;
}
Expand Down Expand Up @@ -467,9 +515,8 @@ static unsigned char *ensure(printbuffer *const p, size_t needed) {

return NULL;
}
if (newbuffer) {
memcpy(newbuffer, p->buffer, p->offset + 1);
}

memcpy(newbuffer, p->buffer, p->offset + 1);
p->hooks.deallocate(p->buffer);
}
p->length = newsize;
Expand Down Expand Up @@ -515,6 +562,8 @@ static cJSON_bool print_number(const cJSON *const item,
/* This checks for NaN and Infinity */
if (isnan(d) || isinf(d)) {
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 */
Expand Down Expand Up @@ -809,6 +858,7 @@ static cJSON_bool parse_string(cJSON *const item,
fail:
if (output != NULL) {
input_buffer->hooks.deallocate(output);
output = NULL;
}

if (input_pointer != NULL) {
Expand Down Expand Up @@ -1137,17 +1187,20 @@ static unsigned char *print(const cJSON *const item,

/* free the buffer */
hooks->deallocate(buffer->buffer);
buffer->buffer = NULL;
}

return printed;

fail:
if (buffer->buffer != NULL) {
hooks->deallocate(buffer->buffer);
buffer->buffer = NULL;
}

if (printed != NULL) {
hooks->deallocate(printed);
printed = NULL;
}

return NULL;
Expand Down Expand Up @@ -1183,6 +1236,7 @@ cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) {

if (!print_value(item, &p)) {
global_hooks.deallocate(p.buffer);
p.buffer = NULL;
return NULL;
}

Expand Down Expand Up @@ -1527,6 +1581,10 @@ static cJSON_bool parse_object(cJSON *const item,
current_item = new_item;
}

if (cannot_access_at_index(input_buffer, 1)) {
goto fail; /* nothing comes after the comma */
}

/* parse the name of the child */
input_buffer->offset++;
buffer_skip_whitespace(input_buffer);
Expand Down Expand Up @@ -2033,7 +2091,8 @@ cJSON_AddArrayToObject(cJSON *const object, const char *const name) {

CJSON_PUBLIC(cJSON *)
cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item) {
if ((parent == NULL) || (item == NULL)) {
if ((parent == NULL) || (item == NULL) ||
(item != parent->child && item->prev == NULL)) {
return NULL;
}

Expand Down Expand Up @@ -2103,7 +2162,7 @@ CJSON_PUBLIC(cJSON_bool)
cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
cJSON *after_inserted = NULL;

if (which < 0) {
if (which < 0 || newitem == NULL) {
return false;
}

Expand All @@ -2112,6 +2171,11 @@ cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
return add_item_to_array(array, newitem);
}

if (after_inserted != array->child && after_inserted->prev == NULL) {
/* return false if after_inserted is a corrupted array item */
return false;
}

newitem->next = after_inserted;
newitem->prev = after_inserted->prev;
after_inserted->prev = newitem;
Expand All @@ -2127,7 +2191,8 @@ CJSON_PUBLIC(cJSON_bool)
cJSON_ReplaceItemViaPointer(cJSON *const parent,
cJSON *const item,
cJSON *replacement) {
if ((parent == NULL) || (replacement == NULL) || (item == NULL)) {
if ((parent == NULL) || (parent->child == NULL) ||
(replacement == NULL) || (item == NULL)) {
return false;
}

Expand Down Expand Up @@ -2191,6 +2256,10 @@ static cJSON_bool replace_item_in_object(cJSON *object,
}
replacement->string =
(char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
if (replacement->string == NULL) {
return false;
}

replacement->type &= ~cJSON_StringIsConst;

return cJSON_ReplaceItemViaPointer(
Expand Down Expand Up @@ -2356,6 +2425,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) {
}

a = cJSON_CreateArray();

for (i = 0; a && (i < (size_t)count); i++) {
n = cJSON_CreateNumber(numbers[i]);
if (!n) {
Expand All @@ -2369,7 +2439,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) {
}
p = n;
}
a->child->prev = n;

if (a && a->child) {
a->child->prev = n;
}

return a;
}
Expand Down Expand Up @@ -2399,7 +2472,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) {
}
p = n;
}
a->child->prev = n;

if (a && a->child) {
a->child->prev = n;
}

return a;
}
Expand Down Expand Up @@ -2430,7 +2506,10 @@ cJSON_CreateDoubleArray(const double *numbers, int count) {
}
p = n;
}
a->child->prev = n;

if (a && a->child) {
a->child->prev = n;
}

return a;
}
Expand Down Expand Up @@ -2461,13 +2540,23 @@ cJSON_CreateStringArray(const char *const *strings, int count) {
}
p = n;
}
a->child->prev = n;

if (a && a->child) {
a->child->prev = n;
}

return a;
}

/* Duplication */
cJSON *cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse);

CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) {
return cJSON_Duplicate_rec(item, 0, recurse);
}

cJSON *
cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse) {
cJSON *newitem = NULL;
cJSON *child = NULL;
cJSON *next = NULL;
Expand Down Expand Up @@ -2510,9 +2599,12 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) {
/* Walk the ->next chain for the child. */
child = item->child;
while (child != NULL) {
newchild = cJSON_Duplicate(
child, true); /* Duplicate (with recurse) each item in the
->next chain */
if (depth >= CJSON_CIRCULAR_LIMIT) {
goto fail;
}
newchild = cJSON_Duplicate_rec(
child, depth + 1, true); /* Duplicate (with recurse) each
item in the ->next chain */
if (!newchild) {
goto fail;
}
Expand Down Expand Up @@ -2713,7 +2805,7 @@ cJSON_Compare(const cJSON *const a,
const cJSON *const b,
const cJSON_bool case_sensitive) {
if ((a == NULL) || (b == NULL) ||
((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) {
((a->type & 0xFF) != (b->type & 0xFF))) {
return false;
}

Expand Down Expand Up @@ -2831,4 +2923,5 @@ CJSON_PUBLIC(void *) cJSON_malloc(size_t size) {

CJSON_PUBLIC(void) cJSON_free(void *object) {
global_hooks.deallocate(object);
object = NULL;
}
Loading