From 074766997246481dfc72bfa78f07898a2716473f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Feb 2017 22:09:04 +0100 Subject: [PATCH 1/4] parse_number: Switch to C library's strtod Replaces the hand written floating point parser with the C library implementation. --- cJSON.c | 71 +++++++++------------------------------------------------ 1 file changed, 11 insertions(+), 60 deletions(-) diff --git a/cJSON.c b/cJSON.c index b64e4e7..e2efd31 100644 --- a/cJSON.c +++ b/cJSON.c @@ -164,83 +164,34 @@ void cJSON_Delete(cJSON *c) /* Parse the input text to generate a number, and populate the result into item. */ static const unsigned char *parse_number(cJSON *item, const unsigned char *num) { - double n = 0; - double sign = 1; - double scale = 0; - int subscale = 0; - int signsubscale = 1; + double number = 0; + unsigned char *endpointer = NULL; - /* Has sign? */ - if (*num == '-') + number = strtod((const char*)num, (char**)&endpointer); + if ((num == endpointer) || (num == NULL)) { - sign = -1; - num++; - } - /* is zero */ - if (*num == '0') - { - num++; - } - /* Number? */ - if ((*num >= '1') && (*num <= '9')) - { - do - { - n = (n * 10.0) + (*num++ - '0'); - } - while ((*num >= '0') && (*num<='9')); - } - /* Fractional part? */ - if ((*num == '.') && (num[1] >= '0') && (num[1] <= '9')) - { - num++; - do - { - n = (n *10.0) + (*num++ - '0'); - scale--; - } while ((*num >= '0') && (*num <= '9')); - } - /* Exponent? */ - if ((*num == 'e') || (*num == 'E')) - { - num++; - /* With sign? */ - if (*num == '+') - { - num++; - } - else if (*num == '-') - { - signsubscale = -1; - num++; - } - /* Number? */ - while ((*num>='0') && (*num<='9')) - { - subscale = (subscale * 10) + (*num++ - '0'); - } + /* parse_error */ + return NULL; } - /* number = +/- number.fraction * 10^+/- exponent */ - n = sign * n * pow(10.0, (scale + subscale * signsubscale)); + item->valuedouble = number; - item->valuedouble = n; /* use saturation in case of overflow */ - if (n >= INT_MAX) + if (number >= INT_MAX) { item->valueint = INT_MAX; } - else if (n <= INT_MIN) + else if (number <= INT_MIN) { item->valueint = INT_MIN; } else { - item->valueint = (int)n; + item->valueint = (int)number; } item->type = cJSON_Number; - return num; + return endpointer; } /* calculate the next largest power of 2 */ From d7b5545748fde88ad6b67732308722a2565f5dcf Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 6 Feb 2017 23:01:18 +0100 Subject: [PATCH 2/4] parse_hex4: deduplicate into a for loop --- cJSON.c | 100 ++++++++++++++------------------------------------------ 1 file changed, 25 insertions(+), 75 deletions(-) diff --git a/cJSON.c b/cJSON.c index e2efd31..e0c1b57 100644 --- a/cJSON.c +++ b/cJSON.c @@ -362,84 +362,34 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) static unsigned parse_hex4(const unsigned char *str) { unsigned int h = 0; + size_t i = 0; - /* first digit */ - if ((*str >= '0') && (*str <= '9')) + for (i = 0; i < 4; i++) { - h += (unsigned int) (*str) - '0'; - } - else if ((*str >= 'A') && (*str <= 'F')) - { - h += (unsigned int) 10 + (*str) - 'A'; - } - else if ((*str >= 'a') && (*str <= 'f')) - { - h += (unsigned int) 10 + (*str) - 'a'; - } - else /* invalid */ - { - return 0; - } + /* parse digit */ + if ((*str >= '0') && (*str <= '9')) + { + h += (unsigned int) (*str) - '0'; + } + else if ((*str >= 'A') && (*str <= 'F')) + { + h += (unsigned int) 10 + (*str) - 'A'; + } + else if ((*str >= 'a') && (*str <= 'f')) + { + h += (unsigned int) 10 + (*str) - 'a'; + } + else /* invalid */ + { + return 0; + } - - /* second digit */ - h = h << 4; - str++; - if ((*str >= '0') && (*str <= '9')) - { - h += (unsigned int) (*str) - '0'; - } - else if ((*str >= 'A') && (*str <= 'F')) - { - h += (unsigned int) 10 + (*str) - 'A'; - } - else if ((*str >= 'a') && (*str <= 'f')) - { - h += (unsigned int) 10 + (*str) - 'a'; - } - else /* invalid */ - { - return 0; - } - - /* third digit */ - h = h << 4; - str++; - if ((*str >= '0') && (*str <= '9')) - { - h += (unsigned int) (*str) - '0'; - } - else if ((*str >= 'A') && (*str <= 'F')) - { - h += (unsigned int) 10 + (*str) - 'A'; - } - else if ((*str >= 'a') && (*str <= 'f')) - { - h += (unsigned int) 10 + (*str) - 'a'; - } - else /* invalid */ - { - return 0; - } - - /* fourth digit */ - h = h << 4; - str++; - if ((*str >= '0') && (*str <= '9')) - { - h += (unsigned int) (*str) - '0'; - } - else if ((*str >= 'A') && (*str <= 'F')) - { - h += (unsigned int) 10 + (*str) - 'A'; - } - else if ((*str >= 'a') && (*str <= 'f')) - { - h += (unsigned int) 10 + (*str) - 'a'; - } - else /* invalid */ - { - return 0; + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + str++; + } } return h; From dded75175796d70b8defbd9c6e5cf4f77d53add6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 6 Feb 2017 23:06:00 +0100 Subject: [PATCH 3/4] parse_string: remove useless first byte marks for utf8 --- cJSON.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index e0c1b57..c53f10e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -396,15 +396,13 @@ static unsigned parse_hex4(const unsigned char *str) } /* first bytes of UTF8 encoding for a given length in bytes */ -static const unsigned char firstByteMark[7] = +static const unsigned char firstByteMark[5] = { 0x00, /* should never happen */ 0x00, /* 0xxxxxxx */ 0xC0, /* 110xxxxx */ 0xE0, /* 1110xxxx */ - 0xF0, /* 11110xxx */ - 0xF8, - 0xFC + 0xF0 /* 11110xxx */ }; /* Parse the input text into an unescaped cstring, and populate item. */ From 87f77274de6b3af00fb9b9a7f3b900ef382296c2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 7 Feb 2017 00:05:27 +0100 Subject: [PATCH 4/4] cJSON_SetNumberValue: Fix undefined double to int conversion This might cause slight changes in behavior, but it shouldn't break anything that is not already broken (for example the original macro could either return a double, or an integer or whatever depending on if object is NULL or not.) --- cJSON.c | 19 +++++++++++++++++++ cJSON.h | 6 ++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index c53f10e..13d5a02 100644 --- a/cJSON.c +++ b/cJSON.c @@ -194,6 +194,25 @@ static const unsigned char *parse_number(cJSON *item, const unsigned char *num) return endpointer; } +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +double cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = cJSON_Number; + } + + return object->valuedouble = number; +} + /* calculate the next largest power of 2 */ static int pow2gt (int x) { diff --git a/cJSON.h b/cJSON.h index a9bf4f2..8502048 100644 --- a/cJSON.h +++ b/cJSON.h @@ -169,8 +169,10 @@ extern void cJSON_Minify(char *json); #define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) /* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val)) -#define cJSON_SetNumberValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val)) +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +extern double cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object) ? cJSON_SetNumberHelper(object, (double)number) : (number)) /* Macro for iterating over an array */ #define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)