From 22ff3962884dcebab714478d727660c6da47f3ee Mon Sep 17 00:00:00 2001 From: Eyal Gal Date: Thu, 30 Apr 2020 20:58:08 +0300 Subject: [PATCH 1/4] adding string length to string objects there is an isssue with the strings in this library. on one hand when parsing the string it's parsed from \" till \" on the other hand when you want to actually get the data it's aviable but if you had something like this: "data\u0000\n" it's a problem since the \0 is before the end of the string. To solve the zero teminrated string i added an extra value stringvalue_len that can be retrived using a function that holds the length of the pased string. The length takes into account the parsing of special escaped chars. --- cJSON.c | 20 ++++++++++++++++++-- cJSON.h | 2 ++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 23270c48..d20cea50 100644 --- a/cJSON.c +++ b/cJSON.c @@ -102,6 +102,17 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) return item->valuestring; } +CJSON_PUBLIC(size_t) cJSON_GetStringValueLength(cJSON *item) +{ + if (!cJSON_IsString(item)) + { + return 0; + } + + return item->valuestring_len; +} + + CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) { if (!cJSON_IsNumber(item)) @@ -769,7 +780,9 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; unsigned char *output_pointer = NULL; + unsigned char *output_pointer_before = NULL; unsigned char *output = NULL; + size_t string_length = 0; /* not a string */ if (buffer_at_offset(input_buffer)[0] != '\"') @@ -808,8 +821,8 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu { goto fail; /* allocation failure */ } + string_length = allocation_length - sizeof("") + skipped_bytes; } - output_pointer = output; /* loop through the string literal */ while (input_pointer < input_end) @@ -852,26 +865,29 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* UTF-16 literal */ case 'u': + output_pointer_before = output_pointer; sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); if (sequence_length == 0) { /* failed to convert UTF16-literal to UTF-8 */ goto fail; } + string_length += (unsigned int)(output_pointer - output_pointer_before); break; default: goto fail; } input_pointer += sequence_length; + string_length -= sequence_length; } } /* zero terminate the output */ *output_pointer = '\0'; - item->type = cJSON_String; item->valuestring = (char*)output; + item->valuestring_len = string_length; input_buffer->offset = (size_t) (input_end - input_buffer->content); input_buffer->offset++; diff --git a/cJSON.h b/cJSON.h index 0c6c8e07..e482d34a 100644 --- a/cJSON.h +++ b/cJSON.h @@ -120,6 +120,7 @@ typedef struct cJSON /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ char *string; + size_t valuestring_len; } cJSON; typedef struct cJSON_Hooks @@ -177,6 +178,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* Check item type and return its value */ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); +CJSON_PUBLIC(size_t) cJSON_GetStringValueLength(cJSON *item); CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item); /* These functions check the type of an item */ From b508681b4d183bc98f4015abc48cb7636f65d084 Mon Sep 17 00:00:00 2001 From: Eyal Gal Date: Sun, 24 May 2020 18:50:37 +0300 Subject: [PATCH 2/4] fixed len issue with espaced non unicode sequance --- Makefile | 5 ++++- cJSON.c | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4e727b73..7ce253e8 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ UTILS_STATIC = $(UTILS_LIBNAME).$(STATIC) SHARED_CMD = $(CC) -shared -o -.PHONY: all shared static tests clean install +.PHONY: all shared static tests mytests clean install all: shared static tests @@ -79,6 +79,9 @@ tests: $(CJSON_TEST) test: tests ./$(CJSON_TEST) +mytests: cJSON.c mytest.c cJSON.h + gcc -std=c11 -ggdb3 $(R_CFLAGS) cJSON.c mytest.c -o $@ $(LDLIBS) -I. + .c.o: $(CC) -c $(R_CFLAGS) $< diff --git a/cJSON.c b/cJSON.c index d20cea50..bfbc2db2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -839,7 +839,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu { goto fail; } - + string_length++; switch (input_pointer[1]) { case 'b': @@ -872,7 +872,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* failed to convert UTF16-literal to UTF-8 */ goto fail; } - string_length += (unsigned int)(output_pointer - output_pointer_before); + string_length += (unsigned int)(output_pointer - output_pointer_before - 1); break; default: From a1108152302c814708da2ff4d305b77045b8b21d Mon Sep 17 00:00:00 2001 From: Eyal Gal Date: Sun, 24 May 2020 20:30:36 +0300 Subject: [PATCH 3/4] merge from origin master --- cJSON.c | 1 + mytest.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 mytest.c diff --git a/cJSON.c b/cJSON.c index bfbc2db2..a5c230f3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -885,6 +885,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* zero terminate the output */ *output_pointer = '\0'; + item->type = cJSON_String; item->valuestring = (char*)output; item->valuestring_len = string_length; diff --git a/mytest.c b/mytest.c new file mode 100644 index 00000000..ecfd3d38 --- /dev/null +++ b/mytest.c @@ -0,0 +1,30 @@ +#include "cJSON.h" +#include +#include + +char JSON_STR[] = "{ \"val\": \"\\u0000\\u0001\", \"vval\":true, \"test_plain\":\"\\r\\n\", \"plain_text\": \"i'm a text\"}"; +int main(void) { + printf("%s\n", JSON_STR); + cJSON *json = cJSON_Parse(JSON_STR); + if(json == NULL) { + printf("could not parse\n"); + return 1; + } + cJSON *json1 = cJSON_GetObjectItem(json, "val"); + if(json1 == NULL) { + printf("could not get val\n"); + } + printf("val is : *%s*\n", cJSON_GetStringValue(json1)); + cJSON *json2 = cJSON_GetObjectItem(json, "test_plain"); + if(json2 == NULL) { + printf("could not get val\n"); + } + printf("val is : *%s*\n", cJSON_GetStringValue(json2)); + cJSON *json3 = cJSON_GetObjectItem(json, "plain_text"); + if(json3 == NULL) { + printf("could not get val\n"); + } + printf("val is : *%s*\nlen is : %lu as opposed to: %lu\n", cJSON_GetStringValue(json3), json3->valuestring_len, strlen(json3->valuestring)); + cJSON_Delete(json); + return 0; +} From bab60ee563824cf6edc17c6bd57dd7c49b9ef55b Mon Sep 17 00:00:00 2001 From: Eyal Gal Date: Wed, 17 Jun 2020 09:58:53 +0300 Subject: [PATCH 4/4] adding support for int64 parsing --- Makefile | 2 +- cJSON.c | 10 ++++++++-- cJSON.h | 5 +++-- cJSON_Utils.c | 2 +- mytest.c | 7 ++++++- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 7ce253e8..b858861d 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ INSTALL_LIBRARY_PATH = $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) INSTALL ?= cp -a -CC = gcc -std=c89 +CC = gcc -std=c11 # validate gcc version for use fstack-protector-strong MIN_GCC_VERSION = "4.9" diff --git a/cJSON.c b/cJSON.c index a5c230f3..39ceaab9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -44,7 +44,7 @@ #include #include #include - +#include #ifdef ENABLE_LOCALES #include #endif @@ -312,6 +312,7 @@ typedef struct static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) { double number = 0; + uint64_t number64; unsigned char *after_end = NULL; unsigned char number_c_string[64]; unsigned char decimal_point = get_decimal_point(); @@ -378,7 +379,12 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu { item->valueint = (int)number; } - + number64 = strtoull((const char*)number_c_string, (char**)&after_end, 10); + if(number_c_string == after_end) + { + return false; + } + item->valueint64 = number64; item->type = cJSON_Number; input_buffer->offset += (size_t)(after_end - number_c_string); diff --git a/cJSON.h b/cJSON.h index e482d34a..b2dec41d 100644 --- a/cJSON.h +++ b/cJSON.h @@ -84,7 +84,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ #define CJSON_VERSION_PATCH 13 #include - +#include /* cJSON Types: */ #define cJSON_Invalid (0) #define cJSON_False (1 << 0) @@ -117,7 +117,7 @@ typedef struct cJSON int valueint; /* The item's number, if type==cJSON_Number */ double valuedouble; - + uint64_t valueint64; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ char *string; size_t valuestring_len; @@ -180,6 +180,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); CJSON_PUBLIC(size_t) cJSON_GetStringValueLength(cJSON *item); CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item); +CJSON_PUBLIC(long int) cJSON_Get64NumberValue(cJSON *item); /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); diff --git a/cJSON_Utils.c b/cJSON_Utils.c index c750f7fc..ecc6b862 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -836,7 +836,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ { if (opcode == REMOVE) { - static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL}; + static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, 0, NULL, 0}; overwrite_item(object, invalid); diff --git a/mytest.c b/mytest.c index ecfd3d38..34ebcfa0 100644 --- a/mytest.c +++ b/mytest.c @@ -2,7 +2,7 @@ #include #include -char JSON_STR[] = "{ \"val\": \"\\u0000\\u0001\", \"vval\":true, \"test_plain\":\"\\r\\n\", \"plain_text\": \"i'm a text\"}"; +char JSON_STR[] = "{ \"val\": \"\\u0000\\u0001\", \"vval\":true, \"test_plain\":\"\\r\\n\", \"plain_text\": \"i'm a text\", \"test_int64\": 18446744073709551610}"; int main(void) { printf("%s\n", JSON_STR); cJSON *json = cJSON_Parse(JSON_STR); @@ -24,6 +24,11 @@ int main(void) { if(json3 == NULL) { printf("could not get val\n"); } + cJSON *json4 = cJSON_GetObjectItem(json, "test_int64"); + printf("got int 64 val: %016lx\n", json4->valueint64); + double asDouble = cJSON_GetNumberValue(json4); + int asInt = json4->valueint; + printf("got val: %e %lx %u\n",asDouble, *((uint64_t*)&asDouble), asInt); printf("val is : *%s*\nlen is : %lu as opposed to: %lu\n", cJSON_GetStringValue(json3), json3->valuestring_len, strlen(json3->valuestring)); cJSON_Delete(json); return 0;