diff --git a/cJSON.c b/cJSON.c index 56f65efe..91507e61 100644 --- a/cJSON.c +++ b/cJSON.c @@ -185,27 +185,38 @@ static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +static char* cJSON_strndup(const char* string, const size_t length, const internal_hooks * const hooks) { - size_t length = 0; - unsigned char *copy = NULL; + char *copy = NULL; - if (string == NULL) + if ((string == NULL) && (length > 0)) { return NULL; } - length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)hooks->allocate(length); + /* allocate an extra byte for the null terminator */ + copy = (char *) hooks->allocate(length + 1); if (copy == NULL) { return NULL; } memcpy(copy, string, length); + copy[length] = '\0'; return copy; } +static char* cJSON_strdup(const char *string, const internal_hooks * const hooks) +{ + if (string == NULL) + { + return NULL; + } + + return cJSON_strndup(string, strlen(string), hooks); +} + + CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { if (hooks == NULL) @@ -429,7 +440,7 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) strcpy(object->valuestring, valuestring); return object->valuestring; } - copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + copy = cJSON_strndup(valuestring, v1_len, &global_hooks); if (copy == NULL) { return NULL; @@ -1461,6 +1472,7 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp } } + /* Build an array from input text. */ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) { @@ -2054,7 +2066,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st } else { - new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + new_key = cJSON_strdup(string, hooks); if (new_key == NULL) { return false; @@ -2394,7 +2406,7 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO { cJSON_free(replacement->string); } - replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->string = cJSON_strdup(string, &global_hooks); if (replacement->string == NULL) { return false; @@ -2486,23 +2498,32 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) return item; } -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, const size_t length) { cJSON *item = cJSON_New_Item(&global_hooks); - if(item) + if (item) { item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if(!item->valuestring) + item->valuestring = cJSON_strndup(string, length, &global_hooks); + if (!item->valuestring) { cJSON_Delete(item); return NULL; } } - return item; } +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + if (string == NULL) + { + return NULL; + } + + return cJSON_CreateStringWithLength(string, strlen(string)); +} + CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) { cJSON *item = cJSON_New_Item(&global_hooks); @@ -2536,14 +2557,14 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { return item; } -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +CJSON_PUBLIC(cJSON *) cJSON_CreateRawWithLength(const char *raw, const size_t length) { cJSON *item = cJSON_New_Item(&global_hooks); - if(item) + if (item) { item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if(!item->valuestring) + item->valuestring = cJSON_strndup(raw, length, &global_hooks); + if (!item->valuestring) { cJSON_Delete(item); return NULL; @@ -2553,6 +2574,16 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) return item; } +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + if (raw == NULL) + { + return NULL; + } + + return cJSON_CreateRawWithLength(raw, strlen(raw)); +} + CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) { cJSON *item = cJSON_New_Item(&global_hooks); @@ -2761,7 +2792,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) newitem->valuedouble = item->valuedouble; if (item->valuestring) { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + newitem->valuestring = cJSON_strdup(item->valuestring, &global_hooks); if (!newitem->valuestring) { goto fail; @@ -2769,7 +2800,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) } if (item->string) { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : cJSON_strdup(item->string, &global_hooks); if (!newitem->string) { goto fail; diff --git a/cJSON.h b/cJSON.h index 88cf0bcf..42327479 100644 --- a/cJSON.h +++ b/cJSON.h @@ -198,8 +198,10 @@ 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_CreateRawWithLength(const char *raw, size_t length); CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 606b4603..7023696e 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -409,7 +409,9 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) TEST_ASSERT_FALSE(cJSON_IsObject(NULL)); TEST_ASSERT_FALSE(cJSON_IsRaw(NULL)); TEST_ASSERT_NULL(cJSON_CreateString(NULL)); + TEST_ASSERT_NULL(cJSON_CreateStringWithLength(NULL, 10)); TEST_ASSERT_NULL(cJSON_CreateRaw(NULL)); + TEST_ASSERT_NULL(cJSON_CreateRawWithLength(NULL, 10)); TEST_ASSERT_NULL(cJSON_CreateIntArray(NULL, 10)); TEST_ASSERT_NULL(cJSON_CreateFloatArray(NULL, 10)); TEST_ASSERT_NULL(cJSON_CreateDoubleArray(NULL, 10)); @@ -555,6 +557,32 @@ static void cjson_get_number_value_should_get_a_number(void) cJSON_Delete(string); } +static void cjson_create_string_with_length_should_create_a_string(void) +{ + cJSON *string = cJSON_CreateStringWithLength("testtest", 4); + cJSON *stringNull = cJSON_CreateStringWithLength(NULL, 0); + TEST_ASSERT_EQUAL_INT(cJSON_String, string->type); + TEST_ASSERT_TRUE(strcmp(string->valuestring, "test") == 0); + TEST_ASSERT_NOT_NULL(stringNull); + TEST_ASSERT_EQUAL_INT(cJSON_String, stringNull->type); + TEST_ASSERT_TRUE(strcmp(stringNull->valuestring, "") == 0); + cJSON_Delete(string); + cJSON_Delete(stringNull); +} + +static void cjson_create_raw_with_length_should_create_a_string(void) +{ + cJSON *raw = cJSON_CreateRawWithLength("testtest", 4); + cJSON *rawNull = cJSON_CreateRawWithLength(NULL, 0); + TEST_ASSERT_EQUAL_INT(cJSON_Raw, raw->type); + TEST_ASSERT_TRUE(strcmp(raw->valuestring, "test") == 0); + TEST_ASSERT_NOT_NULL(rawNull); + TEST_ASSERT_EQUAL_INT(cJSON_Raw, rawNull->type); + TEST_ASSERT_TRUE(strcmp(rawNull->valuestring, "") == 0); + cJSON_Delete(raw); + cJSON_Delete(rawNull); +} + static void cjson_create_string_reference_should_create_a_string_reference(void) { const char *string = "I am a string!"; @@ -623,7 +651,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al { cJSON *object = cJSON_CreateObject(); cJSON *number = cJSON_CreateNumber(42); - char *name = (char *)cJSON_strdup((const unsigned char *)"number", &global_hooks); + char *name = cJSON_strdup("number", &global_hooks); TEST_ASSERT_NOT_NULL(object); TEST_ASSERT_NOT_NULL(number); @@ -789,6 +817,8 @@ int CJSON_CDECL main(void) RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(cjson_get_string_value_should_get_a_string); RUN_TEST(cjson_get_number_value_should_get_a_number); + RUN_TEST(cjson_create_string_with_length_should_create_a_string); + RUN_TEST(cjson_create_raw_with_length_should_create_a_string); 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_array_reference_should_create_an_array_reference);