From 7c722dca5f7d67ce81c5d3fa497a912f4e9cb08f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 17 Feb 2017 13:59:26 +0100 Subject: [PATCH 01/73] CMake: Add target "check" that builds and runs tests --- tests/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c3721279..27d6900b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,6 +29,11 @@ if(ENABLE_CJSON_TEST) endif() endif() + #"check" target that automatically builds everything and runs the tests + add_custom_target(check + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + DEPENDS ${unity_tests}) + foreach(unity_test ${unity_tests}) add_executable("${unity_test}" "${unity_test}.c") target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common) From bd073343faa7418d74ed7a87ee32054e1aff1c0f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 17 Feb 2017 19:37:31 +0100 Subject: [PATCH 02/73] rename skip -> skip_whitespace --- cJSON.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cJSON.c b/cJSON.c index c3d1a4e1..7808278a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -819,7 +819,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); /* Utility to jump whitespace and cr/lf */ -static const unsigned char *skip(const unsigned char *in) +static const unsigned char *skip_whitespace(const unsigned char *in) { while (in && *in && (*in <= 32)) { @@ -842,7 +842,7 @@ cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjb return NULL; } - end = parse_value(c, skip((const unsigned char*)value), ep); + end = parse_value(c, skip_whitespace((const unsigned char*)value), ep); if (!end) { /* parse failure. ep is set. */ @@ -853,7 +853,7 @@ cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjb /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ if (require_null_terminated) { - end = skip(end); + end = skip_whitespace(end); if (*end) { cJSON_Delete(c); @@ -1100,7 +1100,7 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char goto fail; } - input = skip(input + 1); /* skip whitespace */ + input = skip_whitespace(input + 1); if (*input == ']') { /* empty array */ @@ -1134,9 +1134,9 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char } /* parse next value */ - input = skip(input + 1); /* skip whitespace before value */ + input = skip_whitespace(input + 1); input = parse_value(current_item, input, error_pointer); - input = skip(input); /* skip whitespace after value */ + input = skip_whitespace(input); if (input == NULL) { goto fail; /* failed to parse value */ @@ -1346,7 +1346,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char goto fail; /* not an object */ } - input = skip(input + 1); /* skip whitespace */ + input = skip_whitespace(input + 1); if (*input == '}') { goto success; /* empty object */ @@ -1379,9 +1379,9 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* parse the name of the child */ - input = skip(input + 1); /* skip whitespaces before name */ + input = skip_whitespace(input + 1); input = parse_string(current_item, input, error_pointer); - input = skip(input); /* skip whitespaces after name */ + input = skip_whitespace(input); if (input == NULL) { goto fail; /* faile to parse name */ @@ -1398,9 +1398,9 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* parse the value */ - input = skip(input + 1); /* skip whitespaces before value */ + input = skip_whitespace(input + 1); input = parse_value(current_item, input, error_pointer); - input = skip(input); /* skip whitespaces after the value */ + input = skip_whitespace(input); if (input == NULL) { goto fail; /* failed to parse value */ From fc1d4b07df7ee98c6b2814d12fd6cec69d4cb481 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 03:17:57 +0100 Subject: [PATCH 03/73] ensure: if printbuffer is null: cJSON_malloc This allowed for the removal of a lot of if (p) checks. --- cJSON.c | 123 +++++++++++++++++--------------------------------------- 1 file changed, 36 insertions(+), 87 deletions(-) diff --git a/cJSON.c b/cJSON.c index 7808278a..c3a3d108 100644 --- a/cJSON.c +++ b/cJSON.c @@ -223,13 +223,18 @@ static unsigned char* ensure(printbuffer *p, size_t needed) unsigned char *newbuffer = NULL; size_t newsize = 0; + if (p == NULL) + { + return (unsigned char*)cJSON_malloc(needed); + } + if (needed > INT_MAX) { /* sizes bigger than INT_MAX are currently not supported */ return NULL; } - if (!p || !p->buffer) + if (p->buffer == NULL) { return NULL; } @@ -299,15 +304,8 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) /* special case for 0. */ if (d == 0) { - if (p) - { - str = ensure(p, 2); - } - else - { - str = (unsigned char*)cJSON_malloc(2); - } - if (str) + str = ensure(p, 2); + if (str != NULL) { strcpy((char*)str,"0"); } @@ -315,16 +313,9 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) /* value is an int */ else if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { - if (p) - { - str = ensure(p, 21); - } - else - { /* 2^64+1 can be represented in 21 chars. */ - str = (unsigned char*)cJSON_malloc(21); - } - if (str) + str = ensure(p, 21); + if (str != NULL) { sprintf((char*)str, "%d", item->valueint); } @@ -332,17 +323,9 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) /* value is a floating point number */ else { - if (p) - { - /* This is a nice tradeoff. */ - str = ensure(p, 64); - } - else - { - /* This is a nice tradeoff. */ - str = (unsigned char*)cJSON_malloc(64); - } - if (str) + /* This is a nice tradeoff. */ + str = ensure(p, 64); + if (str != NULL) { /* This checks for NaN and Infinity */ if ((d * 0) != 0) @@ -671,15 +654,8 @@ static unsigned char *print_string_ptr(const unsigned char *str, printbuffer *p) /* empty string */ if (!str) { - if (p) - { - out = ensure(p, 3); - } - else - { - out = (unsigned char*)cJSON_malloc(3); - } - if (!out) + out = ensure(p, 3); + if (out == NULL) { return NULL; } @@ -701,15 +677,9 @@ static unsigned char *print_string_ptr(const unsigned char *str, printbuffer *p) if (!flag) { len = (size_t)(ptr - str); - if (p) - { - out = ensure(p, len + 3); - } - else - { - out = (unsigned char*)cJSON_malloc(len + 3); - } - if (!out) + + out = ensure(p, len + 3); + if (out == NULL) { return NULL; } @@ -739,15 +709,8 @@ static unsigned char *print_string_ptr(const unsigned char *str, printbuffer *p) ptr++; } - if (p) - { - out = ensure(p, len + 3); - } - else - { - out = (unsigned char*)cJSON_malloc(len + 3); - } - if (!out) + out = ensure(p, len + 3); + if (out == NULL) { return NULL; } @@ -993,21 +956,21 @@ static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, p { case cJSON_NULL: out = ensure(p, 5); - if (out) + if (out != NULL) { strcpy((char*)out, "null"); } break; case cJSON_False: out = ensure(p, 6); - if (out) + if (out != NULL) { strcpy((char*)out, "false"); } break; case cJSON_True: out = ensure(p, 5); - if (out) + if (out != NULL) { strcpy((char*)out, "true"); } @@ -1030,7 +993,7 @@ static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, p raw_length = strlen(item->valuestring) + sizeof('\0'); out = ensure(p, raw_length); - if (out) + if (out != NULL) { memcpy(out, item->valuestring, raw_length); } @@ -1189,15 +1152,8 @@ static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, p /* Explicitly handle numentries == 0 */ if (!numentries) { - if (p) - { - out = ensure(p, 3); - } - else - { - out = (unsigned char*)cJSON_malloc(3); - } - if (out) + out = ensure(p, 3); + if (out != NULL) { strcpy((char*)out, "[]"); } @@ -1211,7 +1167,7 @@ static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, p /* opening square bracket */ i = p->offset; ptr = ensure(p, 1); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1230,7 +1186,7 @@ static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, p { len = fmt ? 2 : 1; ptr = ensure(p, len + 1); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1245,7 +1201,7 @@ static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, p child = child->next; } ptr = ensure(p, 2); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1456,15 +1412,8 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, /* Explicitly handle empty object case */ if (!numentries) { - if (p) - { - out = ensure(p, fmt ? depth + 4 : 3); - } - else - { - out = (unsigned char*)cJSON_malloc(fmt ? depth + 4 : 3); - } - if (!out) + out = ensure(p, fmt ? depth + 4 : 3); + if (out == NULL) { return NULL; } @@ -1489,7 +1438,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, i = p->offset; len = fmt ? 2 : 1; /* fmt: {\n */ ptr = ensure(p, len + 1); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1509,7 +1458,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, if (fmt) { ptr = ensure(p, depth); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1529,7 +1478,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, len = fmt ? 2 : 1; ptr = ensure(p, len); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1550,7 +1499,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, /* print comma if not last */ len = (size_t) (fmt ? 1 : 0) + (child->next ? 1 : 0); ptr = ensure(p, len + 1); - if (!ptr) + if (ptr == NULL) { return NULL; } @@ -1570,7 +1519,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, } ptr = ensure(p, fmt ? (depth + 1) : 2); - if (!ptr) + if (ptr == NULL) { return NULL; } From 4fff92140e1a1b74619a26f4abfc480e5d887c4a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 03:31:08 +0100 Subject: [PATCH 04/73] ensure: use realloc if possible --- cJSON.c | 53 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/cJSON.c b/cJSON.c index c3a3d108..4b5005a4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -81,6 +81,7 @@ static int cJSON_strcasecmp(const unsigned char *s1, const unsigned char *s2) static void *(*cJSON_malloc)(size_t sz) = malloc; static void (*cJSON_free)(void *ptr) = free; +static void *(*cJSON_realloc)(void *pointer, size_t size) = realloc; static unsigned char* cJSON_strdup(const unsigned char* str) { @@ -104,16 +105,33 @@ static unsigned char* cJSON_strdup(const unsigned char* str) void cJSON_InitHooks(cJSON_Hooks* hooks) { - if (!hooks) + if (hooks == NULL) { /* Reset hooks */ cJSON_malloc = malloc; cJSON_free = free; + cJSON_realloc = realloc; return; } - cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc; - cJSON_free = (hooks->free_fn) ? hooks->free_fn : free; + cJSON_malloc = malloc; + if (hooks->malloc_fn != NULL) + { + cJSON_malloc = hooks->malloc_fn; + } + + cJSON_free = free; + if (hooks->free_fn != NULL) + { + cJSON_free = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + cJSON_realloc = NULL; + if ((cJSON_malloc == malloc) && (cJSON_free == free)) + { + cJSON_realloc = realloc; + } } /* Internal constructor. */ @@ -263,20 +281,29 @@ static unsigned char* ensure(printbuffer *p, size_t needed) } } - newbuffer = (unsigned char*)cJSON_malloc(newsize); - if (!newbuffer) + if (cJSON_realloc != NULL) { - cJSON_free(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)cJSON_realloc(p->buffer, newsize); } - if (newbuffer) + else { - memcpy(newbuffer, p->buffer, p->length); + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)cJSON_malloc(newsize); + if (!newbuffer) + { + cJSON_free(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->length); + } + cJSON_free(p->buffer); } - cJSON_free(p->buffer); p->length = newsize; p->buffer = newbuffer; From 331c18d09a7bd2fcda91fcdb025178ec8d3a2720 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 11:58:24 +0100 Subject: [PATCH 05/73] ensure: only memcopy what's necessary We don't need to copy the entire printbuffer, only the part that is used. --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 4b5005a4..89943b5d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -300,7 +300,7 @@ static unsigned char* ensure(printbuffer *p, size_t needed) } if (newbuffer) { - memcpy(newbuffer, p->buffer, p->length); + memcpy(newbuffer, p->buffer, p->offset + 1); } cJSON_free(p->buffer); } From 0e0cd5bae53daf71a420abd8501861b2d12ecd03 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 17 Feb 2017 15:48:50 +0100 Subject: [PATCH 06/73] CMake: Add ENABLE_FUZZING and "afl" target --- CMakeLists.txt | 2 +- fuzzing/.gitignore | 1 + fuzzing/CMakeLists.txt | 21 ++++++++ fuzzing/afl.c | 117 +++++++++++++++++++++++++++++++++++++++++ fuzzing/afl.sh | 9 ++++ fuzzing/inputs/test1 | 22 ++++++++ fuzzing/inputs/test10 | 1 + fuzzing/inputs/test11 | 8 +++ fuzzing/inputs/test2 | 11 ++++ fuzzing/inputs/test3 | 26 +++++++++ fuzzing/inputs/test4 | 88 +++++++++++++++++++++++++++++++ fuzzing/inputs/test5 | 27 ++++++++++ fuzzing/inputs/test6 | 16 ++++++ fuzzing/inputs/test7 | 22 ++++++++ fuzzing/inputs/test8 | 13 +++++ fuzzing/inputs/test9 | 5 ++ fuzzing/json.dict | 47 +++++++++++++++++ 17 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 fuzzing/.gitignore create mode 100644 fuzzing/CMakeLists.txt create mode 100644 fuzzing/afl.c create mode 100755 fuzzing/afl.sh create mode 100644 fuzzing/inputs/test1 create mode 100644 fuzzing/inputs/test10 create mode 100644 fuzzing/inputs/test11 create mode 100644 fuzzing/inputs/test2 create mode 100644 fuzzing/inputs/test3 create mode 100644 fuzzing/inputs/test4 create mode 100644 fuzzing/inputs/test5 create mode 100644 fuzzing/inputs/test6 create mode 100644 fuzzing/inputs/test7 create mode 100644 fuzzing/inputs/test8 create mode 100644 fuzzing/inputs/test9 create mode 100644 fuzzing/json.dict diff --git a/CMakeLists.txt b/CMakeLists.txt index e7f2f7ef..de01b79a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 2.8) -subdirs(tests) +subdirs(tests fuzzing) include(GNUInstallDirs) diff --git a/fuzzing/.gitignore b/fuzzing/.gitignore new file mode 100644 index 00000000..c82a2620 --- /dev/null +++ b/fuzzing/.gitignore @@ -0,0 +1 @@ +afl-build diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt new file mode 100644 index 00000000..d95be854 --- /dev/null +++ b/fuzzing/CMakeLists.txt @@ -0,0 +1,21 @@ +option(ENABLE_FUZZING "Create executables and targets for fuzzing cJSON with afl." Off) +if (ENABLE_FUZZING) + find_program(AFL_FUZZ afl-fuzz) + if ("${AFL_FUZZ}" MATCHES "AFL_FUZZ-NOTFOUND") + message(FATAL_ERROR "Couldn't find afl-fuzz.") + endif() + + + add_executable(afl-main afl.c) + target_link_libraries(afl-main "${CJSON_LIB}") + + if (NOT ENABLE_SANITIZERS) + message(FATAL_ERROR "Enable sanitizers with -DENABLE_SANITIZERS=On to do fuzzing.") + endif() + + add_custom_target(afl + COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" + DEPENDS afl-main) + + +endif() diff --git a/fuzzing/afl.c b/fuzzing/afl.c new file mode 100644 index 00000000..28c7e40c --- /dev/null +++ b/fuzzing/afl.c @@ -0,0 +1,117 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include + +#include "../cJSON.h" + +static char *read_file(const char *filename) +{ + FILE *file = NULL; + long length = 0; + char *content = NULL; + size_t read_chars = 0; + + /* open in read binary mode */ + file = fopen(filename, "rb"); + if (file == NULL) + { + goto cleanup; + } + + /* get the length */ + if (fseek(file, 0, SEEK_END) != 0) + { + goto cleanup; + } + length = ftell(file); + if (length < 0) + { + goto cleanup; + } + if (fseek(file, 0, SEEK_SET) != 0) + { + goto cleanup; + } + + /* allocate content buffer */ + content = (char*)malloc((size_t)length + sizeof('\0')); + if (content == NULL) + { + goto cleanup; + } + + /* read the file into memory */ + read_chars = fread(content, sizeof(char), (size_t)length, file); + if ((long)read_chars != length) + { + free(content); + content = NULL; + goto cleanup; + } + content[read_chars] = '\0'; + + +cleanup: + if (file != NULL) + { + fclose(file); + } + + return content; +} + +int main(int argc, char** argv) +{ + const char *filename = NULL; + cJSON *item = NULL; + char *json = NULL; + + if (argc < 2) + { + printf("Usage:\n"); + printf("%s input_file\n", argv[0]); + printf("\t input_file: file containing the test data"); + } + + filename = argv[1]; + + json = read_file(filename); + item = cJSON_Parse(json); + if (item == NULL) + { + goto cleanup; + } + +cleanup: + if (item != NULL) + { + cJSON_Delete(item); + } + if (json != NULL) + { + free(json); + } + + return EXIT_SUCCESS; +} diff --git a/fuzzing/afl.sh b/fuzzing/afl.sh new file mode 100755 index 00000000..64b60a35 --- /dev/null +++ b/fuzzing/afl.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +mkdir -p afl-build || exit 1 +cd afl-build || exit 1 +#cleanup +rm -r -- * + +CC=afl-gcc cmake ../.. -DENABLE_FUZZING=On -DENABLE_SANITIZERS=On -DBUILD_SHARED_LIBS=Off +make afl diff --git a/fuzzing/inputs/test1 b/fuzzing/inputs/test1 new file mode 100644 index 00000000..eacfbf5e --- /dev/null +++ b/fuzzing/inputs/test1 @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/fuzzing/inputs/test10 b/fuzzing/inputs/test10 new file mode 100644 index 00000000..d19eb8b5 --- /dev/null +++ b/fuzzing/inputs/test10 @@ -0,0 +1 @@ +["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] diff --git a/fuzzing/inputs/test11 b/fuzzing/inputs/test11 new file mode 100644 index 00000000..eaf43e6e --- /dev/null +++ b/fuzzing/inputs/test11 @@ -0,0 +1,8 @@ +{ +"name": "Jack (\"Bee\") Nimble", +"format": {"type": "rect", +"width": 1920, +"height": 1080, +"interlace": false,"frame rate": 24 +} +} diff --git a/fuzzing/inputs/test2 b/fuzzing/inputs/test2 new file mode 100644 index 00000000..5600991a --- /dev/null +++ b/fuzzing/inputs/test2 @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} diff --git a/fuzzing/inputs/test3 b/fuzzing/inputs/test3 new file mode 100644 index 00000000..5662b377 --- /dev/null +++ b/fuzzing/inputs/test3 @@ -0,0 +1,26 @@ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} \ No newline at end of file diff --git a/fuzzing/inputs/test4 b/fuzzing/inputs/test4 new file mode 100644 index 00000000..d540b57f --- /dev/null +++ b/fuzzing/inputs/test4 @@ -0,0 +1,88 @@ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file diff --git a/fuzzing/inputs/test5 b/fuzzing/inputs/test5 new file mode 100644 index 00000000..49980ca2 --- /dev/null +++ b/fuzzing/inputs/test5 @@ -0,0 +1,27 @@ +{"menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] +}} diff --git a/fuzzing/inputs/test6 b/fuzzing/inputs/test6 new file mode 100644 index 00000000..d5cb28f6 --- /dev/null +++ b/fuzzing/inputs/test6 @@ -0,0 +1,16 @@ + + + + + + Application Error + + + + + \ No newline at end of file diff --git a/fuzzing/inputs/test7 b/fuzzing/inputs/test7 new file mode 100644 index 00000000..33085366 --- /dev/null +++ b/fuzzing/inputs/test7 @@ -0,0 +1,22 @@ +[ + { + "precision": "zip", + "Latitude": 37.7668, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" + }, + { + "precision": "zip", + "Latitude": 37.371991, + "Longitude": -122.026020, + "Address": "", + "City": "SUNNYVALE", + "State": "CA", + "Zip": "94085", + "Country": "US" + } + ] diff --git a/fuzzing/inputs/test8 b/fuzzing/inputs/test8 new file mode 100644 index 00000000..4b1f5b97 --- /dev/null +++ b/fuzzing/inputs/test8 @@ -0,0 +1,13 @@ +{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http:/*www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } + } diff --git a/fuzzing/inputs/test9 b/fuzzing/inputs/test9 new file mode 100644 index 00000000..2a939b96 --- /dev/null +++ b/fuzzing/inputs/test9 @@ -0,0 +1,5 @@ +[ + [0, -1, 0], + [1, 0, 0], + [0, 0, 1] + ] diff --git a/fuzzing/json.dict b/fuzzing/json.dict new file mode 100644 index 00000000..ac9c08c8 --- /dev/null +++ b/fuzzing/json.dict @@ -0,0 +1,47 @@ +# +# AFL dictionary for JSON +# ----------------------------- +# + +object_start="{" +object_end="}" +object_empty="{}" +object_one_element="{\"one\":1}" +object_two_elements="{\"1\":1,\"2\":2}" +object_separator=":" + +array_start="[" +array_end="]" +array_empty="[]" +array_one_element="[1]" +array_two_elements="[1,2]" + +separator="," + +escape_sequence_b="\\b" +escape_sequence_f="\\f" +escape_sequence_n="\\n" +escape_sequence_r="\\r" +escape_sequence_t="\\t" +escape_sequence_quote="\\\"" +escape_sequence_backslash="\\\\" +escapce_sequence_slash="\\/" +escpae_sequence_utf16_base="\\u" +escape_sequence_utf16="\\u12ab" + +number_integer="1" +number_double="1.0" +number_negative_integer="-1" +number_negative_double="-1.0" +number_engineering1="1e1" +number_engineering2="1e-1" +number_positive_integer="+1" +number_positive_double="+1.0" +number_e="e" +number_plus="+" +number_minus="-" +number_separator="." + +null="null" +true="true" +false="false" From 4785070ad33b211230f24b5bd28628b560174629 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 02:07:12 +0100 Subject: [PATCH 07/73] fuzzing: Fuzz printing as well. With one big limitation: It can only be fuzzed with what has been parsed by the library beforehand. --- fuzzing/CMakeLists.txt | 9 +++++++-- fuzzing/afl.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index d95be854..d39a6521 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -5,7 +5,6 @@ if (ENABLE_FUZZING) message(FATAL_ERROR "Couldn't find afl-fuzz.") endif() - add_executable(afl-main afl.c) target_link_libraries(afl-main "${CJSON_LIB}") @@ -13,8 +12,14 @@ if (ENABLE_FUZZING) message(FATAL_ERROR "Enable sanitizers with -DENABLE_SANITIZERS=On to do fuzzing.") endif() + option(ENABLE_FUZZING_PRINT "Fuzz printing functions together with parser." On) + set(fuzz_print_parameter "no") + if (ENABLE_FUZZING_PRINT) + set(fuzz_print_parameter "yes") + endif() + add_custom_target(afl - COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" + COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" "${fuzz_print_parameter}" DEPENDS afl-main) diff --git a/fuzzing/afl.c b/fuzzing/afl.c index 28c7e40c..f2452def 100644 --- a/fuzzing/afl.c +++ b/fuzzing/afl.c @@ -22,6 +22,7 @@ #include #include +#include #include "../cJSON.h" @@ -86,23 +87,42 @@ int main(int argc, char** argv) const char *filename = NULL; cJSON *item = NULL; char *json = NULL; + int status = EXIT_SUCCESS; + char *printed_json = NULL; - if (argc < 2) + if ((argc < 2) || (argc > 3)) { printf("Usage:\n"); - printf("%s input_file\n", argv[0]); - printf("\t input_file: file containing the test data"); + printf("%s input_file [enable_printing]\n", argv[0]); + printf("\t input_file: file containing the test data\n"); + printf("\t enable_printing: print after parsing, 'yes' or 'no', defaults to 'no'\n"); } filename = argv[1]; json = read_file(filename); + if (json == NULL) + { + status = EXIT_FAILURE; + goto cleanup; + } item = cJSON_Parse(json); if (item == NULL) { goto cleanup; } + if ((argc == 3) && (strncmp(argv[2], "yes", 3) == 0)) + { + printed_json = cJSON_Print(item); + if (printed_json == NULL) + { + status = EXIT_FAILURE; + goto cleanup; + } + printf("%s\n", printed_json); + } + cleanup: if (item != NULL) { @@ -112,6 +132,10 @@ int main(int argc, char** argv) { free(json); } + if (printed_json != NULL) + { + free(printed_json); + } - return EXIT_SUCCESS; + return status; } From c5a09a32a9ca1ca6c614a2b61db69350beeedadc Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 02:31:42 +0100 Subject: [PATCH 08/73] fuzzing: Fuzz different print methods This is achieved by encoding the type of function used in the first two bytes. First byte: b: buffered Second byte: f: formatted --- fuzzing/afl.c | 28 +++++++++++++++++++++++++--- fuzzing/inputs/test1 | 2 +- fuzzing/inputs/test10 | 2 +- fuzzing/inputs/test11 | 2 +- fuzzing/inputs/test2 | 2 +- fuzzing/inputs/test3 | 4 ++-- fuzzing/inputs/test3.bu | 26 ++++++++++++++++++++++++++ fuzzing/inputs/test3.uf | 26 ++++++++++++++++++++++++++ fuzzing/inputs/test3.uu | 26 ++++++++++++++++++++++++++ fuzzing/inputs/test4 | 4 ++-- fuzzing/inputs/test5 | 2 +- fuzzing/inputs/test6 | 4 ++-- fuzzing/inputs/test7 | 2 +- fuzzing/inputs/test8 | 2 +- fuzzing/inputs/test9 | 2 +- 15 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 fuzzing/inputs/test3.bu create mode 100644 fuzzing/inputs/test3.uf create mode 100644 fuzzing/inputs/test3.uu diff --git a/fuzzing/afl.c b/fuzzing/afl.c index f2452def..59bbca79 100644 --- a/fuzzing/afl.c +++ b/fuzzing/afl.c @@ -101,12 +101,12 @@ int main(int argc, char** argv) filename = argv[1]; json = read_file(filename); - if (json == NULL) + if ((json == NULL) || (json[0] == '\0') || (json[1] == '\0')) { status = EXIT_FAILURE; goto cleanup; } - item = cJSON_Parse(json); + item = cJSON_Parse(json + 2); if (item == NULL) { goto cleanup; @@ -114,7 +114,29 @@ int main(int argc, char** argv) if ((argc == 3) && (strncmp(argv[2], "yes", 3) == 0)) { - printed_json = cJSON_Print(item); + int do_format = 0; + if (json[1] == 'f') + { + do_format = 1; + } + + if (json[0] == 'b') + { + /* buffered printing */ + printed_json = cJSON_PrintBuffered(item, 1, do_format); + } + else + { + /* unbuffered printing */ + if (do_format) + { + printed_json = cJSON_Print(item); + } + else + { + printed_json = cJSON_PrintUnformatted(item); + } + } if (printed_json == NULL) { status = EXIT_FAILURE; diff --git a/fuzzing/inputs/test1 b/fuzzing/inputs/test1 index eacfbf5e..6a0c0d7c 100644 --- a/fuzzing/inputs/test1 +++ b/fuzzing/inputs/test1 @@ -1,4 +1,4 @@ -{ +bf{ "glossary": { "title": "example glossary", "GlossDiv": { diff --git a/fuzzing/inputs/test10 b/fuzzing/inputs/test10 index d19eb8b5..01e9a82f 100644 --- a/fuzzing/inputs/test10 +++ b/fuzzing/inputs/test10 @@ -1 +1 @@ -["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] +bf["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] diff --git a/fuzzing/inputs/test11 b/fuzzing/inputs/test11 index eaf43e6e..818c6e0f 100644 --- a/fuzzing/inputs/test11 +++ b/fuzzing/inputs/test11 @@ -1,4 +1,4 @@ -{ +bf{ "name": "Jack (\"Bee\") Nimble", "format": {"type": "rect", "width": 1920, diff --git a/fuzzing/inputs/test2 b/fuzzing/inputs/test2 index 5600991a..3fdf8cb7 100644 --- a/fuzzing/inputs/test2 +++ b/fuzzing/inputs/test2 @@ -1,4 +1,4 @@ -{"menu": { +bf{"menu": { "id": "file", "value": "File", "popup": { diff --git a/fuzzing/inputs/test3 b/fuzzing/inputs/test3 index 5662b377..7143163b 100644 --- a/fuzzing/inputs/test3 +++ b/fuzzing/inputs/test3 @@ -1,4 +1,4 @@ -{"widget": { +bf{"widget": { "debug": "on", "window": { "title": "Sample Konfabulator Widget", @@ -23,4 +23,4 @@ "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}} \ No newline at end of file +}} diff --git a/fuzzing/inputs/test3.bu b/fuzzing/inputs/test3.bu new file mode 100644 index 00000000..6fc93d3c --- /dev/null +++ b/fuzzing/inputs/test3.bu @@ -0,0 +1,26 @@ +bu{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} diff --git a/fuzzing/inputs/test3.uf b/fuzzing/inputs/test3.uf new file mode 100644 index 00000000..d48df612 --- /dev/null +++ b/fuzzing/inputs/test3.uf @@ -0,0 +1,26 @@ +uf{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} diff --git a/fuzzing/inputs/test3.uu b/fuzzing/inputs/test3.uu new file mode 100644 index 00000000..ad6ae541 --- /dev/null +++ b/fuzzing/inputs/test3.uu @@ -0,0 +1,26 @@ +uu{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} diff --git a/fuzzing/inputs/test4 b/fuzzing/inputs/test4 index d540b57f..e24ae9b3 100644 --- a/fuzzing/inputs/test4 +++ b/fuzzing/inputs/test4 @@ -1,4 +1,4 @@ -{"web-app": { +bf{"web-app": { "servlet": [ { "servlet-name": "cofaxCDS", @@ -85,4 +85,4 @@ "taglib": { "taglib-uri": "cofax.tld", - "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} diff --git a/fuzzing/inputs/test5 b/fuzzing/inputs/test5 index 49980ca2..f6cc84e1 100644 --- a/fuzzing/inputs/test5 +++ b/fuzzing/inputs/test5 @@ -1,4 +1,4 @@ -{"menu": { +bf{"menu": { "header": "SVG Viewer", "items": [ {"id": "Open"}, diff --git a/fuzzing/inputs/test6 b/fuzzing/inputs/test6 index d5cb28f6..af279752 100644 --- a/fuzzing/inputs/test6 +++ b/fuzzing/inputs/test6 @@ -1,4 +1,4 @@ - +bf @@ -13,4 +13,4 @@

Application Error

- \ No newline at end of file + diff --git a/fuzzing/inputs/test7 b/fuzzing/inputs/test7 index 33085366..4a3c0b7a 100644 --- a/fuzzing/inputs/test7 +++ b/fuzzing/inputs/test7 @@ -1,4 +1,4 @@ -[ +bf[ { "precision": "zip", "Latitude": 37.7668, diff --git a/fuzzing/inputs/test8 b/fuzzing/inputs/test8 index 4b1f5b97..3ffe570c 100644 --- a/fuzzing/inputs/test8 +++ b/fuzzing/inputs/test8 @@ -1,4 +1,4 @@ -{ +bf{ "Image": { "Width": 800, "Height": 600, diff --git a/fuzzing/inputs/test9 b/fuzzing/inputs/test9 index 2a939b96..28c9033a 100644 --- a/fuzzing/inputs/test9 +++ b/fuzzing/inputs/test9 @@ -1,4 +1,4 @@ -[ +bf[ [0, -1, 0], [1, 0, 0], [0, 0, 1] From ae4681b7871d2cc7fb159c67f5b1af3d887a5e3b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 02:46:36 +0100 Subject: [PATCH 09/73] fuzzing: use llvm source code instrumentation --- fuzzing/afl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzing/afl.sh b/fuzzing/afl.sh index 64b60a35..8f0f02fb 100755 --- a/fuzzing/afl.sh +++ b/fuzzing/afl.sh @@ -5,5 +5,5 @@ cd afl-build || exit 1 #cleanup rm -r -- * -CC=afl-gcc cmake ../.. -DENABLE_FUZZING=On -DENABLE_SANITIZERS=On -DBUILD_SHARED_LIBS=Off +CC=afl-clang-fast cmake ../.. -DENABLE_FUZZING=On -DENABLE_SANITIZERS=On -DBUILD_SHARED_LIBS=Off make afl From da551c753f49ded690d60d5dbe81ad35c4eaefb8 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 02:52:38 +0100 Subject: [PATCH 10/73] fuzzing: Speed up afl using persistent mode (in proccess fuzzing) --- fuzzing/CMakeLists.txt | 2 ++ fuzzing/afl.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index d39a6521..fdd7126e 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -18,6 +18,8 @@ if (ENABLE_FUZZING) set(fuzz_print_parameter "yes") endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error") + add_custom_target(afl COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" "${fuzz_print_parameter}" DEPENDS afl-main) diff --git a/fuzzing/afl.c b/fuzzing/afl.c index 59bbca79..af5945d9 100644 --- a/fuzzing/afl.c +++ b/fuzzing/afl.c @@ -87,7 +87,7 @@ int main(int argc, char** argv) const char *filename = NULL; cJSON *item = NULL; char *json = NULL; - int status = EXIT_SUCCESS; + int status; char *printed_json = NULL; if ((argc < 2) || (argc > 3)) @@ -100,6 +100,12 @@ int main(int argc, char** argv) filename = argv[1]; +#if __AFL_HAVE_MANUAL_CONTROL + while (__AFL_LOOP(1000)) + { +#endif + status = EXIT_SUCCESS; + json = read_file(filename); if ((json == NULL) || (json[0] == '\0') || (json[1] == '\0')) { @@ -149,15 +155,21 @@ int main(int argc, char** argv) if (item != NULL) { cJSON_Delete(item); + item = NULL; } if (json != NULL) { free(json); + json = NULL; } if (printed_json != NULL) { free(printed_json); + printed_json = NULL; + } +#if __AFL_HAVE_MANUAL_CONTROL } +#endif return status; } From cf71f3d6277c16b47a506fbe5d1d01be417c19fc Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 18 Feb 2017 12:51:34 +0100 Subject: [PATCH 11/73] fuzzing: script to prepare linux kernel for afl --- fuzzing/afl-prepare-linux.sh | 5 +++++ 1 file changed, 5 insertions(+) create mode 100755 fuzzing/afl-prepare-linux.sh diff --git a/fuzzing/afl-prepare-linux.sh b/fuzzing/afl-prepare-linux.sh new file mode 100755 index 00000000..41c9b899 --- /dev/null +++ b/fuzzing/afl-prepare-linux.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -x +echo core | sudo tee /proc/sys/kernel/core_pattern +echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor From 80354bdb06bee60dc4bd21450ae8097bb0a83dfc Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 19 Feb 2017 03:57:11 +0100 Subject: [PATCH 12/73] cJSON_Print: Use printbuffer --- cJSON.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 89943b5d..d658588a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -865,15 +865,66 @@ cJSON *cJSON_Parse(const char *value) return cJSON_ParseWithOpts(value, 0, 0); } +#define min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cjbool format) +{ + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) cJSON_malloc(256); + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (print_value(item, 0, format, buffer) == NULL) + { + goto fail; + } + buffer->offset = update(buffer); /* update the length of the string */ + + /* copy the buffer over to a new one */ + printed = (unsigned char*) cJSON_malloc(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + strncpy((char*)printed, (char*)buffer->buffer, min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + cJSON_free(buffer->buffer); + + return printed; + +fail: + if (buffer->buffer != NULL) + { + cJSON_free(buffer->buffer); + } + + if (printed != NULL) + { + cJSON_free(printed); + } + + return NULL; +} + /* Render a cJSON item/entity/structure to text. */ char *cJSON_Print(const cJSON *item) { - return (char*)print_value(item, 0, 1, 0); + return (char*)print(item, true); } char *cJSON_PrintUnformatted(const cJSON *item) { - return (char*)print_value(item, 0, 0, 0); + return (char*)print(item, false); } char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) From 9bf531ca0561428160cedd4bd30678e1b42023ff Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 19 Feb 2017 04:16:57 +0100 Subject: [PATCH 13/73] Remove printing without buffer --- cJSON.c | 560 +++++++++++++++++--------------------------------------- 1 file changed, 169 insertions(+), 391 deletions(-) diff --git a/cJSON.c b/cJSON.c index d658588a..a5cd84b7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -328,6 +328,12 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) { unsigned char *str = NULL; double d = item->valuedouble; + + if (p == NULL) + { + return NULL; + } + /* special case for 0. */ if (d == 0) { @@ -678,6 +684,11 @@ static unsigned char *print_string_ptr(const unsigned char *str, printbuffer *p) cjbool flag = false; unsigned char token = '\0'; + if (p == NULL) + { + return NULL; + } + /* empty string */ if (!str) { @@ -1028,101 +1039,71 @@ static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, p { return NULL; } - if (p) + + if (p == NULL) + { + return NULL; + } + + switch ((item->type) & 0xFF) { - switch ((item->type) & 0xFF) + case cJSON_NULL: + out = ensure(p, 5); + if (out != NULL) + { + strcpy((char*)out, "null"); + } + break; + case cJSON_False: + out = ensure(p, 6); + if (out != NULL) + { + strcpy((char*)out, "false"); + } + break; + case cJSON_True: + out = ensure(p, 5); + if (out != NULL) + { + strcpy((char*)out, "true"); + } + break; + case cJSON_Number: + out = print_number(item, p); + break; + case cJSON_Raw: { - case cJSON_NULL: - out = ensure(p, 5); - if (out != NULL) - { - strcpy((char*)out, "null"); - } - break; - case cJSON_False: - out = ensure(p, 6); - if (out != NULL) - { - strcpy((char*)out, "false"); - } - break; - case cJSON_True: - out = ensure(p, 5); - if (out != NULL) - { - strcpy((char*)out, "true"); - } - break; - case cJSON_Number: - out = print_number(item, p); - break; - case cJSON_Raw: + size_t raw_length = 0; + if (item->valuestring == NULL) { - size_t raw_length = 0; - if (item->valuestring == NULL) + if (!p->noalloc) { - if (!p->noalloc) - { - cJSON_free(p->buffer); - } - out = NULL; - break; + cJSON_free(p->buffer); } - - raw_length = strlen(item->valuestring) + sizeof('\0'); - out = ensure(p, raw_length); - if (out != NULL) - { - memcpy(out, item->valuestring, raw_length); - } - break; - } - case cJSON_String: - out = print_string(item, p); - break; - case cJSON_Array: - out = print_array(item, depth, fmt, p); - break; - case cJSON_Object: - out = print_object(item, depth, fmt, p); - break; - default: - out = NULL; - break; - } - } - else - { - switch ((item->type) & 0xFF) - { - case cJSON_NULL: - out = cJSON_strdup((const unsigned char*)"null"); - break; - case cJSON_False: - out = cJSON_strdup((const unsigned char*)"false"); - break; - case cJSON_True: - out = cJSON_strdup((const unsigned char*)"true"); - break; - case cJSON_Number: - out = print_number(item, 0); - break; - case cJSON_Raw: - out = cJSON_strdup((unsigned char*)item->valuestring); - break; - case cJSON_String: - out = print_string(item, 0); - break; - case cJSON_Array: - out = print_array(item, depth, fmt, 0); - break; - case cJSON_Object: - out = print_object(item, depth, fmt, 0); - break; - default: out = NULL; break; + } + + raw_length = strlen(item->valuestring) + sizeof('\0'); + out = ensure(p, raw_length); + if (out != NULL) + { + memcpy(out, item->valuestring, raw_length); + } + break; } + case cJSON_String: + out = print_string(item, p); + break; + case cJSON_Array: + out = print_array(item, depth, fmt, p); + break; + case cJSON_Object: + out = print_object(item, depth, fmt, p); + break; + default: + out = NULL; + break; } return out; @@ -1209,16 +1190,18 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char /* Render an array to text */ static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) { - unsigned char **entries; unsigned char *out = NULL; unsigned char *ptr = NULL; - unsigned char *ret = NULL; size_t len = 5; cJSON *child = item->child; size_t numentries = 0; size_t i = 0; cjbool fail = false; - size_t tmplen = 0; + + if (p == NULL) + { + return NULL; + } /* How many entries in the array? */ while (child) @@ -1239,131 +1222,51 @@ static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, p return out; } - if (p) + /* Compose the output array. */ + /* opening square bracket */ + i = p->offset; + ptr = ensure(p, 1); + if (ptr == NULL) { - /* Compose the output array. */ - /* opening square bracket */ - i = p->offset; - ptr = ensure(p, 1); - if (ptr == NULL) + return NULL; + } + *ptr = '['; + p->offset++; + + child = item->child; + while (child && !fail) + { + if (!print_value(child, depth + 1, fmt, p)) { return NULL; } - *ptr = '['; - p->offset++; - - child = item->child; - while (child && !fail) + p->offset = update(p); + if (child->next) { - if (!print_value(child, depth + 1, fmt, p)) + len = fmt ? 2 : 1; + ptr = ensure(p, len + 1); + if (ptr == NULL) { return NULL; } - p->offset = update(p); - if (child->next) + *ptr++ = ','; + if(fmt) { - len = fmt ? 2 : 1; - ptr = ensure(p, len + 1); - if (ptr == NULL) - { - return NULL; - } - *ptr++ = ','; - if(fmt) - { - *ptr++ = ' '; - } - *ptr = '\0'; - p->offset += len; + *ptr++ = ' '; } - child = child->next; - } - ptr = ensure(p, 2); - if (ptr == NULL) - { - return NULL; + *ptr = '\0'; + p->offset += len; } - *ptr++ = ']'; - *ptr = '\0'; - out = (p->buffer) + i; + child = child->next; } - else + ptr = ensure(p, 2); + if (ptr == NULL) { - /* Allocate an array to hold the pointers to all printed values */ - entries = (unsigned char**)cJSON_malloc(numentries * sizeof(unsigned char*)); - if (!entries) - { - return NULL; - } - memset(entries, '\0', numentries * sizeof(unsigned char*)); - - /* Retrieve all the results: */ - child = item->child; - while (child && !fail) - { - ret = print_value(child, depth + 1, fmt, 0); - entries[i++] = ret; - if (ret) - { - len += strlen((char*)ret) + 2 + (fmt ? 1 : 0); - } - else - { - fail = true; - } - child = child->next; - } - - /* If we didn't fail, try to malloc the output string */ - if (!fail) - { - out = (unsigned char*)cJSON_malloc(len); - } - /* If that fails, we fail. */ - if (!out) - { - fail = true; - } - - /* Handle failure. */ - if (fail) - { - /* free all the entries in the array */ - for (i = 0; i < numentries; i++) - { - if (entries[i]) - { - cJSON_free(entries[i]); - } - } - cJSON_free(entries); - return NULL; - } - - /* Compose the output array. */ - *out='['; - ptr = out + 1; - *ptr = '\0'; - for (i = 0; i < numentries; i++) - { - tmplen = strlen((char*)entries[i]); - memcpy(ptr, entries[i], tmplen); - ptr += tmplen; - if (i != (numentries - 1)) - { - *ptr++ = ','; - if(fmt) - { - *ptr++ = ' '; - } - *ptr = '\0'; - } - cJSON_free(entries[i]); - } - cJSON_free(entries); - *ptr++ = ']'; - *ptr++ = '\0'; + return NULL; } + *ptr++ = ']'; + *ptr = '\0'; + out = (p->buffer) + i; return out; } @@ -1466,19 +1369,18 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char /* Render an object to text. */ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) { - unsigned char **entries = NULL; - unsigned char **names = NULL; unsigned char *out = NULL; unsigned char *ptr = NULL; - unsigned char *ret = NULL; - unsigned char *str = NULL; size_t len = 7; size_t i = 0; size_t j = 0; cJSON *child = item->child; size_t numentries = 0; - cjbool fail = false; - size_t tmplen = 0; + + if (p == NULL) + { + return NULL; + } /* Count the number of entries. */ while (child) @@ -1510,229 +1412,105 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, return out; } - if (p) + /* Compose the output: */ + i = p->offset; + len = fmt ? 2 : 1; /* fmt: {\n */ + ptr = ensure(p, len + 1); + if (ptr == NULL) { - /* Compose the output: */ - i = p->offset; - len = fmt ? 2 : 1; /* fmt: {\n */ - ptr = ensure(p, len + 1); - if (ptr == NULL) - { - return NULL; - } + return NULL; + } - *ptr++ = '{'; - if (fmt) - { - *ptr++ = '\n'; - } - *ptr = '\0'; - p->offset += len; + *ptr++ = '{'; + if (fmt) + { + *ptr++ = '\n'; + } + *ptr = '\0'; + p->offset += len; - child = item->child; - depth++; - while (child) + child = item->child; + depth++; + while (child) + { + if (fmt) { - if (fmt) - { - ptr = ensure(p, depth); - if (ptr == NULL) - { - return NULL; - } - for (j = 0; j < depth; j++) - { - *ptr++ = '\t'; - } - p->offset += depth; - } - - /* print key */ - if (!print_string_ptr((unsigned char*)child->string, p)) - { - return NULL; - } - p->offset = update(p); - - len = fmt ? 2 : 1; - ptr = ensure(p, len); + ptr = ensure(p, depth); if (ptr == NULL) { return NULL; } - *ptr++ = ':'; - if (fmt) + for (j = 0; j < depth; j++) { *ptr++ = '\t'; } - p->offset+=len; - - /* print value */ - if (!print_value(child, depth, fmt, p)) - { - return NULL; - }; - p->offset = update(p); - - /* print comma if not last */ - len = (size_t) (fmt ? 1 : 0) + (child->next ? 1 : 0); - ptr = ensure(p, len + 1); - if (ptr == NULL) - { - return NULL; - } - if (child->next) - { - *ptr++ = ','; - } - - if (fmt) - { - *ptr++ = '\n'; - } - *ptr = '\0'; - p->offset += len; - - child = child->next; + p->offset += depth; } - ptr = ensure(p, fmt ? (depth + 1) : 2); - if (ptr == NULL) - { - return NULL; - } - if (fmt) - { - for (i = 0; i < (depth - 1); i++) - { - *ptr++ = '\t'; - } - } - *ptr++ = '}'; - *ptr = '\0'; - out = (p->buffer) + i; - } - else - { - /* Allocate space for the names and the objects */ - entries = (unsigned char**)cJSON_malloc(numentries * sizeof(unsigned char*)); - if (!entries) + /* print key */ + if (!print_string_ptr((unsigned char*)child->string, p)) { return NULL; } - names = (unsigned char**)cJSON_malloc(numentries * sizeof(unsigned char*)); - if (!names) + p->offset = update(p); + + len = fmt ? 2 : 1; + ptr = ensure(p, len); + if (ptr == NULL) { - cJSON_free(entries); return NULL; } - memset(entries, '\0', sizeof(unsigned char*) * numentries); - memset(names, '\0', sizeof(unsigned char*) * numentries); - - /* Collect all the results into our arrays: */ - child = item->child; - depth++; + *ptr++ = ':'; if (fmt) { - len += depth; - } - while (child && !fail) - { - names[i] = str = print_string_ptr((unsigned char*)child->string, 0); /* print key */ - entries[i++] = ret = print_value(child, depth, fmt, 0); - if (str && ret) - { - len += strlen((char*)ret) + strlen((char*)str) + 2 + (fmt ? 2 + depth : 0); - } - else - { - fail = true; - } - child = child->next; + *ptr++ = '\t'; } + p->offset+=len; - /* Try to allocate the output string */ - if (!fail) - { - out = (unsigned char*)cJSON_malloc(len); - } - if (!out) + /* print value */ + if (!print_value(child, depth, fmt, p)) { - fail = true; + return NULL; } + p->offset = update(p); - /* Handle failure */ - if (fail) + /* print comma if not last */ + len = (size_t) (fmt ? 1 : 0) + (child->next ? 1 : 0); + ptr = ensure(p, len + 1); + if (ptr == NULL) { - /* free all the printed keys and values */ - for (i = 0; i < numentries; i++) - { - if (names[i]) - { - cJSON_free(names[i]); - } - if (entries[i]) - { - cJSON_free(entries[i]); - } - } - cJSON_free(names); - cJSON_free(entries); return NULL; } + if (child->next) + { + *ptr++ = ','; + } - /* Compose the output: */ - *out = '{'; - ptr = out + 1; if (fmt) { *ptr++ = '\n'; } *ptr = '\0'; - for (i = 0; i < numentries; i++) - { - if (fmt) - { - for (j = 0; j < depth; j++) - { - *ptr++='\t'; - } - } - tmplen = strlen((char*)names[i]); - memcpy(ptr, names[i], tmplen); - ptr += tmplen; - *ptr++ = ':'; - if (fmt) - { - *ptr++ = '\t'; - } - strcpy((char*)ptr, (char*)entries[i]); - ptr += strlen((char*)entries[i]); - if (i != (numentries - 1)) - { - *ptr++ = ','; - } - if (fmt) - { - *ptr++ = '\n'; - } - *ptr = '\0'; - cJSON_free(names[i]); - cJSON_free(entries[i]); - } + p->offset += len; - cJSON_free(names); - cJSON_free(entries); - if (fmt) + child = child->next; + } + + ptr = ensure(p, fmt ? (depth + 1) : 2); + if (ptr == NULL) + { + return NULL; + } + if (fmt) + { + for (i = 0; i < (depth - 1); i++) { - for (i = 0; i < (depth - 1); i++) - { - *ptr++ = '\t'; - } + *ptr++ = '\t'; } - *ptr++ = '}'; - *ptr++ = '\0'; } + *ptr++ = '}'; + *ptr = '\0'; + out = (p->buffer) + i; return out; } From 3c4d309f621edc21d2ecbc25477b18a7a0fbe9ae Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 19 Feb 2017 04:20:21 +0100 Subject: [PATCH 14/73] ensure: Don't accept empty printbuffers anymore --- cJSON.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index a5cd84b7..598f9cf0 100644 --- a/cJSON.c +++ b/cJSON.c @@ -241,9 +241,9 @@ static unsigned char* ensure(printbuffer *p, size_t needed) unsigned char *newbuffer = NULL; size_t newsize = 0; - if (p == NULL) + if ((p == NULL) || (p->buffer == NULL)) { - return (unsigned char*)cJSON_malloc(needed); + return NULL; } if (needed > INT_MAX) @@ -252,10 +252,6 @@ static unsigned char* ensure(printbuffer *p, size_t needed) return NULL; } - if (p->buffer == NULL) - { - return NULL; - } needed += p->offset; if (needed <= p->length) { From 8aa324fdc8687b3980607dfa527cc0cfae34004a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 19 Feb 2017 17:25:22 +0100 Subject: [PATCH 15/73] tests: print_string --- tests/CMakeLists.txt | 1 + tests/print_string.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/print_string.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 27d6900b..4b72c624 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,6 +14,7 @@ if(ENABLE_CJSON_TEST) parse_array parse_object parse_value + print_string ) add_library(test-common common.c) diff --git a/tests/print_string.c b/tests/print_string.c new file mode 100644 index 00000000..03ea5046 --- /dev/null +++ b/tests/print_string.c @@ -0,0 +1,76 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void assert_print_string(const char *expected, const char *input) +{ + unsigned char printed[1024]; + printbuffer buffer; + buffer.buffer = printed; + buffer.length = sizeof(printed); + buffer.offset = 0; + buffer.noalloc = true; + + TEST_ASSERT_NOT_NULL_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected."); +} + +static void print_string_should_print_empty_strings(void) +{ + assert_print_string("\"\"", ""); +} + +static void print_string_should_print_ascii(void) +{ + char ascii[0x7F]; + size_t i = 1; + + /* create ascii table */ + for (i = 1; i < 0x7F; i++) + { + ascii[i-1] = (char)i; + } + ascii[0x7F-1] = '\0'; + + assert_print_string("\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"", + ascii); +} + +static void print_string_should_print_utf8(void) +{ + assert_print_string("\"ü猫慕\"", "ü猫慕"); +} + +int main(void) +{ + /* initialize cJSON item */ + UNITY_BEGIN(); + + RUN_TEST(print_string_should_print_empty_strings); + RUN_TEST(print_string_should_print_ascii); + RUN_TEST(print_string_should_print_utf8); + + return UNITY_END(); +} From 87691a86e5fca6551a1a8504ac67b87f829a6561 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 19 Feb 2017 19:58:41 +0100 Subject: [PATCH 16/73] cJSON_SetNumberValue: Fix compiler warning with -Waddress --- cJSON.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index e4a7856a..647cc62d 100644 --- a/cJSON.h +++ b/cJSON.h @@ -173,7 +173,7 @@ extern void cJSON_Minify(char *json); #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)) +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? 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) From 924122904e6ed15735f0439c82b7d09ea87b822f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 01:25:19 +0100 Subject: [PATCH 17/73] tests: print_number --- tests/CMakeLists.txt | 1 + tests/print_number.c | 103 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 tests/print_number.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4b72c624..70b74623 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,7 @@ if(ENABLE_CJSON_TEST) parse_object parse_value print_string + print_number ) add_library(test-common common.c) diff --git a/tests/print_number.c b/tests/print_number.c new file mode 100644 index 00000000..e0141b69 --- /dev/null +++ b/tests/print_number.c @@ -0,0 +1,103 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void assert_print_number(const char *expected, double input) +{ + unsigned char printed[1024]; + cJSON item[1]; + printbuffer buffer; + buffer.buffer = printed; + buffer.length = sizeof(printed); + buffer.offset = 0; + buffer.noalloc = true; + + memset(item, 0, sizeof(item)); + cJSON_SetNumberValue(item, input); + + TEST_ASSERT_NOT_NULL_MESSAGE(print_number(item, &buffer), "Failed to print number."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected."); +} + +static void print_number_should_print_zero(void) +{ + assert_print_number("0", 0); +} + +static void print_number_should_print_negative_integers(void) +{ + assert_print_number("-1", -1); + assert_print_number("-32768", -32768); + assert_print_number("-2147483648", -2147483648); +} + +static void print_number_should_print_positive_integers(void) +{ + assert_print_number("1", 1); + assert_print_number("32767", 32767); + assert_print_number("2147483647", 2147483647); +} + +static void print_number_should_print_positive_reals(void) +{ + assert_print_number("0.123000", 0.123); + assert_print_number("1.000000e-09", 10e-10); + assert_print_number("1000000000000", 10e11); + assert_print_number("1.230000e+129", 123e+127); + assert_print_number("0", 123e-128); /* TODO: Maybe this shouldn't be 0 */ +} + +static void print_number_should_print_negative_reals(void) +{ + assert_print_number("-0.012300", -0.0123); + assert_print_number("-1.000000e-09", -10e-10); + assert_print_number("-1000000000000000000000", -10e20); + assert_print_number("-1.230000e+129", -123e+127); + assert_print_number("-1.230000e-126", -123e-128); +} + +static void print_number_should_print_non_number(void) +{ + TEST_IGNORE(); + /* FIXME: Cannot test this easily in C89! */ + /* assert_print_number("null", NaN); */ + /* assert_print_number("null", INFTY); */ + /* assert_print_number("null", -INFTY); */ +} + +int main(void) +{ + /* initialize cJSON item */ + UNITY_BEGIN(); + + RUN_TEST(print_number_should_print_zero); + RUN_TEST(print_number_should_print_negative_integers); + RUN_TEST(print_number_should_print_positive_integers); + RUN_TEST(print_number_should_print_positive_reals); + RUN_TEST(print_number_should_print_negative_reals); + RUN_TEST(print_number_should_print_non_number); + + return UNITY_END(); +} From 3d667662319c88a18622e05ae46aea3ba4f4080f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 02:12:13 +0100 Subject: [PATCH 18/73] tests: print_array --- tests/CMakeLists.txt | 1 + tests/print_array.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 tests/print_array.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 70b74623..559cac3a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,7 @@ if(ENABLE_CJSON_TEST) parse_value print_string print_number + print_array ) add_library(test-common common.c) diff --git a/tests/print_array.c b/tests/print_array.c new file mode 100644 index 00000000..90e87209 --- /dev/null +++ b/tests/print_array.c @@ -0,0 +1,92 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void assert_print_array(const char * const expected, const char * const input) +{ + unsigned char printed_unformatted[1024]; + unsigned char printed_formatted[1024]; + + const unsigned char *error_pointer; + cJSON item[1]; + + printbuffer formatted_buffer; + printbuffer unformatted_buffer; + + /* buffer for formatted printing */ + formatted_buffer.buffer = printed_formatted; + formatted_buffer.length = sizeof(printed_formatted); + formatted_buffer.offset = 0; + formatted_buffer.noalloc = true; + + /* buffer for unformatted printing */ + unformatted_buffer.buffer = printed_unformatted; + unformatted_buffer.length = sizeof(printed_unformatted); + unformatted_buffer.offset = 0; + unformatted_buffer.noalloc = true; + + memset(item, 0, sizeof(item)); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer), "Failed to parse array."); + + TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, false, &unformatted_buffer), "Failed to print unformatted string."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct."); + + TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, true, &formatted_buffer), "Failed to print formatted string."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct."); + + reset(item); +} + +static void print_array_should_print_empty_arrays(void) +{ + assert_print_array("[]", "[]"); +} + +static void print_array_should_print_arrays_with_one_element(void) +{ + + assert_print_array("[1]", "[1]"); + assert_print_array("[\"hello!\"]", "[\"hello!\"]"); + assert_print_array("[[]]", "[[]]"); + assert_print_array("[null]", "[null]"); +} + +static void print_array_should_print_arrays_with_multiple_elements(void) +{ + assert_print_array("[1, 2, 3]", "[1,2,3]"); + assert_print_array("[1, null, true, false, [], \"hello\", {\n\t}]", "[1,null,true,false,[],\"hello\",{}]"); +} + +int main(void) +{ + /* initialize cJSON item */ + UNITY_BEGIN(); + + RUN_TEST(print_array_should_print_empty_arrays); + RUN_TEST(print_array_should_print_arrays_with_one_element); + RUN_TEST(print_array_should_print_arrays_with_multiple_elements); + + return UNITY_END(); +} From b6abef94ff6f2a361153d6a9ae65efa150bb665e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 02:30:37 +0100 Subject: [PATCH 19/73] tests: print_object --- tests/CMakeLists.txt | 1 + tests/print_object.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 tests/print_object.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 559cac3a..90077417 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,6 +17,7 @@ if(ENABLE_CJSON_TEST) print_string print_number print_array + print_object ) add_library(test-common common.c) diff --git a/tests/print_object.c b/tests/print_object.c new file mode 100644 index 00000000..2f6f5bf1 --- /dev/null +++ b/tests/print_object.c @@ -0,0 +1,92 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void assert_print_object(const char * const expected, const char * const input) +{ + unsigned char printed_unformatted[1024]; + unsigned char printed_formatted[1024]; + + const unsigned char *error_pointer; + cJSON item[1]; + + printbuffer formatted_buffer; + printbuffer unformatted_buffer; + + /* buffer for formatted printing */ + formatted_buffer.buffer = printed_formatted; + formatted_buffer.length = sizeof(printed_formatted); + formatted_buffer.offset = 0; + formatted_buffer.noalloc = true; + + /* buffer for unformatted printing */ + unformatted_buffer.buffer = printed_unformatted; + unformatted_buffer.length = sizeof(printed_unformatted); + unformatted_buffer.offset = 0; + unformatted_buffer.noalloc = true; + + memset(item, 0, sizeof(item)); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer), "Failed to parse object."); + + TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, false, &unformatted_buffer), "Failed to print unformatted string."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct."); + + TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, true, &formatted_buffer), "Failed to print formatted string."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct."); + + reset(item); +} + +static void print_object_should_print_empty_objects(void) +{ + assert_print_object("{\n}", "{}"); +} + +static void print_object_should_print_objects_with_one_element(void) +{ + + assert_print_object("{\n\t\"one\":\t1\n}", "{\"one\":1}"); + assert_print_object("{\n\t\"hello\":\t\"world!\"\n}", "{\"hello\":\"world!\"}"); + assert_print_object("{\n\t\"array\":\t[]\n}", "{\"array\":[]}"); + assert_print_object("{\n\t\"null\":\tnull\n}", "{\"null\":null}"); +} + +static void print_object_should_print_objects_with_multiple_elements(void) +{ + assert_print_object("{\n\t\"one\":\t1,\n\t\"two\":\t2,\n\t\"three\":\t3\n}", "{\"one\":1,\"two\":2,\"three\":3}"); + assert_print_object("{\n\t\"one\":\t1,\n\t\"NULL\":\tnull,\n\t\"TRUE\":\ttrue,\n\t\"FALSE\":\tfalse,\n\t\"array\":\t[],\n\t\"world\":\t\"hello\",\n\t\"object\":\t{\n\t}\n}", "{\"one\":1,\"NULL\":null,\"TRUE\":true,\"FALSE\":false,\"array\":[],\"world\":\"hello\",\"object\":{}}"); +} + +int main(void) +{ + /* initialize cJSON item */ + UNITY_BEGIN(); + + RUN_TEST(print_object_should_print_empty_objects); + RUN_TEST(print_object_should_print_objects_with_one_element); + RUN_TEST(print_object_should_print_objects_with_multiple_elements); + + return UNITY_END(); +} From 983a4cd286f12a3eeb096923084d8eb947015983 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 02:31:54 +0100 Subject: [PATCH 20/73] tests: parse_objects: Fix name of test --- tests/parse_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/parse_object.c b/tests/parse_object.c index e8ede1d1..8904e552 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -76,7 +76,7 @@ static void parse_object_should_parse_empty_objects(void) reset(item); } -static void parse_array_should_parse_arrays_with_one_element(void) +static void parse_object_should_parse_objects_with_one_element(void) { assert_parse_object("{\"one\":1}"); @@ -163,6 +163,6 @@ int main(void) RUN_TEST(parse_object_should_parse_empty_objects); RUN_TEST(parse_object_should_not_parse_non_objects); RUN_TEST(parse_object_should_parse_objects_with_multiple_elements); - RUN_TEST(parse_array_should_parse_arrays_with_one_element); + RUN_TEST(parse_object_should_parse_objects_with_one_element); return UNITY_END(); } From de3647609224e04ebda19381d32c2a1cca445f6e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 02:43:18 +0100 Subject: [PATCH 21/73] tests: print_value --- tests/CMakeLists.txt | 1 + tests/print_value.c | 102 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 tests/print_value.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 90077417..e64d5dcb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ if(ENABLE_CJSON_TEST) print_number print_array print_object + print_value ) add_library(test-common common.c) diff --git a/tests/print_value.c b/tests/print_value.c new file mode 100644 index 00000000..5aea9bfd --- /dev/null +++ b/tests/print_value.c @@ -0,0 +1,102 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void assert_print_value(const char *input) +{ + unsigned char printed[1024]; + const unsigned char *error_pointer = NULL; + cJSON item[1]; + printbuffer buffer; + buffer.buffer = printed; + buffer.length = sizeof(printed); + buffer.offset = 0; + buffer.noalloc = true; + + memset(item, 0, sizeof(item)); + + TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer), "Failed to parse value."); + + TEST_ASSERT_NOT_NULL_MESSAGE(print_value(item, 0, false, &buffer), "Failed to print value."); + TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected."); + + reset(item); +} + +static void print_value_should_print_null(void) +{ + assert_print_value("null"); +} + +static void print_value_should_print_true(void) +{ + assert_print_value("true"); +} + +static void print_value_should_print_false(void) +{ + assert_print_value("false"); +} + +static void print_value_should_print_number(void) +{ + assert_print_value("1.500000"); +} + +static void print_value_should_print_string(void) +{ + assert_print_value("\"\""); + assert_print_value("\"hello\""); +} + +static void print_value_should_print_array(void) +{ + assert_print_value("[]"); +} + +static void print_value_should_print_object(void) +{ + assert_print_value("{}"); +} + +int main(void) +{ + /* initialize cJSON item */ + UNITY_BEGIN(); + + RUN_TEST(print_value_should_print_null); + RUN_TEST(print_value_should_print_true); + RUN_TEST(print_value_should_print_false); + RUN_TEST(print_value_should_print_number); + RUN_TEST(print_value_should_print_string); + RUN_TEST(print_value_should_print_array); + RUN_TEST(print_value_should_print_object); + + return UNITY_END(); +} From 61921498d0842a2372766ca4ef158a9505acbd8f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 11:32:53 +0100 Subject: [PATCH 22/73] print_number: remove special case for 0 Now that printbuffer is used for everything, it's not needed anymore. --- cJSON.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/cJSON.c b/cJSON.c index 598f9cf0..06b4c09a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -330,17 +330,8 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) return NULL; } - /* special case for 0. */ - if (d == 0) - { - str = ensure(p, 2); - if (str != NULL) - { - strcpy((char*)str,"0"); - } - } /* value is an int */ - else if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) + if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { /* 2^64+1 can be represented in 21 chars. */ str = ensure(p, 21); @@ -375,6 +366,7 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) } } } + return str; } From 6815d96617d4812e93430c0f38cc7b59554cfc72 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 11:41:40 +0100 Subject: [PATCH 23/73] print_number: rename variables --- cJSON.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cJSON.c b/cJSON.c index 06b4c09a..15b9d314 100644 --- a/cJSON.c +++ b/cJSON.c @@ -320,12 +320,12 @@ static size_t update(const printbuffer *p) } /* Render the number nicely from the given item into a string. */ -static unsigned char *print_number(const cJSON *item, printbuffer *p) +static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer) { - unsigned char *str = NULL; + unsigned char *output_pointer = NULL; double d = item->valuedouble; - if (p == NULL) + if (output_buffer == NULL) { return NULL; } @@ -333,41 +333,41 @@ static unsigned char *print_number(const cJSON *item, printbuffer *p) /* value is an int */ if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { - /* 2^64+1 can be represented in 21 chars. */ - str = ensure(p, 21); - if (str != NULL) + /* 2^64+1 can be represented in 21 chars. */ + output_pointer = ensure(output_buffer, 21); + if (output_pointer != NULL) { - sprintf((char*)str, "%d", item->valueint); + sprintf((char*)output_pointer, "%d", item->valueint); } } /* value is a floating point number */ else { /* This is a nice tradeoff. */ - str = ensure(p, 64); - if (str != NULL) + output_pointer = ensure(output_buffer, 64); + if (output_pointer != NULL) { /* This checks for NaN and Infinity */ if ((d * 0) != 0) { - sprintf((char*)str, "null"); + sprintf((char*)output_pointer, "null"); } else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { - sprintf((char*)str, "%.0f", d); + sprintf((char*)output_pointer, "%.0f", d); } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) { - sprintf((char*)str, "%e", d); + sprintf((char*)output_pointer, "%e", d); } else { - sprintf((char*)str, "%f", d); + sprintf((char*)output_pointer, "%f", d); } } } - return str; + return output_pointer; } /* parse 4 digit hexadecimal number */ From 1e999352d3b3da36971797ce8ff155a95026367f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 12:02:20 +0100 Subject: [PATCH 24/73] print_string_ptr: rename variables --- cJSON.c | 110 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/cJSON.c b/cJSON.c index 15b9d314..963b3893 100644 --- a/cJSON.c +++ b/cJSON.c @@ -236,7 +236,7 @@ typedef struct } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer *p, size_t needed) +static unsigned char* ensure(printbuffer * const p, size_t needed) { unsigned char *newbuffer = NULL; size_t newsize = 0; @@ -663,134 +663,134 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char } /* Render the cstring provided to an escaped version that can be printed. */ -static unsigned char *print_string_ptr(const unsigned char *str, printbuffer *p) +static unsigned char *print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) { - const unsigned char *ptr = NULL; - unsigned char *ptr2 = NULL; - unsigned char *out = NULL; - size_t len = 0; - cjbool flag = false; + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t length = 0; + cjbool contains_special_char = false; unsigned char token = '\0'; - if (p == NULL) + if (output_buffer == NULL) { return NULL; } /* empty string */ - if (!str) + if (input == NULL) { - out = ensure(p, 3); - if (out == NULL) + output = ensure(output_buffer, 3); + if (output == NULL) { return NULL; } - strcpy((char*)out, "\"\""); + strcpy((char*)output, "\"\""); - return out; + return output; } /* set "flag" to 1 if something needs to be escaped */ - for (ptr = str; *ptr; ptr++) + for (input_pointer = input; *input_pointer; input_pointer++) { - flag |= (((*ptr > 0) && (*ptr < 32)) /* unprintable characters */ - || (*ptr == '\"') /* double quote */ - || (*ptr == '\\')) /* backslash */ + contains_special_char |= (((*input_pointer > 0) && (*input_pointer < 32)) /* unprintable characters */ + || (*input_pointer == '\"') /* double quote */ + || (*input_pointer == '\\')) /* backslash */ ? 1 : 0; } /* no characters have to be escaped */ - if (!flag) + if (!contains_special_char) { - len = (size_t)(ptr - str); + length = (size_t)(input_pointer - input); - out = ensure(p, len + 3); - if (out == NULL) + output = ensure(output_buffer, length + 3); + if (output == NULL) { return NULL; } - ptr2 = out; - *ptr2++ = '\"'; - strcpy((char*)ptr2, (const char*)str); - ptr2[len] = '\"'; - ptr2[len + 1] = '\0'; + output_pointer = output; + *output_pointer++ = '\"'; + strcpy((char*)output_pointer, (const char*)input); + output_pointer[length] = '\"'; + output_pointer[length + 1] = '\0'; - return out; + return output; } - ptr = str; + input_pointer = input; /* calculate additional space that is needed for escaping */ - while ((token = *ptr)) + while ((token = *input_pointer)) { - ++len; + ++length; if (strchr("\"\\\b\f\n\r\t", token)) { - len++; /* +1 for the backslash */ + length++; /* +1 for the backslash */ } else if (token < 32) { - len += 5; /* +5 for \uXXXX */ + length += 5; /* +5 for \uXXXX */ } - ptr++; + input_pointer++; } - out = ensure(p, len + 3); - if (out == NULL) + output = ensure(output_buffer, length + 3); + if (output == NULL) { return NULL; } - ptr2 = out; - ptr = str; - *ptr2++ = '\"'; + output_pointer = output; + input_pointer = input; + *output_pointer++ = '\"'; /* copy the string */ - while (*ptr) + while (*input_pointer) { - if ((*ptr > 31) && (*ptr != '\"') && (*ptr != '\\')) + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { /* normal character, copy */ - *ptr2++ = *ptr++; + *output_pointer++ = *input_pointer++; } else { /* character needs to be escaped */ - *ptr2++ = '\\'; - switch (token = *ptr++) + *output_pointer++ = '\\'; + switch (token = *input_pointer++) { case '\\': - *ptr2++ = '\\'; + *output_pointer++ = '\\'; break; case '\"': - *ptr2++ = '\"'; + *output_pointer++ = '\"'; break; case '\b': - *ptr2++ = 'b'; + *output_pointer++ = 'b'; break; case '\f': - *ptr2++ = 'f'; + *output_pointer++ = 'f'; break; case '\n': - *ptr2++ = 'n'; + *output_pointer++ = 'n'; break; case '\r': - *ptr2++ = 'r'; + *output_pointer++ = 'r'; break; case '\t': - *ptr2++ = 't'; + *output_pointer++ = 't'; break; default: /* escape and print as unicode codepoint */ - sprintf((char*)ptr2, "u%04x", token); - ptr2 += 5; + sprintf((char*)output_pointer, "u%04x", token); + output_pointer += 5; break; } } } - *ptr2++ = '\"'; - *ptr2++ = '\0'; + *output_pointer++ = '\"'; + *output_pointer++ = '\0'; - return out; + return output; } /* Invoke print_string_ptr (which is useful) on an item. */ From 6a746a230af20aad075cd0ebd1ae351baa16bc1f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 12:02:56 +0100 Subject: [PATCH 25/73] print_string: Add more const --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 963b3893..5a9f29bd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -794,7 +794,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb } /* Invoke print_string_ptr (which is useful) on an item. */ -static unsigned char *print_string(const cJSON *item, printbuffer *p) +static unsigned char *print_string(const cJSON * const item, printbuffer * const p) { return print_string_ptr((unsigned char*)item->valuestring, p); } From 88e38d042f3c125d06e37d2ed72ad07e52259117 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 12:46:38 +0100 Subject: [PATCH 26/73] tests: print_string: test if NULL is printed as empty string --- tests/print_string.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/print_string.c b/tests/print_string.c index 03ea5046..1404160f 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -40,6 +40,7 @@ static void assert_print_string(const char *expected, const char *input) static void print_string_should_print_empty_strings(void) { assert_print_string("\"\"", ""); + assert_print_string("\"\"", NULL); } static void print_string_should_print_ascii(void) From 0ca8587acc6c569a890456ed9741b2ba1911ec84 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 13:03:51 +0100 Subject: [PATCH 27/73] print_string_ptr: simplify code --- cJSON.c | 97 +++++++++++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 58 deletions(-) diff --git a/cJSON.c b/cJSON.c index 5a9f29bd..2e3f4e8c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -668,9 +668,9 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb const unsigned char *input_pointer = NULL; unsigned char *output = NULL; unsigned char *output_pointer = NULL; - size_t length = 0; - cjbool contains_special_char = false; - unsigned char token = '\0'; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; if (output_buffer == NULL) { @@ -680,7 +680,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb /* empty string */ if (input == NULL) { - output = ensure(output_buffer, 3); + output = ensure(output_buffer, sizeof("\"\"")); if (output == NULL) { return NULL; @@ -693,102 +693,83 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb /* set "flag" to 1 if something needs to be escaped */ for (input_pointer = input; *input_pointer; input_pointer++) { - contains_special_char |= (((*input_pointer > 0) && (*input_pointer < 32)) /* unprintable characters */ - || (*input_pointer == '\"') /* double quote */ - || (*input_pointer == '\\')) /* backslash */ - ? 1 - : 0; - } - /* no characters have to be escaped */ - if (!contains_special_char) - { - length = (size_t)(input_pointer - input); - - output = ensure(output_buffer, length + 3); - if (output == NULL) - { - return NULL; - } - - output_pointer = output; - *output_pointer++ = '\"'; - strcpy((char*)output_pointer, (const char*)input); - output_pointer[length] = '\"'; - output_pointer[length + 1] = '\0'; - - return output; - } - - input_pointer = input; - /* calculate additional space that is needed for escaping */ - while ((token = *input_pointer)) - { - ++length; - if (strchr("\"\\\b\f\n\r\t", token)) + if (strchr("\"\\\b\f\n\r\t", *input_pointer)) { - length++; /* +1 for the backslash */ + /* one character escape sequence */ + escape_characters++; } - else if (token < 32) + else if (*input_pointer < 32) { - length += 5; /* +5 for \uXXXX */ + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; } - input_pointer++; } + output_length = (size_t)(input_pointer - input) + escape_characters; - output = ensure(output_buffer, length + 3); + output = ensure(output_buffer, output_length + sizeof("\"\"")); if (output == NULL) { return NULL; } - output_pointer = output; - input_pointer = input; - *output_pointer++ = '\"'; + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return output; + } + + output[0] = '\"'; + output_pointer = output + 1; /* copy the string */ - while (*input_pointer) + for (input_pointer = input; *input_pointer != '\0'; input_pointer++, output_pointer++) { if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { /* normal character, copy */ - *output_pointer++ = *input_pointer++; + *output_pointer = *input_pointer; } else { /* character needs to be escaped */ *output_pointer++ = '\\'; - switch (token = *input_pointer++) + switch (*input_pointer) { case '\\': - *output_pointer++ = '\\'; + *output_pointer = '\\'; break; case '\"': - *output_pointer++ = '\"'; + *output_pointer = '\"'; break; case '\b': - *output_pointer++ = 'b'; + *output_pointer = 'b'; break; case '\f': - *output_pointer++ = 'f'; + *output_pointer = 'f'; break; case '\n': - *output_pointer++ = 'n'; + *output_pointer = 'n'; break; case '\r': - *output_pointer++ = 'r'; + *output_pointer = 'r'; break; case '\t': - *output_pointer++ = 't'; + *output_pointer = 't'; break; default: /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", token); - output_pointer += 5; + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; break; } } } - *output_pointer++ = '\"'; - *output_pointer++ = '\0'; + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; return output; } From 08770fc246fd8993f007acba38ab9e9dd919e403 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 13:30:40 +0100 Subject: [PATCH 28/73] print_value: rename variables --- cJSON.c | 55 +++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/cJSON.c b/cJSON.c index 2e3f4e8c..af707cff 100644 --- a/cJSON.c +++ b/cJSON.c @@ -782,7 +782,7 @@ static unsigned char *print_string(const cJSON * const item, printbuffer * const /* Predeclare these prototypes. */ static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep); -static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); +static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); @@ -1000,16 +1000,11 @@ static const unsigned char *parse_value(cJSON * const item, const unsigned char } /* Render a value to text. */ -static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) +static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer) { - unsigned char *out = NULL; - - if (!item) - { - return NULL; - } + unsigned char *output = NULL; - if (p == NULL) + if ((item == NULL) || (output_buffer == NULL)) { return NULL; } @@ -1017,65 +1012,65 @@ static unsigned char *print_value(const cJSON *item, size_t depth, cjbool fmt, p switch ((item->type) & 0xFF) { case cJSON_NULL: - out = ensure(p, 5); - if (out != NULL) + output = ensure(output_buffer, 5); + if (output != NULL) { - strcpy((char*)out, "null"); + strcpy((char*)output, "null"); } break; case cJSON_False: - out = ensure(p, 6); - if (out != NULL) + output = ensure(output_buffer, 6); + if (output != NULL) { - strcpy((char*)out, "false"); + strcpy((char*)output, "false"); } break; case cJSON_True: - out = ensure(p, 5); - if (out != NULL) + output = ensure(output_buffer, 5); + if (output != NULL) { - strcpy((char*)out, "true"); + strcpy((char*)output, "true"); } break; case cJSON_Number: - out = print_number(item, p); + output = print_number(item, output_buffer); break; case cJSON_Raw: { size_t raw_length = 0; if (item->valuestring == NULL) { - if (!p->noalloc) + if (!output_buffer->noalloc) { - cJSON_free(p->buffer); + cJSON_free(output_buffer->buffer); } - out = NULL; + output = NULL; break; } raw_length = strlen(item->valuestring) + sizeof('\0'); - out = ensure(p, raw_length); - if (out != NULL) + output = ensure(output_buffer, raw_length); + if (output != NULL) { - memcpy(out, item->valuestring, raw_length); + memcpy(output, item->valuestring, raw_length); } break; } case cJSON_String: - out = print_string(item, p); + output = print_string(item, output_buffer); break; case cJSON_Array: - out = print_array(item, depth, fmt, p); + output = print_array(item, depth, format, output_buffer); break; case cJSON_Object: - out = print_object(item, depth, fmt, p); + output = print_object(item, depth, format, output_buffer); break; default: - out = NULL; + output = NULL; break; } - return out; + return output; } /* Build an array from input text. */ From f16dd7e028a7fa9609dfd0dce8883fa4c9cdf9e7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 13:58:13 +0100 Subject: [PATCH 29/73] print_array: rename variables --- cJSON.c | 84 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/cJSON.c b/cJSON.c index af707cff..b9eaa2ca 100644 --- a/cJSON.c +++ b/cJSON.c @@ -784,7 +784,7 @@ static unsigned char *print_string(const cJSON * const item, printbuffer * const static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep); static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); -static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); +static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); @@ -1152,87 +1152,87 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char } /* Render an array to text */ -static unsigned char *print_array(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) +static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer) { - unsigned char *out = NULL; - unsigned char *ptr = NULL; - size_t len = 5; - cJSON *child = item->child; - size_t numentries = 0; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t length = 5; + cJSON *current_element = item->child; + size_t array_length = 0; size_t i = 0; cjbool fail = false; - if (p == NULL) + if (output_buffer == NULL) { return NULL; } /* How many entries in the array? */ - while (child) + while (current_element) { - numentries++; - child = child->next; + array_length++; + current_element = current_element->next; } - /* Explicitly handle numentries == 0 */ - if (!numentries) + /* Explicitly handle empty arrays */ + if (array_length == 0) { - out = ensure(p, 3); - if (out != NULL) + output = ensure(output_buffer, 3); + if (output != NULL) { - strcpy((char*)out, "[]"); + strcpy((char*)output, "[]"); } - return out; + return output; } /* Compose the output array. */ /* opening square bracket */ - i = p->offset; - ptr = ensure(p, 1); - if (ptr == NULL) + i = output_buffer->offset; + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) { return NULL; } - *ptr = '['; - p->offset++; + *output_pointer = '['; + output_buffer->offset++; - child = item->child; - while (child && !fail) + current_element = item->child; + while (current_element && !fail) { - if (!print_value(child, depth + 1, fmt, p)) + if (!print_value(current_element, depth + 1, format, output_buffer)) { return NULL; } - p->offset = update(p); - if (child->next) + output_buffer->offset = update(output_buffer); + if (current_element->next) { - len = fmt ? 2 : 1; - ptr = ensure(p, len + 1); - if (ptr == NULL) + length = format ? 2 : 1; + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { return NULL; } - *ptr++ = ','; - if(fmt) + *output_pointer++ = ','; + if(format) { - *ptr++ = ' '; + *output_pointer++ = ' '; } - *ptr = '\0'; - p->offset += len; + *output_pointer = '\0'; + output_buffer->offset += length; } - child = child->next; + current_element = current_element->next; } - ptr = ensure(p, 2); - if (ptr == NULL) + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) { return NULL; } - *ptr++ = ']'; - *ptr = '\0'; - out = (p->buffer) + i; + *output_pointer++ = ']'; + *output_pointer = '\0'; + output = (output_buffer->buffer) + i; - return out; + return output; } /* Build an object from the text. */ From 8c1ed3ab82a04ff494370b8a28eee7f970043b74 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 15:02:49 +0100 Subject: [PATCH 30/73] update: rename to update_offset and change offset directly --- cJSON.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cJSON.c b/cJSON.c index b9eaa2ca..4f6cac5f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -306,17 +306,17 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) return newbuffer + p->offset; } -/* calculate the new length of the string in a printbuffer */ -static size_t update(const printbuffer *p) +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) { - const unsigned char *str = NULL; - if (!p || !p->buffer) + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) { - return 0; + return; } - str = p->buffer + p->offset; + buffer_pointer = buffer->buffer + buffer->offset; - return p->offset + strlen((const char*)str); + buffer->offset += strlen((const char*)buffer_pointer); } /* Render the number nicely from the given item into a string. */ @@ -866,7 +866,7 @@ static unsigned char *print(const cJSON * const item, cjbool format) { goto fail; } - buffer->offset = update(buffer); /* update the length of the string */ + update_offset(buffer); /* copy the buffer over to a new one */ printed = (unsigned char*) cJSON_malloc(buffer->offset + 1); @@ -1204,7 +1204,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, { return NULL; } - output_buffer->offset = update(output_buffer); + update_offset(output_buffer); if (current_element->next) { length = format ? 2 : 1; @@ -1416,7 +1416,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, { return NULL; } - p->offset = update(p); + update_offset(p); len = fmt ? 2 : 1; ptr = ensure(p, len); @@ -1436,7 +1436,7 @@ static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, { return NULL; } - p->offset = update(p); + update_offset(p); /* print comma if not last */ len = (size_t) (fmt ? 1 : 0) + (child->next ? 1 : 0); From 6d5a7c8c404521d8a51176a5db79b203e52ad3ce Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 15:12:10 +0100 Subject: [PATCH 31/73] print_array: simplify code --- cJSON.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/cJSON.c b/cJSON.c index 4f6cac5f..bc40d08a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1156,51 +1156,31 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, { unsigned char *output = NULL; unsigned char *output_pointer = NULL; - size_t length = 5; + size_t length = 0; cJSON *current_element = item->child; - size_t array_length = 0; - size_t i = 0; - cjbool fail = false; + size_t output_offset = 0; if (output_buffer == NULL) { return NULL; } - /* How many entries in the array? */ - while (current_element) - { - array_length++; - current_element = current_element->next; - } - - /* Explicitly handle empty arrays */ - if (array_length == 0) - { - output = ensure(output_buffer, 3); - if (output != NULL) - { - strcpy((char*)output, "[]"); - } - - return output; - } - /* Compose the output array. */ /* opening square bracket */ - i = output_buffer->offset; + output_offset = output_buffer->offset; output_pointer = ensure(output_buffer, 1); if (output_pointer == NULL) { return NULL; } + *output_pointer = '['; output_buffer->offset++; current_element = item->child; - while (current_element && !fail) + while (current_element != NULL) { - if (!print_value(current_element, depth + 1, format, output_buffer)) + if (print_value(current_element, depth + 1, format, output_buffer) == NULL) { return NULL; } @@ -1223,6 +1203,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, } current_element = current_element->next; } + output_pointer = ensure(output_buffer, 2); if (output_pointer == NULL) { @@ -1230,7 +1211,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, } *output_pointer++ = ']'; *output_pointer = '\0'; - output = (output_buffer->buffer) + i; + output = output_buffer->buffer + output_offset; return output; } From b71db93e0373ae361d3d5d42b8e8da3ab932c3c7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 15:57:22 +0100 Subject: [PATCH 32/73] print_object: rename variables --- cJSON.c | 134 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/cJSON.c b/cJSON.c index bc40d08a..4fe5a954 100644 --- a/cJSON.c +++ b/cJSON.c @@ -786,7 +786,7 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); -static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p); +static unsigned char *print_object(const cJSON * const item, size_t depth, const cjbool format, printbuffer * const output_buffer); /* Utility to jump whitespace and cr/lf */ static const unsigned char *skip_whitespace(const unsigned char *in) @@ -1312,152 +1312,152 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* Render an object to text. */ -static unsigned char *print_object(const cJSON *item, size_t depth, cjbool fmt, printbuffer *p) +static unsigned char *print_object(const cJSON * const item, size_t depth, const cjbool format, printbuffer * const output_buffer) { - unsigned char *out = NULL; - unsigned char *ptr = NULL; - size_t len = 7; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t length = 7; size_t i = 0; size_t j = 0; - cJSON *child = item->child; - size_t numentries = 0; + cJSON *current_item = item->child; + size_t object_length = 0; - if (p == NULL) + if (output_buffer == NULL) { return NULL; } /* Count the number of entries. */ - while (child) + while (current_item) { - numentries++; - child = child->next; + object_length++; + current_item = current_item->next; } /* Explicitly handle empty object case */ - if (!numentries) + if (!object_length) { - out = ensure(p, fmt ? depth + 4 : 3); - if (out == NULL) + output = ensure(output_buffer, format ? depth + 4 : 3); + if (output == NULL) { return NULL; } - ptr = out; - *ptr++ = '{'; - if (fmt) { - *ptr++ = '\n'; + output_pointer = output; + *output_pointer++ = '{'; + if (format) { + *output_pointer++ = '\n'; for (i = 0; i < depth; i++) { - *ptr++ = '\t'; + *output_pointer++ = '\t'; } } - *ptr++ = '}'; - *ptr++ = '\0'; + *output_pointer++ = '}'; + *output_pointer++ = '\0'; - return out; + return output; } /* Compose the output: */ - i = p->offset; - len = fmt ? 2 : 1; /* fmt: {\n */ - ptr = ensure(p, len + 1); - if (ptr == NULL) + i = output_buffer->offset; + length = format ? 2 : 1; /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { return NULL; } - *ptr++ = '{'; - if (fmt) + *output_pointer++ = '{'; + if (format) { - *ptr++ = '\n'; + *output_pointer++ = '\n'; } - *ptr = '\0'; - p->offset += len; + *output_pointer = '\0'; + output_buffer->offset += length; - child = item->child; + current_item = item->child; depth++; - while (child) + while (current_item) { - if (fmt) + if (format) { - ptr = ensure(p, depth); - if (ptr == NULL) + output_pointer = ensure(output_buffer, depth); + if (output_pointer == NULL) { return NULL; } for (j = 0; j < depth; j++) { - *ptr++ = '\t'; + *output_pointer++ = '\t'; } - p->offset += depth; + output_buffer->offset += depth; } /* print key */ - if (!print_string_ptr((unsigned char*)child->string, p)) + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) { return NULL; } - update_offset(p); + update_offset(output_buffer); - len = fmt ? 2 : 1; - ptr = ensure(p, len); - if (ptr == NULL) + length = format ? 2 : 1; + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) { return NULL; } - *ptr++ = ':'; - if (fmt) + *output_pointer++ = ':'; + if (format) { - *ptr++ = '\t'; + *output_pointer++ = '\t'; } - p->offset+=len; + output_buffer->offset += length; /* print value */ - if (!print_value(child, depth, fmt, p)) + if (!print_value(current_item, depth, format, output_buffer)) { return NULL; } - update_offset(p); + update_offset(output_buffer); /* print comma if not last */ - len = (size_t) (fmt ? 1 : 0) + (child->next ? 1 : 0); - ptr = ensure(p, len + 1); - if (ptr == NULL) + length = (size_t) (format ? 1 : 0) + (current_item->next ? 1 : 0); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) { return NULL; } - if (child->next) + if (current_item->next) { - *ptr++ = ','; + *output_pointer++ = ','; } - if (fmt) + if (format) { - *ptr++ = '\n'; + *output_pointer++ = '\n'; } - *ptr = '\0'; - p->offset += len; + *output_pointer = '\0'; + output_buffer->offset += length; - child = child->next; + current_item = current_item->next; } - ptr = ensure(p, fmt ? (depth + 1) : 2); - if (ptr == NULL) + output_pointer = ensure(output_buffer, format ? (depth + 1) : 2); + if (output_pointer == NULL) { return NULL; } - if (fmt) + if (format) { for (i = 0; i < (depth - 1); i++) { - *ptr++ = '\t'; + *output_pointer++ = '\t'; } } - *ptr++ = '}'; - *ptr = '\0'; - out = (p->buffer) + i; + *output_pointer++ = '}'; + *output_pointer = '\0'; + output = (output_buffer->buffer) + i; - return out; + return output; } /* Get Array size/item / object item. */ From 1d42c9bc603cbc36191711867272e5d7b7af9e8a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Feb 2017 16:58:22 +0100 Subject: [PATCH 33/73] print_object: simplify code --- cJSON.c | 62 ++++++++++++++------------------------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/cJSON.c b/cJSON.c index 4fe5a954..46187c69 100644 --- a/cJSON.c +++ b/cJSON.c @@ -786,7 +786,7 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); -static unsigned char *print_object(const cJSON * const item, size_t depth, const cjbool format, printbuffer * const output_buffer); +static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); /* Utility to jump whitespace and cr/lf */ static const unsigned char *skip_whitespace(const unsigned char *in) @@ -1312,53 +1312,21 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* Render an object to text. */ -static unsigned char *print_object(const cJSON * const item, size_t depth, const cjbool format, printbuffer * const output_buffer) +static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer) { unsigned char *output = NULL; unsigned char *output_pointer = NULL; - size_t length = 7; - size_t i = 0; - size_t j = 0; + size_t length = 0; + size_t output_offset = 0; cJSON *current_item = item->child; - size_t object_length = 0; if (output_buffer == NULL) { return NULL; } - /* Count the number of entries. */ - while (current_item) - { - object_length++; - current_item = current_item->next; - } - - /* Explicitly handle empty object case */ - if (!object_length) - { - output = ensure(output_buffer, format ? depth + 4 : 3); - if (output == NULL) - { - return NULL; - } - output_pointer = output; - *output_pointer++ = '{'; - if (format) { - *output_pointer++ = '\n'; - for (i = 0; i < depth; i++) - { - *output_pointer++ = '\t'; - } - } - *output_pointer++ = '}'; - *output_pointer++ = '\0'; - - return output; - } - /* Compose the output: */ - i = output_buffer->offset; + output_offset = output_buffer->offset; length = format ? 2 : 1; /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) @@ -1371,29 +1339,28 @@ static unsigned char *print_object(const cJSON * const item, size_t depth, const { *output_pointer++ = '\n'; } - *output_pointer = '\0'; output_buffer->offset += length; current_item = item->child; - depth++; while (current_item) { if (format) { - output_pointer = ensure(output_buffer, depth); + size_t i; + output_pointer = ensure(output_buffer, depth + 1); if (output_pointer == NULL) { return NULL; } - for (j = 0; j < depth; j++) + for (i = 0; i < depth + 1; i++) { *output_pointer++ = '\t'; } - output_buffer->offset += depth; + output_buffer->offset += depth + 1; } /* print key */ - if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + if (print_string_ptr((unsigned char*)current_item->string, output_buffer) == NULL) { return NULL; } @@ -1413,7 +1380,7 @@ static unsigned char *print_object(const cJSON * const item, size_t depth, const output_buffer->offset += length; /* print value */ - if (!print_value(current_item, depth, format, output_buffer)) + if (!print_value(current_item, depth + 1, format, output_buffer)) { return NULL; } @@ -1441,21 +1408,22 @@ static unsigned char *print_object(const cJSON * const item, size_t depth, const current_item = current_item->next; } - output_pointer = ensure(output_buffer, format ? (depth + 1) : 2); + output_pointer = ensure(output_buffer, format ? (depth + 2) : 2); if (output_pointer == NULL) { return NULL; } if (format) { - for (i = 0; i < (depth - 1); i++) + size_t i; + for (i = 0; i < (depth); i++) { *output_pointer++ = '\t'; } } *output_pointer++ = '}'; *output_pointer = '\0'; - output = (output_buffer->buffer) + i; + output = (output_buffer->buffer) + output_offset; return output; } From b47d0e34caaef298edfb7bd09a72cfff21d231ff Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Feb 2017 09:17:34 +0100 Subject: [PATCH 34/73] cJSON_ArrayForEach: Fix handling of NULL pointers --- cJSON.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 647cc62d..88c91307 100644 --- a/cJSON.h +++ b/cJSON.h @@ -176,7 +176,7 @@ extern double cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? 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) +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) #ifdef __cplusplus } From cbbcc914987366007dfc6bd40af5b24ef9992c9d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Feb 2017 09:17:49 +0100 Subject: [PATCH 35/73] tests: cJSON_ArrayForEach --- tests/CMakeLists.txt | 1 + tests/misc_tests.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/misc_tests.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e64d5dcb..3e3e8c79 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,7 @@ if(ENABLE_CJSON_TEST) print_array print_object print_value + misc_tests ) add_library(test-common common.c) diff --git a/tests/misc_tests.c b/tests/misc_tests.c new file mode 100644 index 00000000..d5f977fa --- /dev/null +++ b/tests/misc_tests.c @@ -0,0 +1,75 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + + +static void cjson_array_foreach_should_loop_over_arrays(void) +{ + cJSON array[1]; + cJSON elements[10]; + cJSON *element_pointer = NULL; + size_t i = 0; + + memset(array, 0, sizeof(array)); + memset(elements, 0, sizeof(elements)); + + /* create array */ + array[0].child = &elements[0]; + elements[0].prev = NULL; + elements[9].next = NULL; + for (i = 0; i < 9; i++) + { + elements[i].next = &elements[i + 1]; + elements[i + 1].prev = &elements[i]; + } + + i = 0; + cJSON_ArrayForEach(element_pointer, array) + { + TEST_ASSERT_TRUE_MESSAGE(element_pointer == &elements[i], "Not iterating over array properly"); + i++; + } +} + +static void cjson_array_foreach_should_not_dereference_null_pointer(void) +{ + cJSON *array = NULL; + cJSON *element = NULL; + cJSON_ArrayForEach(element, array); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(cjson_array_foreach_should_loop_over_arrays); + RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer); + + return UNITY_END(); +} From 605422c60acb2be2c33e25c9b9a5fa7a83335a68 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Feb 2017 10:43:43 +0100 Subject: [PATCH 36/73] cJSON: New function cJSON_GetObjectItemCaseSensitive --- cJSON.c | 18 ++++++++++++++++++ cJSON.h | 1 + 2 files changed, 19 insertions(+) diff --git a/cJSON.c b/cJSON.c index 46187c69..dddc1afc 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1466,6 +1466,24 @@ cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string) return c; } +cJSON *cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (string == NULL)) + { + return NULL; + } + + current_element = object->child; + while ((current_element != NULL) && (strcmp(string, current_element->string) != 0)) + { + current_element = current_element->next; + } + + return current_element; +} + cjbool cJSON_HasObjectItem(const cJSON *object, const char *string) { return cJSON_GetObjectItem(object, string) ? 1 : 0; diff --git a/cJSON.h b/cJSON.h index 88c91307..de1f69f7 100644 --- a/cJSON.h +++ b/cJSON.h @@ -104,6 +104,7 @@ extern int cJSON_GetArraySize(const cJSON *array); extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item); /* Get item "string" from object. Case insensitive. */ extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string); +extern cJSON *cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string); extern int cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ extern const char *cJSON_GetErrorPtr(void); From 56b819bfbc8490a11ca8c23578ff49ab6120a3fa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Feb 2017 10:45:22 +0100 Subject: [PATCH 37/73] tests: test cJSON_GetObjectItem and cJSON_GetObjectItemCaseSensitive --- tests/misc_tests.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index d5f977fa..518ac72f 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -64,12 +64,77 @@ static void cjson_array_foreach_should_not_dereference_null_pointer(void) cJSON_ArrayForEach(element, array); } +static void cjson_get_object_item_should_get_object_items(void) +{ + cJSON *item = NULL; + cJSON *found = NULL; + + item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}"); + + found = cJSON_GetObjectItem(NULL, "test"); + TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer."); + + found = cJSON_GetObjectItem(item, NULL); + TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string."); + + + found = cJSON_GetObjectItem(item, "one"); + TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item."); + TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1); + + found = cJSON_GetObjectItem(item, "tWo"); + TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item."); + TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2); + + found = cJSON_GetObjectItem(item, "three"); + TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item."); + TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3); + + found = cJSON_GetObjectItem(item, "four"); + TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there."); + + cJSON_Delete(item); +} + +static void cjson_get_object_item_case_sensitive_should_get_object_items(void) +{ + cJSON *item = NULL; + cJSON *found = NULL; + + item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}"); + + found = cJSON_GetObjectItemCaseSensitive(NULL, "test"); + TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer."); + + found = cJSON_GetObjectItemCaseSensitive(item, NULL); + TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string."); + + found = cJSON_GetObjectItemCaseSensitive(item, "one"); + TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item."); + TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1); + + found = cJSON_GetObjectItemCaseSensitive(item, "Two"); + TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item."); + TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2); + + found = cJSON_GetObjectItemCaseSensitive(item, "tHree"); + TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item."); + TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3); + + found = cJSON_GetObjectItemCaseSensitive(item, "One"); + TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there."); + + cJSON_Delete(item); +} + int main(void) { UNITY_BEGIN(); RUN_TEST(cjson_array_foreach_should_loop_over_arrays); RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer); + RUN_TEST(cjson_get_object_item_should_get_object_items); + RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items); return UNITY_END(); } From 68cd0d4a111337d9138b3fe59227ec282df5b5ca Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Feb 2017 14:50:49 +0100 Subject: [PATCH 38/73] cJSON.c: Pass allocation functions through internal functions This is the first step in removing the global allocator functions. Every internal function now only accesses its locally available set of allocators. --- cJSON.c | 231 ++++++++++++++++++++++--------------------- tests/common.c | 4 +- tests/parse_array.c | 4 +- tests/parse_object.c | 4 +- tests/parse_string.c | 6 +- tests/parse_value.c | 2 +- tests/print_array.c | 6 +- tests/print_number.c | 2 +- tests/print_object.c | 6 +- tests/print_string.c | 2 +- tests/print_value.c | 4 +- 11 files changed, 138 insertions(+), 133 deletions(-) diff --git a/cJSON.c b/cJSON.c index dddc1afc..68a7bb85 100644 --- a/cJSON.c +++ b/cJSON.c @@ -79,11 +79,16 @@ static int cJSON_strcasecmp(const unsigned char *s1, const unsigned char *s2) return tolower(*s1) - tolower(*s2); } -static void *(*cJSON_malloc)(size_t sz) = malloc; -static void (*cJSON_free)(void *ptr) = free; -static void *(*cJSON_realloc)(void *pointer, size_t size) = realloc; +typedef struct internal_hooks +{ + void *(*allocate)(size_t size); + void (*deallocate)(void *pointer); + void *(*reallocate)(void *pointer, size_t size); +} internal_hooks; + +static internal_hooks global_hooks = { malloc, free, realloc }; -static unsigned char* cJSON_strdup(const unsigned char* str) +static unsigned char* cJSON_strdup(const unsigned char* str, const internal_hooks * const hooks) { size_t len = 0; unsigned char *copy = NULL; @@ -94,7 +99,7 @@ static unsigned char* cJSON_strdup(const unsigned char* str) } len = strlen((const char*)str) + 1; - if (!(copy = (unsigned char*)cJSON_malloc(len))) + if (!(copy = (unsigned char*)hooks->allocate(len))) { return NULL; } @@ -108,36 +113,36 @@ void cJSON_InitHooks(cJSON_Hooks* hooks) if (hooks == NULL) { /* Reset hooks */ - cJSON_malloc = malloc; - cJSON_free = free; - cJSON_realloc = realloc; + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; return; } - cJSON_malloc = malloc; + global_hooks.allocate = malloc; if (hooks->malloc_fn != NULL) { - cJSON_malloc = hooks->malloc_fn; + global_hooks.allocate = hooks->malloc_fn; } - cJSON_free = free; + global_hooks.deallocate = free; if (hooks->free_fn != NULL) { - cJSON_free = hooks->free_fn; + global_hooks.deallocate = hooks->free_fn; } /* use realloc only if both free and malloc are used */ - cJSON_realloc = NULL; - if ((cJSON_malloc == malloc) && (cJSON_free == free)) + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) { - cJSON_realloc = realloc; + global_hooks.reallocate = realloc; } } /* Internal constructor. */ -static cJSON *cJSON_New_Item(void) +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) { - cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); if (node) { memset(node, '\0', sizeof(cJSON)); @@ -159,13 +164,13 @@ void cJSON_Delete(cJSON *c) } if (!(c->type & cJSON_IsReference) && c->valuestring) { - cJSON_free(c->valuestring); + global_hooks.deallocate(c->valuestring); } if (!(c->type & cJSON_StringIsConst) && c->string) { - cJSON_free(c->string); + global_hooks.deallocate(c->string); } - cJSON_free(c); + global_hooks.deallocate(c); c = next; } } @@ -236,7 +241,7 @@ typedef struct } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed) +static unsigned char* ensure(printbuffer * const p, size_t needed, const internal_hooks * const hooks) { unsigned char *newbuffer = NULL; size_t newsize = 0; @@ -277,18 +282,18 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) } } - if (cJSON_realloc != NULL) + if (hooks->reallocate != NULL) { /* reallocate with realloc if available */ - newbuffer = (unsigned char*)cJSON_realloc(p->buffer, newsize); + newbuffer = (unsigned char*)hooks->reallocate(p->buffer, newsize); } else { /* otherwise reallocate manually */ - newbuffer = (unsigned char*)cJSON_malloc(newsize); + newbuffer = (unsigned char*)hooks->allocate(newsize); if (!newbuffer) { - cJSON_free(p->buffer); + hooks->deallocate(p->buffer); p->length = 0; p->buffer = NULL; @@ -298,7 +303,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) { memcpy(newbuffer, p->buffer, p->offset + 1); } - cJSON_free(p->buffer); + hooks->deallocate(p->buffer); } p->length = newsize; p->buffer = newbuffer; @@ -320,7 +325,7 @@ static void update_offset(printbuffer * const buffer) } /* Render the number nicely from the given item into a string. */ -static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer) +static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output_pointer = NULL; double d = item->valuedouble; @@ -334,7 +339,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { /* 2^64+1 can be represented in 21 chars. */ - output_pointer = ensure(output_buffer, 21); + output_pointer = ensure(output_buffer, 21, hooks); if (output_pointer != NULL) { sprintf((char*)output_pointer, "%d", item->valueint); @@ -344,7 +349,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const else { /* This is a nice tradeoff. */ - output_pointer = ensure(output_buffer, 64); + output_pointer = ensure(output_buffer, 64, hooks); if (output_pointer != NULL) { /* This checks for NaN and Infinity */ @@ -545,7 +550,7 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi } /* Parse the input text into an unescaped cinput, and populate item. */ -static const unsigned char *parse_string(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer) +static const unsigned char *parse_string(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { const unsigned char *input_pointer = input + 1; const unsigned char *input_end = input + 1; @@ -585,7 +590,7 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - input) - skipped_bytes; - output = (unsigned char*)cJSON_malloc(allocation_length + sizeof('\0')); + output = (unsigned char*)hooks->allocate(allocation_length + sizeof('\0')); if (output == NULL) { goto fail; /* allocation failure */ @@ -656,14 +661,14 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char fail: if (output != NULL) { - cJSON_free(output); + hooks->deallocate(output); } return NULL; } /* Render the cstring provided to an escaped version that can be printed. */ -static unsigned char *print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +static unsigned char *print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer, const internal_hooks * const hooks) { const unsigned char *input_pointer = NULL; unsigned char *output = NULL; @@ -680,7 +685,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb /* empty string */ if (input == NULL) { - output = ensure(output_buffer, sizeof("\"\"")); + output = ensure(output_buffer, sizeof("\"\""), hooks); if (output == NULL) { return NULL; @@ -706,7 +711,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb } output_length = (size_t)(input_pointer - input) + escape_characters; - output = ensure(output_buffer, output_length + sizeof("\"\"")); + output = ensure(output_buffer, output_length + sizeof("\"\""), hooks); if (output == NULL) { return NULL; @@ -775,18 +780,18 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb } /* Invoke print_string_ptr (which is useful) on an item. */ -static unsigned char *print_string(const cJSON * const item, printbuffer * const p) +static unsigned char *print_string(const cJSON * const item, printbuffer * const p, const internal_hooks * const hooks) { - return print_string_ptr((unsigned char*)item->valuestring, p); + return print_string_ptr((unsigned char*)item->valuestring, p, hooks); } /* Predeclare these prototypes. */ -static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep); -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); -static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); -static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep); -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer); +static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep, const internal_hooks * const hooks); +static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); +static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); +static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); /* Utility to jump whitespace and cr/lf */ static const unsigned char *skip_whitespace(const unsigned char *in) @@ -805,14 +810,14 @@ cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjb const unsigned char *end = NULL; /* use global error pointer if no specific one was given */ const unsigned char **ep = return_parse_end ? (const unsigned char**)return_parse_end : &global_ep; - cJSON *c = cJSON_New_Item(); + cJSON *c = cJSON_New_Item(&global_hooks); *ep = NULL; if (!c) /* memory fail */ { return NULL; } - end = parse_value(c, skip_whitespace((const unsigned char*)value), ep); + end = parse_value(c, skip_whitespace((const unsigned char*)value), ep, &global_hooks); if (!end) { /* parse failure. ep is set. */ @@ -847,7 +852,7 @@ cJSON *cJSON_Parse(const char *value) #define min(a, b) ((a < b) ? a : b) -static unsigned char *print(const cJSON * const item, cjbool format) +static unsigned char *print(const cJSON * const item, cjbool format, const internal_hooks * const hooks) { printbuffer buffer[1]; unsigned char *printed = NULL; @@ -855,21 +860,21 @@ static unsigned char *print(const cJSON * const item, cjbool format) memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*) cJSON_malloc(256); + buffer->buffer = (unsigned char*) hooks->allocate(256); if (buffer->buffer == NULL) { goto fail; } /* print the value */ - if (print_value(item, 0, format, buffer) == NULL) + if (print_value(item, 0, format, buffer, hooks) == NULL) { goto fail; } update_offset(buffer); /* copy the buffer over to a new one */ - printed = (unsigned char*) cJSON_malloc(buffer->offset + 1); + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); if (printed == NULL) { goto fail; @@ -878,19 +883,19 @@ static unsigned char *print(const cJSON * const item, cjbool format) printed[buffer->offset] = '\0'; /* just to be sure */ /* free the buffer */ - cJSON_free(buffer->buffer); + hooks->deallocate(buffer->buffer); return printed; fail: if (buffer->buffer != NULL) { - cJSON_free(buffer->buffer); + hooks->deallocate(buffer->buffer); } if (printed != NULL) { - cJSON_free(printed); + hooks->deallocate(printed); } return NULL; @@ -899,12 +904,12 @@ static unsigned char *print(const cJSON * const item, cjbool format) /* Render a cJSON item/entity/structure to text. */ char *cJSON_Print(const cJSON *item) { - return (char*)print(item, true); + return (char*)print(item, true, &global_hooks); } char *cJSON_PrintUnformatted(const cJSON *item) { - return (char*)print(item, false); + return (char*)print(item, false, &global_hooks); } char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) @@ -916,7 +921,7 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) return NULL; } - p.buffer = (unsigned char*)cJSON_malloc((size_t)prebuffer); + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); if (!p.buffer) { return NULL; @@ -926,7 +931,7 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) p.offset = 0; p.noalloc = false; - return (char*)print_value(item, 0, fmt, &p); + return (char*)print_value(item, 0, fmt, &p, &global_hooks); } int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool fmt) @@ -942,11 +947,11 @@ int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool p.length = (size_t)len; p.offset = 0; p.noalloc = true; - return print_value(item, 0, fmt, &p) != NULL; + return print_value(item, 0, fmt, &p, &global_hooks) != NULL; } /* Parser core - when encountering text, process appropriately. */ -static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer) +static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { if (input == NULL) { @@ -976,7 +981,7 @@ static const unsigned char *parse_value(cJSON * const item, const unsigned char /* string */ if (*input == '\"') { - return parse_string(item, input, error_pointer); + return parse_string(item, input, error_pointer, hooks); } /* number */ if ((*input == '-') || ((*input >= '0') && (*input <= '9'))) @@ -986,12 +991,12 @@ static const unsigned char *parse_value(cJSON * const item, const unsigned char /* array */ if (*input == '[') { - return parse_array(item, input, error_pointer); + return parse_array(item, input, error_pointer, hooks); } /* object */ if (*input == '{') { - return parse_object(item, input, error_pointer); + return parse_object(item, input, error_pointer, hooks); } /* failure. */ @@ -1000,7 +1005,7 @@ static const unsigned char *parse_value(cJSON * const item, const unsigned char } /* Render a value to text. */ -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer) +static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; @@ -1012,28 +1017,28 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, switch ((item->type) & 0xFF) { case cJSON_NULL: - output = ensure(output_buffer, 5); + output = ensure(output_buffer, 5, hooks); if (output != NULL) { strcpy((char*)output, "null"); } break; case cJSON_False: - output = ensure(output_buffer, 6); + output = ensure(output_buffer, 6, hooks); if (output != NULL) { strcpy((char*)output, "false"); } break; case cJSON_True: - output = ensure(output_buffer, 5); + output = ensure(output_buffer, 5, hooks); if (output != NULL) { strcpy((char*)output, "true"); } break; case cJSON_Number: - output = print_number(item, output_buffer); + output = print_number(item, output_buffer, hooks); break; case cJSON_Raw: { @@ -1042,14 +1047,14 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, { if (!output_buffer->noalloc) { - cJSON_free(output_buffer->buffer); + hooks->deallocate(output_buffer->buffer); } output = NULL; break; } raw_length = strlen(item->valuestring) + sizeof('\0'); - output = ensure(output_buffer, raw_length); + output = ensure(output_buffer, raw_length, hooks); if (output != NULL) { memcpy(output, item->valuestring, raw_length); @@ -1057,13 +1062,13 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, break; } case cJSON_String: - output = print_string(item, output_buffer); + output = print_string(item, output_buffer, hooks); break; case cJSON_Array: - output = print_array(item, depth, format, output_buffer); + output = print_array(item, depth, format, output_buffer, hooks); break; case cJSON_Object: - output = print_object(item, depth, format, output_buffer); + output = print_object(item, depth, format, output_buffer, hooks); break; default: output = NULL; @@ -1074,7 +1079,7 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, } /* Build an array from input text. */ -static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer) +static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { cJSON *head = NULL; /* head of the linked list */ cJSON *current_item = NULL; @@ -1099,7 +1104,7 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char do { /* allocate next item */ - cJSON *new_item = cJSON_New_Item(); + cJSON *new_item = cJSON_New_Item(hooks); if (new_item == NULL) { goto fail; /* allocation failure */ @@ -1121,7 +1126,7 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char /* parse next value */ input = skip_whitespace(input + 1); - input = parse_value(current_item, input, error_pointer); + input = parse_value(current_item, input, error_pointer, hooks); input = skip_whitespace(input); if (input == NULL) { @@ -1152,7 +1157,7 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char } /* Render an array to text */ -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer) +static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; unsigned char *output_pointer = NULL; @@ -1168,7 +1173,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, /* Compose the output array. */ /* opening square bracket */ output_offset = output_buffer->offset; - output_pointer = ensure(output_buffer, 1); + output_pointer = ensure(output_buffer, 1, hooks); if (output_pointer == NULL) { return NULL; @@ -1180,7 +1185,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, current_element = item->child; while (current_element != NULL) { - if (print_value(current_element, depth + 1, format, output_buffer) == NULL) + if (print_value(current_element, depth + 1, format, output_buffer, hooks) == NULL) { return NULL; } @@ -1188,7 +1193,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, if (current_element->next) { length = format ? 2 : 1; - output_pointer = ensure(output_buffer, length + 1); + output_pointer = ensure(output_buffer, length + 1, hooks); if (output_pointer == NULL) { return NULL; @@ -1204,7 +1209,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, current_element = current_element->next; } - output_pointer = ensure(output_buffer, 2); + output_pointer = ensure(output_buffer, 2, hooks); if (output_pointer == NULL) { return NULL; @@ -1217,7 +1222,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, } /* Build an object from the text. */ -static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer) +static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { cJSON *head = NULL; /* linked list head */ cJSON *current_item = NULL; @@ -1240,7 +1245,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char do { /* allocate next item */ - cJSON *new_item = cJSON_New_Item(); + cJSON *new_item = cJSON_New_Item(hooks); if (new_item == NULL) { goto fail; /* allocation failure */ @@ -1262,7 +1267,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char /* parse the name of the child */ input = skip_whitespace(input + 1); - input = parse_string(current_item, input, error_pointer); + input = parse_string(current_item, input, error_pointer, hooks); input = skip_whitespace(input); if (input == NULL) { @@ -1281,7 +1286,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char /* parse the value */ input = skip_whitespace(input + 1); - input = parse_value(current_item, input, error_pointer); + input = parse_value(current_item, input, error_pointer, hooks); input = skip_whitespace(input); if (input == NULL) { @@ -1312,7 +1317,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* Render an object to text. */ -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer) +static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; unsigned char *output_pointer = NULL; @@ -1328,7 +1333,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, /* Compose the output: */ output_offset = output_buffer->offset; length = format ? 2 : 1; /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1); + output_pointer = ensure(output_buffer, length + 1, hooks); if (output_pointer == NULL) { return NULL; @@ -1347,7 +1352,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, if (format) { size_t i; - output_pointer = ensure(output_buffer, depth + 1); + output_pointer = ensure(output_buffer, depth + 1, hooks); if (output_pointer == NULL) { return NULL; @@ -1360,14 +1365,14 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, } /* print key */ - if (print_string_ptr((unsigned char*)current_item->string, output_buffer) == NULL) + if (print_string_ptr((unsigned char*)current_item->string, output_buffer, hooks) == NULL) { return NULL; } update_offset(output_buffer); length = format ? 2 : 1; - output_pointer = ensure(output_buffer, length); + output_pointer = ensure(output_buffer, length, hooks); if (output_pointer == NULL) { return NULL; @@ -1380,7 +1385,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, output_buffer->offset += length; /* print value */ - if (!print_value(current_item, depth + 1, format, output_buffer)) + if (!print_value(current_item, depth + 1, format, output_buffer, hooks)) { return NULL; } @@ -1388,7 +1393,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, /* print comma if not last */ length = (size_t) (format ? 1 : 0) + (current_item->next ? 1 : 0); - output_pointer = ensure(output_buffer, length + 1); + output_pointer = ensure(output_buffer, length + 1, hooks); if (output_pointer == NULL) { return NULL; @@ -1408,7 +1413,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, current_item = current_item->next; } - output_pointer = ensure(output_buffer, format ? (depth + 2) : 2); + output_pointer = ensure(output_buffer, format ? (depth + 2) : 2, hooks); if (output_pointer == NULL) { return NULL; @@ -1497,9 +1502,9 @@ static void suffix_object(cJSON *prev, cJSON *item) } /* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item) +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) { - cJSON *ref = cJSON_New_Item(); + cJSON *ref = cJSON_New_Item(hooks); if (!ref) { return NULL; @@ -1542,7 +1547,7 @@ void cJSON_AddItemToArray(cJSON *array, cJSON *item) void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { /* call cJSON_AddItemToObjectCS for code reuse */ - cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string), item); + cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); /* remove cJSON_StringIsConst flag */ item->type &= ~cJSON_StringIsConst; } @@ -1556,7 +1561,7 @@ void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) } if (!(item->type & cJSON_StringIsConst) && item->string) { - cJSON_free(item->string); + global_hooks.deallocate(item->string); } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-qual" @@ -1568,12 +1573,12 @@ void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { - cJSON_AddItemToArray(array, create_reference(item)); + cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); } void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { - cJSON_AddItemToObject(object, string, create_reference(item)); + cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); } static cJSON *DetachItemFromArray(cJSON *array, size_t which) @@ -1724,10 +1729,10 @@ void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem /* free the old string if not const */ if (!(newitem->type & cJSON_StringIsConst) && newitem->string) { - cJSON_free(newitem->string); + global_hooks.deallocate(newitem->string); } - newitem->string = (char*)cJSON_strdup((const unsigned char*)string); + newitem->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); ReplaceItemInArray(object, i, newitem); } } @@ -1735,7 +1740,7 @@ void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem /* Create basic types: */ cJSON *cJSON_CreateNull(void) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_NULL; @@ -1746,7 +1751,7 @@ cJSON *cJSON_CreateNull(void) cJSON *cJSON_CreateTrue(void) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_True; @@ -1757,7 +1762,7 @@ cJSON *cJSON_CreateTrue(void) cJSON *cJSON_CreateFalse(void) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_False; @@ -1768,7 +1773,7 @@ cJSON *cJSON_CreateFalse(void) cJSON *cJSON_CreateBool(cjbool b) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = b ? cJSON_True : cJSON_False; @@ -1779,7 +1784,7 @@ cJSON *cJSON_CreateBool(cjbool b) cJSON *cJSON_CreateNumber(double num) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_Number; @@ -1805,11 +1810,11 @@ cJSON *cJSON_CreateNumber(double num) cJSON *cJSON_CreateString(const char *string) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string); + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); if(!item->valuestring) { cJSON_Delete(item); @@ -1822,11 +1827,11 @@ cJSON *cJSON_CreateString(const char *string) extern cJSON *cJSON_CreateRaw(const char *raw) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw); + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); if(!item->valuestring) { cJSON_Delete(item); @@ -1839,7 +1844,7 @@ extern cJSON *cJSON_CreateRaw(const char *raw) cJSON *cJSON_CreateArray(void) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type=cJSON_Array; @@ -1850,7 +1855,7 @@ cJSON *cJSON_CreateArray(void) cJSON *cJSON_CreateObject(void) { - cJSON *item = cJSON_New_Item(); + cJSON *item = cJSON_New_Item(&global_hooks); if (item) { item->type = cJSON_Object; @@ -2017,7 +2022,7 @@ cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse) goto fail; } /* Create new item */ - newitem = cJSON_New_Item(); + newitem = cJSON_New_Item(&global_hooks); if (!newitem) { goto fail; @@ -2028,7 +2033,7 @@ cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse) newitem->valuedouble = item->valuedouble; if (item->valuestring) { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring); + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); if (!newitem->valuestring) { goto fail; @@ -2036,7 +2041,7 @@ cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse) } if (item->string) { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string); + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); if (!newitem->string) { goto fail; diff --git a/tests/common.c b/tests/common.c index 65ef97c0..9c1a109a 100644 --- a/tests/common.c +++ b/tests/common.c @@ -30,11 +30,11 @@ extern void reset(cJSON *item) } if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) { - cJSON_free(item->valuestring); + global_hooks.deallocate(item->valuestring); } if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) { - cJSON_free(item->string); + global_hooks.deallocate(item->string); } memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_array.c b/tests/parse_array.c index 5364739b..3b6a90fe 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -46,13 +46,13 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer)); + TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks)); assert_is_invalid(item); } static void assert_parse_array(const char *json) { - TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer)); + TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks)); assert_is_array(item); } diff --git a/tests/parse_object.c b/tests/parse_object.c index 8904e552..f6699388 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -54,14 +54,14 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer)); + TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks)); assert_is_invalid(item); reset(item); } static void assert_parse_object(const char *json) { - TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer)); + TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks)); assert_is_object(item); } diff --git a/tests/parse_string.c b/tests/parse_string.c index 67d78c42..f1352a00 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -47,15 +47,15 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Couldn't parse string."); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Couldn't parse string."); assert_is_string(item); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); - cJSON_free(item->valuestring); + global_hooks.deallocate(item->valuestring); item->valuestring = NULL; } #define assert_not_parse_string(string) \ - TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Malformed string should not be accepted");\ + TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Malformed string should not be accepted");\ assert_is_invalid(item) diff --git a/tests/parse_value.c b/tests/parse_value.c index bbd52c59..9db967f2 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -44,7 +44,7 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer)); + TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer, &global_hooks)); assert_is_value(item, type); } diff --git a/tests/print_array.c b/tests/print_array.c index 90e87209..e121c653 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -48,12 +48,12 @@ static void assert_print_array(const char * const expected, const char * const i unformatted_buffer.noalloc = true; memset(item, 0, sizeof(item)); - TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer), "Failed to parse array."); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse array."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, false, &unformatted_buffer), "Failed to print unformatted string."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, true, &formatted_buffer), "Failed to print formatted string."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct."); reset(item); diff --git a/tests/print_number.c b/tests/print_number.c index e0141b69..b195ccd8 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -37,7 +37,7 @@ static void assert_print_number(const char *expected, double input) memset(item, 0, sizeof(item)); cJSON_SetNumberValue(item, input); - TEST_ASSERT_NOT_NULL_MESSAGE(print_number(item, &buffer), "Failed to print number."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_number(item, &buffer, &global_hooks), "Failed to print number."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected."); } diff --git a/tests/print_object.c b/tests/print_object.c index 2f6f5bf1..b6dad6ee 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -48,12 +48,12 @@ static void assert_print_object(const char * const expected, const char * const unformatted_buffer.noalloc = true; memset(item, 0, sizeof(item)); - TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer), "Failed to parse object."); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse object."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, false, &unformatted_buffer), "Failed to print unformatted string."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, true, &formatted_buffer), "Failed to print formatted string."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct."); reset(item); diff --git a/tests/print_string.c b/tests/print_string.c index 1404160f..95214346 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -33,7 +33,7 @@ static void assert_print_string(const char *expected, const char *input) buffer.offset = 0; buffer.noalloc = true; - TEST_ASSERT_NOT_NULL_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer, &global_hooks), "Failed to print string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected."); } diff --git a/tests/print_value.c b/tests/print_value.c index 5aea9bfd..e72b78d8 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -41,9 +41,9 @@ static void assert_print_value(const char *input) memset(item, 0, sizeof(item)); - TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer), "Failed to parse value."); + TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse value."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_value(item, 0, false, &buffer), "Failed to print value."); + TEST_ASSERT_NOT_NULL_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected."); reset(item); From 501046247db97e470ba40b6ebc0f602e200c6511 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 21 Feb 2017 15:08:36 +0100 Subject: [PATCH 39/73] fix clang-sanitizer warnings --- cJSON.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 68a7bb85..cf43ce99 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1182,7 +1182,6 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, *output_pointer = '['; output_buffer->offset++; - current_element = item->child; while (current_element != NULL) { if (print_value(current_element, depth + 1, format, output_buffer, hooks) == NULL) @@ -1346,7 +1345,6 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, } output_buffer->offset += length; - current_item = item->child; while (current_item) { if (format) From c26d53f0d74b10b4f8fb290ee663cfdd14d0115a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 26 Feb 2017 14:30:50 +0100 Subject: [PATCH 40/73] Helper function to check the type of an item This is necessary, because you can get it wrong if you do it manually. (when you forget the & 0xFF in the comparison) --- cJSON.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cJSON.h | 12 +++++++ 2 files changed, 112 insertions(+) diff --git a/cJSON.c b/cJSON.c index cf43ce99..39593b79 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2149,3 +2149,103 @@ void cJSON_Minify(char *json) /* and null-terminate. */ *into = '\0'; } + +extern cjbool cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +extern cjbool cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +extern cjbool cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +extern cjbool cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +extern cjbool cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +extern cjbool cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +extern cjbool cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +extern cjbool cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +extern cjbool cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +extern cjbool cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} diff --git a/cJSON.h b/cJSON.h index de1f69f7..831df39f 100644 --- a/cJSON.h +++ b/cJSON.h @@ -109,6 +109,18 @@ extern int cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ extern const char *cJSON_GetErrorPtr(void); +/* These functions check the type of an item */ +extern int cJSON_IsInvalid(const cJSON * const item); +extern int cJSON_IsFalse(const cJSON * const item); +extern int cJSON_IsTrue(const cJSON * const item); +extern int cJSON_IsBool(const cJSON * const item); +extern int cJSON_IsNull(const cJSON * const item); +extern int cJSON_IsNumber(const cJSON * const item); +extern int cJSON_IsString(const cJSON * const item); +extern int cJSON_IsArray(const cJSON * const item); +extern int cJSON_IsObject(const cJSON * const item); +extern int cJSON_IsRaw(const cJSON * const item); + /* These calls create a cJSON item of the appropriate type. */ extern cJSON *cJSON_CreateNull(void); extern cJSON *cJSON_CreateTrue(void); From ed8dc536994dfe13cbf7a2c01b87f50cc5874977 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 26 Feb 2017 21:26:34 +0100 Subject: [PATCH 41/73] cJSON_Utils: Use new typecheck functions --- cJSON_Utils.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index d43b8e2a..d3e9a3fa 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -117,7 +117,6 @@ static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned cha char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) { - int type = object->type; size_t c = 0; cJSON *obj = 0; @@ -133,7 +132,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); if (found) { - if ((type & 0xFF) == cJSON_Array) + if (cJSON_IsArray(object)) { /* reserve enough memory for a 64 bit integer + '/' and '\0' */ unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23); @@ -150,7 +149,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) return (char*)ret; } - else if ((type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(object)) { unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2); *ret = '/'; @@ -176,7 +175,7 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer) /* follow path of the pointer */ while ((*pointer++ == '/') && object) { - if ((object->type & 0xFF) == cJSON_Array) + if (cJSON_IsArray(object)) { size_t which = 0; /* parse array index */ @@ -195,7 +194,7 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer) } object = cJSON_GetArrayItem(object, (int)which); } - else if ((object->type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(object)) { object = object->child; /* GetObjectItem. */ @@ -269,11 +268,11 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) /* Couldn't find object to remove child from. */ ret = NULL; } - else if ((parent->type & 0xFF) == cJSON_Array) + else if (cJSON_IsArray(parent)) { ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr)); } - else if ((parent->type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(parent)) { ret = cJSON_DetachItemFromObject(parent, (char*)childptr); } @@ -474,7 +473,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) cJSON_Delete(value); return 9; } - else if ((parent->type & 0xFF) == cJSON_Array) + else if (cJSON_IsArray(parent)) { if (!strcmp((char*)childptr, "-")) { @@ -485,7 +484,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) cJSON_InsertItemInArray(parent, atoi((char*)childptr), value); } } - else if ((parent->type & 0xFF) == cJSON_Object) + else if (cJSON_IsObject(parent)) { cJSON_DeleteItemFromObject(parent, (char*)childptr); cJSON_AddItemToObject(parent, (char*)childptr, value); @@ -508,7 +507,7 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) return 1; } - if ((patches->type & 0xFF) != cJSON_Array) + if (cJSON_IsArray(patches)) { /* malformed patches. */ return 1; @@ -793,14 +792,14 @@ void cJSONUtils_SortObject(cJSON *object) cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) { - if (!patch || ((patch->type & 0xFF) != cJSON_Object)) + if (!cJSON_IsObject(patch)) { /* scalar value, array or NULL, just duplicate */ cJSON_Delete(target); return cJSON_Duplicate(patch, 1); } - if (!target || ((target->type & 0xFF) != cJSON_Object)) + if (!cJSON_IsObject(target)) { cJSON_Delete(target); target = cJSON_CreateObject(); @@ -809,7 +808,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) patch = patch->child; while (patch) { - if ((patch->type & 0xFF) == cJSON_NULL) + if (cJSON_IsNull(patch)) { /* NULL is the indicator to remove a value, see RFC7396 */ cJSON_DeleteItemFromObject(target, patch->string); @@ -832,7 +831,7 @@ cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) /* patch to delete everything */ return cJSON_CreateNull(); } - if (((to->type & 0xFF) != cJSON_Object) || !from || ((from->type & 0xFF) != cJSON_Object)) + if (!cJSON_IsObject(to) || !cJSON_IsObject(from)) { return cJSON_Duplicate(to, 1); } From c45dc12fd74676be304b5e1f8db346e311fb54e2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 26 Feb 2017 21:54:01 +0100 Subject: [PATCH 42/73] Tests for typecheck functions --- tests/misc_tests.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 518ac72f..47dff72e 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -127,6 +127,62 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void) cJSON_Delete(item); } +static void typecheck_functions_should_check_type(void) +{ + cJSON invalid[1]; + cJSON item[1]; + invalid->type = cJSON_Invalid; + invalid->type |= cJSON_StringIsConst; + item->type = cJSON_False; + item->type |= cJSON_StringIsConst; + + TEST_ASSERT_FALSE(cJSON_IsInvalid(NULL)); + TEST_ASSERT_FALSE(cJSON_IsInvalid(item)); + TEST_ASSERT_TRUE(cJSON_IsInvalid(invalid)); + + item->type = cJSON_False | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsFalse(NULL)); + TEST_ASSERT_FALSE(cJSON_IsFalse(invalid)); + TEST_ASSERT_TRUE(cJSON_IsFalse(item)); + TEST_ASSERT_TRUE(cJSON_IsBool(item)); + + item->type = cJSON_True | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsTrue(NULL)); + TEST_ASSERT_FALSE(cJSON_IsTrue(invalid)); + TEST_ASSERT_TRUE(cJSON_IsTrue(item)); + TEST_ASSERT_TRUE(cJSON_IsBool(item)); + + item->type = cJSON_NULL | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsNull(NULL)); + TEST_ASSERT_FALSE(cJSON_IsNull(invalid)); + TEST_ASSERT_TRUE(cJSON_IsNull(item)); + + item->type = cJSON_Number | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsNumber(NULL)); + TEST_ASSERT_FALSE(cJSON_IsNumber(invalid)); + TEST_ASSERT_TRUE(cJSON_IsNumber(item)); + + item->type = cJSON_String | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsString(NULL)); + TEST_ASSERT_FALSE(cJSON_IsString(invalid)); + TEST_ASSERT_TRUE(cJSON_IsString(item)); + + item->type = cJSON_Array | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsArray(NULL)); + TEST_ASSERT_FALSE(cJSON_IsArray(invalid)); + TEST_ASSERT_TRUE(cJSON_IsArray(item)); + + item->type = cJSON_Object | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsObject(NULL)); + TEST_ASSERT_FALSE(cJSON_IsObject(invalid)); + TEST_ASSERT_TRUE(cJSON_IsObject(item)); + + item->type = cJSON_Raw | cJSON_StringIsConst; + TEST_ASSERT_FALSE(cJSON_IsRaw(NULL)); + TEST_ASSERT_FALSE(cJSON_IsRaw(invalid)); + TEST_ASSERT_TRUE(cJSON_IsRaw(item)); +} + int main(void) { UNITY_BEGIN(); @@ -135,6 +191,7 @@ int main(void) RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer); RUN_TEST(cjson_get_object_item_should_get_object_items); RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items); + RUN_TEST(typecheck_functions_should_check_type); return UNITY_END(); } From 039b1cc6538e96de2957b0714febf5d787941e9e Mon Sep 17 00:00:00 2001 From: Mike Jerris Date: Mon, 27 Feb 2017 13:02:50 -0600 Subject: [PATCH 43/73] add CJSON_PUBLIC macro to public functions to support visibility and dllimport/dllexport --- cJSON.c | 86 +++++++++++++++++------------------ cJSON.h | 121 ++++++++++++++++++++++++++++++++------------------ cJSON_Utils.c | 16 +++---- cJSON_Utils.h | 16 +++---- 4 files changed, 138 insertions(+), 101 deletions(-) diff --git a/cJSON.c b/cJSON.c index cf43ce99..5e809a94 100644 --- a/cJSON.c +++ b/cJSON.c @@ -39,7 +39,7 @@ typedef int cjbool; static const unsigned char *global_ep = NULL; -const char *cJSON_GetErrorPtr(void) +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) { return (const char*) global_ep; } @@ -49,7 +49,7 @@ const char *cJSON_GetErrorPtr(void) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif -extern const char* cJSON_Version(void) +CJSON_PUBLIC(const char*) cJSON_Version(void) { static char version[15]; sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); @@ -108,7 +108,7 @@ static unsigned char* cJSON_strdup(const unsigned char* str, const internal_hook return copy; } -void cJSON_InitHooks(cJSON_Hooks* hooks) +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { if (hooks == NULL) { @@ -152,7 +152,7 @@ static cJSON *cJSON_New_Item(const internal_hooks * const hooks) } /* Delete a cJSON structure. */ -void cJSON_Delete(cJSON *c) +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c) { cJSON *next = NULL; while (c) @@ -214,7 +214,7 @@ static const unsigned char *parse_number(cJSON * const item, const unsigned char } /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -double cJSON_SetNumberHelper(cJSON *object, double number) +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) { if (number >= INT_MAX) { @@ -805,7 +805,7 @@ static const unsigned char *skip_whitespace(const unsigned char *in) } /* Parse an object - create a new root, and populate. */ -cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated) +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated) { const unsigned char *end = NULL; /* use global error pointer if no specific one was given */ @@ -845,7 +845,7 @@ cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjb } /* Default options for cJSON_Parse */ -cJSON *cJSON_Parse(const char *value) +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); } @@ -902,17 +902,17 @@ static unsigned char *print(const cJSON * const item, cjbool format, const inter } /* Render a cJSON item/entity/structure to text. */ -char *cJSON_Print(const cJSON *item) +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { return (char*)print(item, true, &global_hooks); } -char *cJSON_PrintUnformatted(const cJSON *item) +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { return (char*)print(item, false, &global_hooks); } -char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) { printbuffer p; @@ -934,7 +934,7 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) return (char*)print_value(item, 0, fmt, &p, &global_hooks); } -int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool fmt) +CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool fmt) { printbuffer p; @@ -1432,7 +1432,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, } /* Get Array size/item / object item. */ -int cJSON_GetArraySize(const cJSON *array) +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) { cJSON *c = array->child; size_t i = 0; @@ -1447,7 +1447,7 @@ int cJSON_GetArraySize(const cJSON *array) return (int)i; } -cJSON *cJSON_GetArrayItem(const cJSON *array, int item) +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item) { cJSON *c = array ? array->child : NULL; while (c && item > 0) @@ -1459,7 +1459,7 @@ cJSON *cJSON_GetArrayItem(const cJSON *array, int item) return c; } -cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string) +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string) { cJSON *c = object ? object->child : NULL; while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) @@ -1469,7 +1469,7 @@ cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string) return c; } -cJSON *cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) { cJSON *current_element = NULL; @@ -1487,7 +1487,7 @@ cJSON *cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * return current_element; } -cjbool cJSON_HasObjectItem(const cJSON *object, const char *string) +CJSON_PUBLIC(cjbool) cJSON_HasObjectItem(const cJSON *object, const char *string) { return cJSON_GetObjectItem(object, string) ? 1 : 0; } @@ -1515,7 +1515,7 @@ static cJSON *create_reference(const cJSON *item, const internal_hooks * const h } /* Add item to array/object. */ -void cJSON_AddItemToArray(cJSON *array, cJSON *item) +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) { cJSON *child = NULL; @@ -1542,7 +1542,7 @@ void cJSON_AddItemToArray(cJSON *array, cJSON *item) } } -void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { /* call cJSON_AddItemToObjectCS for code reuse */ cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); @@ -1551,7 +1551,7 @@ void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) } /* Add an item to an object with constant string as key */ -void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { if (!item) { @@ -1569,12 +1569,12 @@ void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) cJSON_AddItemToArray(object, item); } -void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); } -void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); } @@ -1610,7 +1610,7 @@ static cJSON *DetachItemFromArray(cJSON *array, size_t which) return c; } -cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) { if (which < 0) { @@ -1620,12 +1620,12 @@ cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) return DetachItemFromArray(array, (size_t)which); } -void cJSON_DeleteItemFromArray(cJSON *array, int which) +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); } -cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) { size_t i = 0; cJSON *c = object->child; @@ -1642,13 +1642,13 @@ cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) return NULL; } -void cJSON_DeleteItemFromObject(cJSON *object, const char *string) +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); } /* Replace array/object items with new ones. */ -void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) { cJSON *c = array->child; while (c && (which > 0)) @@ -1703,7 +1703,7 @@ static void ReplaceItemInArray(cJSON *array, size_t which, cJSON *newitem) c->next = c->prev = NULL; cJSON_Delete(c); } -void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { if (which < 0) { @@ -1713,7 +1713,7 @@ void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) ReplaceItemInArray(array, (size_t)which, newitem); } -void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { size_t i = 0; cJSON *c = object->child; @@ -1736,7 +1736,7 @@ void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem } /* Create basic types: */ -cJSON *cJSON_CreateNull(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1747,7 +1747,7 @@ cJSON *cJSON_CreateNull(void) return item; } -cJSON *cJSON_CreateTrue(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1758,7 +1758,7 @@ cJSON *cJSON_CreateTrue(void) return item; } -cJSON *cJSON_CreateFalse(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1769,7 +1769,7 @@ cJSON *cJSON_CreateFalse(void) return item; } -cJSON *cJSON_CreateBool(cjbool b) +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cjbool b) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1780,7 +1780,7 @@ cJSON *cJSON_CreateBool(cjbool b) return item; } -cJSON *cJSON_CreateNumber(double num) +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1806,7 +1806,7 @@ cJSON *cJSON_CreateNumber(double num) return item; } -cJSON *cJSON_CreateString(const char *string) +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1823,7 +1823,7 @@ cJSON *cJSON_CreateString(const char *string) return item; } -extern cJSON *cJSON_CreateRaw(const char *raw) +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1840,7 +1840,7 @@ extern cJSON *cJSON_CreateRaw(const char *raw) return item; } -cJSON *cJSON_CreateArray(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -1851,7 +1851,7 @@ cJSON *cJSON_CreateArray(void) return item; } -cJSON *cJSON_CreateObject(void) +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) { cJSON *item = cJSON_New_Item(&global_hooks); if (item) @@ -1863,7 +1863,7 @@ cJSON *cJSON_CreateObject(void) } /* Create Arrays: */ -cJSON *cJSON_CreateIntArray(const int *numbers, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) { size_t i = 0; cJSON *n = NULL; @@ -1898,7 +1898,7 @@ cJSON *cJSON_CreateIntArray(const int *numbers, int count) return a; } -cJSON *cJSON_CreateFloatArray(const float *numbers, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) { size_t i = 0; cJSON *n = NULL; @@ -1934,7 +1934,7 @@ cJSON *cJSON_CreateFloatArray(const float *numbers, int count) return a; } -cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) { size_t i = 0; cJSON *n = NULL; @@ -1970,7 +1970,7 @@ cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) return a; } -cJSON *cJSON_CreateStringArray(const char **strings, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) { size_t i = 0; cJSON *n = NULL; @@ -2007,7 +2007,7 @@ cJSON *cJSON_CreateStringArray(const char **strings, int count) } /* Duplication */ -cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse) +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cjbool recurse) { cJSON *newitem = NULL; cJSON *child = NULL; @@ -2086,7 +2086,7 @@ cJSON *cJSON_Duplicate(const cJSON *item, cjbool recurse) return NULL; } -void cJSON_Minify(char *json) +CJSON_PUBLIC(void) cJSON_Minify(char *json) { unsigned char *into = (unsigned char*)json; while (*json) diff --git a/cJSON.h b/cJSON.h index de1f69f7..4064a5b2 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,85 +81,122 @@ typedef struct cJSON_Hooks void (*free_fn)(void *ptr); } cJSON_Hooks; +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type __stdcall +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall +#else +#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall +#endif +#else /* !WIN32 */ +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + /* Supply malloc, realloc and free functions to cJSON */ -extern void cJSON_InitHooks(cJSON_Hooks* hooks); +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ -extern cJSON *cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ -extern char *cJSON_Print(const cJSON *item); +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ -extern char *cJSON_PrintUnformatted(const cJSON *item); +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); /* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */ -extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); +CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); /* Delete a cJSON entity and all subentities. */ -extern void cJSON_Delete(cJSON *c); +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); /* Returns the number of items in an array (or object). */ -extern int cJSON_GetArraySize(const cJSON *array); +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ -extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item); +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item); /* Get item "string" from object. Case insensitive. */ -extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string); -extern cJSON *cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string); -extern int cJSON_HasObjectItem(const cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string); +CJSON_PUBLIC(int) cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -extern const char *cJSON_GetErrorPtr(void); +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* These calls create a cJSON item of the appropriate type. */ -extern cJSON *cJSON_CreateNull(void); -extern cJSON *cJSON_CreateTrue(void); -extern cJSON *cJSON_CreateFalse(void); -extern cJSON *cJSON_CreateBool(int b); -extern cJSON *cJSON_CreateNumber(double num); -extern cJSON *cJSON_CreateString(const char *string); +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(int b); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); /* raw json */ -extern cJSON *cJSON_CreateRaw(const char *raw); -extern cJSON *cJSON_CreateArray(void); -extern cJSON *cJSON_CreateObject(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* These utilities create an Array of count items. */ -extern cJSON *cJSON_CreateIntArray(const int *numbers, int count); -extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count); -extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count); -extern cJSON *cJSON_CreateStringArray(const char **strings, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); /* Append item to the specified array/object. */ -extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before * writing to `item->string` */ -extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); /* Remove/Detatch items from Arrays/Objects. */ -extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which); -extern void cJSON_DeleteItemFromArray(cJSON *array, int which); -extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string); -extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); /* Update array items. */ -extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); /* Duplicate a cJSON item */ -extern cJSON *cJSON_Duplicate(const cJSON *item, int recurse); +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, int recurse); /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will need to be released. With recurse!=0, it will duplicate any children connected to the item. The item->next and ->prev pointers are always zero on return from Duplicate. */ /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ -extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated); -extern void cJSON_Minify(char *json); +CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Macros for creating things quickly. */ #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) @@ -173,7 +210,7 @@ extern void cJSON_Minify(char *json); /* When assigning an integer value, it needs to be propagated to valuedouble too. */ #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); +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) /* Macro for iterating over an array */ diff --git a/cJSON_Utils.c b/cJSON_Utils.c index d43b8e2a..c38071cf 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -115,7 +115,7 @@ static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned cha *d = '\0'; } -char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) +CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) { int type = object->type; size_t c = 0; @@ -171,7 +171,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) return NULL; } -cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer) +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer) { /* follow path of the pointer */ while ((*pointer++ == '/') && object) @@ -499,7 +499,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) return 0; } -int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) +CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) { int err = 0; @@ -551,7 +551,7 @@ static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, co cJSON_AddItemToArray(patches, patch); } -void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val) +CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val) { cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val); } @@ -671,7 +671,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, } } -cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to) +CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to) { cJSON *patches = cJSON_CreateArray(); cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to); @@ -786,12 +786,12 @@ static cJSON *cJSONUtils_SortList(cJSON *list) return list; } -void cJSONUtils_SortObject(cJSON *object) +CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object) { object->child = cJSONUtils_SortList(object->child); } -cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch) { if (!patch || ((patch->type & 0xFF) != cJSON_Object)) { @@ -824,7 +824,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch) return target; } -cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) { cJSON *patch = NULL; if (!to) diff --git a/cJSON_Utils.h b/cJSON_Utils.h index cefda08b..6baf9c62 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -1,14 +1,14 @@ #include "cJSON.h" /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ -cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer); +CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer); /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ -cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); +CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); /* Utility for generating patch array entries. */ -void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val); +CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val); /* Returns 0 for success. */ -int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches); +CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches); /* // Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use: @@ -33,12 +33,12 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches); /* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */ /* target will be modified by patch. return value is new ptr for target. */ -cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch); +CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch); /* generates a patch to move from -> to */ -cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); +CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); /* Given a root object and a target object, construct a pointer from one to the other. */ -char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target); +CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target); /* Sorts the members of the object into alphabetical order. */ -void cJSONUtils_SortObject(cJSON *object); +CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object); From 2837aac23efbd789f50c6e346119eab4e5041515 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Feb 2017 23:04:29 +0100 Subject: [PATCH 44/73] Contributors: Add Mike Jerris --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6ab649b4..e0f4473a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -21,6 +21,7 @@ Contributors * [Linus Wallgren](https://github.com/ecksun) * [Max Bruckner](https://github.com/FSMaxB) * Mike Pontillo +* [Mike Jerris](https://github.com/mjerris) * Paulo Antonio Alvarez * [Rafael Leal Dias](https://github.com/rafaeldias) * [Rod Vagg](https://github.com/rvagg) From 1f422b586ac57ca4b409aa5ecc92000a40a06835 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 09:23:18 +0100 Subject: [PATCH 45/73] Squashed 'tests/unity/' changes from 1782bab..2988e98 2988e98 Merge pull request #262 from codehearts/patch-2 1732698 Fixed incorrect TEST_PROTECT explanation in readme 3817375 Merge pull request #260 from jeremyhannon/parseUnityFixtureOutputToJUnitFormat 9d5159f Merge pull request #261 from codehearts/patch-1 65ce727 Fixed typo for TEST_PROTECT in readme 4dc04d3 Enhance parseOutput.rb to support Unity fixture output git-subtree-dir: tests/unity git-subtree-split: 2988e980fbc2252fa4290b608517d4ae25cd9a46 --- README.md | 4 ++-- auto/parseOutput.rb | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fef275c9..11759c84 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ Example: main() { - if (TEST_PROTECT() == 0) + if (TEST_PROTECT()) { MyTest(); } } -If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a non-zero return value. +If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a return value of zero. Unity Assertion Summary diff --git a/auto/parseOutput.rb b/auto/parseOutput.rb index 7ea180f4..e8dbf08b 100644 --- a/auto/parseOutput.rb +++ b/auto/parseOutput.rb @@ -65,6 +65,17 @@ def testPassed(array) @arrayList.push " " end end + +# Test was flagged as having passed so format the output. +# This is using the Unity fixture output and not the original Unity output. + def testPassedUnityFixture(array) + testSuite = array[0].sub("TEST(", "") + testSuite = testSuite.sub(",", "") + testName = array[1].sub(")", "") + if @xmlOut == true + @arrayList.push " " + end + end # Test was flagged as being ingored so format the output def testIgnored(array) @@ -73,6 +84,14 @@ def testIgnored(array) reason = array[lastItem].chomp testSuiteVerify(array[@className]) printf "%-40s IGNORED\n", testName + + if testName.start_with? "TEST(" + array2 = testName.split(" ") + @testSuite = array2[0].sub("TEST(", "") + @testSuite = @testSuite.sub(",", "") + testName = array2[1].sub(")", "") + end + if @xmlOut == true @arrayList.push " " @arrayList.push " " + reason + " " @@ -87,6 +106,14 @@ def testFailed(array) reason = array[lastItem].chomp + " at line: " + array[lastItem - 3] testSuiteVerify(array[@className]) printf "%-40s FAILED\n", testName + + if testName.start_with? "TEST(" + array2 = testName.split(" ") + @testSuite = array2[0].sub("TEST(", "") + @testSuite = @testSuite.sub(",", "") + testName = array2[1].sub(")", "") + end + if @xmlOut == true @arrayList.push " " @arrayList.push " " + reason + " " @@ -138,7 +165,7 @@ def process(name) lineSize = lineArray.size # If we were able to split the line then we can look to see if any of our target words # were found. Case is important. - if lineSize >= 4 + if ((lineSize >= 4) || (line.start_with? "TEST(")) # Determine if this test passed if line.include? ":PASS" testPassed(lineArray) @@ -149,6 +176,12 @@ def process(name) elsif line.include? ":IGNORE:" testIgnored(lineArray) testIgnore += 1 + elsif line.start_with? "TEST(" + if line.include? " PASS" + lineArray = line.split(" ") + testPassedUnityFixture(lineArray) + testPass += 1 + end # If none of the keywords are found there are no more tests for this suite so clear # the test flag else From b056d7cb74ba9f507c5c8c9d8b93cfac17197c24 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 08:36:34 +0100 Subject: [PATCH 46/73] Add -Wcomma compiler flag --- CMakeLists.txt | 1 + cJSON.c | 4 ++-- cJSON_Utils.c | 18 +++++++++--------- tests/parse_array.c | 2 +- tests/parse_object.c | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de01b79a..c9a22ffa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wconversion -Wc++-compat -fstack-protector-strong + -Wcomma ) endif() diff --git a/cJSON.c b/cJSON.c index c6cb4664..71dee8d8 100644 --- a/cJSON.c +++ b/cJSON.c @@ -68,7 +68,7 @@ static int cJSON_strcasecmp(const unsigned char *s1, const unsigned char *s2) { return 1; } - for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) + for(; tolower(*s1) == tolower(*s2); (void)++s1, ++s2) { if (*s1 == '\0') { @@ -731,7 +731,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb output[0] = '\"'; output_pointer = output + 1; /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; input_pointer++, output_pointer++) + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 534f897a..8ff1b335 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -31,7 +31,7 @@ static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s { return 1; } - for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) + for(; tolower(*s1) == tolower(*s2); (void)++s1, ++s2) { if(*s1 == 0) { @@ -49,7 +49,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e { return (a == e) ? 0 : 1; /* both NULL? */ } - for (; *a && *e && (*e != '/'); a++, e++) /* compare until next '/' */ + for (; *a && *e && (*e != '/'); (void)a++, e++) /* compare until next '/' */ { if (*e == '~') { @@ -81,7 +81,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s) { size_t l = 0; - for (; *s; s++, l++) + for (; *s; (void)s++, l++) { if ((*s == '~') || (*s == '/')) { @@ -127,7 +127,7 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *ta } /* recursively search all children of the object */ - for (obj = object->child; obj; obj = obj->next, c++) + for (obj = object->child; obj; (void)(obj = obj->next), c++) { unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); if (found) @@ -226,7 +226,7 @@ static void cJSONUtils_InplaceDecodePointerString(unsigned char *string) return; } - for (; *string; s2++, string++) + for (; *string; (void)s2++, string++) { *s2 = (*string != '~') ? (*string) @@ -298,7 +298,7 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b) /* string mismatch. */ return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0; case cJSON_Array: - for (a = a->child, b = b->child; a && b; a = a->next, b = b->next) + for ((void)(a = a->child), b = b->child; a && b; (void)(a = a->next), b = b->next) { int err = cJSONUtils_Compare(a, b); if (err) @@ -589,7 +589,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, size_t c = 0; unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */ /* generate patches for all array elements that exist in "from" and "to" */ - for (c = 0, from = from->child, to = to->child; from && to; from = from->next, to = to->next, c++) + for ((void)(c = 0), (void)(from = from->child), to = to->child; from && to; (void)(from = from->next), (void)(to = to->next), c++) { /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination @@ -603,7 +603,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSONUtils_CompareToPatch(patches, newpath, from, to); } /* remove leftover elements from 'from' that are not in 'to' */ - for (; from; from = from->next, c++) + for (; from; (void)(from = from->next), c++) { /* check if conversion to unsigned long is valid * This should be eliminated at compile time by dead code elimination @@ -617,7 +617,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0); } /* add new elements in 'to' that were not in 'from' */ - for (; to; to = to->next, c++) + for (; to; (void)(to = to->next), c++) { cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to); } diff --git a/tests/parse_array.c b/tests/parse_array.c index 3b6a90fe..47dd44f8 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -124,7 +124,7 @@ static void parse_array_should_parse_arrays_with_multiple_elements(void) i = 0; (i < (sizeof(expected_types)/sizeof(int))) && (node != NULL); - i++, node = node->next) + (void)i++, node = node->next) { TEST_ASSERT_BITS(0xFF, expected_types[i], node->type); } diff --git a/tests/parse_object.c b/tests/parse_object.c index f6699388..0f8569cd 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -134,7 +134,7 @@ static void parse_object_should_parse_objects_with_multiple_elements(void) i = 0; (i < (sizeof(expected_types)/sizeof(int))) && (node != NULL); - i++, node = node->next) + (void)i++, node = node->next) { assert_is_child(node, expected_names[i], expected_types[i]); } From 40e3781e9ba326a89625dd12b46c55c9916dd6ed Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 08:56:17 +0100 Subject: [PATCH 47/73] CMake: Disable -Werror for Unity --- tests/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3e3e8c79..4767e502 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,13 @@ add_library(unity unity/src/unity.c) if(ENABLE_CJSON_TEST) + + # Disable -Werror for Unity + list(FIND custom_compiler_flags "-Werror" werror_found) + if (werror_found) + target_compile_options(unity PRIVATE "-Wno-error") + endif() + #copy test files file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs") file(GLOB test_files "inputs/*") From 3f349a425880131a09ab4839d36dc416291adedb Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 08:58:11 +0100 Subject: [PATCH 48/73] Add -Wdouble-promotion compiler flag --- CMakeLists.txt | 1 + cJSON.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9a22ffa..730ee1f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wc++-compat -fstack-protector-strong -Wcomma + -Wdouble-promotion ) endif() diff --git a/cJSON.c b/cJSON.c index 71dee8d8..392da69e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1914,7 +1914,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) for(i = 0; a && (i < (size_t)count); i++) { - n = cJSON_CreateNumber(numbers[i]); + n = cJSON_CreateNumber((double)numbers[i]); if(!n) { cJSON_Delete(a); From 5cf56fa4fad0e656e3779e4589fb38a6f846c079 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 09:05:43 +0100 Subject: [PATCH 49/73] Add -Wparentheses compile option --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 730ee1f3..745e52f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -fstack-protector-strong -Wcomma -Wdouble-promotion + -Wparentheses ) endif() From 1e0bd24f2cae585a198e6661def3f9b82e81cf5a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 09:12:09 +0100 Subject: [PATCH 50/73] Revert "unity: make it work with -Wconversion" This reverts commit 12acc57967aef0c859e2a0a877b7a1530faad068. --- tests/unity/src/unity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unity/src/unity.c b/tests/unity/src/unity.c index ece0d9be..54a34526 100644 --- a/tests/unity/src/unity.c +++ b/tests/unity/src/unity.c @@ -194,7 +194,7 @@ void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) while (nibbles > 0) { nibbles--; - nibble = (int)(number >> (nibbles * 4)) & 0x0F; + nibble = (number >> (nibbles * 4)) & 0x0F; if (nibble <= 9) { UNITY_OUTPUT_CHAR((char)('0' + nibble)); From 6f271e511f2e4efe2d2be7043c896423365b004a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 12:56:01 +0100 Subject: [PATCH 51/73] print_number: Use sprintf's return value This is used to update the buffer offset and determine success --- cJSON.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index 392da69e..25977fa9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -329,6 +329,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const { unsigned char *output_pointer = NULL; double d = item->valuedouble; + int length = 0; if (output_buffer == NULL) { @@ -342,7 +343,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_pointer = ensure(output_buffer, 21, hooks); if (output_pointer != NULL) { - sprintf((char*)output_pointer, "%d", item->valueint); + length = sprintf((char*)output_pointer, "%d", item->valueint); } } /* value is a floating point number */ @@ -355,23 +356,31 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const /* This checks for NaN and Infinity */ if ((d * 0) != 0) { - sprintf((char*)output_pointer, "null"); + length = sprintf((char*)output_pointer, "null"); } else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { - sprintf((char*)output_pointer, "%.0f", d); + length = sprintf((char*)output_pointer, "%.0f", d); } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) { - sprintf((char*)output_pointer, "%e", d); + length = sprintf((char*)output_pointer, "%e", d); } else { - sprintf((char*)output_pointer, "%f", d); + length = sprintf((char*)output_pointer, "%f", d); } } } + /* sprintf failed */ + if (length < 0) + { + return NULL; + } + + output_buffer->offset += (size_t)length; + return output_pointer; } From e78bc423622e8276e22e3d788ccd2588b9432205 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 13:00:52 +0100 Subject: [PATCH 52/73] print_number: Return buffer + offset instead of beginning of the number --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 25977fa9..a823e60d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -381,7 +381,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer->offset += (size_t)length; - return output_pointer; + return output_buffer->buffer + output_buffer->offset; } /* parse 4 digit hexadecimal number */ From 1ea72f8260916bb70e6443509556b6f53922b941 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 13:20:14 +0100 Subject: [PATCH 53/73] print_number: Remove trailing zeroes (for doubles) --- cJSON.c | 41 +++++++++++++++++++++++++++++++++++++ tests/inputs/test7.expected | 6 +++--- tests/print_number.c | 4 ++-- tests/print_value.c | 2 +- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index a823e60d..5f586894 100644 --- a/cJSON.c +++ b/cJSON.c @@ -324,12 +324,44 @@ static void update_offset(printbuffer * const buffer) buffer->offset += strlen((const char*)buffer_pointer); } +/* Removes trailing zeroes from the end of a printed number */ +static unsigned char *trim_trailing_zeroes(printbuffer * const buffer) +{ + size_t offset = 0; + unsigned char *content = NULL; + + if ((buffer == NULL) || (buffer->buffer == NULL) || (buffer->offset < 1)) + { + return NULL; + } + + offset = buffer->offset - 1; + content = buffer->buffer; + + while ((offset > 0) && (content[offset] == '0')) + { + offset--; + } + if ((offset > 0) && (content[offset] == '.')) + { + offset--; + } + + offset++; + content[offset] = '\0'; + + buffer->offset = offset; + + return content + offset; +} + /* Render the number nicely from the given item into a string. */ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output_pointer = NULL; double d = item->valuedouble; int length = 0; + cjbool trim_zeroes = true; /* should at the end be removed? */ if (output_buffer == NULL) { @@ -339,6 +371,8 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const /* value is an int */ if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { + trim_zeroes = false; /* don't remove zeroes for integers */ + /* 2^64+1 can be represented in 21 chars. */ output_pointer = ensure(output_buffer, 21, hooks); if (output_pointer != NULL) @@ -361,10 +395,12 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { length = sprintf((char*)output_pointer, "%.0f", d); + trim_zeroes = false; /* don't remove zeroes for "big integers" */ } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) { length = sprintf((char*)output_pointer, "%e", d); + trim_zeroes = false; /* don't remove zeroes in engineering notation */ } else { @@ -381,6 +417,11 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer->offset += (size_t)length; + if (trim_zeroes) + { + return trim_trailing_zeroes(output_buffer); + } + return output_buffer->buffer + output_buffer->offset; } diff --git a/tests/inputs/test7.expected b/tests/inputs/test7.expected index 6e2e0757..15adf793 100644 --- a/tests/inputs/test7.expected +++ b/tests/inputs/test7.expected @@ -1,7 +1,7 @@ [{ "precision": "zip", - "Latitude": 37.766800, - "Longitude": -122.395900, + "Latitude": 37.7668, + "Longitude": -122.3959, "Address": "", "City": "SAN FRANCISCO", "State": "CA", @@ -10,7 +10,7 @@ }, { "precision": "zip", "Latitude": 37.371991, - "Longitude": -122.026020, + "Longitude": -122.02602, "Address": "", "City": "SUNNYVALE", "State": "CA", diff --git a/tests/print_number.c b/tests/print_number.c index b195ccd8..e9037340 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -62,7 +62,7 @@ static void print_number_should_print_positive_integers(void) static void print_number_should_print_positive_reals(void) { - assert_print_number("0.123000", 0.123); + assert_print_number("0.123", 0.123); assert_print_number("1.000000e-09", 10e-10); assert_print_number("1000000000000", 10e11); assert_print_number("1.230000e+129", 123e+127); @@ -71,7 +71,7 @@ static void print_number_should_print_positive_reals(void) static void print_number_should_print_negative_reals(void) { - assert_print_number("-0.012300", -0.0123); + assert_print_number("-0.0123", -0.0123); assert_print_number("-1.000000e-09", -10e-10); assert_print_number("-1000000000000000000000", -10e20); assert_print_number("-1.230000e+129", -123e+127); diff --git a/tests/print_value.c b/tests/print_value.c index e72b78d8..41ee2864 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -66,7 +66,7 @@ static void print_value_should_print_false(void) static void print_value_should_print_number(void) { - assert_print_value("1.500000"); + assert_print_value("1.5"); } static void print_value_should_print_string(void) From dd4cb5400ffd02dc4c09d50501a22d63e65bb497 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 13:26:52 +0100 Subject: [PATCH 54/73] print_number: Remove unnecessary integer handling --- cJSON.c | 53 +++++++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/cJSON.c b/cJSON.c index 5f586894..8bb545dd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -368,44 +368,29 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const return NULL; } - /* value is an int */ - if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) + /* This is a nice tradeoff. */ + output_pointer = ensure(output_buffer, 64, hooks); + if (output_pointer != NULL) { - trim_zeroes = false; /* don't remove zeroes for integers */ - - /* 2^64+1 can be represented in 21 chars. */ - output_pointer = ensure(output_buffer, 21, hooks); - if (output_pointer != NULL) + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) { - length = sprintf((char*)output_pointer, "%d", item->valueint); + length = sprintf((char*)output_pointer, "null"); } - } - /* value is a floating point number */ - else - { - /* This is a nice tradeoff. */ - output_pointer = ensure(output_buffer, 64, hooks); - if (output_pointer != NULL) + else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { - /* This checks for NaN and Infinity */ - if ((d * 0) != 0) - { - length = sprintf((char*)output_pointer, "null"); - } - else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) - { - length = sprintf((char*)output_pointer, "%.0f", d); - trim_zeroes = false; /* don't remove zeroes for "big integers" */ - } - else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) - { - length = sprintf((char*)output_pointer, "%e", d); - trim_zeroes = false; /* don't remove zeroes in engineering notation */ - } - else - { - length = sprintf((char*)output_pointer, "%f", d); - } + /* integer */ + length = sprintf((char*)output_pointer, "%.0f", d); + trim_zeroes = false; /* don't remove zeroes for "big integers" */ + } + else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) + { + length = sprintf((char*)output_pointer, "%e", d); + trim_zeroes = false; /* don't remove zeroes in engineering notation */ + } + else + { + length = sprintf((char*)output_pointer, "%f", d); } } From 0c0dd4a5b099a5a748da9f074fbd8aac062c1a26 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 18:29:01 +0100 Subject: [PATCH 55/73] tests: test trim_trailing_zeroes --- tests/print_number.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/print_number.c b/tests/print_number.c index e9037340..ad25b744 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -87,6 +87,22 @@ static void print_number_should_print_non_number(void) /* assert_print_number("null", -INFTY); */ } +static void trim_trailing_zeroes_should_trim_trailing_zeroes(void) +{ + printbuffer buffer; + unsigned char number[100]; + unsigned char *pointer = NULL; + buffer.length = sizeof(number); + buffer.buffer = number; + + strcpy((char*)number, "10.00"); + buffer.offset = sizeof("10.00") - 1; + pointer = trim_trailing_zeroes(&buffer); + TEST_ASSERT_EQUAL_UINT8('\0', *pointer); + TEST_ASSERT_EQUAL_STRING("10", number); + TEST_ASSERT_EQUAL_UINT(sizeof("10") - 1, buffer.offset); +} + int main(void) { /* initialize cJSON item */ @@ -98,6 +114,7 @@ int main(void) RUN_TEST(print_number_should_print_positive_reals); RUN_TEST(print_number_should_print_negative_reals); RUN_TEST(print_number_should_print_non_number); + RUN_TEST(trim_trailing_zeroes_should_trim_trailing_zeroes); return UNITY_END(); } From 412f4f7d6263f88490460d999b5f7ba028f46bb3 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 20:01:58 +0100 Subject: [PATCH 56/73] Use CJSON_PUBLIC for typecheck functions --- cJSON.c | 20 ++++++++++---------- cJSON.h | 26 +++++++++++++------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cJSON.c b/cJSON.c index 8bb545dd..be6f19a3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2185,7 +2185,7 @@ CJSON_PUBLIC(void) cJSON_Minify(char *json) *into = '\0'; } -extern cjbool cJSON_IsInvalid(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsInvalid(const cJSON * const item) { if (item == NULL) { @@ -2195,7 +2195,7 @@ extern cjbool cJSON_IsInvalid(const cJSON * const item) return (item->type & 0xFF) == cJSON_Invalid; } -extern cjbool cJSON_IsFalse(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsFalse(const cJSON * const item) { if (item == NULL) { @@ -2205,7 +2205,7 @@ extern cjbool cJSON_IsFalse(const cJSON * const item) return (item->type & 0xFF) == cJSON_False; } -extern cjbool cJSON_IsTrue(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsTrue(const cJSON * const item) { if (item == NULL) { @@ -2216,7 +2216,7 @@ extern cjbool cJSON_IsTrue(const cJSON * const item) } -extern cjbool cJSON_IsBool(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsBool(const cJSON * const item) { if (item == NULL) { @@ -2225,7 +2225,7 @@ extern cjbool cJSON_IsBool(const cJSON * const item) return (item->type & (cJSON_True | cJSON_False)) != 0; } -extern cjbool cJSON_IsNull(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsNull(const cJSON * const item) { if (item == NULL) { @@ -2235,7 +2235,7 @@ extern cjbool cJSON_IsNull(const cJSON * const item) return (item->type & 0xFF) == cJSON_NULL; } -extern cjbool cJSON_IsNumber(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsNumber(const cJSON * const item) { if (item == NULL) { @@ -2245,7 +2245,7 @@ extern cjbool cJSON_IsNumber(const cJSON * const item) return (item->type & 0xFF) == cJSON_Number; } -extern cjbool cJSON_IsString(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsString(const cJSON * const item) { if (item == NULL) { @@ -2255,7 +2255,7 @@ extern cjbool cJSON_IsString(const cJSON * const item) return (item->type & 0xFF) == cJSON_String; } -extern cjbool cJSON_IsArray(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsArray(const cJSON * const item) { if (item == NULL) { @@ -2265,7 +2265,7 @@ extern cjbool cJSON_IsArray(const cJSON * const item) return (item->type & 0xFF) == cJSON_Array; } -extern cjbool cJSON_IsObject(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsObject(const cJSON * const item) { if (item == NULL) { @@ -2275,7 +2275,7 @@ extern cjbool cJSON_IsObject(const cJSON * const item) return (item->type & 0xFF) == cJSON_Object; } -extern cjbool cJSON_IsRaw(const cJSON * const item) +CJSON_PUBLIC(cjbool) cJSON_IsRaw(const cJSON * const item) { if (item == NULL) { diff --git a/cJSON.h b/cJSON.h index 3066891e..59a05992 100644 --- a/cJSON.h +++ b/cJSON.h @@ -33,9 +33,6 @@ extern "C" #define CJSON_VERSION_MINOR 3 #define CJSON_VERSION_PATCH 0 -/* returns the version of cJSON as a string */ -extern const char* cJSON_Version(void); - #include /* cJSON Types: */ @@ -118,6 +115,9 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ #endif #endif +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + /* Supply malloc, realloc and free functions to cJSON */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); @@ -147,16 +147,16 @@ CJSON_PUBLIC(int) cJSON_HasObjectItem(const cJSON *object, const char *string); CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* These functions check the type of an item */ -extern int cJSON_IsInvalid(const cJSON * const item); -extern int cJSON_IsFalse(const cJSON * const item); -extern int cJSON_IsTrue(const cJSON * const item); -extern int cJSON_IsBool(const cJSON * const item); -extern int cJSON_IsNull(const cJSON * const item); -extern int cJSON_IsNumber(const cJSON * const item); -extern int cJSON_IsString(const cJSON * const item); -extern int cJSON_IsArray(const cJSON * const item); -extern int cJSON_IsObject(const cJSON * const item); -extern int cJSON_IsRaw(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(int) cJSON_IsRaw(const cJSON * const item); /* These calls create a cJSON item of the appropriate type. */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); From 2e118df0cdfaeb3fd14166e92e01bc9e88e3b472 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 22:42:10 +0100 Subject: [PATCH 57/73] tests/common.h: Remove unused prototype --- tests/common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/common.h b/tests/common.h index d5c8def6..53173455 100644 --- a/tests/common.h +++ b/tests/common.h @@ -27,7 +27,6 @@ extern void reset(cJSON *item); extern char *read_file(const char *filename); -extern cjbool assert_is_invalid(cJSON *item); /* assertion helper macros */ #define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.") From 2d3520e0b9d0eb870e8886e8a21c571eeddbb310 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 22:50:12 +0100 Subject: [PATCH 58/73] Use own cJSON_bool boolean type in the header --- cJSON.c | 55 +++++++++++++++++++++++++++---------------------------- cJSON.h | 34 ++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/cJSON.c b/cJSON.c index be6f19a3..af93a8af 100644 --- a/cJSON.c +++ b/cJSON.c @@ -33,9 +33,8 @@ #include "cJSON.h" /* define our own boolean type */ -typedef int cjbool; -#define true ((cjbool)1) -#define false ((cjbool)0) +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) static const unsigned char *global_ep = NULL; @@ -237,7 +236,7 @@ typedef struct unsigned char *buffer; size_t length; size_t offset; - cjbool noalloc; + cJSON_bool noalloc; } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ @@ -361,7 +360,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const unsigned char *output_pointer = NULL; double d = item->valuedouble; int length = 0; - cjbool trim_zeroes = true; /* should at the end be removed? */ + cJSON_bool trim_zeroes = true; /* should at the end be removed? */ if (output_buffer == NULL) { @@ -822,11 +821,11 @@ static unsigned char *print_string(const cJSON * const item, printbuffer * const /* Predeclare these prototypes. */ static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static unsigned char *print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static unsigned char *print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static unsigned char *print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); /* Utility to jump whitespace and cr/lf */ static const unsigned char *skip_whitespace(const unsigned char *in) @@ -840,7 +839,7 @@ static const unsigned char *skip_whitespace(const unsigned char *in) } /* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated) +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) { const unsigned char *end = NULL; /* use global error pointer if no specific one was given */ @@ -887,7 +886,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) #define min(a, b) ((a < b) ? a : b) -static unsigned char *print(const cJSON * const item, cjbool format, const internal_hooks * const hooks) +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) { printbuffer buffer[1]; unsigned char *printed = NULL; @@ -947,7 +946,7 @@ CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) return (char*)print(item, false, &global_hooks); } -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) { printbuffer p; @@ -969,7 +968,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjboo return (char*)print_value(item, 0, fmt, &p, &global_hooks); } -CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool fmt) +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) { printbuffer p; @@ -1040,7 +1039,7 @@ static const unsigned char *parse_value(cJSON * const item, const unsigned char } /* Render a value to text. */ -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) +static unsigned char *print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; @@ -1192,7 +1191,7 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char } /* Render an array to text */ -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) +static unsigned char *print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; unsigned char *output_pointer = NULL; @@ -1351,7 +1350,7 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* Render an object to text. */ -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) +static unsigned char *print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; unsigned char *output_pointer = NULL; @@ -1522,7 +1521,7 @@ CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const objec return current_element; } -CJSON_PUBLIC(cjbool) cJSON_HasObjectItem(const cJSON *object, const char *string) +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) { return cJSON_GetObjectItem(object, string) ? 1 : 0; } @@ -1804,7 +1803,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) return item; } -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cjbool b) +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) @@ -2042,7 +2041,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) } /* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cjbool recurse) +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) { cJSON *newitem = NULL; cJSON *child = NULL; @@ -2185,7 +2184,7 @@ CJSON_PUBLIC(void) cJSON_Minify(char *json) *into = '\0'; } -CJSON_PUBLIC(cjbool) cJSON_IsInvalid(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) { if (item == NULL) { @@ -2195,7 +2194,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsInvalid(const cJSON * const item) return (item->type & 0xFF) == cJSON_Invalid; } -CJSON_PUBLIC(cjbool) cJSON_IsFalse(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) { if (item == NULL) { @@ -2205,7 +2204,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsFalse(const cJSON * const item) return (item->type & 0xFF) == cJSON_False; } -CJSON_PUBLIC(cjbool) cJSON_IsTrue(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) { if (item == NULL) { @@ -2216,7 +2215,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsTrue(const cJSON * const item) } -CJSON_PUBLIC(cjbool) cJSON_IsBool(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) { if (item == NULL) { @@ -2225,7 +2224,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsBool(const cJSON * const item) return (item->type & (cJSON_True | cJSON_False)) != 0; } -CJSON_PUBLIC(cjbool) cJSON_IsNull(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) { if (item == NULL) { @@ -2235,7 +2234,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsNull(const cJSON * const item) return (item->type & 0xFF) == cJSON_NULL; } -CJSON_PUBLIC(cjbool) cJSON_IsNumber(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) { if (item == NULL) { @@ -2245,7 +2244,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsNumber(const cJSON * const item) return (item->type & 0xFF) == cJSON_Number; } -CJSON_PUBLIC(cjbool) cJSON_IsString(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) { if (item == NULL) { @@ -2255,7 +2254,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsString(const cJSON * const item) return (item->type & 0xFF) == cJSON_String; } -CJSON_PUBLIC(cjbool) cJSON_IsArray(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) { if (item == NULL) { @@ -2265,7 +2264,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsArray(const cJSON * const item) return (item->type & 0xFF) == cJSON_Array; } -CJSON_PUBLIC(cjbool) cJSON_IsObject(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) { if (item == NULL) { @@ -2275,7 +2274,7 @@ CJSON_PUBLIC(cjbool) cJSON_IsObject(const cJSON * const item) return (item->type & 0xFF) == cJSON_Object; } -CJSON_PUBLIC(cjbool) cJSON_IsRaw(const cJSON * const item) +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) { if (item == NULL) { diff --git a/cJSON.h b/cJSON.h index 59a05992..2b7b625c 100644 --- a/cJSON.h +++ b/cJSON.h @@ -78,6 +78,8 @@ typedef struct cJSON_Hooks void (*free_fn)(void *ptr); } cJSON_Hooks; +typedef int cJSON_bool; + #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) #define __WINDOWS__ #endif @@ -129,9 +131,9 @@ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); /* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */ -CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt); /* Delete a cJSON entity and all subentities. */ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); @@ -142,27 +144,27 @@ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item); /* Get item "string" from object. Case insensitive. */ CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string); CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string); -CJSON_PUBLIC(int) cJSON_HasObjectItem(const cJSON *object, const char *string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* These functions check the type of an item */ -CJSON_PUBLIC(int) cJSON_IsInvalid(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsFalse(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsTrue(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsBool(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsNull(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsNumber(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsString(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsArray(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsObject(const cJSON * const item); -CJSON_PUBLIC(int) cJSON_IsRaw(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); /* These calls create a cJSON item of the appropriate type. */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(int b); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); /* raw json */ @@ -199,14 +201,14 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newi CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); /* Duplicate a cJSON item */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, int recurse); +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will need to be released. With recurse!=0, it will duplicate any children connected to the item. The item->next and ->prev pointers are always zero on return from Duplicate. */ /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); CJSON_PUBLIC(void) cJSON_Minify(char *json); From b44c917be91508f4e4fcd80f07dbb81d7be4233d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 23:16:19 +0100 Subject: [PATCH 59/73] tests/common: use CJSON_PUBLIC --- tests/common.c | 4 ++-- tests/common.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/common.c b/tests/common.c index 9c1a109a..3870896a 100644 --- a/tests/common.c +++ b/tests/common.c @@ -22,7 +22,7 @@ #include "common.h" -extern void reset(cJSON *item) +CJSON_PUBLIC(void) reset(cJSON *item) { if ((item != NULL) && (item->child != NULL)) { @@ -40,7 +40,7 @@ extern void reset(cJSON *item) memset(item, 0, sizeof(cJSON)); } -extern char *read_file(const char *filename) +CJSON_PUBLIC(char*) read_file(const char *filename) { FILE *file = NULL; long length = 0; diff --git a/tests/common.h b/tests/common.h index 53173455..97c09bf2 100644 --- a/tests/common.h +++ b/tests/common.h @@ -25,8 +25,8 @@ #include "../cJSON.c" -extern void reset(cJSON *item); -extern char *read_file(const char *filename); +CJSON_PUBLIC(void) reset(cJSON *item); +CJSON_PUBLIC(char*) read_file(const char *filename); /* assertion helper macros */ #define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.") From 6405fd15e3d05a0b28a953e2cfb363a6ae5c3609 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 23:16:47 +0100 Subject: [PATCH 60/73] CMake: Set default visibility to hidden and dllexport on windows --- CMakeLists.txt | 10 ++++++++++ cJSON.c | 3 +++ tests/CMakeLists.txt | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 745e52f9..0f32f2eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,16 @@ if (ENABLE_SANITIZERS) ) endif() +option(ENABLE_PUBLIC_SYMBOLS "Export library symbols." On) +if (ENABLE_PUBLIC_SYMBOLS) + list(APPEND custom_compiler_flags -fvisibility=hidden) + add_definitions(-DCJSON_EXPORT_SYMBOLS -DCJSON_API_VISIBILITY) +endif() +option(ENABLE_HIDDEN_SYMBOLS "Hide library symbols." Off) +if (ENABLE_HIDDEN_SYMBOLS) + add_definitions(-DCJSON_HIDE_SYMBOLS -UCJSON_API_VISIBILITY) +endif() + # apply custom compiler flags foreach(compiler_flag ${custom_compiler_flags}) #remove problematic characters diff --git a/cJSON.c b/cJSON.c index af93a8af..766b0f7d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -23,6 +23,7 @@ /* cJSON */ /* JSON parser in C. */ +#pragma GCC visibility push(default) #include #include #include @@ -30,6 +31,8 @@ #include #include #include +#pragma GCC visibility pop + #include "cJSON.h" /* define our own boolean type */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4767e502..f9cd5649 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,11 @@ if(ENABLE_CJSON_TEST) if (werror_found) target_compile_options(unity PRIVATE "-Wno-error") endif() + # Disable -fvisibility=hidden for Unity + list(FIND custom_compiler_flags "-fvisibility=hidden" visibility_found) + if (visibility_found) + target_compile_options(unity PRIVATE "-fvisibility=default") + endif() #copy test files file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs") From 2c45ad7816fe85e0947656e29ae6840786685283 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 23:20:30 +0100 Subject: [PATCH 61/73] Squashed 'tests/unity/' changes from 2988e98..1f52255 1f52255 Merge pull request #267 from FSMaxB/fix-wconversion 7bce0b4 Fix warning with ubsan and -Wconversion b5da224 Merge pull request #266 from FSMaxB/fix-double-promotion 1bf22d3 Fix warnings with -Wdouble-promotion git-subtree-dir: tests/unity git-subtree-split: 1f522558a6c4577aa937341bf856ba3b1436768a --- src/unity.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unity.c b/src/unity.c index 54a34526..52663642 100644 --- a/src/unity.c +++ b/src/unity.c @@ -194,7 +194,7 @@ void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) while (nibbles > 0) { nibbles--; - nibble = (number >> (nibbles * 4)) & 0x0F; + nibble = (int)(number >> (nibbles * 4)) & 0x0F; if (nibble <= 9) { UNITY_OUTPUT_CHAR((char)('0' + nibble)); @@ -669,7 +669,7 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrElement); UnityPrintNumberUnsigned(num_elements - elements - 1); - UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } @@ -691,7 +691,7 @@ void UnityAssertFloatsWithin(const UNITY_FLOAT delta, if (!UnityFloatsWithin(delta, expected, actual)) { UnityTestResultsFailBegin(lineNumber); - UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } @@ -746,7 +746,7 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual, UnityPrint(trait_names[trait_index]); UnityPrint(UnityStrWas); #ifndef UNITY_EXCLUDE_FLOAT_PRINT - UnityPrintFloat(actual); + UnityPrintFloat((UNITY_DOUBLE)actual); #else if (should_be_trait) UnityPrint(UnityStrNot); From 9d07917feb1b613544a7513d19233d4c851ad7ad Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 2 Mar 2017 13:46:31 +0100 Subject: [PATCH 62/73] utf16_literal_to_utf8: Eliminate Duff's Device This fixes -Wimplicit-fallthrough warnings with GCC7. --- cJSON.c | 51 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/cJSON.c b/cJSON.c index 766b0f7d..1dfd7967 100644 --- a/cJSON.c +++ b/cJSON.c @@ -452,21 +452,13 @@ static unsigned parse_hex4(const unsigned char * const input) * A literal can be one or two sequences of the form \uXXXX */ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer, const unsigned char **error_pointer) { - /* first bytes of UTF8 encoding for a given length in bytes */ - static const unsigned char firstByteMark[5] = - { - 0x00, /* should never happen */ - 0x00, /* 0xxxxxxx */ - 0xC0, /* 110xxxxx */ - 0xE0, /* 1110xxxx */ - 0xF0 /* 11110xxx */ - }; - long unsigned int codepoint = 0; unsigned int first_code = 0; const unsigned char *first_sequence = input_pointer; unsigned char utf8_length = 0; + unsigned char utf8_position = 0; unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; /* get the first utf16 sequence */ first_code = parse_hex4(first_sequence + 2); @@ -537,16 +529,19 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi { /* two bytes, encoding 110xxxxx 10xxxxxx */ utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ } else if (codepoint < 0x10000) { /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ } else if (codepoint <= 0x10FFFF) { /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ } else { @@ -556,28 +551,22 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi } /* encode as utf8 */ - switch (utf8_length) - { - case 4: - /* 10xxxxxx */ - (*output_pointer)[3] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - case 3: - /* 10xxxxxx */ - (*output_pointer)[2] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - case 2: - (*output_pointer)[1] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - case 1: - /* depending on the length in bytes this determines the - encoding of the first UTF8 byte */ - (*output_pointer)[0] = (unsigned char)((codepoint | firstByteMark[utf8_length]) & 0xFF); - break; - default: - *error_pointer = first_sequence; - goto fail; + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + *output_pointer += utf8_length; return sequence_length; From d8d0ae66d3c52137598ec59fa21c1ab450030edc Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 2 Mar 2017 23:48:03 +0100 Subject: [PATCH 63/73] print_number: Fix incorrect output pointer --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 1dfd7967..c780b773 100644 --- a/cJSON.c +++ b/cJSON.c @@ -409,7 +409,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const return trim_trailing_zeroes(output_buffer); } - return output_buffer->buffer + output_buffer->offset; + return output_buffer->buffer; } /* parse 4 digit hexadecimal number */ From 3fe72cf2b8cad9faccf0a6fa81cc39537876521b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 2 Mar 2017 23:48:57 +0100 Subject: [PATCH 64/73] fuzzing: afl.c: Fix printing usage --- fuzzing/afl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fuzzing/afl.c b/fuzzing/afl.c index af5945d9..ac4f2303 100644 --- a/fuzzing/afl.c +++ b/fuzzing/afl.c @@ -87,7 +87,7 @@ int main(int argc, char** argv) const char *filename = NULL; cJSON *item = NULL; char *json = NULL; - int status; + int status = EXIT_FAILURE; char *printed_json = NULL; if ((argc < 2) || (argc > 3)) @@ -96,6 +96,7 @@ int main(int argc, char** argv) printf("%s input_file [enable_printing]\n", argv[0]); printf("\t input_file: file containing the test data\n"); printf("\t enable_printing: print after parsing, 'yes' or 'no', defaults to 'no'\n"); + goto cleanup; } filename = argv[1]; From d441fa05b3f012d5d9c1af1ff6886154aaf6eef8 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:05:11 +0100 Subject: [PATCH 65/73] print_value: return boolean instead of pointer --- cJSON.c | 21 +++++++++++++-------- tests/print_value.c | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cJSON.c b/cJSON.c index c780b773..675ce2f7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -813,7 +813,7 @@ static unsigned char *print_string(const cJSON * const item, printbuffer * const /* Predeclare these prototypes. */ static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static cJSON_bool print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); static unsigned char *print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); @@ -893,7 +893,7 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i } /* print the value */ - if (print_value(item, 0, format, buffer, hooks) == NULL) + if (!print_value(item, 0, format, buffer, hooks)) { goto fail; } @@ -957,7 +957,12 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON p.offset = 0; p.noalloc = false; - return (char*)print_value(item, 0, fmt, &p, &global_hooks); + if (!print_value(item, 0, fmt, &p, &global_hooks)) + { + return NULL; + } + + return (char*)p.buffer; } CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) @@ -973,7 +978,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const i p.length = (size_t)len; p.offset = 0; p.noalloc = true; - return print_value(item, 0, fmt, &p, &global_hooks) != NULL; + return print_value(item, 0, fmt, &p, &global_hooks); } /* Parser core - when encountering text, process appropriately. */ @@ -1031,13 +1036,13 @@ static const unsigned char *parse_value(cJSON * const item, const unsigned char } /* Render a value to text. */ -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) +static cJSON_bool print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output = NULL; if ((item == NULL) || (output_buffer == NULL)) { - return NULL; + return false; } switch ((item->type) & 0xFF) @@ -1101,7 +1106,7 @@ static unsigned char *print_value(const cJSON * const item, const size_t depth, break; } - return output; + return output != NULL; } /* Build an array from input text. */ @@ -1210,7 +1215,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, while (current_element != NULL) { - if (print_value(current_element, depth + 1, format, output_buffer, hooks) == NULL) + if (!print_value(current_element, depth + 1, format, output_buffer, hooks)) { return NULL; } diff --git a/tests/print_value.c b/tests/print_value.c index 41ee2864..7e0f52fe 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -43,7 +43,7 @@ static void assert_print_value(const char *input) TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse value."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value."); + TEST_ASSERT_TRUE_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected."); reset(item); From bea1d102fd145c5c1401e5c04675760466186166 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:16:54 +0100 Subject: [PATCH 66/73] print_array: return boolean instead of pointer --- cJSON.c | 23 +++++++++-------------- tests/print_array.c | 4 ++-- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/cJSON.c b/cJSON.c index 675ce2f7..69f5b31f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -815,7 +815,7 @@ static unsigned char *print_string(const cJSON * const item, printbuffer * const static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep, const internal_hooks * const hooks); static cJSON_bool print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static cJSON_bool print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); static unsigned char *print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); @@ -1096,8 +1096,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons output = print_string(item, output_buffer, hooks); break; case cJSON_Array: - output = print_array(item, depth, format, output_buffer, hooks); - break; + return print_array(item, depth, format, output_buffer, hooks); case cJSON_Object: output = print_object(item, depth, format, output_buffer, hooks); break; @@ -1188,26 +1187,23 @@ static const unsigned char *parse_array(cJSON * const item, const unsigned char } /* Render an array to text */ -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) +static cJSON_bool print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { - unsigned char *output = NULL; unsigned char *output_pointer = NULL; size_t length = 0; cJSON *current_element = item->child; - size_t output_offset = 0; if (output_buffer == NULL) { - return NULL; + return false; } /* Compose the output array. */ /* opening square bracket */ - output_offset = output_buffer->offset; output_pointer = ensure(output_buffer, 1, hooks); if (output_pointer == NULL) { - return NULL; + return false; } *output_pointer = '['; @@ -1217,7 +1213,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, { if (!print_value(current_element, depth + 1, format, output_buffer, hooks)) { - return NULL; + return false; } update_offset(output_buffer); if (current_element->next) @@ -1226,7 +1222,7 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, output_pointer = ensure(output_buffer, length + 1, hooks); if (output_pointer == NULL) { - return NULL; + return false; } *output_pointer++ = ','; if(format) @@ -1242,13 +1238,12 @@ static unsigned char *print_array(const cJSON * const item, const size_t depth, output_pointer = ensure(output_buffer, 2, hooks); if (output_pointer == NULL) { - return NULL; + return false; } *output_pointer++ = ']'; *output_pointer = '\0'; - output = output_buffer->buffer + output_offset; - return output; + return true; } /* Build an object from the text. */ diff --git a/tests/print_array.c b/tests/print_array.c index e121c653..df32be67 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -50,10 +50,10 @@ static void assert_print_array(const char * const expected, const char * const i memset(item, 0, sizeof(item)); TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse array."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); + TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_array(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string."); + TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct."); reset(item); From 748f4bfd4f7b58729201ec5606234780f082e717 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:21:34 +0100 Subject: [PATCH 67/73] print_object: return boolean instead of pointer --- cJSON.c | 29 ++++++++++++----------------- tests/print_object.c | 4 ++-- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/cJSON.c b/cJSON.c index 69f5b31f..d72b62b7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -817,7 +817,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); static cJSON_bool print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); +static cJSON_bool print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks); /* Utility to jump whitespace and cr/lf */ static const unsigned char *skip_whitespace(const unsigned char *in) @@ -1098,8 +1098,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons case cJSON_Array: return print_array(item, depth, format, output_buffer, hooks); case cJSON_Object: - output = print_object(item, depth, format, output_buffer, hooks); - break; + return print_object(item, depth, format, output_buffer, hooks); default: output = NULL; break; @@ -1342,26 +1341,23 @@ static const unsigned char *parse_object(cJSON * const item, const unsigned char } /* Render an object to text. */ -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) +static cJSON_bool print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks) { - unsigned char *output = NULL; unsigned char *output_pointer = NULL; size_t length = 0; - size_t output_offset = 0; cJSON *current_item = item->child; if (output_buffer == NULL) { - return NULL; + return false; } /* Compose the output: */ - output_offset = output_buffer->offset; length = format ? 2 : 1; /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1, hooks); if (output_pointer == NULL) { - return NULL; + return false; } *output_pointer++ = '{'; @@ -1379,7 +1375,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, output_pointer = ensure(output_buffer, depth + 1, hooks); if (output_pointer == NULL) { - return NULL; + return false; } for (i = 0; i < depth + 1; i++) { @@ -1391,7 +1387,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, /* print key */ if (print_string_ptr((unsigned char*)current_item->string, output_buffer, hooks) == NULL) { - return NULL; + return false; } update_offset(output_buffer); @@ -1399,7 +1395,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, output_pointer = ensure(output_buffer, length, hooks); if (output_pointer == NULL) { - return NULL; + return false; } *output_pointer++ = ':'; if (format) @@ -1411,7 +1407,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, /* print value */ if (!print_value(current_item, depth + 1, format, output_buffer, hooks)) { - return NULL; + return false; } update_offset(output_buffer); @@ -1420,7 +1416,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, output_pointer = ensure(output_buffer, length + 1, hooks); if (output_pointer == NULL) { - return NULL; + return false; } if (current_item->next) { @@ -1440,7 +1436,7 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, output_pointer = ensure(output_buffer, format ? (depth + 2) : 2, hooks); if (output_pointer == NULL) { - return NULL; + return false; } if (format) { @@ -1452,9 +1448,8 @@ static unsigned char *print_object(const cJSON * const item, const size_t depth, } *output_pointer++ = '}'; *output_pointer = '\0'; - output = (output_buffer->buffer) + output_offset; - return output; + return true; } /* Get Array size/item / object item. */ diff --git a/tests/print_object.c b/tests/print_object.c index b6dad6ee..f7f53444 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -50,10 +50,10 @@ static void assert_print_object(const char * const expected, const char * const memset(item, 0, sizeof(item)); TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse object."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); + TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct."); - TEST_ASSERT_NOT_NULL_MESSAGE(print_object(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string."); + TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct."); reset(item); From 1749de02f8e115482ebdd60cf8fc1709a8b16c00 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:26:58 +0100 Subject: [PATCH 68/73] print_number: return boolean instead of pointer --- cJSON.c | 17 ++++++++--------- tests/print_number.c | 7 +++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/cJSON.c b/cJSON.c index d72b62b7..2f8ab5f8 100644 --- a/cJSON.c +++ b/cJSON.c @@ -327,14 +327,14 @@ static void update_offset(printbuffer * const buffer) } /* Removes trailing zeroes from the end of a printed number */ -static unsigned char *trim_trailing_zeroes(printbuffer * const buffer) +static cJSON_bool trim_trailing_zeroes(printbuffer * const buffer) { size_t offset = 0; unsigned char *content = NULL; if ((buffer == NULL) || (buffer->buffer == NULL) || (buffer->offset < 1)) { - return NULL; + return false; } offset = buffer->offset - 1; @@ -354,11 +354,11 @@ static unsigned char *trim_trailing_zeroes(printbuffer * const buffer) buffer->offset = offset; - return content + offset; + return true; } /* Render the number nicely from the given item into a string. */ -static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks) +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output_pointer = NULL; double d = item->valuedouble; @@ -367,7 +367,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const if (output_buffer == NULL) { - return NULL; + return false; } /* This is a nice tradeoff. */ @@ -399,7 +399,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const /* sprintf failed */ if (length < 0) { - return NULL; + return false; } output_buffer->offset += (size_t)length; @@ -409,7 +409,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const return trim_trailing_zeroes(output_buffer); } - return output_buffer->buffer; + return true; } /* parse 4 digit hexadecimal number */ @@ -1069,8 +1069,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons } break; case cJSON_Number: - output = print_number(item, output_buffer, hooks); - break; + return print_number(item, output_buffer, hooks); case cJSON_Raw: { size_t raw_length = 0; diff --git a/tests/print_number.c b/tests/print_number.c index ad25b744..b478049c 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -37,7 +37,7 @@ static void assert_print_number(const char *expected, double input) memset(item, 0, sizeof(item)); cJSON_SetNumberValue(item, input); - TEST_ASSERT_NOT_NULL_MESSAGE(print_number(item, &buffer, &global_hooks), "Failed to print number."); + TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer, &global_hooks), "Failed to print number."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected."); } @@ -91,14 +91,13 @@ static void trim_trailing_zeroes_should_trim_trailing_zeroes(void) { printbuffer buffer; unsigned char number[100]; - unsigned char *pointer = NULL; buffer.length = sizeof(number); buffer.buffer = number; strcpy((char*)number, "10.00"); buffer.offset = sizeof("10.00") - 1; - pointer = trim_trailing_zeroes(&buffer); - TEST_ASSERT_EQUAL_UINT8('\0', *pointer); + TEST_ASSERT_TRUE(trim_trailing_zeroes(&buffer)); + TEST_ASSERT_EQUAL_UINT8('\0', buffer.buffer[buffer.offset]); TEST_ASSERT_EQUAL_STRING("10", number); TEST_ASSERT_EQUAL_UINT(sizeof("10") - 1, buffer.offset); } From 5ea4fad263a696046336a6c667df8c3aa37d0029 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:32:53 +0100 Subject: [PATCH 69/73] print_string: return boolean instead of pointer --- cJSON.c | 20 ++++++++++---------- tests/print_string.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cJSON.c b/cJSON.c index 2f8ab5f8..8cf8fcc4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -694,7 +694,7 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char } /* Render the cstring provided to an escaped version that can be printed. */ -static unsigned char *print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer, const internal_hooks * const hooks) +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer, const internal_hooks * const hooks) { const unsigned char *input_pointer = NULL; unsigned char *output = NULL; @@ -705,7 +705,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb if (output_buffer == NULL) { - return NULL; + return false; } /* empty string */ @@ -714,11 +714,11 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb output = ensure(output_buffer, sizeof("\"\""), hooks); if (output == NULL) { - return NULL; + return false; } strcpy((char*)output, "\"\""); - return output; + return true; } /* set "flag" to 1 if something needs to be escaped */ @@ -740,7 +740,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb output = ensure(output_buffer, output_length + sizeof("\"\""), hooks); if (output == NULL) { - return NULL; + return false; } /* no characters have to be escaped */ @@ -751,7 +751,7 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb output[output_length + 1] = '\"'; output[output_length + 2] = '\0'; - return output; + return true; } output[0] = '\"'; @@ -802,11 +802,11 @@ static unsigned char *print_string_ptr(const unsigned char * const input, printb output[output_length + 1] = '\"'; output[output_length + 2] = '\0'; - return output; + return true; } /* Invoke print_string_ptr (which is useful) on an item. */ -static unsigned char *print_string(const cJSON * const item, printbuffer * const p, const internal_hooks * const hooks) +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p, const internal_hooks * const hooks) { return print_string_ptr((unsigned char*)item->valuestring, p, hooks); } @@ -1092,7 +1092,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons break; } case cJSON_String: - output = print_string(item, output_buffer, hooks); + return print_string(item, output_buffer, hooks); break; case cJSON_Array: return print_array(item, depth, format, output_buffer, hooks); @@ -1384,7 +1384,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con } /* print key */ - if (print_string_ptr((unsigned char*)current_item->string, output_buffer, hooks) == NULL) + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer, hooks)) { return false; } diff --git a/tests/print_string.c b/tests/print_string.c index 95214346..2e38eaa6 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -33,7 +33,7 @@ static void assert_print_string(const char *expected, const char *input) buffer.offset = 0; buffer.noalloc = true; - TEST_ASSERT_NOT_NULL_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer, &global_hooks), "Failed to print string."); + TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer, &global_hooks), "Failed to print string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected."); } From 0bb1843925172e70a3dab0af9ec2bf2ce62f3a54 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:40:02 +0100 Subject: [PATCH 70/73] print_value: return as soon as possible --- cJSON.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/cJSON.c b/cJSON.c index 8cf8fcc4..7b411fce 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1049,27 +1049,34 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons { case cJSON_NULL: output = ensure(output_buffer, 5, hooks); - if (output != NULL) + if (output == NULL) { - strcpy((char*)output, "null"); + return false; } - break; + strcpy((char*)output, "null"); + return true; + case cJSON_False: output = ensure(output_buffer, 6, hooks); - if (output != NULL) + if (output == NULL) { - strcpy((char*)output, "false"); + return false; } - break; + strcpy((char*)output, "false"); + return true; + case cJSON_True: output = ensure(output_buffer, 5, hooks); - if (output != NULL) + if (output == NULL) { - strcpy((char*)output, "true"); + return false; } - break; + strcpy((char*)output, "true"); + return true; + case cJSON_Number: return print_number(item, output_buffer, hooks); + case cJSON_Raw: { size_t raw_length = 0; @@ -1079,31 +1086,31 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons { hooks->deallocate(output_buffer->buffer); } - output = NULL; - break; + return false; } raw_length = strlen(item->valuestring) + sizeof('\0'); output = ensure(output_buffer, raw_length, hooks); - if (output != NULL) + if (output == NULL) { - memcpy(output, item->valuestring, raw_length); + return false; } - break; + memcpy(output, item->valuestring, raw_length); + return true; } + case cJSON_String: return print_string(item, output_buffer, hooks); - break; + case cJSON_Array: return print_array(item, depth, format, output_buffer, hooks); + case cJSON_Object: return print_object(item, depth, format, output_buffer, hooks); + default: - output = NULL; - break; + return false; } - - return output != NULL; } /* Build an array from input text. */ From 5f783fff11dcb2d76bcbfb99cd2d8484c4e42282 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 00:45:50 +0100 Subject: [PATCH 71/73] cJSON_Utils: Add gcc pragma to use default visibility for system headers --- cJSON_Utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8ff1b335..b18def39 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1,8 +1,10 @@ +#pragma GCC visibility push(default) #include #include #include #include #include +#pragma GCC visibility pop #include "cJSON_Utils.h" From bdb59f09def2f8c2670de4e3bdd2f12e7861612a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 22:14:11 +0100 Subject: [PATCH 72/73] Add contributing guideline --- .github/CONTRIBUTING.md | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..172cfcd3 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,54 @@ +Contribution Guidelines +======================= + +Contributions to cJSON are welcome. If you find a bug or want to improve cJSON in another way, pull requests are appreciated. + +For bigger changes, in order to avoid wasted effort, please open an issue to discuss the technical details before creating a pull request. + +The further sections explain the process in more detail and provides some guidelines on how contributions should look like. + +Branches +-------- +There are two branches to be aware of, the `master` and the `develop` branch. The `master` branch is reserved for the latest release, so only make pull requests to the `master` branch for small bug- or security fixes (these are usually just a few lines). In all other cases, please make a pull request to the `develop` branch. + +Coding Style +------------ +The coding style has been discussed in [#24](https://github.com/DaveGamble/cJSON/issues/24). The basics are: + +* Use 4 tabs for indentation +* No oneliners (conditions, loops, variable declarations ...) +* Always use parenthesis for control structures +* Don't implicitly rely on operator precedence, use round brackets in expressions. e.g. `(a > b) && (c < d)` instead of `a>b && cbuffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} +``` + +Unit Tests +---------- +cJSON uses the [Unity](https://github.com/ThrowTheSwitch/Unity) library for unit tests. The tests are located in the `tests` directory. In order to add a new test, either add it to one of the existing files (if it fits) or add a new C file for the test. That new file has to be added to the list of tests in `tests/CMakeLists.txt`. + +All new features have to be covered by unit tests. + +Other Notes +----------- +* Internal functions are to be declared static. +* Wrap the return type of external function in the `CJSON_PUBLIC` macro. From 02cd3eec3742f5cdf211c034dbe7c2d89b657424 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 3 Mar 2017 23:21:53 +0100 Subject: [PATCH 73/73] Update version number to 1.4.0 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f32f2eb..01a1f3bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ include(GNUInstallDirs) project(cJSON C) set(PROJECT_VERSION_MAJOR 1) -set(PROJECT_VERSION_MINOR 3) +set(PROJECT_VERSION_MINOR 4) set(PROJECT_VERSION_PATCH 0) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) diff --git a/Makefile b/Makefile index ace075c2..2e1b1e11 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c LDLIBS = -lm -LIBVERSION = 1.3.0 +LIBVERSION = 1.4.0 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 7b411fce..eef6275c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -47,7 +47,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 3) || (CJSON_VERSION_PATCH != 0) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 4) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 2b7b625c..e5918d67 100644 --- a/cJSON.h +++ b/cJSON.h @@ -30,7 +30,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 3 +#define CJSON_VERSION_MINOR 4 #define CJSON_VERSION_PATCH 0 #include