From 6bc55ec35d02931960ec1f5768fc9c56ab62ef66 Mon Sep 17 00:00:00 2001 From: David Seifert <16636962+SoapGentoo@users.noreply.github.com> Date: Tue, 7 Jan 2020 02:23:50 +0100 Subject: [PATCH 001/196] Meson updates (#1124) * Modernize meson.build * Make tests optional * Use `files()` for quick sanity checks * Bump version to 1.9.3 * Bump SOVERSION, as some functions were removed and structs were changed, as determined by libabigail. --- CMakeLists.txt | 2 +- include/json/version.h | 4 ++-- meson.build | 33 ++++++++++++++++++--------------- meson_options.txt | 5 +++++ 4 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 meson_options.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e0633173..c05ddccbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,7 @@ project(JSONCPP # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - VERSION 1.9.2 # [.[.[.]]] + VERSION 1.9.3 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}") diff --git a/include/json/version.h b/include/json/version.h index ff94372b0..0f2983411 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -9,10 +9,10 @@ // 3. /CMakeLists.txt // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "1.9.2" +#define JSONCPP_VERSION_STRING "1.9.3" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 2 +#define JSONCPP_VERSION_PATCH 3 #define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ diff --git a/meson.build b/meson.build index 1bc94a8af..c29320307 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - version : '1.9.2', + version : '1.9.3', default_options : [ 'buildtype=release', 'cpp_std=c++11', @@ -18,7 +18,7 @@ project( meson_version : '>= 0.49.0') -jsoncpp_headers = [ +jsoncpp_headers = files([ 'include/json/allocator.h', 'include/json/assertions.h', 'include/json/config.h', @@ -28,7 +28,8 @@ jsoncpp_headers = [ 'include/json/reader.h', 'include/json/value.h', 'include/json/version.h', - 'include/json/writer.h'] + 'include/json/writer.h', +]) jsoncpp_include_directories = include_directories('include') install_headers( @@ -44,13 +45,12 @@ else endif jsoncpp_lib = library( - 'jsoncpp', - [ jsoncpp_headers, - 'src/lib_json/json_tool.h', + 'jsoncpp', files([ 'src/lib_json/json_reader.cpp', 'src/lib_json/json_value.cpp', - 'src/lib_json/json_writer.cpp'], - soversion : 22, + 'src/lib_json/json_writer.cpp', + ]), + soversion : 23, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) @@ -66,18 +66,21 @@ import('pkgconfig').generate( jsoncpp_dep = declare_dependency( include_directories : jsoncpp_include_directories, link_with : jsoncpp_lib, - version : meson.project_version(), - ) + version : meson.project_version()) # tests -python = import('python').find_installation() +if meson.is_subproject() or not get_option('tests') + subdir_done() +endif + +python = import('python').find_installation('python3') jsoncpp_test = executable( - 'jsoncpp_test', - [ 'src/test_lib_json/jsontest.cpp', - 'src/test_lib_json/jsontest.h', + 'jsoncpp_test', files([ + 'src/test_lib_json/jsontest.cpp', 'src/test_lib_json/main.cpp', - 'src/test_lib_json/fuzz.cpp'], + 'src/test_lib_json/fuzz.cpp', + ]), include_directories : jsoncpp_include_directories, link_with : jsoncpp_lib, install : false, diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 000000000..9c215ae6f --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,5 @@ +option( + 'tests', + type : 'boolean', + value : true, + description : 'Enable building tests') From 6317f9a406c43e264e0ae0164fa701362ef04c9a Mon Sep 17 00:00:00 2001 From: Chen <50514813+dota17@users.noreply.github.com> Date: Mon, 20 Jan 2020 17:12:35 +0800 Subject: [PATCH 002/196] fix compile warnning using cmake (#1132) --- src/test_lib_json/main.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 40d8ff273..c2df69db0 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3309,15 +3309,15 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) { {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))}, {__LINE__, R"({"a":})", 1, objGetAnd("a", checkEq(nullValue))}, {__LINE__, "[]", 0, checkEq(emptyArray)}, - {__LINE__, "[null]", 1}, - {__LINE__, "[,]", 2}, - {__LINE__, "[,,,]", 4}, - {__LINE__, "[null,]", 2}, - {__LINE__, "[,null]", 2}, - {__LINE__, "[,,]", 3}, - {__LINE__, "[null,,]", 3}, - {__LINE__, "[,null,]", 3}, - {__LINE__, "[,,null]", 3}, + {__LINE__, "[null]", 1, nullptr}, + {__LINE__, "[,]", 2, nullptr}, + {__LINE__, "[,,,]", 4, nullptr}, + {__LINE__, "[null,]", 2, nullptr}, + {__LINE__, "[,null]", 2, nullptr}, + {__LINE__, "[,,]", 3, nullptr}, + {__LINE__, "[null,,]", 3, nullptr}, + {__LINE__, "[,null,]", 3, nullptr}, + {__LINE__, "[,,null]", 3, nullptr}, {__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))}, {__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))}, {__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))}, From edf528edfa66fd02f54f81ae341592f50e61c39f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 2 Feb 2020 20:03:45 -0800 Subject: [PATCH 003/196] clang-tidy fixes again (#1087) * [clang-tidy] Do not use else after return Found with readability-else-after-return Signed-off-by: Rosen Penev * [clang-tidy] Convert several loops to be range based Found with modernize-loop-convert Signed-off-by: Rosen Penev * [clang-tidy] Replace deprecated C headers Found with modernize-deprecated-headers Signed-off-by: Rosen Penev * [clang-tidy] Use auto where applicable Found with modernize-use-auto Signed-off-by: Rosen Penev * .clang-tidy: Add these checks --- .clang-tidy | 2 +- src/jsontestrunner/main.cpp | 6 +++--- src/lib_json/json_reader.cpp | 19 +++++++++---------- src/lib_json/json_value.cpp | 14 ++++++-------- src/test_lib_json/fuzz.cpp | 1 - src/test_lib_json/jsontest.cpp | 24 ++++++++++++------------ src/test_lib_json/main.cpp | 8 +++----- 7 files changed, 34 insertions(+), 40 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index b78b3247e..be3d06a52 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,5 @@ --- -Checks: 'google-readability-casting,modernize-use-default-member-init,modernize-use-using,modernize-use-auto,readability-redundant-member-init' +Checks: 'google-readability-casting,modernize-deprecated-headers,modernize-loop-convert,modernize-use-auto,modernize-use-default-member-init,modernize-use-using,readability-else-after-return,readability-redundant-member-init,readability-redundant-string-cstr' WarningsAsErrors: '' HeaderFilterRegex: '' AnalyzeTemporaryDtors: false diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp index f6b1a4dc3..cdf6bffb0 100644 --- a/src/jsontestrunner/main.cpp +++ b/src/jsontestrunner/main.cpp @@ -57,10 +57,10 @@ static Json::String readInputTestFile(const char* path) { if (!file) return ""; fseek(file, 0, SEEK_END); - long const size = ftell(file); - const auto usize = static_cast(size); + auto const size = ftell(file); + auto const usize = static_cast(size); fseek(file, 0, SEEK_SET); - char* buffer = new char[size + 1]; + auto buffer = new char[size + 1]; buffer[size] = 0; Json::String text; if (fread(buffer, 1, usize, file) == usize) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 9818b5bf2..2c6fead19 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -637,7 +637,7 @@ bool Reader::decodeString(Token& token, String& decoded) { Char c = *current++; if (c == '"') break; - else if (c == '\\') { + if (c == '\\') { if (current == end) return addError("Empty escape sequence in string", token, current); Char escape = *current++; @@ -1358,11 +1358,10 @@ bool OurReader::readCStyleComment(bool* containsNewLineResult) { while ((current_ + 1) < end_) { Char c = getNextChar(); - if (c == '*' && *current_ == '/') { + if (c == '*' && *current_ == '/') break; - } else if (c == '\n') { + if (c == '\n') *containsNewLineResult = true; - } } return getNextChar() == '/'; @@ -1586,9 +1585,9 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { // then take the inverse. This assumes that minLargestInt is only a single // power of 10 different in magnitude, which we check above. For the last // digit, we take the modulus before negating for the same reason. - static constexpr Value::LargestUInt negative_threshold = + static constexpr auto negative_threshold = Value::LargestUInt(-(Value::minLargestInt / 10)); - static constexpr Value::UInt negative_last_digit = + static constexpr auto negative_last_digit = Value::UInt(-(Value::minLargestInt % 10)); const Value::LargestUInt threshold = @@ -1602,7 +1601,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { if (c < '0' || c > '9') return decodeDouble(token, decoded); - const Value::UInt digit(static_cast(c - '0')); + const auto digit(static_cast(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, meaing value == threshold, @@ -1619,7 +1618,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { if (isNegative) { // We use the same magnitude assumption here, just in case. - const Value::UInt last_digit = static_cast(value % 10); + const auto last_digit = static_cast(value % 10); decoded = -Value::LargestInt(value / 10) * 10 - last_digit; } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { decoded = Value::LargestInt(value); @@ -1669,9 +1668,9 @@ bool OurReader::decodeString(Token& token, String& decoded) { Location end = token.end_ - 1; // do not include '"' while (current != end) { Char c = *current++; - if (c == '"') { + if (c == '"') break; - } else if (c == '\\') { + if (c == '\\') { if (current == end) return addError("Empty escape sequence in string", token, current); Char escape = *current++; diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 1e3bbdebd..74535fbd9 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -875,8 +875,7 @@ ArrayIndex Value::size() const { bool Value::empty() const { if (isNull() || isArray() || isObject()) return size() == 0U; - else - return false; + return false; } Value::operator bool() const { return !isNull(); } @@ -1137,13 +1136,12 @@ bool Value::insert(ArrayIndex index, Value&& newValue) { ArrayIndex length = size(); if (index > length) { return false; - } else { - for (ArrayIndex i = length; i > index; i--) { - (*this)[i] = std::move((*this)[i - 1]); - } - (*this)[index] = std::move(newValue); - return true; } + for (ArrayIndex i = length; i > index; i--) { + (*this)[i] = std::move((*this)[i - 1]); + } + (*this)[index] = std::move(newValue); + return true; } Value Value::get(char const* begin, char const* end, diff --git a/src/test_lib_json/fuzz.cpp b/src/test_lib_json/fuzz.cpp index 68f839d53..5b75c22e6 100644 --- a/src/test_lib_json/fuzz.cpp +++ b/src/test_lib_json/fuzz.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include namespace Json { diff --git a/src/test_lib_json/jsontest.cpp b/src/test_lib_json/jsontest.cpp index 0cc500a88..0b7d12b97 100644 --- a/src/test_lib_json/jsontest.cpp +++ b/src/test_lib_json/jsontest.cpp @@ -267,19 +267,18 @@ bool Runner::runAllTest(bool printSummary) const { printf("All %zu tests passed\n", count); } return true; - } else { - for (auto& result : failures) { - result.printFailure(count > 1); - } + } + for (auto& result : failures) { + result.printFailure(count > 1); + } - if (printSummary) { - size_t const failedCount = failures.size(); - size_t const passedCount = count - failedCount; - printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count, - failedCount); - } - return false; + if (printSummary) { + size_t const failedCount = failures.size(); + size_t const passedCount = count - failedCount; + printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count, + failedCount); } + return false; } bool Runner::testIndex(const Json::String& testName, size_t& indexOut) const { @@ -308,7 +307,8 @@ int Runner::runCommandLine(int argc, const char* argv[]) const { if (opt == "--list-tests") { listTests(); return 0; - } else if (opt == "--test-auto") { + } + if (opt == "--test-auto") { preventDialogOnCrash(); } else if (opt == "--test") { ++index; diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index c2df69db0..7b20e41ec 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -1476,9 +1476,7 @@ void ValueTest::checkMemberCount(Json::Value& value, JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount)); } -ValueTest::IsCheck::IsCheck() - - = default; +ValueTest::IsCheck::IsCheck() = default; void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) { JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject()); @@ -3752,8 +3750,8 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) { int main(int argc, const char* argv[]) { JsonTest::Runner runner; - for (auto it = local_.begin(); it != local_.end(); it++) { - runner.add(*it); + for (auto& local : local_) { + runner.add(local); } return runner.runCommandLine(argc, argv); From a6fe8e27d84b927d820a89a0f134a934e09a63ed Mon Sep 17 00:00:00 2001 From: Claus Klein Date: Thu, 13 Feb 2020 22:20:46 +0100 Subject: [PATCH 004/196] Use ccache right (#1139) * Prevent cmakelint warnings Use 4 spaces for indent, no tabs * Use ccache right fix indents too at CMakeLists.txt --- CMakeLists.txt | 134 +++++++++++++++--------------- example/CMakeLists.txt | 33 ++++---- src/jsontestrunner/CMakeLists.txt | 42 +++++----- src/lib_json/CMakeLists.txt | 68 ++++++++------- src/test_lib_json/CMakeLists.txt | 44 +++++----- 5 files changed, 166 insertions(+), 155 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c05ddccbb..b7e2e09ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ foreach(pold "") # Currently Empty endforeach() # ==== Define language standard configurations requiring at least c++11 standard -if(CMAKE_CXX_STANDARD EQUAL "98" ) +if(CMAKE_CXX_STANDARD EQUAL "98") message(FATAL_ERROR "CMAKE_CXX_STANDARD:STRING=98 is not supported.") endif() @@ -62,19 +62,29 @@ if(NOT DEFINED CMAKE_BUILD_TYPE) "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") endif() +# --------------------------------------------------------------------------- +# use ccache if found, has to be done before project() +# --------------------------------------------------------------------------- +find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin) +if(CCACHE_EXECUTABLE) + message(STATUS "use ccache") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) +endif() + project(JSONCPP # Note: version must be updated in three places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the # correct version. - # 1. /meson.build - # 2. /include/json/version.h - # 3. /CMakeLists.txt - # IMPORTANT: also update the SOVERSION!! + # 1. ./meson.build + # 2. ./include/json/version.h + # 3. ./CMakeLists.txt + # IMPORTANT: also update the JSONCPP_SOVERSION!! VERSION 1.9.3 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}") -set( JSONCPP_SOVERSION 22 ) +set(JSONCPP_SOVERSION 23) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) @@ -95,105 +105,99 @@ include(GNUInstallDirs) set(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build") -set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL" ) +set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL") -configure_file( "${PROJECT_SOURCE_DIR}/version.in" - "${PROJECT_BINARY_DIR}/version" - NEWLINE_STYLE UNIX ) +configure_file("${PROJECT_SOURCE_DIR}/version.in" + "${PROJECT_BINARY_DIR}/version" + NEWLINE_STYLE UNIX) -macro(UseCompilationWarningAsError) +macro(use_compilation_warning_as_error) if(MSVC) # Only enabled in debug because some old versions of VS STL generate # warnings when compiled in release configuration. if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options($<$:/WX>) + add_compile_options($<$:/WX>) else() - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Werror) + add_compile_options(-Werror) else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") endif() if(JSONCPP_WITH_STRICT_ISO) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-pedantic-errors) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors") - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_options(-pedantic-errors) + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors") + endif() endif() endif() endmacro() # Include our configuration header -include_directories( ${jsoncpp_SOURCE_DIR}/include ) +include_directories(${jsoncpp_SOURCE_DIR}/include) if(MSVC) # Only enabled in debug because some old versions of VS STL generate # unreachable code warning when compiled in release configuration. if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options($<$:/W4>) + add_compile_options($<$:/W4>) else() - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ") endif() endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # using regular Clang or AppleClang if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare) + add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare) else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # using GCC if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wall -Wconversion -Wshadow -Wextra) + add_compile_options(-Wall -Wconversion -Wshadow -Wextra) else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra") endif() # not yet ready for -Wsign-conversion if(JSONCPP_WITH_STRICT_ISO) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-pedantic) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_options(-Wpedantic) + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") + endif() endif() if(JSONCPP_WITH_WARNING_AS_ERROR) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Werror=conversion) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=conversion") - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_options(-Werror=conversion) + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=conversion") + endif() endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") # using Intel compiler if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion) + add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion) else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra -Werror=conversion") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra -Werror=conversion") endif() if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-pedantic) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_options(-Wpedantic) + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") + endif() endif() endif() -find_program(CCACHE_FOUND ccache) -if(CCACHE_FOUND) - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) - set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) -endif(CCACHE_FOUND) - if(JSONCPP_WITH_WARNING_AS_ERROR) - UseCompilationWarningAsError() + use_compilation_warning_as_error() endif() if(JSONCPP_WITH_PKGCONFIG_SUPPORT) @@ -206,29 +210,29 @@ if(JSONCPP_WITH_PKGCONFIG_SUPPORT) endif() if(JSONCPP_WITH_CMAKE_PACKAGE) - include (CMakePackageConfigHelpers) - install(EXPORT jsoncpp - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp - FILE jsoncppConfig.cmake) - write_basic_package_version_file ("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) + include(CMakePackageConfigHelpers) + install(EXPORT jsoncpp + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp + FILE jsoncppConfig.cmake) + write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) endif() if(JSONCPP_WITH_TESTS) - enable_testing() - include(CTest) + enable_testing() + include(CTest) endif() # Build the different applications -add_subdirectory( src ) +add_subdirectory(src) #install the includes -add_subdirectory( include ) +add_subdirectory(include) #install the example if(JSONCPP_WITH_EXAMPLE) - add_subdirectory( example ) + add_subdirectory(example) endif() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index c8eba5335..51c32182d 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -2,28 +2,29 @@ cmake_minimum_required(VERSION 3.1) set(EXAMPLES - readFromString - readFromStream - stringWrite - streamWrite - ) + readFromString + readFromStream + stringWrite + streamWrite +) add_definitions(-D_GLIBCXX_USE_CXX11_ABI) set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra ") -else() - add_definitions( - -D_SCL_SECURE_NO_WARNINGS - -D_CRT_SECURE_NO_WARNINGS - -D_WIN32_WINNT=0x601 - -D_WINSOCK_DEPRECATED_NO_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra ") +else() + add_definitions( + -D_SCL_SECURE_NO_WARNINGS + -D_CRT_SECURE_NO_WARNINGS + -D_WIN32_WINNT=0x601 + -D_WINSOCK_DEPRECATED_NO_WARNINGS + ) endif() -foreach (example ${EXAMPLES}) - add_executable(${example} ${example}/${example}.cpp) - target_include_directories(${example} PUBLIC ${CMAKE_SOURCE_DIR}/include) - target_link_libraries(${example} jsoncpp_lib) +foreach(example ${EXAMPLES}) + add_executable(${example} ${example}/${example}.cpp) + target_include_directories(${example} PUBLIC ${CMAKE_SOURCE_DIR}/include) + target_link_libraries(${example} jsoncpp_lib) endforeach() add_custom_target(examples ALL DEPENDS ${EXAMPLES}) diff --git a/src/jsontestrunner/CMakeLists.txt b/src/jsontestrunner/CMakeLists.txt index 210e0900b..d24aa6f46 100644 --- a/src/jsontestrunner/CMakeLists.txt +++ b/src/jsontestrunner/CMakeLists.txt @@ -1,24 +1,24 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - # The new Python3 module is much more robust than the previous PythonInterp - find_package (Python3 COMPONENTS Interpreter) - # Set variables for backwards compatibility with cmake < 3.12.0 - set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND}) - set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + # The new Python3 module is much more robust than the previous PythonInterp + find_package(Python3 COMPONENTS Interpreter) + # Set variables for backwards compatibility with cmake < 3.12.0 + set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND}) + set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) else() - set(Python_ADDITIONAL_VERSIONS 3.8) - find_package(PythonInterp 3) + set(Python_ADDITIONAL_VERSIONS 3.8) + find_package(PythonInterp 3) endif() add_executable(jsontestrunner_exe - main.cpp - ) + main.cpp +) if(BUILD_SHARED_LIBS) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions( JSON_DLL ) - else() - add_definitions( -DJSON_DLL ) - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_definitions( JSON_DLL ) + else() + add_definitions(-DJSON_DLL) + endif() endif() target_link_libraries(jsontestrunner_exe jsoncpp_lib) @@ -32,18 +32,18 @@ if(PYTHONINTERP_FOUND) # Run unit tests in post-build # (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?) add_custom_target(jsoncpp_readerwriter_tests - "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $ "${TEST_DIR}/data" - DEPENDS jsontestrunner_exe jsoncpp_test - ) + "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $ "${TEST_DIR}/data" + DEPENDS jsontestrunner_exe jsoncpp_test + ) add_custom_target(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests) ## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp add_test(NAME jsoncpp_readerwriter - COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $ "${TEST_DIR}/data" - WORKING_DIRECTORY "${TEST_DIR}/data" + COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $ "${TEST_DIR}/data" + WORKING_DIRECTORY "${TEST_DIR}/data" ) add_test(NAME jsoncpp_readerwriter_json_checker - COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $ "${TEST_DIR}/data" - WORKING_DIRECTORY "${TEST_DIR}/data" + COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $ "${TEST_DIR}/data" + WORKING_DIRECTORY "${TEST_DIR}/data" ) endif() diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index b56788e27..401e1f7e8 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -1,13 +1,14 @@ -if( CMAKE_COMPILER_IS_GNUCXX ) +if(CMAKE_COMPILER_IS_GNUCXX) #Get compiler version. - execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion - OUTPUT_VARIABLE GNUCXX_VERSION ) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion + OUTPUT_VARIABLE GNUCXX_VERSION + ) #-Werror=* was introduced -after- GCC 4.1.2 - if( GNUCXX_VERSION VERSION_GREATER 4.1.2 ) + if(GNUCXX_VERSION VERSION_GREATER 4.1.2) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing") endif() -endif( CMAKE_COMPILER_IS_GNUCXX ) +endif() include(CheckIncludeFileCXX) include(CheckTypeSize) @@ -35,15 +36,15 @@ endif() if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV)) message(WARNING "Locale functionality is not supported") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions(JSONCPP_NO_LOCALE_SUPPORT) + add_compile_definitions(JSONCPP_NO_LOCALE_SUPPORT) else() - add_definitions(-DJSONCPP_NO_LOCALE_SUPPORT) + add_definitions(-DJSONCPP_NO_LOCALE_SUPPORT) endif() endif() -set( JSONCPP_INCLUDE_DIR ../../include ) +set(JSONCPP_INCLUDE_DIR ../../include) -set( PUBLIC_HEADERS +set(PUBLIC_HEADERS ${JSONCPP_INCLUDE_DIR}/json/config.h ${JSONCPP_INCLUDE_DIR}/json/forwards.h ${JSONCPP_INCLUDE_DIR}/json/json_features.h @@ -52,43 +53,44 @@ set( PUBLIC_HEADERS ${JSONCPP_INCLUDE_DIR}/json/version.h ${JSONCPP_INCLUDE_DIR}/json/writer.h ${JSONCPP_INCLUDE_DIR}/json/assertions.h - ) +) -source_group( "Public API" FILES ${PUBLIC_HEADERS} ) +source_group("Public API" FILES ${PUBLIC_HEADERS}) set(jsoncpp_sources - json_tool.h - json_reader.cpp - json_valueiterator.inl - json_value.cpp - json_writer.cpp) + json_tool.h + json_reader.cpp + json_valueiterator.inl + json_value.cpp + json_writer.cpp +) # Install instructions for this target if(JSONCPP_WITH_CMAKE_PACKAGE) set(INSTALL_EXPORT EXPORT jsoncpp) -else(JSONCPP_WITH_CMAKE_PACKAGE) +else() set(INSTALL_EXPORT) endif() if(BUILD_SHARED_LIBS) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions( JSON_DLL_BUILD ) + add_compile_definitions(JSON_DLL_BUILD) else() - add_definitions( -DJSON_DLL_BUILD ) + add_definitions(-DJSON_DLL_BUILD) endif() endif() add_library(jsoncpp_lib ${PUBLIC_HEADERS} ${jsoncpp_sources}) -set_target_properties( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION}) -set_target_properties( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp - DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX} ) -set_target_properties( jsoncpp_lib PROPERTIES POSITION_INDEPENDENT_CODE ON) +set_target_properties(jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION}) +set_target_properties(jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp + DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX}) +set_target_properties(jsoncpp_lib PROPERTIES POSITION_INDEPENDENT_CODE ON) # Set library's runtime search path on OSX if(APPLE) - set_target_properties( jsoncpp_lib PROPERTIES INSTALL_RPATH "@loader_path/." ) + set_target_properties(jsoncpp_lib PROPERTIES INSTALL_RPATH "@loader_path/.") endif() # Specify compiler features required when compiling a given target. @@ -141,14 +143,16 @@ target_compile_features(jsoncpp_lib PUBLIC cxx_variadic_templates # Variadic templates, as defined in N2242. ) -install( TARGETS jsoncpp_lib ${INSTALL_EXPORT} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS jsoncpp_lib ${INSTALL_EXPORT} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories( jsoncpp_lib PUBLIC - $ - $ - $) + target_include_directories(jsoncpp_lib PUBLIC + $ + $ + $ + ) endif() diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt index 6e301ec69..c9730d0d2 100644 --- a/src/test_lib_json/CMakeLists.txt +++ b/src/test_lib_json/CMakeLists.txt @@ -1,20 +1,20 @@ # vim: et ts=4 sts=4 sw=4 tw=0 -add_executable( jsoncpp_test - jsontest.cpp - jsontest.h - fuzz.cpp - fuzz.h - main.cpp - ) +add_executable(jsoncpp_test + jsontest.cpp + jsontest.h + fuzz.cpp + fuzz.h + main.cpp +) if(BUILD_SHARED_LIBS) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions( JSON_DLL ) - else() - add_definitions( -DJSON_DLL ) - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_definitions( JSON_DLL ) + else() + add_definitions( -DJSON_DLL ) + endif() endif() target_link_libraries(jsoncpp_test jsoncpp_lib) @@ -27,19 +27,21 @@ if(JSONCPP_WITH_POST_BUILD_UNITTEST) if(BUILD_SHARED_LIBS) # First, copy the shared lib, for Microsoft. # Then, run the test executable. - add_custom_command( TARGET jsoncpp_test - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ - COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) - else(BUILD_SHARED_LIBS) + add_custom_command(TARGET jsoncpp_test + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ + ) + else() # Just run the test executable. - add_custom_command( TARGET jsoncpp_test - POST_BUILD - COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) + add_custom_command(TARGET jsoncpp_test + POST_BUILD + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ + ) endif() ## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp add_test(NAME jsoncpp_test - COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ ) endif() From dc180eb25eca8d7ce16f062641e005e464ea398f Mon Sep 17 00:00:00 2001 From: David Gobbi Date: Thu, 13 Feb 2020 14:22:49 -0700 Subject: [PATCH 005/196] Remove '=delete' from template methods for Xcode 8 (#1133) For Apple clang-800.0.42.1, which was released with Xcode 8 in September 2016, the '=delete' on the 'is' and 'as' methods causes the following errors for value.h: inline declaration of 'as' follows non-inline definition inline declaration of 'is' follows non-inline definition etcetera for the other specializations of 'is' and 'as'. The same problem also occurs for clang-3.8 but not clang-3.9 or later. --- include/json/value.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index e169c3c69..bea2a568e 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -21,6 +21,24 @@ #endif #endif +// Support for '= delete' with template declarations was a late addition +// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 +// even though these declare themselves to be c++11 compilers. +#if !defined(JSONCPP_TEMPLATE_DELETE) +#if defined(__clang__) && defined(__apple_build_version__) +#if __apple_build_version__ <= 8000042 +#define JSONCPP_TEMPLATE_DELETE +#endif +#elif defined(__clang__) +#if __clang_major__ == 3 && __clang_minor__ <= 8 +#define JSONCPP_TEMPLATE_DELETE +#endif +#endif +#if !defined(JSONCPP_TEMPLATE_DELETE) +#define JSONCPP_TEMPLATE_DELETE = delete +#endif +#endif + #include #include #include @@ -390,8 +408,8 @@ class JSON_API Value { bool isObject() const; /// The `as` and `is` member function templates and specializations. - template T as() const = delete; - template bool is() const = delete; + template T as() const JSONCPP_TEMPLATE_DELETE; + template bool is() const JSONCPP_TEMPLATE_DELETE; bool isConvertibleTo(ValueType other) const; From 3beb37ea14aec1bdce1a6d542dc464d00f4a6cec Mon Sep 17 00:00:00 2001 From: Chen <50514813+dota17@users.noreply.github.com> Date: Fri, 14 Feb 2020 05:25:08 +0800 Subject: [PATCH 006/196] revert trailing comma in old Reader (#1126) --- include/json/json_features.h | 6 ------ src/lib_json/json_reader.cpp | 24 ++++++++---------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/include/json/json_features.h b/include/json/json_features.h index a5b73052a..7c7e9f5de 100644 --- a/include/json/json_features.h +++ b/include/json/json_features.h @@ -23,7 +23,6 @@ class JSON_API Features { /** \brief A configuration that allows all features and assumes all strings * are UTF-8. * - C & C++ comments are allowed - * - Trailing commas in objects and arrays are allowed. * - Root object can be any JSON value * - Assumes Value strings are encoded in UTF-8 */ @@ -32,7 +31,6 @@ class JSON_API Features { /** \brief A configuration that is strictly compatible with the JSON * specification. * - Comments are forbidden. - * - Trailing commas in objects and arrays are forbidden. * - Root object must be either an array or an object value. * - Assumes Value strings are encoded in UTF-8 */ @@ -45,10 +43,6 @@ class JSON_API Features { /// \c true if comments are allowed. Default: \c true. bool allowComments_{true}; - /// \c true if trailing commas in objects and arrays are allowed. Default \c - /// true. - bool allowTrailingCommas_{true}; - /// \c true if root must be either an array or an object value. Default: \c /// false. bool strictRoot_{false}; diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 2c6fead19..10be6d2cf 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -67,7 +67,6 @@ Features Features::all() { return {}; } Features Features::strictMode() { Features features; features.allowComments_ = false; - features.allowTrailingCommas_ = false; features.strictRoot_ = true; features.allowDroppedNullPlaceholders_ = false; features.allowNumericKeys_ = false; @@ -455,9 +454,7 @@ bool Reader::readObject(Token& token) { initialTokenOk = readToken(tokenName); if (!initialTokenOk) break; - if (tokenName.type_ == tokenObjectEnd && - (name.empty() || - features_.allowTrailingCommas_)) // empty object or trailing comma + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; name.clear(); if (tokenName.type_ == tokenString) { @@ -505,20 +502,15 @@ bool Reader::readArray(Token& token) { Value init(arrayValue); currentValue().swapPayload(init); currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } int index = 0; for (;;) { - skipSpaces(); - if (current_ != end_ && *current_ == ']' && - (index == 0 || - (features_.allowTrailingCommas_ && - !features_.allowDroppedNullPlaceholders_))) // empty array or trailing - // comma - { - Token endArray; - readToken(endArray); - return true; - } - Value& value = currentValue()[index++]; nodes_.push(&value); bool ok = readValue(); From 90ca694e4697497a8c2bc8c60a9c9f89e7290a10 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 11 Apr 2020 22:26:04 -0700 Subject: [PATCH 007/196] clang-tidy fixes again (#1155) * [clang-tidy] remove redundant string initialization Found with readability-redundant-string-init Signed-off-by: Rosen Penev * [clang-tidy] switch to raw strings Easier to read. Found with modernize-raw-string-literal Signed-off-by: Rosen Penev * [clang-tidy] fix performance issues Found with performance* Signed-off-by: Rosen Penev * fix extra comma warnings Found with clang's -Wextra-semi-stmt Signed-off-by: Rosen Penev * remove JSONCPP_OP_EXPLICIT This codebase in C++11. No need for compatibility with C++98. Signed-off-by: Rosen Penev * remove JSONCPP_NOEXCEPT This codebase is C++11 now. No need for this macro. Signed-off-by: Rosen Penev --- include/json/assertions.h | 16 ++++++++------ include/json/config.h | 14 ------------ include/json/value.h | 6 ++--- src/jsontestrunner/main.cpp | 2 +- src/lib_json/json_value.cpp | 4 ++-- src/test_lib_json/jsontest.h | 8 +++---- src/test_lib_json/main.cpp | 43 ++++++++++++++++++------------------ 7 files changed, 40 insertions(+), 53 deletions(-) diff --git a/include/json/assertions.h b/include/json/assertions.h index 9d93238dc..666fa7f54 100644 --- a/include/json/assertions.h +++ b/include/json/assertions.h @@ -21,19 +21,19 @@ // @todo <= add detail about condition in exception #define JSON_ASSERT(condition) \ - { \ + do { \ if (!(condition)) { \ Json::throwLogicError("assert json failed"); \ } \ - } + } while (0) #define JSON_FAIL_MESSAGE(message) \ - { \ + do { \ OStringStream oss; \ oss << message; \ Json::throwLogicError(oss.str()); \ abort(); \ - } + } while (0) #else // JSON_USE_EXCEPTION @@ -52,8 +52,10 @@ #endif #define JSON_ASSERT_MESSAGE(condition, message) \ - if (!(condition)) { \ - JSON_FAIL_MESSAGE(message); \ - } + do { \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } \ + } while (0) #endif // JSON_ASSERTIONS_H_INCLUDED diff --git a/include/json/config.h b/include/json/config.h index 3d148a69b..6359273a2 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -74,20 +74,6 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, // C++11 should be used directly in JSONCPP. #define JSONCPP_OVERRIDE override -#if __cplusplus >= 201103L -#define JSONCPP_NOEXCEPT noexcept -#define JSONCPP_OP_EXPLICIT explicit -#elif defined(_MSC_VER) && _MSC_VER < 1900 -#define JSONCPP_NOEXCEPT throw() -#define JSONCPP_OP_EXPLICIT explicit -#elif defined(_MSC_VER) && _MSC_VER >= 1900 -#define JSONCPP_NOEXCEPT noexcept -#define JSONCPP_OP_EXPLICIT explicit -#else -#define JSONCPP_NOEXCEPT throw() -#define JSONCPP_OP_EXPLICIT -#endif - #ifdef __clang__ #if __has_extension(attribute_deprecated_with_message) #define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) diff --git a/include/json/value.h b/include/json/value.h index bea2a568e..dffc51a85 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -67,8 +67,8 @@ namespace Json { class JSON_API Exception : public std::exception { public: Exception(String msg); - ~Exception() JSONCPP_NOEXCEPT override; - char const* what() const JSONCPP_NOEXCEPT override; + ~Exception() noexcept override; + char const* what() const noexcept override; protected: String msg_; @@ -421,7 +421,7 @@ class JSON_API Value { bool empty() const; /// Return !isNull() - JSONCPP_OP_EXPLICIT operator bool() const; + explicit operator bool() const; /// Remove all object members and array elements. /// \pre type() is arrayValue, objectValue, or nullValue diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp index cdf6bffb0..3452c5986 100644 --- a/src/jsontestrunner/main.cpp +++ b/src/jsontestrunner/main.cpp @@ -111,7 +111,7 @@ static void printValueTree(FILE* fout, Json::Value& value, Json::Value::Members members(value.getMemberNames()); std::sort(members.begin(), members.end()); Json::String suffix = *(path.end() - 1) == '.' ? "" : "."; - for (auto name : members) { + for (const auto& name : members) { printValueTree(fout, value[name], path + suffix + name); } } break; diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 74535fbd9..71dba6e8c 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -200,8 +200,8 @@ namespace Json { #if JSON_USE_EXCEPTION Exception::Exception(String msg) : msg_(std::move(msg)) {} -Exception::~Exception() JSONCPP_NOEXCEPT = default; -char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } +Exception::~Exception() noexcept = default; +char const* Exception::what() const noexcept { return msg_.c_str(); } RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} LogicError::LogicError(String const& msg) : Exception(msg) {} JSONCPP_NORETURN void throwRuntimeError(String const& msg) { diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h index 8c3aa5e32..4e8af0f25 100644 --- a/src/test_lib_json/jsontest.h +++ b/src/test_lib_json/jsontest.h @@ -207,7 +207,7 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, /// The predicate may do other assertions and be a member function of the /// fixture. #define JSONTEST_ASSERT_PRED(expr) \ - { \ + do { \ JsonTest::PredicateContext _minitest_Context = { \ result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL}; \ result_->predicateStackTail_->next_ = &_minitest_Context; \ @@ -215,7 +215,7 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, result_->predicateStackTail_ = &_minitest_Context; \ (expr); \ result_->popPredicateContext(); \ - } + } while (0) /// \brief Asserts that two values are equals. #define JSONTEST_ASSERT_EQUAL(expected, actual) \ @@ -230,7 +230,7 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, /// \brief Asserts that a given expression throws an exception #define JSONTEST_ASSERT_THROWS(expr) \ - { \ + do { \ bool _threw = false; \ try { \ expr; \ @@ -240,7 +240,7 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, if (!_threw) \ result_->addFailure(__FILE__, __LINE__, \ "expected exception thrown: " #expr); \ - } + } while (0) /// \brief Begin a fixture test case. #define JSONTEST_FIXTURE(FixtureType, name) \ diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 7b20e41ec..f0b84fcc7 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -1874,7 +1874,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, CommentBefore) { Json::String result = Json::writeString(wbuilder, val); JSONTEST_ASSERT_STRING_EQUAL(expected, result); Json::String res2 = val.toStyledString(); - Json::String exp2 = ""; + Json::String exp2; exp2 += expected; exp2 += "\n"; JSONTEST_ASSERT_STRING_EQUAL(exp2, res2); @@ -2592,7 +2592,7 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, indentation) { JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) { Json::String binary("hi", 3); // include trailing 0 JSONTEST_ASSERT_EQUAL(3, binary.length()); - Json::String expected("\"hi\\u0000\""); // unicoded zero + Json::String expected(R"("hi\u0000")"); // unicoded zero Json::StreamWriterBuilder b; { Json::Value root; @@ -2866,7 +2866,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) { CharReaderPtr reader(b.newCharReader()); Json::String errs; Json::Value root; - char const doc[] = "{ \"property\" : \"value\" }"; + char const doc[] = R"({ "property" : "value" })"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); @@ -2914,14 +2914,14 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { JSONTEST_ASSERT_EQUAL("", root[0]); } { - char const doc[] = "[\"\\u8A2a\"]"; + char const doc[] = R"(["\u8A2a"])"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪" } { - char const doc[] = "[ \"\\uD801\" ]"; + char const doc[] = R"([ "\uD801" ])"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" @@ -2930,7 +2930,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { "See Line 1, Column 10 for detail.\n"); } { - char const doc[] = "[ \"\\uD801\\d1234\" ]"; + char const doc[] = R"([ "\uD801\d1234" ])"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" @@ -2939,7 +2939,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { "See Line 1, Column 12 for detail.\n"); } { - char const doc[] = "[ \"\\ua3t@\" ]"; + char const doc[] = R"([ "\ua3t@" ])"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" @@ -2948,7 +2948,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { "See Line 1, Column 9 for detail.\n"); } { - char const doc[] = "[ \"\\ua3t\" ]"; + char const doc[] = R"([ "\ua3t" ])"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT( @@ -2960,7 +2960,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { { b.settings_["allowSingleQuotes"] = true; CharReaderPtr charreader(b.newCharReader()); - char const doc[] = "{'a': 'x\\ty', \"b\":'x\\\\y'}"; + char const doc[] = R"({'a': 'x\ty', "b":'x\\y'})"; bool ok = charreader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); @@ -3007,7 +3007,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { Json::Value root; Json::String errs; { - char const doc[] = "{ \"property\" : \"value\" "; + char const doc[] = R"({ "property" : "value" )"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 24\n" @@ -3015,7 +3015,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { JSONTEST_ASSERT_EQUAL("value", root["property"]); } { - char const doc[] = "{ \"property\" : \"value\" ,"; + char const doc[] = R"({ "property" : "value" ,)"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 25\n" @@ -3038,7 +3038,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) { JSONTEST_ASSERT_EQUAL("value", root[0]); } { - char const doc[] = "[ \"value1\" \"value2\" ]"; + char const doc[] = R"([ "value1" "value2" ])"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 12\n" @@ -3052,7 +3052,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) { CharReaderPtr reader(b.newCharReader()); Json::String errs; Json::Value root; - char const doc[] = "{ \"property\" :: \"value\" }"; + char const doc[] = R"({ "property" :: "value" })"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == @@ -3078,7 +3078,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { CharReaderPtr reader(b.newCharReader()); Json::String errs; Json::Value root; - char const doc[] = "{ \"property\" : \"v\\alue\" }"; + char const doc[] = R"({ "property" : "v\alue" })"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == @@ -3089,7 +3089,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { Json::CharReaderBuilder b; Json::Value root; - char const doc[] = "{ \"property\" : \"value\" }"; + char const doc[] = R"({ "property" : "value" })"; { b.settings_["stackLimit"] = 2; CharReaderPtr reader(b.newCharReader()); @@ -3109,7 +3109,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { } JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) { - const std::string styled = "{ \"property\" : \"value\" }"; + const std::string styled = R"({ "property" : "value" })"; std::istringstream iss(styled); Json::Value root; iss >> root; @@ -3122,7 +3122,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) { Json::CharReaderBuilder b; Json::Value root; char const doc[] = - "{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }"; + R"({ "property" : "value", "key" : "val1", "key" : "val2" })"; { b.strictMode(&b.settings_); CharReaderPtr reader(b.newCharReader()); @@ -3141,7 +3141,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) { // This is interpreted as a string value followed by a colon. Json::CharReaderBuilder b; Json::Value root; - char const doc[] = " \"property\" : \"value\" }"; + char const doc[] = R"( "property" : "value" })"; { b.settings_["failIfExtra"] = false; CharReaderPtr reader(b.newCharReader()); @@ -3445,8 +3445,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { Json::String errs; CharReaderPtr reader(b.newCharReader()); { - char const doc[] = - "{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity,\"d\":+Infinity}"; + char const doc[] = R"({"a":NaN,"b":Infinity,"c":-Infinity,"d":+Infinity})"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); @@ -3497,7 +3496,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { } { - char const doc[] = "{\"posInf\": +Infinity, \"NegInf\": -Infinity}"; + char const doc[] = R"({"posInf": +Infinity, "NegInf": -Infinity})"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); @@ -3719,7 +3718,7 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) { for (; iter != value.end(); ++iter) { out << *iter << ','; } - Json::String expected = "\" 9\",\"10\",\"11\","; + Json::String expected = R"(" 9","10","11",)"; JSONTEST_ASSERT_STRING_EQUAL(expected, out.str()); } From 2e54e8ff1c9d3438297bdfd33b1a305fc7cbae98 Mon Sep 17 00:00:00 2001 From: Stefano Fiorentino Date: Fri, 24 Apr 2020 05:52:56 +0200 Subject: [PATCH 008/196] adding myself to AUTHORS as per commits (#1109) commits: ff923658c4d9f1492617557148369b34c71ba623 5907cef86ca699a842d0a8cad4c018b4da5d6e17 --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 3723d546a..6cddf9796 100644 --- a/AUTHORS +++ b/AUTHORS @@ -97,6 +97,7 @@ selaselah Sergiy80 sergzub Stefan Schweter +Stefano Fiorentino Steffen Kieß Steven Hahn Stuart Eichert From 8b20b7a317b671fadcdff760dce7e341312503aa Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2019 11:37:14 -0500 Subject: [PATCH 009/196] amalgamate: add version.h and allocator.h to the forwards header Required to get JSONCPP_USING_SECURE_MEMORY and the SecureAllocator available for the definition of Allocator. --- amalgamate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/amalgamate.py b/amalgamate.py index fedee1eae..4a328ab5a 100755 --- a/amalgamate.py +++ b/amalgamate.py @@ -99,6 +99,8 @@ def amalgamate_source(source_top_dir=None, header.add_text("/// If defined, indicates that the source file is amalgamated") header.add_text("/// to prevent private header inclusion.") header.add_text("#define JSON_IS_AMALGAMATION") + header.add_file(os.path.join(INCLUDE_PATH, "version.h")) + header.add_file(os.path.join(INCLUDE_PATH, "allocator.h")) header.add_file(os.path.join(INCLUDE_PATH, "config.h")) header.add_file(os.path.join(INCLUDE_PATH, "forwards.h")) header.add_text("#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED") From 1ff6bb65a0a845dfe4e29fef01f5f42ddfe4f67a Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Fri, 24 Apr 2020 00:58:35 -0500 Subject: [PATCH 010/196] ninja test --- CONTRIBUTING.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08428b6f8..9c9fc6a04 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,8 +27,13 @@ Then, #LIB_TYPE=static meson --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . build-${LIB_TYPE} ninja -v -C build-${LIB_TYPE} - cd build-${LIB_TYPE} - meson test --no-rebuild --print-errorlogs + + ninja -C build-static/ test + + # Or + #cd build-${LIB_TYPE} + #meson test --no-rebuild --print-errorlogs + sudo ninja install ## Building and testing with other build systems From 411d88fae895d7d2dbc06dcccc80d4f747746c2b Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Fri, 24 Apr 2020 01:45:19 -0500 Subject: [PATCH 011/196] Stop checking status; raise instead --- test/runjsontests.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/runjsontests.py b/test/runjsontests.py index dfdeca3ea..26caf0cfb 100644 --- a/test/runjsontests.py +++ b/test/runjsontests.py @@ -62,6 +62,10 @@ def safeReadFile(path): except IOError as e: return '' % (path,e) +class FailError(Exception): + def __init__(self, msg): + super(Exception, self).__init__(msg) + def runAllTests(jsontest_executable_path, input_dir = None, use_valgrind=False, with_json_checker=False, writerClass='StyledWriter'): @@ -161,10 +165,9 @@ def runAllTests(jsontest_executable_path, input_dir = None, print() print('Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests), len(failed_tests))) - return 1 + raise FailError(repr(failed_tests)) else: print('All %d tests passed.' % len(tests)) - return 0 def main(): from optparse import OptionParser @@ -187,24 +190,21 @@ def main(): input_path = os.path.normpath(os.path.abspath(args[1])) else: input_path = None - status = runAllTests(jsontest_executable_path, input_path, + runAllTests(jsontest_executable_path, input_path, use_valgrind=options.valgrind, with_json_checker=options.with_json_checker, writerClass='StyledWriter') - if status: - sys.exit(status) - status = runAllTests(jsontest_executable_path, input_path, + runAllTests(jsontest_executable_path, input_path, use_valgrind=options.valgrind, with_json_checker=options.with_json_checker, writerClass='StyledStreamWriter') - if status: - sys.exit(status) - status = runAllTests(jsontest_executable_path, input_path, + runAllTests(jsontest_executable_path, input_path, use_valgrind=options.valgrind, with_json_checker=options.with_json_checker, writerClass='BuiltStyledStreamWriter') - if status: - sys.exit(status) if __name__ == '__main__': - main() + try: + main() + except FailError: + sys.exit(1) From 9e23f66f614d23c4c2b540d2d62ce3b2725d422a Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 14 Nov 2019 10:41:25 -0800 Subject: [PATCH 012/196] Issue 1102: Fixup test suite, fix broken tests A recent PR broken the JsonChecker tests by adding support for trailing commas. This didn't end up breaking the build, because those tests aren't run, except locally and only using CMake. This patch fixes the tests by adding exclusions for trailing comma tests, as well as updates Meson to run these tests as part of `ninja test`. See issue #1102. --- meson.build | 10 +++++++++ test/runjsontests.py | 53 ++++++++++++++------------------------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/meson.build b/meson.build index c29320307..e2e92ad54 100644 --- a/meson.build +++ b/meson.build @@ -105,3 +105,13 @@ test( jsontestrunner, join_paths(meson.current_source_dir(), 'test/data')] ) +test( + 'jsonchecker_jsontestrunner', + python, + args : [ + '-B', + join_paths(meson.current_source_dir(), 'test/runjsontests.py'), + '--with-json-checker', + jsontestrunner, + join_paths(meson.current_source_dir(), 'test/data')] + ) diff --git a/test/runjsontests.py b/test/runjsontests.py index 26caf0cfb..fb1fb399b 100644 --- a/test/runjsontests.py +++ b/test/runjsontests.py @@ -73,45 +73,26 @@ def runAllTests(jsontest_executable_path, input_dir = None, input_dir = os.path.join(os.getcwd(), 'data') tests = glob(os.path.join(input_dir, '*.json')) if with_json_checker: - all_test_jsonchecker = glob(os.path.join(input_dir, '../jsonchecker', '*.json')) - # These tests fail with strict json support, but pass with jsoncpp extra lieniency - """ - Failure details: - * Test ../jsonchecker/fail25.json - Parsing should have failed: - [" tab character in string "] - - * Test ../jsonchecker/fail13.json - Parsing should have failed: - {"Numbers cannot have leading zeroes": 013} - - * Test ../jsonchecker/fail18.json - Parsing should have failed: - [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] - - * Test ../jsonchecker/fail8.json - Parsing should have failed: - ["Extra close"]] - - * Test ../jsonchecker/fail7.json - Parsing should have failed: - ["Comma after the close"], - - * Test ../jsonchecker/fail10.json - Parsing should have failed: - {"Extra value after close": true} "misplaced quoted value" - - * Test ../jsonchecker/fail27.json - Parsing should have failed: - ["line - break"] - """ - known_differences_withjsonchecker = [ "fail25.json", "fail13.json", "fail18.json", "fail8.json", - "fail7.json", "fail10.json", "fail27.json" ] - test_jsonchecker = [ test for test in all_test_jsonchecker if os.path.basename(test) not in known_differences_withjsonchecker ] + all_tests = glob(os.path.join(input_dir, '../jsonchecker', '*.json')) + # These tests fail with strict json support, but pass with JsonCPP's + # extra leniency features. When adding a new exclusion to this list, + # remember to add the test's number and reasoning here: + known = ["fail{}.json".format(n) for n in [ + 4, 9, # fail because we allow trailing commas + 7, # fails because we allow commas after close + 8, # fails because we allow extra close + 10, # fails because we allow extra values after close + 13, # fails because we allow leading zeroes in numbers + 18, # fails because we allow deeply nested values + 25, # fails because we allow tab characters in strings. + 27, # fails because we allow string line breaks + ]] + test_jsonchecker = [ test for test in all_tests + if os.path.basename(test) not in known] else: test_jsonchecker = [] + failed_tests = [] valgrind_path = use_valgrind and VALGRIND_CMD or '' for input_path in tests + test_jsonchecker: From b3492219385ba41f9f8167a68e3f56a2b6cdd7a9 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 14 Nov 2019 10:52:13 -0800 Subject: [PATCH 013/196] Cleanup test configurations --- meson.build | 5 +++-- test/runjsontests.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index e2e92ad54..7bacdfcda 100644 --- a/meson.build +++ b/meson.build @@ -103,7 +103,7 @@ test( '-B', join_paths(meson.current_source_dir(), 'test/runjsontests.py'), jsontestrunner, - join_paths(meson.current_source_dir(), 'test/data')] + join_paths(meson.current_source_dir(), 'test/data')], ) test( 'jsonchecker_jsontestrunner', @@ -113,5 +113,6 @@ test( join_paths(meson.current_source_dir(), 'test/runjsontests.py'), '--with-json-checker', jsontestrunner, - join_paths(meson.current_source_dir(), 'test/data')] + join_paths(meson.current_source_dir(), 'test/data')], + workdir : join_paths(meson.current_source_dir(), 'test/data'), ) diff --git a/test/runjsontests.py b/test/runjsontests.py index fb1fb399b..5496e2c58 100644 --- a/test/runjsontests.py +++ b/test/runjsontests.py @@ -84,7 +84,7 @@ def runAllTests(jsontest_executable_path, input_dir = None, 10, # fails because we allow extra values after close 13, # fails because we allow leading zeroes in numbers 18, # fails because we allow deeply nested values - 25, # fails because we allow tab characters in strings. + 25, # fails because we allow tab characters in strings 27, # fails because we allow string line breaks ]] test_jsonchecker = [ test for test in all_tests From a0b8c3ecb418a8d5fcf992a3250fd3634b5cb563 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Fri, 24 Apr 2020 09:24:22 -0500 Subject: [PATCH 014/196] Do not run colliding tests at same time --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 7bacdfcda..975d56cda 100644 --- a/meson.build +++ b/meson.build @@ -108,6 +108,7 @@ test( test( 'jsonchecker_jsontestrunner', python, + is_parallel : false, args : [ '-B', join_paths(meson.current_source_dir(), 'test/runjsontests.py'), From 91f1553f2c65e8c3d200fa309efe784673c27125 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Mon, 23 Mar 2020 17:34:46 -0700 Subject: [PATCH 015/196] Make throwRuntimeError/throwLogicError print msg when built with JSON_USE_EXCEPTION=0 --- src/lib_json/json_value.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 71dba6e8c..0872ff548 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -211,8 +212,14 @@ JSONCPP_NORETURN void throwLogicError(String const& msg) { throw LogicError(msg); } #else // !JSON_USE_EXCEPTION -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { abort(); } -JSONCPP_NORETURN void throwLogicError(String const& msg) { abort(); } +JSONCPP_NORETURN void throwRuntimeError(String const& msg) { + std::cerr << msg << std::endl; + abort(); +} +JSONCPP_NORETURN void throwLogicError(String const& msg) { + std::cerr << msg << std::endl; + abort(); +} #endif // ////////////////////////////////////////////////////////////////// From 83946a28db3d13ffe8184bdae23287a81c09fd7f Mon Sep 17 00:00:00 2001 From: Chen <50514813+dota17@users.noreply.github.com> Date: Tue, 28 Apr 2020 15:16:05 +0800 Subject: [PATCH 016/196] Ignore byte order mark in the head of UTF-8 text. (#1149) * Ignore bom at the beginning of the UTF-8 text --- src/lib_json/json_reader.cpp | 19 +++++++++++++++++++ src/test_lib_json/main.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 10be6d2cf..341162bcd 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -871,6 +871,7 @@ class OurFeatures { bool failIfExtra_; bool rejectDupKeys_; bool allowSpecialFloats_; + bool allowBom_; size_t stackLimit_; }; // OurFeatures @@ -939,6 +940,7 @@ class OurReader { bool readToken(Token& token); void skipSpaces(); + void skipBom(bool allowBom); bool match(const Char* pattern, int patternLength); bool readComment(); bool readCStyleComment(bool* containsNewLineResult); @@ -1022,6 +1024,8 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, nodes_.pop(); nodes_.push(&root); + // skip byte order mark if it exists at the beginning of the UTF-8 text. + skipBom(features_.allowBom_); bool successful = readValue(); nodes_.pop(); Token token; @@ -1268,6 +1272,17 @@ void OurReader::skipSpaces() { } } +void OurReader::skipBom(bool allowBom) { + // If BOM is not allowed, then skip it. + // The default value is: false + if (!allowBom) { + if (strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { + begin_ += 3; + current_ = begin_; + } + } +} + bool OurReader::match(const Char* pattern, int patternLength) { if (end_ - current_ < patternLength) return false; @@ -1885,6 +1900,7 @@ CharReader* CharReaderBuilder::newCharReader() const { features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + features.allowBom_ = settings_["allowBom"].asBool(); return new OurCharReader(collectComments, features); } static void getValidReaderKeys(std::set* valid_keys) { @@ -1900,6 +1916,7 @@ static void getValidReaderKeys(std::set* valid_keys) { valid_keys->insert("failIfExtra"); valid_keys->insert("rejectDupKeys"); valid_keys->insert("allowSpecialFloats"); + valid_keys->insert("allowBom"); } bool CharReaderBuilder::validate(Json::Value* invalid) const { Json::Value my_invalid; @@ -1934,6 +1951,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings) { (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; (*settings)["allowSpecialFloats"] = false; + (*settings)["allowBom"] = false; //! [CharReaderBuilderStrictMode] } // static @@ -1950,6 +1968,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) { (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; (*settings)["allowSpecialFloats"] = false; + (*settings)["allowBom"] = false; //! [CharReaderBuilderDefaults] } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index f0b84fcc7..ede39ee89 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3577,6 +3577,32 @@ JSONTEST_FIXTURE_LOCAL(BuilderTest, settings) { } } +struct BomTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE_LOCAL(BomTest, skipBom) { + const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}"; + Json::Value root; + JSONCPP_STRING errs; + std::istringstream iss(with_bom); + bool ok = parseFromStream(Json::CharReaderBuilder(), iss, &root, &errs); + // The default behavior is to skip the BOM, so we can parse it normally. + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs.empty()); + JSONTEST_ASSERT_STRING_EQUAL(root["key"].asString(), "value"); +} +JSONTEST_FIXTURE_LOCAL(BomTest, allowBom) { + const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}"; + Json::Value root; + JSONCPP_STRING errs; + std::istringstream iss(with_bom); + Json::CharReaderBuilder b; + b.settings_["allowBom"] = true; + bool ok = parseFromStream(b, iss, &root, &errs); + // Detect the BOM, and failed on it. + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(!errs.empty()); +} + struct IteratorTest : JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) { From 2cb16b35dcfe0703272c9bbe777ad09546846a04 Mon Sep 17 00:00:00 2001 From: Chen <50514813+dota17@users.noreply.github.com> Date: Tue, 28 Apr 2020 17:30:08 +0800 Subject: [PATCH 017/196] allowBom -> skipBom (#1162) --- src/lib_json/json_reader.cpp | 21 ++++++++++----------- src/test_lib_json/main.cpp | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 341162bcd..02a7d54ca 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -871,7 +871,7 @@ class OurFeatures { bool failIfExtra_; bool rejectDupKeys_; bool allowSpecialFloats_; - bool allowBom_; + bool skipBom_; size_t stackLimit_; }; // OurFeatures @@ -940,7 +940,7 @@ class OurReader { bool readToken(Token& token); void skipSpaces(); - void skipBom(bool allowBom); + void skipBom(bool skipBom); bool match(const Char* pattern, int patternLength); bool readComment(); bool readCStyleComment(bool* containsNewLineResult); @@ -1025,7 +1025,7 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, nodes_.push(&root); // skip byte order mark if it exists at the beginning of the UTF-8 text. - skipBom(features_.allowBom_); + skipBom(features_.skipBom_); bool successful = readValue(); nodes_.pop(); Token token; @@ -1272,10 +1272,9 @@ void OurReader::skipSpaces() { } } -void OurReader::skipBom(bool allowBom) { - // If BOM is not allowed, then skip it. - // The default value is: false - if (!allowBom) { +void OurReader::skipBom(bool skipBom) { + // The default behavior is to skip BOM. + if (skipBom) { if (strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { begin_ += 3; current_ = begin_; @@ -1900,7 +1899,7 @@ CharReader* CharReaderBuilder::newCharReader() const { features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); - features.allowBom_ = settings_["allowBom"].asBool(); + features.skipBom_ = settings_["skipBom"].asBool(); return new OurCharReader(collectComments, features); } static void getValidReaderKeys(std::set* valid_keys) { @@ -1916,7 +1915,7 @@ static void getValidReaderKeys(std::set* valid_keys) { valid_keys->insert("failIfExtra"); valid_keys->insert("rejectDupKeys"); valid_keys->insert("allowSpecialFloats"); - valid_keys->insert("allowBom"); + valid_keys->insert("skipBom"); } bool CharReaderBuilder::validate(Json::Value* invalid) const { Json::Value my_invalid; @@ -1951,7 +1950,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings) { (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; (*settings)["allowSpecialFloats"] = false; - (*settings)["allowBom"] = false; + (*settings)["skipBom"] = true; //! [CharReaderBuilderStrictMode] } // static @@ -1968,7 +1967,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) { (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; (*settings)["allowSpecialFloats"] = false; - (*settings)["allowBom"] = false; + (*settings)["skipBom"] = true; //! [CharReaderBuilderDefaults] } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index ede39ee89..e6fe43d79 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3590,13 +3590,13 @@ JSONTEST_FIXTURE_LOCAL(BomTest, skipBom) { JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT_STRING_EQUAL(root["key"].asString(), "value"); } -JSONTEST_FIXTURE_LOCAL(BomTest, allowBom) { +JSONTEST_FIXTURE_LOCAL(BomTest, notSkipBom) { const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}"; Json::Value root; JSONCPP_STRING errs; std::istringstream iss(with_bom); Json::CharReaderBuilder b; - b.settings_["allowBom"] = true; + b.settings_["skipBom"] = false; bool ok = parseFromStream(b, iss, &root, &errs); // Detect the BOM, and failed on it. JSONTEST_ASSERT(!ok); From a3afd74b80715a0a1f2d7b5c47b90385b7e1b136 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 18 Feb 2020 18:04:04 -0700 Subject: [PATCH 018/196] Don't use unique variable for postfix The more general CMake way to handle library suffixing is to set CMAKE__POSTFIX, so setting the Debug output suffix name should be more correctly done by the caller or CMake configurer by setting the desired value in CMAKE_DEBUG_POSTFIX. --- CMakeLists.txt | 2 -- src/lib_json/CMakeLists.txt | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7e2e09ad..da6b51e17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,8 +103,6 @@ endif() # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) -set(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build") - set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL") configure_file("${PROJECT_SOURCE_DIR}/version.in" diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 401e1f7e8..1128381f2 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -84,8 +84,7 @@ endif() add_library(jsoncpp_lib ${PUBLIC_HEADERS} ${jsoncpp_sources}) set_target_properties(jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION}) -set_target_properties(jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp - DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX}) +set_target_properties(jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp) set_target_properties(jsoncpp_lib PROPERTIES POSITION_INDEPENDENT_CODE ON) # Set library's runtime search path on OSX From c648b0378addd7834c1c530ea20853303c1de535 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 18 Feb 2020 18:04:59 -0700 Subject: [PATCH 019/196] Consolidate setting of jsoncpp target properties --- src/lib_json/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 1128381f2..e22fb1c37 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -81,11 +81,13 @@ if(BUILD_SHARED_LIBS) endif() endif() - add_library(jsoncpp_lib ${PUBLIC_HEADERS} ${jsoncpp_sources}) -set_target_properties(jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION}) -set_target_properties(jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp) -set_target_properties(jsoncpp_lib PROPERTIES POSITION_INDEPENDENT_CODE ON) +set_target_properties( jsoncpp_lib PROPERTIES + OUTPUT_NAME jsoncpp + VERSION ${JSONCPP_VERSION} + SOVERSION ${JSONCPP_SOVERSION} + POSITION_INDEPENDENT_CODE ON +) # Set library's runtime search path on OSX if(APPLE) From 5a0152ae1b0b6a683365e56306dcac613f0859a1 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 31 Dec 2019 15:42:19 -0700 Subject: [PATCH 020/196] Only set CMAKE_BUILD_TYPE for single config generators --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da6b51e17..714960bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,8 +56,8 @@ endif() # ==== -# Ensures that CMAKE_BUILD_TYPE has a default value -if(NOT DEFINED CMAKE_BUILD_TYPE) +# Ensure that CMAKE_BUILD_TYPE has a value specified for single configuration generators. +if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") endif() From edc6239f3934d39ce635d2127790f464ca08a125 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 31 Dec 2019 16:03:32 -0700 Subject: [PATCH 021/196] Not needed to specify CMAKE_MACOSX_RPATH As of CMake 3.0 with CMP0042, MACOSX_RPATH is enabled by default. Since the validated version used by jsoncpp is later than 3.0, this is already covered. --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 714960bc2..4f3b60119 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,11 +95,6 @@ option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON) option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF) option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) -# Enable runtime search path support for dynamic libraries on OSX -if(APPLE) - set(CMAKE_MACOSX_RPATH 1) -endif() - # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) From 12ceb014850d2a7bbaf7f23cd4a1ab8f6571b17f Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 31 Dec 2019 16:07:22 -0700 Subject: [PATCH 022/196] Always use consistent CXX_STANDARD Since CMake has subdirectory variable scope, unilaterally set the CMAKE_CXX_STANDARD variable to use C++11. This covers cases with the library being included externally, both in cases of only C++98 being specified, as well as later versions being specified (since the CXX_STANDARD itself isn't a library dependency, only the PUBLIC target_compile_features on jsoncpp_lib). The previous direct check for C++98 is handled by requiring C++11 on this library; should the compiler being used not support C++11 then CMake will issue an error. --- CMakeLists.txt | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f3b60119..e636eebc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,24 +37,11 @@ foreach(pold "") # Currently Empty endif() endforeach() -# ==== Define language standard configurations requiring at least c++11 standard -if(CMAKE_CXX_STANDARD EQUAL "98") - message(FATAL_ERROR "CMAKE_CXX_STANDARD:STRING=98 is not supported.") -endif() - -##### -## Set the default target properties -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 11) # Supported values are ``11``, ``14``, and ``17``. -endif() -if(NOT CMAKE_CXX_STANDARD_REQUIRED) - set(CMAKE_CXX_STANDARD_REQUIRED ON) -endif() -if(NOT CMAKE_CXX_EXTENSIONS) - set(CMAKE_CXX_EXTENSIONS OFF) -endif() - -# ==== +# Build the library with C++11 standard support, independent from other including +# software which may use a different CXX_STANDARD or CMAKE_CXX_STANDARD. +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) # Ensure that CMAKE_BUILD_TYPE has a value specified for single configuration generators. if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) From 30eb5ce128d4880febbb82c71c62952380be542a Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 31 Dec 2019 20:23:08 -0700 Subject: [PATCH 023/196] Check compiler using CMAKE_CXX_COMPILER_ID Since the introduction of CMAKE_COMPILER_IS_GNUCXX CMake has suggested using CMAKE_CXX_COMPILER_ID for more general checks. --- src/lib_json/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index e22fb1c37..f2377208c 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -1,4 +1,4 @@ -if(CMAKE_COMPILER_IS_GNUCXX) +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") #Get compiler version. execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GNUCXX_VERSION From 8a5e792f206626a102d8e08d8b3a0db68b9876c2 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 31 Dec 2019 20:38:39 -0700 Subject: [PATCH 024/196] Add Clang support, be explicit about MSVC flags --- example/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 51c32182d..017f56030 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -10,9 +10,9 @@ set(EXAMPLES add_definitions(-D_GLIBCXX_USE_CXX11_ABI) set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS}) -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra ") -else() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_definitions( -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS From 9abf11935c02543f6f7481a4aa09305feb1bbb05 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 18 Feb 2020 16:55:45 -0700 Subject: [PATCH 025/196] Remove unused CMake variable EXTRA_CXX_FLAGS is never defined, making this a noop. Further, COMPILE_OPTIONS is invalid to set as a DIRECTORY property. --- example/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 017f56030..2636e88f6 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -8,7 +8,6 @@ set(EXAMPLES streamWrite ) add_definitions(-D_GLIBCXX_USE_CXX11_ABI) -set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS}) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra ") From 524234e479daf2eb406521dcf9eb30d94554c21b Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Mon, 20 Jan 2020 13:21:14 -0700 Subject: [PATCH 026/196] Use non-version checked add_compile_options Commit aebc7fa added version checks for CMake compatibility. In reality, only the add_compile_definitions need the check - add_compile_options itself has been supported since 3.0. Tested and confirmed built successfully with CMake 3.8.0. --- CMakeLists.txt | 60 +++++++------------------------------ example/CMakeLists.txt | 2 +- src/lib_json/CMakeLists.txt | 2 +- 3 files changed, 12 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e636eebc6..bc7553aec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,23 +95,11 @@ macro(use_compilation_warning_as_error) if(MSVC) # Only enabled in debug because some old versions of VS STL generate # warnings when compiled in release configuration. - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options($<$:/WX>) - else() - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") - endif() + add_compile_options($<$:/WX>) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Werror) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - endif() + add_compile_options(-Werror) if(JSONCPP_WITH_STRICT_ISO) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-pedantic-errors) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors") - endif() + add_compile_options(-pedantic-errors) endif() endif() endmacro() @@ -122,57 +110,29 @@ include_directories(${jsoncpp_SOURCE_DIR}/include) if(MSVC) # Only enabled in debug because some old versions of VS STL generate # unreachable code warning when compiled in release configuration. - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options($<$:/W4>) - else() - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ") - endif() + add_compile_options($<$:/W4>) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # using regular Clang or AppleClang - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare") - endif() + add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # using GCC - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wall -Wconversion -Wshadow -Wextra) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra") - endif() + add_compile_options(-Wall -Wconversion -Wshadow -Wextra) # not yet ready for -Wsign-conversion if(JSONCPP_WITH_STRICT_ISO) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wpedantic) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") - endif() + add_compile_options(-Wpedantic) endif() if(JSONCPP_WITH_WARNING_AS_ERROR) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Werror=conversion) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=conversion") - endif() + add_compile_options(-Werror=conversion) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") # using Intel compiler - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra -Werror=conversion") - endif() + add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion) if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_options(-Wpedantic) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") - endif() + add_compile_options(-Wpedantic) endif() endif() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 2636e88f6..d252a5069 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -10,7 +10,7 @@ set(EXAMPLES add_definitions(-D_GLIBCXX_USE_CXX11_ABI) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra ") + add_compile_options(-Wall -Wextra) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_definitions( -D_SCL_SECURE_NO_WARNINGS diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index f2377208c..caa9cc039 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -6,7 +6,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") #-Werror=* was introduced -after- GCC 4.1.2 if(GNUCXX_VERSION VERSION_GREATER 4.1.2) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing") + add_compile_options("-Werror=strict-aliasing") endif() endif() From 3f0d63b5a9487feb2b75f13b05c4930a668da08d Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Tue, 18 Feb 2020 13:56:26 -0700 Subject: [PATCH 027/196] Use internal CMake compiler version directly --- src/lib_json/CMakeLists.txt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index caa9cc039..b3306659b 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -1,13 +1,6 @@ -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - #Get compiler version. - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion - OUTPUT_VARIABLE GNUCXX_VERSION - ) - +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.1.2) #-Werror=* was introduced -after- GCC 4.1.2 - if(GNUCXX_VERSION VERSION_GREATER 4.1.2) - add_compile_options("-Werror=strict-aliasing") - endif() + add_compile_options("-Werror=strict-aliasing") endif() include(CheckIncludeFileCXX) From e9b0b96be677f011d0e9e3d153b25f3274bdb2e0 Mon Sep 17 00:00:00 2001 From: Joel Johnson Date: Wed, 19 Feb 2020 09:14:08 -0700 Subject: [PATCH 028/196] Remove redundant cmake_minimum_required from example This is already covered by the toplevel CMake, which also serves to provide a consistent minimum version. --- example/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index d252a5069..230d1bd7b 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,6 +1,4 @@ #vim: et ts =4 sts = 4 sw = 4 tw = 0 -cmake_minimum_required(VERSION 3.1) - set(EXAMPLES readFromString readFromStream From a4fb5db54389e618a4968a3feb7f20d5ce853232 Mon Sep 17 00:00:00 2001 From: xkszltl Date: Thu, 30 Apr 2020 10:31:54 +0800 Subject: [PATCH 029/196] Put ".exe" and ".dll" together to make test usable in build dir. (#1166) --- CMakeLists.txt | 5 +++++ src/test_lib_json/CMakeLists.txt | 27 ++++++++------------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc7553aec..cd978bb79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,11 @@ option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir.") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir.") +set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.") + set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL") configure_file("${PROJECT_SOURCE_DIR}/version.in" diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt index c9730d0d2..b803db669 100644 --- a/src/test_lib_json/CMakeLists.txt +++ b/src/test_lib_json/CMakeLists.txt @@ -21,28 +21,17 @@ target_link_libraries(jsoncpp_test jsoncpp_lib) # another way to solve issue #90 #set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store) +## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp +add_test(NAME jsoncpp_test + COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ +) +set_target_properties(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test) + # Run unit tests in post-build # (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?) if(JSONCPP_WITH_POST_BUILD_UNITTEST) - if(BUILD_SHARED_LIBS) - # First, copy the shared lib, for Microsoft. - # Then, run the test executable. - add_custom_command(TARGET jsoncpp_test - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ - COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ - ) - else() - # Just run the test executable. - add_custom_command(TARGET jsoncpp_test - POST_BUILD - COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ - ) - endif() - ## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp - add_test(NAME jsoncpp_test + add_custom_command(TARGET jsoncpp_test + POST_BUILD COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ ) endif() - -set_target_properties(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test) From 8b7ea09b8055df01866a5ce4142b12ed8f9f13eb Mon Sep 17 00:00:00 2001 From: Chen <50514813+dota17@users.noreply.github.com> Date: Thu, 30 Apr 2020 17:58:07 +0800 Subject: [PATCH 030/196] Bump soversion to 24 (#1167) --- CMakeLists.txt | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd978bb79..01b8c9d42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ project(JSONCPP LANGUAGES CXX) message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}") -set(JSONCPP_SOVERSION 23) +set(JSONCPP_SOVERSION 24) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) diff --git a/meson.build b/meson.build index 975d56cda..75ec97446 100644 --- a/meson.build +++ b/meson.build @@ -50,7 +50,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 23, + soversion : 24, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) From d2d4c74a03036c18d7171993bfaa6e0bea38e07d Mon Sep 17 00:00:00 2001 From: Chen <50514813+dota17@users.noreply.github.com> Date: Thu, 30 Apr 2020 18:05:17 +0800 Subject: [PATCH 031/196] Update README.md and add dota17 to AUTHORS list. (#1168) * update README * add dota17 to AUTHORS list --- AUTHORS | 1 + README.md | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/AUTHORS b/AUTHORS index 6cddf9796..e1fa0fc3a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,6 +21,7 @@ Braden McDorman Brandon Myers Brendan Drew chason +chenguoping Chris Gilling Christopher Dawes Christopher Dunn diff --git a/README.md b/README.md index b6fc76913..393bb300b 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,14 @@ format to store user input files. * `1.y.z` is built with C++11. * `0.y.z` can be used with older compilers. +* `00.11.z` can be used both in old and new compilers. * Major versions maintain binary-compatibility. +### Special note +The branch `00.11.z`is a new branch, its major version number `00` is to show that it is +different from `0.y.z` and `1.y.z`, the main purpose of this branch is to make a balance +between the other two branches. Thus, users can use some new features in this new branch +that introduced in 1.y.z, but can hardly applied into 0.y.z. ## Using JsonCpp in your project From b8cb8889aab726a35c49472228256f7bb1d44388 Mon Sep 17 00:00:00 2001 From: Edward Brey Date: Thu, 7 May 2020 20:00:12 -0500 Subject: [PATCH 032/196] Added current dir specifier for PowerShell (#1169) The `./` is needed before `vcpkg install jsoncpp` when installing with PowerShell. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 393bb300b..5bff8dca2 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ You can download and install JsonCpp using the [vcpkg](https://github.com/Micros cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install - vcpkg install jsoncpp + ./vcpkg install jsoncpp The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. From e36cff19f098723a45a98f53bba113da3c3781f3 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 12 May 2020 16:19:36 -0700 Subject: [PATCH 033/196] clang-tidy + any_of usage (#1171) * [clang-tidy] change functions to static Found with readability-convert-member-functions-to-static Signed-off-by: Rosen Penev * optimize JsonWriter::validate #1171 * do the same for json_reader Signed-off-by: Rosen Penev * use std::any_of Also simplified two loops. Signed-off-by: Rosen Penev Co-authored-by: Billy Donahue --- src/lib_json/json_reader.cpp | 65 ++++++++++++++++-------------------- src/lib_json/json_writer.cpp | 59 +++++++++++++++----------------- src/test_lib_json/main.cpp | 4 +-- 3 files changed, 56 insertions(+), 72 deletions(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 02a7d54ca..2dca4ca87 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -10,6 +10,7 @@ #include #include #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include #include #include @@ -77,10 +78,7 @@ Features Features::strictMode() { // //////////////////////////////// bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); } // Class Reader @@ -998,10 +996,7 @@ class OurReader { bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); } OurReader::OurReader(OurFeatures const& features) : features_(features) {} @@ -1902,38 +1897,34 @@ CharReader* CharReaderBuilder::newCharReader() const { features.skipBom_ = settings_["skipBom"].asBool(); return new OurCharReader(collectComments, features); } -static void getValidReaderKeys(std::set* valid_keys) { - valid_keys->clear(); - valid_keys->insert("collectComments"); - valid_keys->insert("allowComments"); - valid_keys->insert("allowTrailingCommas"); - valid_keys->insert("strictRoot"); - valid_keys->insert("allowDroppedNullPlaceholders"); - valid_keys->insert("allowNumericKeys"); - valid_keys->insert("allowSingleQuotes"); - valid_keys->insert("stackLimit"); - valid_keys->insert("failIfExtra"); - valid_keys->insert("rejectDupKeys"); - valid_keys->insert("allowSpecialFloats"); - valid_keys->insert("skipBom"); -} + bool CharReaderBuilder::validate(Json::Value* invalid) const { - Json::Value my_invalid; - if (!invalid) - invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidReaderKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - String const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } + static const auto& valid_keys = *new std::set{ + "collectComments", + "allowComments", + "allowTrailingCommas", + "strictRoot", + "allowDroppedNullPlaceholders", + "allowNumericKeys", + "allowSingleQuotes", + "stackLimit", + "failIfExtra", + "rejectDupKeys", + "allowSpecialFloats", + "skipBom", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[std::move(key)] = *si; + else + return false; } - return inv.empty(); + return invalid ? invalid->empty() : true; } + Value& CharReaderBuilder::operator[](const String& key) { return settings_[key]; } diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 56195dc15..cb528b8b6 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -7,7 +7,9 @@ #include "json_tool.h" #include #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include +#include #include #include #include @@ -176,14 +178,9 @@ String valueToString(bool value) { return value ? "true" : "false"; } static bool isAnyCharRequiredQuoting(char const* s, size_t n) { assert(s || !n); - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - if (*cur == '\\' || *cur == '\"' || - static_cast(*cur) < ' ' || - static_cast(*cur) >= 0x80) - return true; - } - return false; + return std::any_of(s, s + n, [](int c) { + return c == '\\' || c == '"' || !std::isprint(c); + }); } static unsigned int utf8ToCodepoint(const char*& s, const char* e) { @@ -1198,34 +1195,30 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const { endingLineFeedSymbol, usf, emitUTF8, pre, precisionType); } -static void getValidWriterKeys(std::set* valid_keys) { - valid_keys->clear(); - valid_keys->insert("indentation"); - valid_keys->insert("commentStyle"); - valid_keys->insert("enableYAMLCompatibility"); - valid_keys->insert("dropNullPlaceholders"); - valid_keys->insert("useSpecialFloats"); - valid_keys->insert("emitUTF8"); - valid_keys->insert("precision"); - valid_keys->insert("precisionType"); -} + bool StreamWriterBuilder::validate(Json::Value* invalid) const { - Json::Value my_invalid; - if (!invalid) - invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidWriterKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - String const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } + static const auto& valid_keys = *new std::set{ + "indentation", + "commentStyle", + "enableYAMLCompatibility", + "dropNullPlaceholders", + "useSpecialFloats", + "emitUTF8", + "precision", + "precisionType", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[std::move(key)] = *si; + else + return false; } - return inv.empty(); + return invalid ? invalid->empty() : true; } + Value& StreamWriterBuilder::operator[](const String& key) { return settings_[key]; } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index e6fe43d79..73850cfd8 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3286,11 +3286,11 @@ struct CharReaderAllowDropNullTest : JsonTest::TestCase { return [=](const Value& root) { JSONTEST_ASSERT_EQUAL(root, v); }; } - ValueCheck objGetAnd(std::string idx, ValueCheck f) { + static ValueCheck objGetAnd(std::string idx, ValueCheck f) { return [=](const Value& root) { f(root.get(idx, true)); }; } - ValueCheck arrGetAnd(int idx, ValueCheck f) { + static ValueCheck arrGetAnd(int idx, ValueCheck f) { return [=](const Value& root) { f(root[idx]); }; } }; From 75b360af4ae3949c003e39d57dad43238e3178c2 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Wed, 13 May 2020 18:37:02 -0400 Subject: [PATCH 034/196] spot fix #1171: isprint argument must be representable as unsigned char (#1173) --- src/lib_json/json_writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index cb528b8b6..56ee65ef6 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -178,7 +178,7 @@ String valueToString(bool value) { return value ? "true" : "false"; } static bool isAnyCharRequiredQuoting(char const* s, size_t n) { assert(s || !n); - return std::any_of(s, s + n, [](int c) { + return std::any_of(s, s + n, [](unsigned char c) { return c == '\\' || c == '"' || !std::isprint(c); }); } From c161f4ac69633deb2ed43bc8569cb9b183f63c32 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Thu, 21 May 2020 11:30:59 -0400 Subject: [PATCH 035/196] Escape control chars even if emitting UTF8 (#1178) * Escape control chars even if emitting UTF8 See #1176 Fixes #1175 * review comments * fix test by stopping early enough to punt on utf8-input. --- src/lib_json/json_writer.cpp | 49 +++++++++++++++------------- src/test_lib_json/main.cpp | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 56ee65ef6..03a777f90 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -262,6 +262,14 @@ static String toHex16Bit(unsigned int x) { return result; } +static void appendRaw(String& result, unsigned ch) { + result += static_cast(ch); +} + +static void appendHex(String& result, unsigned ch) { + result.append("\\u").append(toHex16Bit(ch)); +} + static String valueToQuotedStringN(const char* value, unsigned length, bool emitUTF8 = false) { if (value == nullptr) @@ -310,29 +318,26 @@ static String valueToQuotedStringN(const char* value, unsigned length, // sequence from occurring. default: { if (emitUTF8) { - result += *c; + unsigned codepoint = static_cast(*c); + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else { + appendRaw(result, codepoint); + } } else { - unsigned int codepoint = utf8ToCodepoint(c, end); - const unsigned int FIRST_NON_CONTROL_CODEPOINT = 0x20; - const unsigned int LAST_NON_CONTROL_CODEPOINT = 0x7F; - const unsigned int FIRST_SURROGATE_PAIR_CODEPOINT = 0x10000; - // don't escape non-control characters - // (short escape sequence are applied above) - if (FIRST_NON_CONTROL_CODEPOINT <= codepoint && - codepoint <= LAST_NON_CONTROL_CODEPOINT) { - result += static_cast(codepoint); - } else if (codepoint < - FIRST_SURROGATE_PAIR_CODEPOINT) { // codepoint is in Basic - // Multilingual Plane - result += "\\u"; - result += toHex16Bit(codepoint); - } else { // codepoint is not in Basic Multilingual Plane - // convert to surrogate pair first - codepoint -= FIRST_SURROGATE_PAIR_CODEPOINT; - result += "\\u"; - result += toHex16Bit((codepoint >> 10) + 0xD800); - result += "\\u"; - result += toHex16Bit((codepoint & 0x3FF) + 0xDC00); + unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else if (codepoint < 0x80) { + appendRaw(result, codepoint); + } else if (codepoint < 0x10000) { + // Basic Multilingual Plane + appendHex(result, codepoint); + } else { + // Extended Unicode. Encode 20 bits as a surrogate pair. + codepoint -= 0x10000; + appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); + appendHex(result, 0xdc00 + (codepoint & 0x3ff)); } } } break; diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 73850cfd8..639b5a24e 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -2640,6 +2640,68 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, unicode) { "\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}"); } +// Control chars should be escaped regardless of UTF-8 input encoding. +JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeControlCharacters) { + auto uEscape = [](unsigned ch) { + static const char h[] = "0123456789abcdef"; + std::string r = "\\u"; + r += h[(ch >> (3 * 4)) & 0xf]; + r += h[(ch >> (2 * 4)) & 0xf]; + r += h[(ch >> (1 * 4)) & 0xf]; + r += h[(ch >> (0 * 4)) & 0xf]; + return r; + }; + auto shortEscape = [](unsigned ch) -> const char* { + switch (ch) { + case '\"': + return "\\\""; + case '\\': + return "\\\\"; + case '\b': + return "\\b"; + case '\f': + return "\\f"; + case '\n': + return "\\n"; + case '\r': + return "\\r"; + case '\t': + return "\\t"; + default: + return nullptr; + } + }; + + Json::StreamWriterBuilder b; + + for (bool emitUTF8 : {true, false}) { + b.settings_["emitUTF8"] = emitUTF8; + + for (unsigned i = 0; i != 0x100; ++i) { + if (!emitUTF8 && i >= 0x80) + break; // The algorithm would try to parse UTF-8, so stop here. + + std::string raw({static_cast(i)}); + std::string esc = raw; + if (i < 0x20) + esc = uEscape(i); + if (const char* shEsc = shortEscape(i)) + esc = shEsc; + + // std::cout << "emit=" << emitUTF8 << ", i=" << std::hex << i << std::dec + // << std::endl; + + Json::Value root; + root["test"] = raw; + JSONTEST_ASSERT_STRING_EQUAL( + std::string("{\n\t\"test\" : \"").append(esc).append("\"\n}"), + Json::writeString(b, root)) + << ", emit=" << emitUTF8 << ", i=" << i << ", raw=\"" << raw << "\"" + << ", esc=\"" << esc << "\""; + } + } +} + struct ReaderTest : JsonTest::TestCase { void setStrictMode() { reader = std::unique_ptr( From 6aba23f4a8628d599a9ef7fa4811c4ff6e4070e2 Mon Sep 17 00:00:00 2001 From: kabeer27 <32016558+kabeer27@users.noreply.github.com> Date: Fri, 29 May 2020 19:20:26 +0530 Subject: [PATCH 036/196] Fixes Oss-Fuzz issue: 21916 (#1180) * Fix heap-buffer-overflow in json_reader --- src/lib_json/json_reader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 2dca4ca87..23cbe60e1 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -1270,7 +1270,7 @@ void OurReader::skipSpaces() { void OurReader::skipBom(bool skipBom) { // The default behavior is to skip BOM. if (skipBom) { - if (strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { + if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { begin_ += 3; current_ = begin_; } From 9be589598595963f94ba264d7b416d0533421106 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sat, 30 May 2020 20:20:20 -0700 Subject: [PATCH 037/196] Issue 1182: Fix fuzzing bug (#1183) This patch fixes a fuzzing bug by resolving a bad fallthrough in the setComment logic. The result is that we get a proper error instead of an assert, making the library friendlier to use and less likely to cause issue for consumers. See related Chromium project bug: https://bugs.chromium.org/p/chromium/issues/detail?id=989851 Issue: 1182 --- src/lib_json/json_reader.cpp | 7 +++++-- test/data/fail_invalid_quote.json | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 test/data/fail_invalid_quote.json diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 23cbe60e1..19922a823 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -1175,8 +1175,11 @@ bool OurReader::readToken(Token& token) { if (features_.allowSingleQuotes_) { token.type_ = tokenString; ok = readStringSingleQuote(); - break; - } // else fall through + } else { + // If we don't allow single quotes, this is a failure case. + ok = false; + } + break; case '/': token.type_ = tokenComment; ok = readComment(); diff --git a/test/data/fail_invalid_quote.json b/test/data/fail_invalid_quote.json new file mode 100644 index 000000000..dae27f53f --- /dev/null +++ b/test/data/fail_invalid_quote.json @@ -0,0 +1 @@ +{'//this is bad JSON.'} \ No newline at end of file From b3189a0800e2d6af9c507d149c37a65dec72199d Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Thu, 11 Jun 2020 17:43:44 -0400 Subject: [PATCH 038/196] avoid isprint, because it is locale specific (#1189) * avoid isprint `std::isprint` is locale-specific and the JSON-spec is not. In particular, isprint('\t') is true in Windows CP1252. Has bitten others, e.g. https://github.com/laurikari/tre/issues/64 Fixes #1187 * semicolon (rookie mistake!) --- src/lib_json/json_writer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 03a777f90..8bf02dbdb 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -175,11 +175,11 @@ String valueToString(double value, unsigned int precision, String valueToString(bool value) { return value ? "true" : "false"; } -static bool isAnyCharRequiredQuoting(char const* s, size_t n) { +static bool doesAnyCharRequireEscaping(char const* s, size_t n) { assert(s || !n); return std::any_of(s, s + n, [](unsigned char c) { - return c == '\\' || c == '"' || !std::isprint(c); + return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; }); } @@ -275,7 +275,7 @@ static String valueToQuotedStringN(const char* value, unsigned length, if (value == nullptr) return ""; - if (!isAnyCharRequiredQuoting(value, length)) + if (!doesAnyCharRequireEscaping(value, length)) return String("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to String is not efficient, but this should be rare. From 632044ad956b9ca55703d98d852bc815077f6afc Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Thu, 11 Jun 2020 18:14:03 -0400 Subject: [PATCH 039/196] Billy donahue avoid isprint (#1191) * avoid isprint `std::isprint` is locale-specific and the JSON-spec is not. In particular, isprint('\t') is true in Windows CP1252. Has bitten others, e.g. https://github.com/laurikari/tre/issues/64 Fixes #1187 * semicolon (rookie mistake!) * Windows tab escape testing with custom locale (#1190) Co-authored-by: Nikolay Baklicharov --- src/test_lib_json/main.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 639b5a24e..991c2473d 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -2702,6 +2702,34 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeControlCharacters) { } } +#ifdef _WIN32 +JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeTabCharacterWindows) { + // Get the current locale before changing it + std::string currentLocale = setlocale(LC_ALL, NULL); + setlocale(LC_ALL, "English_United States.1252"); + + Json::Value root; + root["test"] = "\tTabTesting\t"; + + Json::StreamWriterBuilder b; + + JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : " + "\"\\tTabTesting\\t\"\n}"); + + b.settings_["emitUTF8"] = true; + JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : " + "\"\\tTabTesting\\t\"\n}"); + + b.settings_["emitUTF8"] = false; + JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : " + "\"\\tTabTesting\\t\"\n}"); + + // Restore the locale + if (!currentLocale.empty()) + setlocale(LC_ALL, currentLocale.c_str()); +} +#endif + struct ReaderTest : JsonTest::TestCase { void setStrictMode() { reader = std::unique_ptr( From c8453d39d1d98ddafd15267d9d55223cdc48f2b1 Mon Sep 17 00:00:00 2001 From: nathanruiz Date: Wed, 24 Jun 2020 07:52:28 +1000 Subject: [PATCH 040/196] Delete nullptr Json::Value constructor (#1194) This patch adds an explicit ctor with a std::nullptr_t argument, that is `delete`-d. This keeps Json::Value from exposing a coding error when automatically promoted to a const char* type. --- include/json/value.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/json/value.h b/include/json/value.h index dffc51a85..df1eba6ac 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -342,6 +342,7 @@ class JSON_API Value { Value(const StaticString& value); Value(const String& value); Value(bool value); + Value(std::nullptr_t ptr) = delete; Value(const Value& other); Value(Value&& other); ~Value(); From cfc1ad72ad7e0a6d625686182bce1aefa118b308 Mon Sep 17 00:00:00 2001 From: Chen Date: Mon, 13 Jul 2020 20:33:58 +0800 Subject: [PATCH 041/196] Enhance cmake script (#1197) * BUILD_TYPE corresponds to Release/Debug but LIB_TYPE corresponds to shared/static. * Add support to build shared, static and object lib at the same time. --- .travis_scripts/cmake_builder.sh | 2 +- CMakeLists.txt | 12 +-- src/jsontestrunner/CMakeLists.txt | 4 +- src/lib_json/CMakeLists.txt | 132 ++++++++++++++++++++++-------- src/test_lib_json/CMakeLists.txt | 4 +- 5 files changed, 114 insertions(+), 40 deletions(-) diff --git a/.travis_scripts/cmake_builder.sh b/.travis_scripts/cmake_builder.sh index ccb33312e..f3d4e46b6 100755 --- a/.travis_scripts/cmake_builder.sh +++ b/.travis_scripts/cmake_builder.sh @@ -66,7 +66,7 @@ cmake --version echo ${CXX} ${CXX} --version _COMPILER_NAME=`basename ${CXX}` -if [ "${BUILD_TYPE}" == "shared" ]; then +if [ "${LIB_TYPE}" = "shared" ]; then _CMAKE_BUILD_SHARED_LIBS=ON else _CMAKE_BUILD_SHARED_LIBS=OFF diff --git a/CMakeLists.txt b/CMakeLists.txt index 01b8c9d42..b8d53a63d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,19 +59,19 @@ if(CCACHE_EXECUTABLE) set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) endif() -project(JSONCPP +project(jsoncpp # Note: version must be updated in three places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the # correct version. # 1. ./meson.build # 2. ./include/json/version.h # 3. ./CMakeLists.txt - # IMPORTANT: also update the JSONCPP_SOVERSION!! + # IMPORTANT: also update the PROJECT_SOVERSION!! VERSION 1.9.3 # [.[.[.]]] LANGUAGES CXX) -message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}") -set(JSONCPP_SOVERSION 24) +message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") +set(PROJECT_SOVERSION 24) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) @@ -80,7 +80,9 @@ option(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C option(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON) option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON) option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF) -option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) +option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." ON) +option(BUILD_STATIC_LIBS "Build jsoncpp_lib as a static library." ON) +option(BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON) # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) diff --git a/src/jsontestrunner/CMakeLists.txt b/src/jsontestrunner/CMakeLists.txt index d24aa6f46..1fc71ea87 100644 --- a/src/jsontestrunner/CMakeLists.txt +++ b/src/jsontestrunner/CMakeLists.txt @@ -19,8 +19,10 @@ if(BUILD_SHARED_LIBS) else() add_definitions(-DJSON_DLL) endif() + target_link_libraries(jsontestrunner_exe jsoncpp_lib) +else() + target_link_libraries(jsontestrunner_exe jsoncpp_static) endif() -target_link_libraries(jsontestrunner_exe jsoncpp_lib) set_target_properties(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index b3306659b..cea92efe8 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -50,7 +50,7 @@ set(PUBLIC_HEADERS source_group("Public API" FILES ${PUBLIC_HEADERS}) -set(jsoncpp_sources +set(JSONCPP_SOURCES json_tool.h json_reader.cpp json_valueiterator.inl @@ -65,32 +65,10 @@ else() set(INSTALL_EXPORT) endif() - -if(BUILD_SHARED_LIBS) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions(JSON_DLL_BUILD) - else() - add_definitions(-DJSON_DLL_BUILD) - endif() -endif() - -add_library(jsoncpp_lib ${PUBLIC_HEADERS} ${jsoncpp_sources}) -set_target_properties( jsoncpp_lib PROPERTIES - OUTPUT_NAME jsoncpp - VERSION ${JSONCPP_VERSION} - SOVERSION ${JSONCPP_SOVERSION} - POSITION_INDEPENDENT_CODE ON -) - -# Set library's runtime search path on OSX -if(APPLE) - set_target_properties(jsoncpp_lib PROPERTIES INSTALL_RPATH "@loader_path/.") -endif() - # Specify compiler features required when compiling a given target. # See https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES # for complete list of features available -target_compile_features(jsoncpp_lib PUBLIC +list(APPEND REQUIRED_FEATURES cxx_std_11 # Compiler mode is aware of C++ 11. #MSVC 1900 cxx_alignas # Alignment control alignas, as defined in N2341. #MSVC 1900 cxx_alignof # Alignment control alignof, as defined in N2341. @@ -137,16 +115,106 @@ target_compile_features(jsoncpp_lib PUBLIC cxx_variadic_templates # Variadic templates, as defined in N2242. ) -install(TARGETS jsoncpp_lib ${INSTALL_EXPORT} + +if(BUILD_SHARED_LIBS) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_definitions(JSON_DLL_BUILD) + else() + add_definitions(-DJSON_DLL_BUILD) + endif() + + set(SHARED_LIB ${PROJECT_NAME}_lib) + add_library(${SHARED_LIB} SHARED ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) + set_target_properties(${SHARED_LIB} PROPERTIES + OUTPUT_NAME jsoncpp + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + POSITION_INDEPENDENT_CODE ON + ) + + # Set library's runtime search path on OSX + if(APPLE) + set_target_properties(${SHARED_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") + endif() + + target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) + + if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + target_include_directories(${SHARED_LIB} PUBLIC + $ + $ + $ + ) + endif() + + list(APPEND CMAKE_TARGETS ${SHARED_LIB}) +endif() + +if(BUILD_STATIC_LIBS) + set(STATIC_LIB ${PROJECT_NAME}_static) + add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) + + # avoid name clashes on windows as the shared import lib is alse named jsoncpp.lib + if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) + set(STATIC_SUFFIX "_static") + endif() + + set_target_properties(${STATIC_LIB} PROPERTIES + OUTPUT_NAME jsoncpp${STATIC_SUFFIX} + VERSION ${PROJECT_VERSION} + ) + + # Set library's runtime search path on OSX + if(APPLE) + set_target_properties(${STATIC_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") + endif() + + target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) + + if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + target_include_directories(${STATIC_LIB} PUBLIC + $ + $ + $ + ) + endif() + + list(APPEND CMAKE_TARGETS ${STATIC_LIB}) +endif() + +if(BUILD_OBJECT_LIBS) + set(OBJECT_LIB ${PROJECT_NAME}_object) + add_library(${OBJECT_LIB} OBJECT ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) + + set_target_properties(${OBJECT_LIB} PROPERTIES + OUTPUT_NAME jsoncpp + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + POSITION_INDEPENDENT_CODE ON + ) + + # Set library's runtime search path on OSX + if(APPLE) + set_target_properties(${OBJECT_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") + endif() + + target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) + + if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + target_include_directories(${OBJECT_LIB} PUBLIC + $ + $ + $ + ) + endif() + + list(APPEND CMAKE_TARGETS ${OBJECT_LIB}) +endif() + +install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories(jsoncpp_lib PUBLIC - $ - $ - $ - ) -endif() diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt index b803db669..1c3fce913 100644 --- a/src/test_lib_json/CMakeLists.txt +++ b/src/test_lib_json/CMakeLists.txt @@ -15,8 +15,10 @@ if(BUILD_SHARED_LIBS) else() add_definitions( -DJSON_DLL ) endif() + target_link_libraries(jsoncpp_test jsoncpp_lib) +else() + target_link_libraries(jsoncpp_test jsoncpp_static) endif() -target_link_libraries(jsoncpp_test jsoncpp_lib) # another way to solve issue #90 #set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store) From bf0cfa5b46263b202aceb4d4e2fd000e87d4c96f Mon Sep 17 00:00:00 2001 From: Chen Date: Tue, 14 Jul 2020 16:37:22 +0800 Subject: [PATCH 042/196] hot fix for building static lib (#1203) Fix #1197 --- src/lib_json/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index cea92efe8..af2647652 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -169,7 +169,7 @@ if(BUILD_STATIC_LIBS) set_target_properties(${STATIC_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") endif() - target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) + target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) target_include_directories(${STATIC_LIB} PUBLIC From 5be07bdc5e2d5b7715ecbc73749af3e625674dcb Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Mon, 20 Jul 2020 08:36:30 -0400 Subject: [PATCH 043/196] Fix generation of pkg-config file with absolute includedir/libdir. (#1199) --- .gitignore | 1 - CMakeLists.txt | 7 +++++++ cmake/JoinPaths.cmake | 23 +++++++++++++++++++++++ pkg-config/jsoncpp.pc.in | 4 ++-- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 cmake/JoinPaths.cmake diff --git a/.gitignore b/.gitignore index 91121c230..68f40b06e 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,6 @@ # CMake-generated files: CMakeFiles/ -*.cmake /pkg-config/jsoncpp.pc jsoncpp_lib_static.dir/ diff --git a/CMakeLists.txt b/CMakeLists.txt index b8d53a63d..96d3c9e43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") endif() +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + # --------------------------------------------------------------------------- # use ccache if found, has to be done before project() # --------------------------------------------------------------------------- @@ -148,6 +150,11 @@ if(JSONCPP_WITH_WARNING_AS_ERROR) endif() if(JSONCPP_WITH_PKGCONFIG_SUPPORT) + include(JoinPaths) + + join_paths(libdir_for_pc_file "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}") + join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") + configure_file( "pkg-config/jsoncpp.pc.in" "pkg-config/jsoncpp.pc" diff --git a/cmake/JoinPaths.cmake b/cmake/JoinPaths.cmake new file mode 100644 index 000000000..2b376b733 --- /dev/null +++ b/cmake/JoinPaths.cmake @@ -0,0 +1,23 @@ +# This module provides a function for joining paths +# known from most languages +# +# SPDX-License-Identifier: (MIT OR CC0-1.0) +# Copyright 2020 Jan Tojnar +# https://github.com/jtojnar/cmake-snips +# +# Modelled after Python’s os.path.join +# https://docs.python.org/3.7/library/os.path.html#os.path.join +# Windows not supported +function(join_paths joined_path first_path_segment) + set(temp_path "${first_path_segment}") + foreach(current_segment IN LISTS ARGN) + if(NOT ("${current_segment}" STREQUAL "")) + if(IS_ABSOLUTE "${current_segment}") + set(temp_path "${current_segment}") + else() + set(temp_path "${temp_path}/${current_segment}") + endif() + endif() + endforeach() + set(${joined_path} "${temp_path}" PARENT_SCOPE) +endfunction() diff --git a/pkg-config/jsoncpp.pc.in b/pkg-config/jsoncpp.pc.in index d4fa9ef26..632a377f5 100644 --- a/pkg-config/jsoncpp.pc.in +++ b/pkg-config/jsoncpp.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +libdir=@libdir_for_pc_file@ +includedir=@includedir_for_pc_file@ Name: jsoncpp Description: A C++ library for interacting with JSON From 45733df96cde1af55145909ce5f1c910df98a9be Mon Sep 17 00:00:00 2001 From: Daniel Engberg Date: Wed, 3 Jun 2020 12:19:51 +0200 Subject: [PATCH 044/196] meson: Don't specifically look for python3 Not all distributions provide Python as python3 and as Meson already depends on 3.5+ just use what Meson uses. References: https://mesonbuild.com/Getting-meson.html https://mesonbuild.com/Python-module.html#find_installation Signed-off-by: Daniel Engberg --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 75ec97446..5191d23b5 100644 --- a/meson.build +++ b/meson.build @@ -73,7 +73,7 @@ if meson.is_subproject() or not get_option('tests') subdir_done() endif -python = import('python').find_installation('python3') +python = import('python').find_installation() jsoncpp_test = executable( 'jsoncpp_test', files([ From 9059f5cad030ba11d37818847443a53918c327b1 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Fri, 25 Sep 2020 19:19:16 -0700 Subject: [PATCH 045/196] Roll version numbers for 1.9.4 release (#1223) --- CMakeLists.txt | 2 +- include/json/version.h | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96d3c9e43..51b74fcc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ project(jsoncpp # 2. ./include/json/version.h # 3. ./CMakeLists.txt # IMPORTANT: also update the PROJECT_SOVERSION!! - VERSION 1.9.3 # [.[.[.]]] + VERSION 1.9.4 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/include/json/version.h b/include/json/version.h index 0f2983411..5b9783d96 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -9,7 +9,7 @@ // 3. /CMakeLists.txt // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "1.9.3" +#define JSONCPP_VERSION_STRING "1.9.4" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 #define JSONCPP_VERSION_PATCH 3 diff --git a/meson.build b/meson.build index 5191d23b5..08e0f299e 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - version : '1.9.3', + version : '1.9.4', default_options : [ 'buildtype=release', 'cpp_std=c++11', From 72db27698627d8358ba745ee7f919ad6eeaec772 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 1 Oct 2020 12:21:48 -0400 Subject: [PATCH 046/196] version.h: fix the version number in the header Fixes: #1224 --- include/json/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/json/version.h b/include/json/version.h index 5b9783d96..87cf7e2fb 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -12,7 +12,7 @@ #define JSONCPP_VERSION_STRING "1.9.4" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 3 +#define JSONCPP_VERSION_PATCH 4 #define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ From c60ebf787aaef3c1cf8d58be01d0d3d508e04255 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 1 Oct 2020 12:22:04 -0400 Subject: [PATCH 047/196] test: ensure the version numbers agree --- src/test_lib_json/main.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 991c2473d..540e66bf4 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3916,6 +3916,16 @@ JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) { } } +class VersionTest : public JsonTest::TestCase {}; + +JSONTEST_FIXTURE_LOCAL(VersionTest, VersionNumbersMatch) { + std::ostringstream vstr; + vstr << JSONCPP_VERSION_MAJOR << '.' + << JSONCPP_VERSION_MINOR << '.' + << JSONCPP_VERSION_PATCH; + JSONTEST_ASSERT_EQUAL(vstr.str(), std::string(JSONCPP_VERSION_STRING)); +} + #if defined(__GNUC__) #pragma GCC diagnostic pop #endif From 5d1cb30e40210ec382db41922f25b254ab6e6d31 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sat, 10 Oct 2020 10:29:19 -0500 Subject: [PATCH 048/196] clang-format --- .travis_scripts/run-clang-format.py | 2 +- reformat.sh | 1 + src/test_lib_json/main.cpp | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 reformat.sh diff --git a/.travis_scripts/run-clang-format.py b/.travis_scripts/run-clang-format.py index 68179aafd..605b5aad1 100755 --- a/.travis_scripts/run-clang-format.py +++ b/.travis_scripts/run-clang-format.py @@ -353,4 +353,4 @@ def main(): if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/reformat.sh b/reformat.sh new file mode 100644 index 000000000..cdc03b1ea --- /dev/null +++ b/reformat.sh @@ -0,0 +1 @@ +find src -name '*.cpp' -or -name '*.h' | xargs clang-format -i diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 540e66bf4..f29692396 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3920,8 +3920,7 @@ class VersionTest : public JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(VersionTest, VersionNumbersMatch) { std::ostringstream vstr; - vstr << JSONCPP_VERSION_MAJOR << '.' - << JSONCPP_VERSION_MINOR << '.' + vstr << JSONCPP_VERSION_MAJOR << '.' << JSONCPP_VERSION_MINOR << '.' << JSONCPP_VERSION_PATCH; JSONTEST_ASSERT_EQUAL(vstr.str(), std::string(JSONCPP_VERSION_STRING)); } From 1664b6bbf848ef13b330ced6f0c7ba63d70805d5 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sat, 10 Oct 2020 09:06:43 -0500 Subject: [PATCH 049/196] Try meson/ninja from pypi This lets us simplify linux a little. However, we still want to test cmake, so there is only so much we can simplify. For OSX, we still need `clang-format` from homebrew. * Add PYTHONUSERBASE/bin to PATH for linux --- .travis.yml | 2 ++ .travis_scripts/travis.before_install.osx.sh | 1 - .travis_scripts/travis.install.linux.sh | 11 +++-------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0554dc93b..1e1e1793f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,8 @@ matrix: CC="clang" LIB_TYPE=static BUILD_TYPE=release + PYTHONUSERBASE="$(pwd)/LOCAL" + PATH="$PYTHONUSERBASE/bin:$PATH" # before_install and install steps only needed for linux meson builds before_install: - source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh diff --git a/.travis_scripts/travis.before_install.osx.sh b/.travis_scripts/travis.before_install.osx.sh index 5d83c0c71..e69de29bb 100644 --- a/.travis_scripts/travis.before_install.osx.sh +++ b/.travis_scripts/travis.before_install.osx.sh @@ -1 +0,0 @@ -# NOTHING TO DO HERE diff --git a/.travis_scripts/travis.install.linux.sh b/.travis_scripts/travis.install.linux.sh index 7c5846f1a..6495fefe9 100644 --- a/.travis_scripts/travis.install.linux.sh +++ b/.travis_scripts/travis.install.linux.sh @@ -1,10 +1,5 @@ set -vex -wget https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-linux.zip -unzip -q ninja-linux.zip -d build - -pip3 install meson -echo ${PATH} -ls /usr/local -ls /usr/local/bin -export PATH="${PWD}"/build:/usr/local/bin:/usr/bin:${PATH} +pip3 install --user meson ninja +which meson +which ninja From bb9db78fe27591afacd0df7a9b6b69bdfeec20ea Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sat, 10 Oct 2020 11:20:19 -0500 Subject: [PATCH 050/196] Do not allow failures on osx --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e1e1793f..6d7ccde74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,6 @@ addons: - clang-8 - valgrind matrix: - allow_failures: - - os: osx include: - name: Mac clang meson static release testing os: osx From 30170d651c108400b1b9ed626ba715a5d95c5fd2 Mon Sep 17 00:00:00 2001 From: Christian Ledergerber Date: Tue, 13 Oct 2020 17:55:58 +0200 Subject: [PATCH 051/196] Fix c++20 compilation problem for clang10 and fix potential bug due to compiler optimization --- include/json/allocator.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/json/allocator.h b/include/json/allocator.h index 0f5c224b9..95ef8a5ec 100644 --- a/include/json/allocator.h +++ b/include/json/allocator.h @@ -35,11 +35,10 @@ template class SecureAllocator { * Release memory which was allocated for N items at pointer P. * * The memory block is filled with zeroes before being released. - * The pointer argument is tagged as "volatile" to prevent the - * compiler optimizing out this critical step. */ - void deallocate(volatile pointer p, size_type n) { - std::memset(p, 0, n * sizeof(T)); + void deallocate(pointer p, size_type n) { + // memset_s is used because memset may be optimized away by the compiler + memset_s(p, n * sizeof(T), 0, n * sizeof(T)); // free using "global operator delete" ::operator delete(p); } From ceae0e3867fe16e1227b4a39fe6951ee005591dc Mon Sep 17 00:00:00 2001 From: Marcel Opprecht Date: Fri, 6 Nov 2020 22:22:26 +0100 Subject: [PATCH 052/196] Fix clang-tidy warnings (#1231) * Fix clang-tidy warnings Signed-off-by: Marcel Opprecht * Fixup/clang-format Co-authored-by: Marcel Opprecht Co-authored-by: Jordan Bayles --- CONTRIBUTING.md | 4 +++- include/json/value.h | 12 ++++++------ reformat.sh | 0 src/lib_json/json_reader.cpp | 2 +- src/lib_json/json_value.cpp | 13 +++++++------ src/lib_json/json_writer.cpp | 2 +- 6 files changed, 18 insertions(+), 15 deletions(-) mode change 100644 => 100755 reformat.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c9fc6a04..d72fe9708 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -143,7 +143,9 @@ bool Reader::decodeNumber(Token& token) { ``` Before submitting your code, ensure that you meet the versioning requirements above, follow the style guide of the file you are modifying (or the above rules for new files), and run clang format. Meson exposes clang format with the following command: - ``` ninja -v -C build-${LIB_TYPE}/ clang-format ``` + +For convenience, you can also run the `reformat.sh` script located in the root directory. + diff --git a/include/json/value.h b/include/json/value.h index df1eba6ac..ec9af5666 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -263,10 +263,10 @@ class JSON_API Value { CZString(ArrayIndex index); CZString(char const* str, unsigned length, DuplicationPolicy allocate); CZString(CZString const& other); - CZString(CZString&& other); + CZString(CZString&& other) noexcept; ~CZString(); CZString& operator=(const CZString& other); - CZString& operator=(CZString&& other); + CZString& operator=(CZString&& other) noexcept; bool operator<(CZString const& other) const; bool operator==(CZString const& other) const; @@ -344,13 +344,13 @@ class JSON_API Value { Value(bool value); Value(std::nullptr_t ptr) = delete; Value(const Value& other); - Value(Value&& other); + Value(Value&& other) noexcept; ~Value(); /// \note Overwrite existing comments. To preserve comments, use /// #swapPayload(). Value& operator=(const Value& other); - Value& operator=(Value&& other); + Value& operator=(Value&& other) noexcept; /// Swap everything. void swap(Value& other); @@ -635,9 +635,9 @@ class JSON_API Value { public: Comments() = default; Comments(const Comments& that); - Comments(Comments&& that); + Comments(Comments&& that) noexcept; Comments& operator=(const Comments& that); - Comments& operator=(Comments&& that); + Comments& operator=(Comments&& that) noexcept; bool has(CommentPlacement slot) const; String get(CommentPlacement slot) const; void set(CommentPlacement slot, String comment); diff --git a/reformat.sh b/reformat.sh old mode 100644 new mode 100755 diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 19922a823..a34017d99 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -1921,7 +1921,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const { if (valid_keys.count(key)) continue; if (invalid) - (*invalid)[std::move(key)] = *si; + (*invalid)[key] = *si; else return false; } diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 0872ff548..bfa9263fd 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -259,7 +259,7 @@ Value::CZString::CZString(const CZString& other) { storage_.length_ = other.storage_.length_; } -Value::CZString::CZString(CZString&& other) +Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_), index_(other.index_) { other.cstr_ = nullptr; } @@ -285,7 +285,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) { return *this; } -Value::CZString& Value::CZString::operator=(CZString&& other) { +Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { cstr_ = other.cstr_; index_ = other.index_; other.cstr_ = nullptr; @@ -433,7 +433,7 @@ Value::Value(const Value& other) { dupMeta(other); } -Value::Value(Value&& other) { +Value::Value(Value&& other) noexcept { initBasic(nullValue); swap(other); } @@ -448,7 +448,7 @@ Value& Value::operator=(const Value& other) { return *this; } -Value& Value::operator=(Value&& other) { +Value& Value::operator=(Value&& other) noexcept { other.swap(*this); return *this; } @@ -1373,14 +1373,15 @@ bool Value::isObject() const { return type() == objectValue; } Value::Comments::Comments(const Comments& that) : ptr_{cloneUnique(that.ptr_)} {} -Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {} +Value::Comments::Comments(Comments&& that) noexcept + : ptr_{std::move(that.ptr_)} {} Value::Comments& Value::Comments::operator=(const Comments& that) { ptr_ = cloneUnique(that.ptr_); return *this; } -Value::Comments& Value::Comments::operator=(Comments&& that) { +Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { ptr_ = std::move(that.ptr_); return *this; } diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 8bf02dbdb..c9ae416fc 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -1217,7 +1217,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const { if (valid_keys.count(key)) continue; if (invalid) - (*invalid)[std::move(key)] = *si; + (*invalid)[key] = *si; else return false; } From 8954092f0af9538f3cde47aceb459dbe4d6e2241 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Fri, 6 Nov 2020 15:35:51 -0600 Subject: [PATCH 053/196] ENH: Prevent cmake in source builds (#1091) * ENH: Prevent cmake in source builds Building directly inside the root of the source tree can cause problems where the build intermediate files overwrite or conflict with the intended source code files. This modification identifies this problem and issues failure messages and suggestions to over come the problem with more robust build suggestion. Co-authored-by: Jordan Bayles --- CMakeLists.txt | 3 ++ CONTRIBUTING.md | 3 +- appveyor.yml | 11 +++++-- include/PreventInBuildInstalls.cmake | 9 ++++++ include/PreventInSourceBuilds.cmake | 45 ++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 include/PreventInBuildInstalls.cmake create mode 100644 include/PreventInSourceBuilds.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 51b74fcc9..f1db5e318 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,9 @@ project(jsoncpp message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") set(PROJECT_SOVERSION 24) +include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) + option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) option(JSONCPP_WITH_WARNING_AS_ERROR "Force compilation to fail if a warning occurs" OFF) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d72fe9708..8d992bee7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ If you wish to install to a directory other than /usr/local, set an environment DESTDIR=/path/to/install/dir Then, - +```sh cd jsoncpp/ BUILD_TYPE=debug #BUILD_TYPE=release @@ -35,6 +35,7 @@ Then, #meson test --no-rebuild --print-errorlogs sudo ninja install +``` ## Building and testing with other build systems See https://github.com/open-source-parsers/jsoncpp/wiki/Building diff --git a/appveyor.yml b/appveyor.yml index 0b9c8fe3f..cccce4298 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,7 @@ clone_folder: c:\projects\jsoncpp environment: + matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 CMAKE_GENERATOR: Visual Studio 14 2015 @@ -13,11 +14,15 @@ environment: build_script: - cmake --version - - cd c:\projects\jsoncpp - - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON . + # The build script starts in root. + - set JSONCPP_FOLDER=%cd% + - set JSONCPP_BUILD_FOLDER=%JSONCPP_FOLDER%\build\release + - mkdir -p %JSONCPP_BUILD_FOLDER% + - cd %JSONCPP_BUILD_FOLDER% + - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON %JSONCPP_FOLDER% # Use ctest to make a dashboard build: # - ctest -D Experimental(Start|Update|Configure|Build|Test|Coverage|MemCheck|Submit) - # NOTE: Testing on window is not yet finished: + # NOTE: Testing on windows is not yet finished: # - ctest -C Release -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild -D ExperimentalTest -D ExperimentalSubmit - ctest -C Release -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild -D ExperimentalSubmit # Final step is to verify that installation succeeds diff --git a/include/PreventInBuildInstalls.cmake b/include/PreventInBuildInstalls.cmake new file mode 100644 index 000000000..accfea64c --- /dev/null +++ b/include/PreventInBuildInstalls.cmake @@ -0,0 +1,9 @@ +string(TOLOWER "${CMAKE_INSTALL_PREFIX}" _PREFIX) +string(TOLOWER "${ITK_BINARY_DIR}" _BUILD) +if("${_PREFIX}" STREQUAL "${_BUILD}") + message(FATAL_ERROR + "The current CMAKE_INSTALL_PREFIX points at the build tree:\n" + " ${CMAKE_INSTALL_PREFIX}\n" + "This is not supported." + ) +endif() diff --git a/include/PreventInSourceBuilds.cmake b/include/PreventInSourceBuilds.cmake new file mode 100644 index 000000000..7ddda546a --- /dev/null +++ b/include/PreventInSourceBuilds.cmake @@ -0,0 +1,45 @@ +# +# This function will prevent in-source builds +function(AssureOutOfSourceBuilds) + # make sure the user doesn't play dirty with symlinks + get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + + # disallow in-source builds + if("${srcdir}" STREQUAL "${bindir}") + message("######################################################") + message("# jsoncpp should not be configured & built in the jsoncpp source directory") + message("# You must run cmake in a build directory.") + message("# For example:") + message("# mkdir jsoncpp-Sandbox ; cd jsoncpp-sandbox") + message("# git clone https://github.com/open-source-parsers/jsoncpp.git # or download & unpack the source tarball") + message("# mkdir jsoncpp-build") + message("# this will create the following directory structure") + message("#") + message("# jsoncpp-Sandbox") + message("# +--jsoncpp") + message("# +--jsoncpp-build") + message("#") + message("# Then you can proceed to configure and build") + message("# by using the following commands") + message("#") + message("# cd jsoncpp-build") + message("# cmake ../jsoncpp # or ccmake, or cmake-gui ") + message("# make") + message("#") + message("# NOTE: Given that you already tried to make an in-source build") + message("# CMake have already created several files & directories") + message("# in your source tree. run 'git status' to find them and") + message("# remove them by doing:") + message("#") + message("# cd jsoncpp-Sandbox/jsoncpp") + message("# git clean -n -d") + message("# git clean -f -d") + message("# git checkout --") + message("#") + message("######################################################") + message(FATAL_ERROR "Quitting configuration") + endif() +endfunction() + +AssureOutOfSourceBuilds() From 940982438d01fe2575acef8dd98a9b6893ccc9bb Mon Sep 17 00:00:00 2001 From: Lei Date: Wed, 16 Dec 2020 03:08:05 +0800 Subject: [PATCH 054/196] =?UTF-8?q?Fix=20a=20precision=20bug=20of=20valueT?= =?UTF-8?q?oString,=20prevent=20to=20give=20an=20error=20result=E2=80=A6?= =?UTF-8?q?=20(#1246)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix a precision bug of valueToString, prevent to give an error result on input of wanted precision 0 and a double value which end of zero before decimal point ,such as 1230.01,12300.1; Add test cases for double valueToString with precision 0; * Delete a test case with platform differences in the previous commit * Fix clang-format. * Fix clang-format! Co-authored-by: lilei --- .gitignore | 2 ++ src/lib_json/json_tool.h | 10 +++++++--- src/lib_json/json_writer.cpp | 12 +++++++----- src/test_lib_json/main.cpp | 28 ++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 68f40b06e..2444e6a68 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /libs/ /doc/doxyfile /dist/ +/.cache/ # MSVC project files: *.sln @@ -30,6 +31,7 @@ CMakeFiles/ /pkg-config/jsoncpp.pc jsoncpp_lib_static.dir/ +compile_commands.json # In case someone runs cmake in the root-dir: /CMakeCache.txt diff --git a/src/lib_json/json_tool.h b/src/lib_json/json_tool.h index 2d7b7d9a0..b952c1916 100644 --- a/src/lib_json/json_tool.h +++ b/src/lib_json/json_tool.h @@ -116,14 +116,18 @@ template void fixNumericLocaleInput(Iter begin, Iter end) { * Return iterator that would be the new end of the range [begin,end), if we * were to delete zeros in the end of string, but not the last zero before '.'. */ -template Iter fixZerosInTheEnd(Iter begin, Iter end) { +template +Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) { for (; begin != end; --end) { if (*(end - 1) != '0') { return end; } // Don't delete the last zero before the decimal point. - if (begin != (end - 1) && *(end - 2) == '.') { - return end; + if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') { + if (precision) { + return end; + } + return end - 2; } } return end; diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index c9ae416fc..18e7a42cb 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -154,16 +154,18 @@ String valueToString(double value, bool useSpecialFloats, buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); - // strip the zero padding from the right - if (precisionType == PrecisionType::decimalPlaces) { - buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); - } - // try to ensure we preserve the fact that this was given to us as a double on // input if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { buffer += ".0"; } + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision), + buffer.end()); + } + return buffer; } } // namespace diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index f29692396..be9c4a73d 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -2005,6 +2005,34 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, precision) { result = Json::writeString(b, v); JSONTEST_ASSERT_STRING_EQUAL(expected, result); + b.settings_["precision"] = 0; + b.settings_["precisionType"] = "decimal"; + v = 123.56345694873740545068; + expected = "124"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 1; + b.settings_["precisionType"] = "decimal"; + v = 1230.001; + expected = "1230.0"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 0; + b.settings_["precisionType"] = "decimal"; + v = 1230.001; + expected = "1230"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 0; + b.settings_["precisionType"] = "decimal"; + v = 1231.5; + expected = "1232"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + b.settings_["precision"] = 10; b.settings_["precisionType"] = "decimal"; v = 0.23300000; From be4a512887e350adc8b1ae19bc2cb81d15c8846f Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sat, 9 Jan 2021 22:39:07 -0600 Subject: [PATCH 055/196] Remove trailing space characters (#1256) Also add two newlines (rebased from `aaronfranke/formatting`) resolves #1220 Co-authored-by: Aaron Franke --- .clang-tidy | 2 +- .travis_scripts/run-clang-format.sh | 2 +- LICENSE | 14 ++++++------ devtools/antglob.py | 2 +- devtools/fixeol.py | 4 ++-- devtools/licenseupdater.py | 4 ++-- doxybuild.py | 4 ++-- example/README.md | 4 ++-- test/data/legacy_test_array_06.json | 2 +- test/data/legacy_test_complex_01.json | 22 +++++++++---------- test/data/legacy_test_object_03.json | 2 +- test/data/legacy_test_object_04.json | 2 +- .../legacy_test_preserve_comment_01.expected | 2 +- .../data/legacy_test_preserve_comment_01.json | 2 +- test/pyjsontestrunner.py | 8 +++---- 15 files changed, 38 insertions(+), 38 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index be3d06a52..99e914df9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,7 +4,7 @@ WarningsAsErrors: '' HeaderFilterRegex: '' AnalyzeTemporaryDtors: false FormatStyle: none -CheckOptions: +CheckOptions: - key: modernize-use-using.IgnoreMacros value: '0' ... diff --git a/.travis_scripts/run-clang-format.sh b/.travis_scripts/run-clang-format.sh index 91972840d..ded76aaf5 100755 --- a/.travis_scripts/run-clang-format.sh +++ b/.travis_scripts/run-clang-format.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -python $DIR/run-clang-format.py -r $DIR/../src/**/ $DIR/../include/**/ \ No newline at end of file +python $DIR/run-clang-format.py -r $DIR/../src/**/ $DIR/../include/**/ diff --git a/LICENSE b/LICENSE index 89280a6c4..c41a1d1c7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,25 +1,25 @@ -The JsonCpp library's source code, including accompanying documentation, +The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and The JsonCpp Authors, and is released under the terms of the MIT License (see below). -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License - + The full text of the MIT License follows: ======================================================================== diff --git a/devtools/antglob.py b/devtools/antglob.py index 98437658c..bd2d7aee9 100644 --- a/devtools/antglob.py +++ b/devtools/antglob.py @@ -146,7 +146,7 @@ def glob_impl(root_dir_path): entry_type = is_file and FILE_LINK or DIR_LINK else: entry_type = is_file and FILE or DIR -## print '=> type: %d' % entry_type, +## print '=> type: %d' % entry_type, if (entry_type & entry_type_filter) != 0: ## print ' => KEEP' yield os.path.join(dir_path, entry) diff --git a/devtools/fixeol.py b/devtools/fixeol.py index 45252a07d..11e1ce2a1 100644 --- a/devtools/fixeol.py +++ b/devtools/fixeol.py @@ -32,8 +32,8 @@ def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'): if verbose: print(is_dry_run and ' NEED FIX' or ' FIXED') return True -## -## +## +## ## ##def _do_fix(is_dry_run = True): ## from waftools import antglob diff --git a/devtools/licenseupdater.py b/devtools/licenseupdater.py index 36bdb5c09..d9b662e01 100644 --- a/devtools/licenseupdater.py +++ b/devtools/licenseupdater.py @@ -20,7 +20,7 @@ def update_license(path, dry_run, show_diff): dry_run: if True, just print the path of the file that would be updated, but don't change it. show_diff: if True, print the path of the file that would be modified, - as well as the change made to the file. + as well as the change made to the file. """ with open(path, 'rt') as fin: original_text = fin.read().replace('\r\n','\n') @@ -51,7 +51,7 @@ def update_license_in_source_directories(source_dirs, dry_run, show_diff): dry_run: if True, just print the path of the file that would be updated, but don't change it. show_diff: if True, print the path of the file that would be modified, - as well as the change made to the file. + as well as the change made to the file. """ from devtools import antglob prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist' diff --git a/doxybuild.py b/doxybuild.py index 862c1f43f..254ab714b 100644 --- a/doxybuild.py +++ b/doxybuild.py @@ -46,7 +46,7 @@ def do_subst_in_file(targetfile, sourcefile, dict): with open(sourcefile, 'r') as f: contents = f.read() for (k,v) in list(dict.items()): - v = v.replace('\\','\\\\') + v = v.replace('\\','\\\\') contents = re.sub(k, v, contents) with open(targetfile, 'w') as f: f.write(contents) @@ -158,7 +158,7 @@ def main(): Generates doxygen documentation in build/doxygen. Optionally makes a tarball of the documentation to dist/. - Must be started in the project top directory. + Must be started in the project top directory. """ from optparse import OptionParser parser = OptionParser(usage=usage) diff --git a/example/README.md b/example/README.md index b1ae4c875..92b925c96 100644 --- a/example/README.md +++ b/example/README.md @@ -1,8 +1,8 @@ -***NOTE*** +***NOTE*** If you get linker errors about undefined references to symbols that involve types in the `std::__cxx11` namespace or the tag `[abi:cxx11]` then it probably indicates that you are trying to link together object files that were compiled with different -values for the _GLIBCXX_USE_CXX11_ABI marco. This commonly happens when linking to a third-party library that was compiled with +values for the _GLIBCXX_USE_CXX11_ABI marco. This commonly happens when linking to a third-party library that was compiled with an older version of GCC. If the third-party library cannot be rebuilt with the new ABI, then you need to recompile your code with the old ABI,just like: **g++ stringWrite.cpp -ljsoncpp -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 -o stringWrite** diff --git a/test/data/legacy_test_array_06.json b/test/data/legacy_test_array_06.json index 7f6c516af..1fda03bb1 100644 --- a/test/data/legacy_test_array_06.json +++ b/test/data/legacy_test_array_06.json @@ -1,4 +1,4 @@ -[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", +[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "ccccccccccccccccccccccc", "dddddddddddddddddddddddddddddddddddddddddddddddddddd" ] \ No newline at end of file diff --git a/test/data/legacy_test_complex_01.json b/test/data/legacy_test_complex_01.json index cc0f30f5c..2c4a869ab 100644 --- a/test/data/legacy_test_complex_01.json +++ b/test/data/legacy_test_complex_01.json @@ -1,17 +1,17 @@ -{ +{ "count" : 1234, "name" : { "aka" : "T.E.S.T.", "id" : 123987 }, - "attribute" : [ - "random", - "short", - "bold", - 12, - { "height" : 7, "width" : 64 } + "attribute" : [ + "random", + "short", + "bold", + 12, + { "height" : 7, "width" : 64 } ], - "test": { "1" : - { "2" : - { "3" : { "coord" : [ 1,2] } - } + "test": { "1" : + { "2" : + { "3" : { "coord" : [ 1,2] } + } } } } diff --git a/test/data/legacy_test_object_03.json b/test/data/legacy_test_object_03.json index 4fcd4d821..90dba2af8 100644 --- a/test/data/legacy_test_object_03.json +++ b/test/data/legacy_test_object_03.json @@ -1,4 +1,4 @@ -{ +{ "count" : 1234, "name" : "test", "attribute" : "random" diff --git a/test/data/legacy_test_object_04.json b/test/data/legacy_test_object_04.json index 450762d71..9e43ff89b 100644 --- a/test/data/legacy_test_object_04.json +++ b/test/data/legacy_test_object_04.json @@ -1,3 +1,3 @@ -{ +{ "" : 1234 } diff --git a/test/data/legacy_test_preserve_comment_01.expected b/test/data/legacy_test_preserve_comment_01.expected index 2797aa7d6..d6c11b4c9 100644 --- a/test/data/legacy_test_preserve_comment_01.expected +++ b/test/data/legacy_test_preserve_comment_01.expected @@ -6,6 +6,6 @@ /* Comment before 'second' */ .second=2 -/* A comment at +/* A comment at the end of the file. */ diff --git a/test/data/legacy_test_preserve_comment_01.json b/test/data/legacy_test_preserve_comment_01.json index fabd55dd9..21b5ea7fa 100644 --- a/test/data/legacy_test_preserve_comment_01.json +++ b/test/data/legacy_test_preserve_comment_01.json @@ -9,6 +9,6 @@ "second" : 2 } -/* A comment at +/* A comment at the end of the file. */ diff --git a/test/pyjsontestrunner.py b/test/pyjsontestrunner.py index bd749b530..8acdbd2de 100644 --- a/test/pyjsontestrunner.py +++ b/test/pyjsontestrunner.py @@ -15,7 +15,7 @@ if len(sys.argv) != 2: print("Usage: %s input-json-file", sys.argv[0]) sys.exit(3) - + input_path = sys.argv[1] base_path = os.path.splitext(input_path)[0] actual_path = base_path + '.actual' @@ -23,7 +23,7 @@ rewrite_actual_path = base_path + '.actual-rewrite' def valueTreeToString(fout, value, path = '.'): - ty = type(value) + ty = type(value) if ty is types.DictType: fout.write('%s={}\n' % path) suffix = path[-1] != '.' and '.' or '' @@ -49,7 +49,7 @@ def valueTreeToString(fout, value, path = '.'): fout.write('%s=null\n' % path) else: assert False and "Unexpected value type" - + def parseAndSaveValueTree(input, actual_path): root = json.loads(input) fout = file(actual_path, 'wt') @@ -62,7 +62,7 @@ def rewriteValueTree(value, rewrite_path): #rewrite = rewrite[1:-1] # Somehow the string is quoted ! jsonpy bug ? file(rewrite_path, 'wt').write(rewrite + '\n') return rewrite - + input = file(input_path, 'rt').read() root = parseAndSaveValueTree(input, actual_path) rewrite = rewriteValueTree(json.write(root), rewrite_path) From 5c4219b8ae2d14a6bd12e895e2ce1b2503fffd4d Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sun, 10 Jan 2021 00:17:35 -0600 Subject: [PATCH 056/196] Update version in dox We should automate this, but for now we can at least update: make -f dev.makefile update-version make -f dev.makefile dox # Then, go to jsoncpp-doc repo, add, and push. * https://github.com/open-source-parsers/jsoncpp-docs/issues/2 --- .gitignore | 3 +++ dev.makefile | 4 +++- get_version.pl | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 get_version.pl diff --git a/.gitignore b/.gitignore index 2444e6a68..9682782fa 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ compile_commands.json # DS_Store .DS_Store + +# temps +/version diff --git a/dev.makefile b/dev.makefile index 1a4be6a91..545ff2730 100644 --- a/dev.makefile +++ b/dev.makefile @@ -1,9 +1,11 @@ # This is only for jsoncpp developers/contributors. # We use this to sign releases, generate documentation, etc. -VER?=$(shell cat version.txt) +VER?=$(shell cat version) default: @echo "VER=${VER}" +update-version: + perl get_version.pl meson.build >| version sign: jsoncpp-${VER}.tar.gz gpg --armor --detach-sign $< gpg --verify $<.asc diff --git a/get_version.pl b/get_version.pl new file mode 100644 index 000000000..19b6a543b --- /dev/null +++ b/get_version.pl @@ -0,0 +1,5 @@ +while (<>) { + if (/version : '(.+)',/) { + print "$1"; + } +} From fe9663e7edaf5c179af9c42ffd47428b83f8842a Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Mon, 21 Dec 2020 04:41:37 -0500 Subject: [PATCH 057/196] `Json::ValueIterator` operators `*` and `->` need to be const Fixes #1249. --- include/json/value.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index ec9af5666..7ec418571 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -918,8 +918,8 @@ class JSON_API ValueIterator : public ValueIteratorBase { * because the returned references/pointers can be used * to change state of the base class. */ - reference operator*() { return deref(); } - pointer operator->() { return &deref(); } + reference operator*() const { return const_cast(deref()); } + pointer operator->() const { return const_cast(&deref()); } }; inline void swap(Value& a, Value& b) { a.swap(b); } From eab8ebe6448dc2b9769d985c42bfd2a5d7788843 Mon Sep 17 00:00:00 2001 From: Riccardo Corsi Date: Mon, 4 Jan 2021 15:10:05 +0100 Subject: [PATCH 058/196] Disable also Visual Studio warning C4275 (std::exception used as base class in dll-interface class) when building as DLL and JSONCPP_DISABLE_DLL_INTERFACE_WARNING is defined. --- include/json/value.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/json/value.h b/include/json/value.h index 7ec418571..0edeb050c 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -50,7 +50,7 @@ // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(push) -#pragma warning(disable : 4251) +#pragma warning(disable : 4251 4275) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma pack(push, 8) From c9a976238b8b184a5a2e3b6bfa513ba1657a327b Mon Sep 17 00:00:00 2001 From: GermanAizek Date: Fri, 15 Jan 2021 13:19:59 +0300 Subject: [PATCH 059/196] minor fixes for 64 bits and refactor code --- src/jsontestrunner/main.cpp | 1 + src/lib_json/json_writer.cpp | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp index 3452c5986..df717ffd5 100644 --- a/src/jsontestrunner/main.cpp +++ b/src/jsontestrunner/main.cpp @@ -335,6 +335,7 @@ int main(int argc, const char* argv[]) { std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl; return 1; } + return 0; } #if defined(__GNUC__) diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 18e7a42cb..0dd160e45 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -68,7 +68,7 @@ #if !defined(isnan) // IEEE standard states that NaN values will not compare to themselves -#define isnan(x) (x != x) +#define isnan(x) ((x) != (x)) #endif #if !defined(__APPLE__) @@ -272,7 +272,7 @@ static void appendHex(String& result, unsigned ch) { result.append("\\u").append(toHex16Bit(ch)); } -static String valueToQuotedStringN(const char* value, unsigned length, +static String valueToQuotedStringN(const char* value, size_t length, bool emitUTF8 = false) { if (value == nullptr) return ""; @@ -350,7 +350,7 @@ static String valueToQuotedStringN(const char* value, unsigned length, } String valueToQuotedString(const char* value) { - return valueToQuotedStringN(value, static_cast(strlen(value))); + return valueToQuotedStringN(value, strlen(value)); } // Class Writer @@ -399,7 +399,7 @@ void FastWriter::writeValue(const Value& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - document_ += valueToQuotedStringN(str, static_cast(end - str)); + document_ += valueToQuotedStringN(str, static_cast(end - str)); break; } case booleanValue: @@ -422,8 +422,7 @@ void FastWriter::writeValue(const Value& value) { const String& name = *it; if (it != members.begin()) document_ += ','; - document_ += valueToQuotedStringN(name.data(), - static_cast(name.length())); + document_ += valueToQuotedStringN(name.data(), name.length()); document_ += yamlCompatibilityEnabled_ ? ": " : ":"; writeValue(value[name]); } @@ -468,7 +467,7 @@ void StyledWriter::writeValue(const Value& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); + pushValue(valueToQuotedStringN(str, static_cast(end - str))); else pushValue(""); break; @@ -509,7 +508,7 @@ void StyledWriter::writeValue(const Value& value) { } void StyledWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); + size_t size = value.size(); if (size == 0) pushValue("[]"); else { @@ -518,7 +517,7 @@ void StyledWriter::writeArrayValue(const Value& value) { writeWithIndent("["); indent(); bool hasChildValue = !childValues_.empty(); - unsigned index = 0; + ArrayIndex index = 0; for (;;) { const Value& childValue = value[index]; writeCommentBeforeValue(childValue); @@ -541,7 +540,7 @@ void StyledWriter::writeArrayValue(const Value& value) { { assert(childValues_.size() == size); document_ += "[ "; - for (unsigned index = 0; index < size; ++index) { + for (size_t index = 0; index < size; ++index) { if (index > 0) document_ += ", "; document_ += childValues_[index]; @@ -686,7 +685,7 @@ void StyledStreamWriter::writeValue(const Value& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); + pushValue(valueToQuotedStringN(str, static_cast(end - str))); else pushValue(""); break; @@ -960,8 +959,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str), - emitUTF8_)); + pushValue( + valueToQuotedStringN(str, static_cast(end - str), emitUTF8_)); else pushValue(""); break; @@ -984,8 +983,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { String const& name = *it; Value const& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN( - name.data(), static_cast(name.length()), emitUTF8_)); + writeWithIndent( + valueToQuotedStringN(name.data(), name.length(), emitUTF8_)); *sout_ << colonSymbol_; writeValue(childValue); if (++it == members.end()) { From ac2870298ed5b5a96a688d9df07461b31f83e906 Mon Sep 17 00:00:00 2001 From: Derick Vigne Date: Tue, 26 Jan 2021 14:59:12 -0500 Subject: [PATCH 060/196] Fixed pkg-config Version --- pkg-config/jsoncpp.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg-config/jsoncpp.pc.in b/pkg-config/jsoncpp.pc.in index 632a377f5..2a2221069 100644 --- a/pkg-config/jsoncpp.pc.in +++ b/pkg-config/jsoncpp.pc.in @@ -5,7 +5,7 @@ includedir=@includedir_for_pc_file@ Name: jsoncpp Description: A C++ library for interacting with JSON -Version: @JSONCPP_VERSION@ +Version: @PROJECT_VERSION@ URL: https://github.com/open-source-parsers/jsoncpp Libs: -L${libdir} -ljsoncpp Cflags: -I${includedir} From da9e17d25766b1bb0dcad1b81de35b6e3a2b5cb0 Mon Sep 17 00:00:00 2001 From: Yixing Lao Date: Sun, 17 Jan 2021 18:57:28 -0800 Subject: [PATCH 061/196] allow selection of Windows MSVC runtime --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f1db5e318..1ad82f9c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,9 @@ else() set(JSONCPP_CMAKE_POLICY_VERSION "${JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION}") endif() cmake_policy(VERSION ${JSONCPP_CMAKE_POLICY_VERSION}) +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif() # # Now enumerate specific policies newer than JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION # that may need to be individually set to NEW/OLD @@ -85,6 +88,7 @@ option(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C option(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON) option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON) option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF) +option(JSONCPP_STATIC_WINDOWS_RUNTIME "Use static (MT/MTd) Windows runtime" OFF) option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." ON) option(BUILD_STATIC_LIBS "Build jsoncpp_lib as a static library." ON) option(BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON) @@ -123,6 +127,9 @@ if(MSVC) # Only enabled in debug because some old versions of VS STL generate # unreachable code warning when compiled in release configuration. add_compile_options($<$:/W4>) + if (JSONCPP_STATIC_WINDOWS_RUNTIME) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") From fda274ddd297a53110d43189c2d69fee8f748da9 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Tue, 9 Feb 2021 23:50:37 -0500 Subject: [PATCH 062/196] Fix Value::resize to fill all array elements (#1265) * Fix Value::resize to fill all array elements Fixes #1264 --- src/lib_json/json_value.cpp | 3 ++- src/test_lib_json/main.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index bfa9263fd..378ea7982 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -912,7 +912,8 @@ void Value::resize(ArrayIndex newSize) { if (newSize == 0) clear(); else if (newSize > oldSize) - this->operator[](newSize - 1); + for (ArrayIndex i = oldSize; i < newSize; ++i) + (*this)[i]; else { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index be9c4a73d..e8bc7bcba 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -12,6 +12,7 @@ #include "fuzz.h" #include "jsontest.h" +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include using CharReaderPtr = std::unique_ptr; @@ -347,6 +349,17 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, resizeArray) { JSONTEST_ASSERT_EQUAL(array.size(), 0); } } + +JSONTEST_FIXTURE_LOCAL(ValueTest, resizePopulatesAllMissingElements) { + int n = 10; + Json::Value v; + v.resize(n); + JSONTEST_ASSERT_EQUAL(n, v.size()); + JSONTEST_ASSERT_EQUAL(n, std::distance(v.begin(), v.end())); + for (const Json::Value& e : v) + JSONTEST_ASSERT_EQUAL(e, Json::Value{}); +} + JSONTEST_FIXTURE_LOCAL(ValueTest, getArrayValue) { Json::Value array; for (Json::ArrayIndex i = 0; i < 5; i++) From 09c5ecd84fb754ac6ba1b661c6967f959a3100c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20K=C3=B6hler?= Date: Wed, 3 Feb 2021 23:42:12 +0100 Subject: [PATCH 063/196] only append _static suffix for microsoft toolchains --- src/lib_json/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index af2647652..ae406c04d 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -156,7 +156,11 @@ if(BUILD_STATIC_LIBS) # avoid name clashes on windows as the shared import lib is alse named jsoncpp.lib if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) - set(STATIC_SUFFIX "_static") + if (MSVC) + set(STATIC_SUFFIX "_static") + else() + set(STATIC_SUFFIX "") + endif() endif() set_target_properties(${STATIC_LIB} PROPERTIES From b1bd848241880ccea2d940f67343a899b9f65d5d Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Sat, 20 Feb 2021 16:07:34 -0500 Subject: [PATCH 064/196] fix sign-conversion warning (#1268) Use ArrayIndex instead of int. Fixes #1266 --- src/test_lib_json/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index e8bc7bcba..d0f5364ac 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -351,7 +351,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, resizeArray) { } JSONTEST_FIXTURE_LOCAL(ValueTest, resizePopulatesAllMissingElements) { - int n = 10; + Json::ArrayIndex n = 10; Json::Value v; v.resize(n); JSONTEST_ASSERT_EQUAL(n, v.size()); From 1ee39a6752de999e02fa07482196dc99a90bcada Mon Sep 17 00:00:00 2001 From: PinkD <443657547@qq.com> Date: Tue, 2 Mar 2021 23:57:54 +0800 Subject: [PATCH 065/196] add comment for emitUTF8 in header --- include/json/writer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/json/writer.h b/include/json/writer.h index fb0852a0c..99d74c731 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -110,6 +110,8 @@ class JSON_API StreamWriterBuilder : public StreamWriter::Factory { * - Number of precision digits for formatting of real values. * - "precisionType": "significant"(default) or "decimal" * - Type of precision for formatting of real values. + * - "emitUTF8": false or true + * - If true, outputs raw UTF8 strings instead of escaping them. * You can examine 'settings_` yourself * to see the defaults. You can also write and read them just like any From 94cda30dbddc1859f111848fdd05dfb85d3287c7 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Thu, 18 Mar 2021 05:22:35 -0400 Subject: [PATCH 066/196] Rearrange Comments::set (#1278) * slightly optimize Comments::set Avoid allocation if the set is going to be rejected anyway. Prototype suggestion from #1277 review thread --- src/lib_json/json_value.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 378ea7982..aa2b744ca 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1398,13 +1398,11 @@ String Value::Comments::get(CommentPlacement slot) const { } void Value::Comments::set(CommentPlacement slot, String comment) { - if (!ptr_) { + if (slot >= CommentPlacement::numberOfCommentPlacement) + return; + if (!ptr_) ptr_ = std::unique_ptr(new Array()); - } - // check comments array boundry. - if (slot < CommentPlacement::numberOfCommentPlacement) { - (*ptr_)[slot] = std::move(comment); - } + (*ptr_)[slot] = std::move(comment); } void Value::setComment(String comment, CommentPlacement placement) { From b6407955712b51837cc3dc07ee5e6143761027c6 Mon Sep 17 00:00:00 2001 From: Sergey Rachev Date: Sat, 27 Feb 2021 18:25:11 +0100 Subject: [PATCH 067/196] - exported targets go to separate generated file and package config file generated from template to use automatic package resolving and resolution logic CMake provides helpers to generate config file. Generated config file has usefull macro check_required_components() to set necessary variables like PackageName_FOUND if requirements has been satisfied. An absence of dedicated config file confuses user project as necessary variables are not set. --- CMakeLists.txt | 6 ++++-- jsoncppConfig.cmake.in | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 jsoncppConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ad82f9c6..23aaeeec9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,11 +177,13 @@ if(JSONCPP_WITH_CMAKE_PACKAGE) include(CMakePackageConfigHelpers) install(EXPORT jsoncpp DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp - FILE jsoncppConfig.cmake) + FILE jsoncpp-targets.cmake) + configure_package_config_file(jsoncppConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) + write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) endif() diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in new file mode 100644 index 000000000..e3fa4b961 --- /dev/null +++ b/jsoncppConfig.cmake.in @@ -0,0 +1,10 @@ +cmake_policy(PUSH) +cmake_policy(VERSION 3.0) + +@PACKAGE_INIT@ + +include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-targets.cmake" ) + +check_required_components(JsonCpp) + +cmake_policy(POP) \ No newline at end of file From 62f3e034755c43759da819781bc23882a2ea3e01 Mon Sep 17 00:00:00 2001 From: Sergey Rachev Date: Sat, 27 Feb 2021 22:35:57 +0100 Subject: [PATCH 068/196] - declare namespaced export target to simplify the library usage When the static libary is available use it as exported alias, otherwise use shared library. Cmake takes care about import library when Windows platform DLL is used --- jsoncppConfig.cmake.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in index e3fa4b961..9caa006be 100644 --- a/jsoncppConfig.cmake.in +++ b/jsoncppConfig.cmake.in @@ -5,6 +5,12 @@ cmake_policy(VERSION 3.0) include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-targets.cmake" ) +if(TARGET jsoncpp_static) + add_library(JsonCpp::JsonCpp ALIAS jsoncpp_static) +elseif(TARGET jsoncpp_lib) + add_library(JsonCpp::JsonCpp ALIAS jsoncpp_lib) +endif() + check_required_components(JsonCpp) cmake_policy(POP) \ No newline at end of file From cee42e0bd7ddd58e4a1fd7dd3137610e580964b3 Mon Sep 17 00:00:00 2001 From: Sergey Rachev Date: Sun, 28 Feb 2021 00:25:48 +0100 Subject: [PATCH 069/196] - empty line at end of file --- jsoncppConfig.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in index 9caa006be..789687bb3 100644 --- a/jsoncppConfig.cmake.in +++ b/jsoncppConfig.cmake.in @@ -13,4 +13,4 @@ endif() check_required_components(JsonCpp) -cmake_policy(POP) \ No newline at end of file +cmake_policy(POP) From a3914b792f86d60ab2cc42f50f2d9e329bcf3eb1 Mon Sep 17 00:00:00 2001 From: Sergey Rachev Date: Sat, 6 Mar 2021 13:49:53 +0100 Subject: [PATCH 070/196] - narrowed lines to be aligned with overall file line width --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23aaeeec9..60939051d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,12 +178,14 @@ if(JSONCPP_WITH_CMAKE_PACKAGE) install(EXPORT jsoncpp DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp FILE jsoncpp-targets.cmake) - configure_package_config_file(jsoncppConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) + configure_package_config_file(jsoncppConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) endif() From 2af4a4c6c83fc519b190cf2d9797fd8dc3b31e1d Mon Sep 17 00:00:00 2001 From: Sergey Rachev Date: Fri, 2 Apr 2021 22:30:43 +0200 Subject: [PATCH 071/196] - workaround for CMake < 3.18 ALIAS target limitation to not point to non-GLOBAL IMPORTED target --- jsoncppConfig.cmake.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in index 789687bb3..c1cc6ca0b 100644 --- a/jsoncppConfig.cmake.in +++ b/jsoncppConfig.cmake.in @@ -6,9 +6,11 @@ cmake_policy(VERSION 3.0) include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-targets.cmake" ) if(TARGET jsoncpp_static) - add_library(JsonCpp::JsonCpp ALIAS jsoncpp_static) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED ) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_static") elseif(TARGET jsoncpp_lib) - add_library(JsonCpp::JsonCpp ALIAS jsoncpp_lib) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED ) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_lib") endif() check_required_components(JsonCpp) From 993e4e2828993b017e6e3f5fff99697eead4d134 Mon Sep 17 00:00:00 2001 From: Sergey Rachev Date: Wed, 14 Apr 2021 20:50:43 +0200 Subject: [PATCH 072/196] - isolated namespace targets into separate file --- CMakeLists.txt | 1 + jsoncpp-namespaced-targets.cmake | 7 +++++++ jsoncppConfig.cmake.in | 9 +-------- 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 jsoncpp-namespaced-targets.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 60939051d..48b035006 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,7 @@ if(JSONCPP_WITH_CMAKE_PACKAGE) COMPATIBILITY SameMajorVersion) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp-namespaced-targets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) endif() diff --git a/jsoncpp-namespaced-targets.cmake b/jsoncpp-namespaced-targets.cmake new file mode 100644 index 000000000..ac1504e00 --- /dev/null +++ b/jsoncpp-namespaced-targets.cmake @@ -0,0 +1,7 @@ +if (TARGET jsoncpp_static) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_static") +elseif (TARGET jsoncpp_lib) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_lib") +endif () \ No newline at end of file diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in index c1cc6ca0b..76570bc30 100644 --- a/jsoncppConfig.cmake.in +++ b/jsoncppConfig.cmake.in @@ -4,14 +4,7 @@ cmake_policy(VERSION 3.0) @PACKAGE_INIT@ include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-targets.cmake" ) - -if(TARGET jsoncpp_static) - add_library(JsonCpp::JsonCpp INTERFACE IMPORTED ) - set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_static") -elseif(TARGET jsoncpp_lib) - add_library(JsonCpp::JsonCpp INTERFACE IMPORTED ) - set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_lib") -endif() +include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" ) check_required_components(JsonCpp) From ed1ab7ac452b0fe51f3b0a8364770774175a060e Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Wed, 5 May 2021 00:27:30 -0500 Subject: [PATCH 073/196] Avoid getline(s, EOF) Fixes #1288 --- src/lib_json/json_reader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index a34017d99..a6a3f4e30 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -104,8 +104,7 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) { // Since String is reference-counted, this at least does not // create an extra copy. - String doc; - std::getline(is, doc, static_cast EOF); + String doc(std::istreambuf_iterator(is), {}); return parse(doc.data(), doc.data() + doc.size(), root, collectComments); } From 5fabc5e6d2221594a674425bac054de86a1c43a8 Mon Sep 17 00:00:00 2001 From: SpaceIm <30052553+SpaceIm@users.noreply.github.com> Date: Thu, 6 May 2021 03:55:25 +0200 Subject: [PATCH 074/196] conversion errors only if warnings as errors enabled (#1284) --- CMakeLists.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48b035006..584ecd026 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,7 +134,11 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # using regular Clang or AppleClang - add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare) + add_compile_options(-Wall -Wconversion -Wshadow) + + if(JSONCPP_WITH_WARNING_AS_ERROR) + add_compile_options(-Werror=conversion -Werror=sign-compare) + endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # using GCC add_compile_options(-Wall -Wconversion -Wshadow -Wextra) @@ -148,9 +152,11 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") # using Intel compiler - add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion) + add_compile_options(-Wall -Wconversion -Wshadow -Wextra) - if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR) + if(JSONCPP_WITH_WARNING_AS_ERROR) + add_compile_options(-Werror=conversion) + elseif(JSONCPP_WITH_STRICT_ISO) add_compile_options(-Wpedantic) endif() endif() From 375a1119f8bbbf42e5275f31b281b5d87f2e17f2 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Thu, 6 May 2021 04:03:02 +0200 Subject: [PATCH 075/196] Add support for Bazel build system (#1275) Co-authored-by: Christopher Dunn --- BUILD.bazel | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 BUILD.bazel diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..6d7ac3da9 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,37 @@ +licenses(["unencumbered"]) # Public Domain or MIT + +exports_files(["LICENSE"]) + +cc_library( + name = "jsoncpp", + srcs = [ + "src/lib_json/json_reader.cpp", + "src/lib_json/json_tool.h", + "src/lib_json/json_value.cpp", + "src/lib_json/json_writer.cpp", + ], + hdrs = [ + "include/json/allocator.h", + "include/json/assertions.h", + "include/json/config.h", + "include/json/json_features.h", + "include/json/forwards.h", + "include/json/json.h", + "include/json/reader.h", + "include/json/value.h", + "include/json/version.h", + "include/json/writer.h", + ], + copts = [ + "-DJSON_USE_EXCEPTION=0", + "-DJSON_HAS_INT64", + ], + includes = ["include"], + visibility = ["//visibility:public"], + deps = [":private"], +) + +cc_library( + name = "private", + textual_hdrs = ["src/lib_json/json_valueiterator.inl"], +) From 65bb1b1c1d8019dc72279c12bb74df92925dfd5e Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Wed, 23 Jun 2021 11:03:44 -0700 Subject: [PATCH 076/196] CMake: Remove ancient version checks (#1299) The minimum version for the project is CMake 3.8.0, so there's no point in keeping legacy code for pre-3.0 or pre-2.8 CMake. --- src/lib_json/CMakeLists.txt | 54 +++++++++++++------------------------ 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index ae406c04d..f0e9d0a5b 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -11,20 +11,10 @@ include(CheckCXXSymbolExists) check_include_file_cxx(clocale HAVE_CLOCALE) check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV) -if(CMAKE_VERSION VERSION_LESS 3.0.0) - # The "LANGUAGE CXX" parameter is not supported in CMake versions below 3, - # so the C compiler and header has to be used. - check_include_file(locale.h HAVE_LOCALE_H) - set(CMAKE_EXTRA_INCLUDE_FILES locale.h) - check_type_size("struct lconv" LCONV_SIZE) - unset(CMAKE_EXTRA_INCLUDE_FILES) - check_struct_has_member("struct lconv" decimal_point locale.h HAVE_DECIMAL_POINT) -else() - set(CMAKE_EXTRA_INCLUDE_FILES clocale) - check_type_size(lconv LCONV_SIZE LANGUAGE CXX) - unset(CMAKE_EXTRA_INCLUDE_FILES) - check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX) -endif() +set(CMAKE_EXTRA_INCLUDE_FILES clocale) +check_type_size(lconv LCONV_SIZE LANGUAGE CXX) +unset(CMAKE_EXTRA_INCLUDE_FILES) +check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX) if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV)) message(WARNING "Locale functionality is not supported") @@ -139,13 +129,11 @@ if(BUILD_SHARED_LIBS) target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) - if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories(${SHARED_LIB} PUBLIC - $ - $ - $ - ) - endif() + target_include_directories(${SHARED_LIB} PUBLIC + $ + $ + $ + ) list(APPEND CMAKE_TARGETS ${SHARED_LIB}) endif() @@ -175,13 +163,11 @@ if(BUILD_STATIC_LIBS) target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) - if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories(${STATIC_LIB} PUBLIC - $ - $ - $ - ) - endif() + target_include_directories(${STATIC_LIB} PUBLIC + $ + $ + $ + ) list(APPEND CMAKE_TARGETS ${STATIC_LIB}) endif() @@ -204,13 +190,11 @@ if(BUILD_OBJECT_LIBS) target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) - if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories(${OBJECT_LIB} PUBLIC - $ - $ - $ - ) - endif() + target_include_directories(${OBJECT_LIB} PUBLIC + $ + $ + $ + ) list(APPEND CMAKE_TARGETS ${OBJECT_LIB}) endif() From c39fbdac0f0f6638d5cfca43988750a1aac512db Mon Sep 17 00:00:00 2001 From: Jack Ullery <46848683+jack-ullery@users.noreply.github.com> Date: Thu, 12 Aug 2021 21:08:46 +0000 Subject: [PATCH 077/196] minor fix for code examples (#1317) --- example/readFromString/readFromString.cpp | 1 + example/streamWrite/streamWrite.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/example/readFromString/readFromString.cpp b/example/readFromString/readFromString.cpp index c27bbd5ae..0b29a4e86 100644 --- a/example/readFromString/readFromString.cpp +++ b/example/readFromString/readFromString.cpp @@ -1,5 +1,6 @@ #include "json/json.h" #include +#include /** * \brief Parse a raw string into Value object using the CharReaderBuilder * class, or the legacy Reader class. diff --git a/example/streamWrite/streamWrite.cpp b/example/streamWrite/streamWrite.cpp index 6f7f7972a..a72f5a52e 100644 --- a/example/streamWrite/streamWrite.cpp +++ b/example/streamWrite/streamWrite.cpp @@ -1,5 +1,6 @@ #include "json/json.h" #include +#include /** \brief Write the Value object to a stream. * Example Usage: * $g++ streamWrite.cpp -ljsoncpp -std=c++11 -o streamWrite From 94a6220f7c738d6711d325fd29bb8a60b97fd77e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 21 Sep 2021 06:55:25 +0100 Subject: [PATCH 078/196] Document skipBom in CharReaderBuilder (#1332) --- include/json/reader.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/json/reader.h b/include/json/reader.h index 917546608..250468f1b 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -324,6 +324,9 @@ class JSON_API CharReaderBuilder : public CharReader::Factory { * - `"allowSpecialFloats": false or true` * - If true, special float values (NaNs and infinities) are allowed and * their values are lossfree restorable. + * - `"skipBom": false or true` + * - If true, if the input starts with the Unicode byte order mark (BOM), + * it is skipped. * * You can examine 'settings_` yourself to see the defaults. You can also * write and read them just like any JSON Value. From fa747b1ae34338e764ede2d104803eae5af0a4a0 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Tue, 26 Oct 2021 16:04:17 -0500 Subject: [PATCH 079/196] clang-format is not available by default --- .travis.yml | 2 +- .travis_scripts/meson_builder.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6d7ccde74..23acd4e57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ # Build matrix / environment variables are explained on: -# http://about.travis-ci.org/docs/user/build-configuration/ +# http://about.travis-ci.com/docs/user/build-configuration/ # This file can be validated on: http://www.yamllint.com/ # Or using the Ruby based travel command line tool: # gem install travis --no-rdoc --no-ri diff --git a/.travis_scripts/meson_builder.sh b/.travis_scripts/meson_builder.sh index 1fdd8f65d..bc74732f6 100755 --- a/.travis_scripts/meson_builder.sh +++ b/.travis_scripts/meson_builder.sh @@ -64,7 +64,7 @@ ninja --version _COMPILER_NAME=`basename ${CXX}` _BUILD_DIR_NAME="build-${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}" -./.travis_scripts/run-clang-format.sh +#./.travis_scripts/run-clang-format.sh meson --fatal-meson-warnings --werror --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . "${_BUILD_DIR_NAME}" ninja -v -j 2 -C "${_BUILD_DIR_NAME}" From 29f9853455002bba46262ded9c1b57656796af75 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 25 Oct 2021 23:49:43 +0200 Subject: [PATCH 080/196] Fix cmake config for POSITION_INDEPENDENT_CODE enabling it just when BUILD_SHARED_LIBS is ON --- src/lib_json/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index f0e9d0a5b..b7596e80b 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -119,7 +119,7 @@ if(BUILD_SHARED_LIBS) OUTPUT_NAME jsoncpp VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_SOVERSION} - POSITION_INDEPENDENT_CODE ON + POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} ) # Set library's runtime search path on OSX @@ -180,7 +180,7 @@ if(BUILD_OBJECT_LIBS) OUTPUT_NAME jsoncpp VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_SOVERSION} - POSITION_INDEPENDENT_CODE ON + POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} ) # Set library's runtime search path on OSX From 54a5432c01fb2d2e266229b758b240aa2358d4e7 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Wed, 3 Nov 2021 11:35:15 -0500 Subject: [PATCH 081/196] Drop compile-time deprecation warning --- include/json/reader.h | 7 +++---- include/json/writer.h | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/json/reader.h b/include/json/reader.h index 250468f1b..be0d7676a 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -33,8 +33,7 @@ namespace Json { * \deprecated Use CharReader and CharReaderBuilder. */ -class JSONCPP_DEPRECATED( - "Use CharReader and CharReaderBuilder instead.") JSON_API Reader { +class JSON_API Reader { public: using Char = char; using Location = const Char*; @@ -51,13 +50,13 @@ class JSONCPP_DEPRECATED( }; /** \brief Constructs a Reader allowing all features for parsing. + * \deprecated Use CharReader and CharReaderBuilder. */ - JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") Reader(); /** \brief Constructs a Reader allowing the specified feature set for parsing. + * \deprecated Use CharReader and CharReaderBuilder. */ - JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") Reader(const Features& features); /** \brief Read a Value from a JSON diff --git a/include/json/writer.h b/include/json/writer.h index 99d74c731..88a3b12e9 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -147,7 +147,7 @@ class JSON_API StreamWriterBuilder : public StreamWriter::Factory { /** \brief Abstract class for writers. * \deprecated Use StreamWriter. (And really, this is an implementation detail.) */ -class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +class JSON_API Writer { public: virtual ~Writer(); @@ -167,7 +167,7 @@ class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter +class JSON_API FastWriter : public Writer { public: FastWriter(); @@ -227,7 +227,7 @@ class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API +class JSON_API StyledWriter : public Writer { public: StyledWriter(); @@ -296,7 +296,7 @@ class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API +class JSON_API StyledStreamWriter { public: /** From c4904b2c0d461f84fba88a760161212651e4f536 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Wed, 3 Nov 2021 11:39:54 -0500 Subject: [PATCH 082/196] Bump micro version --- CMakeLists.txt | 4 ++-- include/json/version.h | 4 ++-- meson.build | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 584ecd026..2841277c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,11 +72,11 @@ project(jsoncpp # 2. ./include/json/version.h # 3. ./CMakeLists.txt # IMPORTANT: also update the PROJECT_SOVERSION!! - VERSION 1.9.4 # [.[.[.]]] + VERSION 1.9.5 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(PROJECT_SOVERSION 24) +set(PROJECT_SOVERSION 25) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) diff --git a/include/json/version.h b/include/json/version.h index 87cf7e2fb..e931d0383 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -9,10 +9,10 @@ // 3. /CMakeLists.txt // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "1.9.4" +#define JSONCPP_VERSION_STRING "1.9.5" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 4 +#define JSONCPP_VERSION_PATCH 5 #define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ diff --git a/meson.build b/meson.build index 08e0f299e..f68db30dd 100644 --- a/meson.build +++ b/meson.build @@ -50,7 +50,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 24, + soversion : 25, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) From 2d55c7445ffedf30db62231f223137ef02e611a9 Mon Sep 17 00:00:00 2001 From: Tero Kinnunen Date: Wed, 15 Dec 2021 04:00:28 +0200 Subject: [PATCH 083/196] Parse large floats as infinity (#1349) (#1353) Return 1.9.1 functionality where values too large to fit in double are converted to positive or negative infinity. Commit 645cd04 changed functionality so that large floats cause parse error, while version 1.9.1 accepted them as infinite. This is problematic because writer outputs infinity values as `1e+9999`, which could no longer be parsed back. Fixed also legacy Reader even though it did not parse large values even before breaking change, due to problematic output/parse asymmetry. `>>` operator sets value to numeric_limits::max/lowest value if representation is too large to fit to double. [1][2] In macos value appears to be parsed to infinity. > | value in *val* | description | > |--------------------------|-------------| > | numeric_limits::max() | The sequence represents a value too large for the type of val | > | numeric_limits::lowest() | The sequence represents a value too large negative for the type of val | [1] https://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ [2] https://www.cplusplus.com/reference/locale/num_get/get/ Signed-off-by: Tero Kinnunen Co-authored-by: Tero Kinnunen --- src/lib_json/json_reader.cpp | 18 +++++++++++++++--- test/data/legacy_test_real_13.expected | 3 +++ test/data/legacy_test_real_13.json | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 test/data/legacy_test_real_13.expected create mode 100644 test/data/legacy_test_real_13.json diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index a6a3f4e30..896bf1b91 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -12,6 +12,7 @@ #endif // if !defined(JSON_IS_AMALGAMATION) #include #include +#include #include #include #include @@ -600,9 +601,15 @@ bool Reader::decodeDouble(Token& token, Value& decoded) { double value = 0; String buffer(token.start_, token.end_); IStringStream is(buffer); - if (!(is >> value)) - return addError( + if (!(is >> value)) { + if (value == std::numeric_limits::max()) + value = std::numeric_limits::infinity(); + else if (value == std::numeric_limits::lowest()) + value = -std::numeric_limits::infinity(); + else if (!std::isinf(value)) + return addError( "'" + String(token.start_, token.end_) + "' is not a number.", token); + } decoded = value; return true; } @@ -1647,7 +1654,12 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { const String buffer(token.start_, token.end_); IStringStream is(buffer); if (!(is >> value)) { - return addError( + if (value == std::numeric_limits::max()) + value = std::numeric_limits::infinity(); + else if (value == std::numeric_limits::lowest()) + value = -std::numeric_limits::infinity(); + else if (!std::isinf(value)) + return addError( "'" + String(token.start_, token.end_) + "' is not a number.", token); } decoded = value; diff --git a/test/data/legacy_test_real_13.expected b/test/data/legacy_test_real_13.expected new file mode 100644 index 000000000..8d3f03faa --- /dev/null +++ b/test/data/legacy_test_real_13.expected @@ -0,0 +1,3 @@ +.=[] +.[0]=-inf +.[1]=inf diff --git a/test/data/legacy_test_real_13.json b/test/data/legacy_test_real_13.json new file mode 100644 index 000000000..287258a81 --- /dev/null +++ b/test/data/legacy_test_real_13.json @@ -0,0 +1 @@ +[-1e+9999, 1e+9999] From a1f1613bdd81bf28289e8d3fbeb4eb78b82fb203 Mon Sep 17 00:00:00 2001 From: luzpaz Date: Tue, 14 Dec 2021 21:04:47 -0500 Subject: [PATCH 084/196] Fix various typos (#1350) Found via `codespell -q 3 -L alue,alse` Co-authored-by: Christopher Dunn Co-authored-by: Jordan Bayles --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 2 +- include/json/writer.h | 4 ++-- src/lib_json/CMakeLists.txt | 2 +- src/lib_json/json_reader.cpp | 2 +- src/test_lib_json/jsontest.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2841277c0..fd8bcf2b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ # policies that provide successful builds. By setting JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION # to a value greater than the oldest policies, all policies between # JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION and CMAKE_VERSION (used for this build) -# are set to their NEW behaivor, thereby suppressing policy warnings related to policies +# are set to their NEW behavior, thereby suppressing policy warnings related to policies # between the JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION and CMAKE_VERSION. # # CMake versions greater than the JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION policies will diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8d992bee7..5f5c032a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,7 +77,7 @@ See `doxybuild.py --help` for options. To add a test, you need to create two files in test/data: * a `TESTNAME.json` file, that contains the input document in JSON format. -* a `TESTNAME.expected` file, that contains a flatened representation of the +* a `TESTNAME.expected` file, that contains a flattened representation of the input document. The `TESTNAME.expected` file format is as follows: diff --git a/include/json/writer.h b/include/json/writer.h index 88a3b12e9..03f99065f 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -217,7 +217,7 @@ class JSON_API FastWriter * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * - * If the Value have comments then they are outputed according to their + * If the Value have comments then they are outputted according to their *#CommentPlacement. * * \sa Reader, Value, Value::setComment() @@ -286,7 +286,7 @@ class JSON_API * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * - * If the Value have comments then they are outputed according to their + * If the Value have comments then they are outputted according to their #CommentPlacement. * * \sa Reader, Value, Value::setComment() diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index b7596e80b..3cf66eb34 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -142,7 +142,7 @@ if(BUILD_STATIC_LIBS) set(STATIC_LIB ${PROJECT_NAME}_static) add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) - # avoid name clashes on windows as the shared import lib is alse named jsoncpp.lib + # avoid name clashes on windows as the shared import lib is also named jsoncpp.lib if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) if (MSVC) set(STATIC_SUFFIX "_static") diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 896bf1b91..1ac5e81ab 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -1614,7 +1614,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { const auto digit(static_cast(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, meaing value == threshold, + // a) we've only just touched the limit, meaning value == threshold, // b) this is the last digit, or // c) it's small enough to fit in that rounding delta, we're okay. // Otherwise treat this number as a double to avoid overflow. diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h index 4e8af0f25..a2385fa3f 100644 --- a/src/test_lib_json/jsontest.h +++ b/src/test_lib_json/jsontest.h @@ -74,7 +74,7 @@ class TestResult { /// Removes the last PredicateContext added to the predicate stack /// chained list. - /// Next messages will be targed at the PredicateContext that was removed. + /// Next messages will be targeted at the PredicateContext that was removed. TestResult& popPredicateContext(); bool failed() const; From 42e892d96e47b1f6e29844cc705e148ec4856448 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 12 Jan 2022 21:27:16 +0000 Subject: [PATCH 085/196] Use default rather than hard-coded 8 for maximum aggregate member alignment (#1378) On CHERI, and thus Arm's Morello prototype, pointers are represented as hardware capabilities. These capabilities are comprised of not just an integer address, as is the representation for traditional pointers, but also bounds, permissions and other metadata, plus a tag bit used as the validity bit, which provides fine-grained spatial and referential safety for C and C++ in hardware. This tag bit is not part of the data itself and is instead kept on the side, flowing with the capability between registers and the memory subsystem, and any attempt to amplify the privilege of or corrupt a capability clears this tag (or, in some cases, traps), rendering them impossible to forge; you can only create capabilities that are (possibly trivial) subsets of existing ones. When the capability is stored in memory, this tag bit needs to be preserved, which is done through the use of tagged memory. Every capability-sized word gains an additional non-addressable (from the CPU's perspective; depending on the implementation the tag bits may be stored in a small block of memory carved out of normal DRAM that the CPU is blocked from accessing) bit. This means that capabilities can only be stored to aligned locations; attempting to store them to unaligned locations will trap with an alignment fault or, if you end up using a memcpy call, will copy the raw bytes of the capability's representation but lose the tag, so when it is eventually loaded back as a capability and dereferenced it will fault. Since, on 64-bit architectures, our capabilities, used to implement C language pointers, are 128-bit quantities, this means they need 16-byte alignment. Currently the various #pragma pack directives, used to work around (extremely broken and bogus) code that includes jsoncpp in a context where the maximum alignment has been overridden, hard-code 8 as the maximum alignment to use, and so do not sufficiently align CHERI / Morello capabilities on 64-bit architectures. On Windows x64, the default is also not 8 but 16 (ARM64 is supposedly 8), so this is slightly dodgy to do there too, but in practice likely not an issue so long as you don't use any 128-bit types there. Instead of hard-coding a width, use a directive that resets the packing back to the default. Unfortunately, whilst GCC and Clang both accept using #pragma pack(push, 0) as shorthand like for any non-zero value, MSVC does not, so this needs to be two directives. --- include/json/allocator.h | 3 ++- include/json/json_features.h | 3 ++- include/json/reader.h | 3 ++- include/json/value.h | 3 ++- include/json/writer.h | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/json/allocator.h b/include/json/allocator.h index 95ef8a5ec..75406428f 100644 --- a/include/json/allocator.h +++ b/include/json/allocator.h @@ -9,7 +9,8 @@ #include #include -#pragma pack(push, 8) +#pragma pack(push) +#pragma pack() namespace Json { template class SecureAllocator { diff --git a/include/json/json_features.h b/include/json/json_features.h index 7c7e9f5de..e4a61d6f1 100644 --- a/include/json/json_features.h +++ b/include/json/json_features.h @@ -10,7 +10,8 @@ #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) -#pragma pack(push, 8) +#pragma pack(push) +#pragma pack() namespace Json { diff --git a/include/json/reader.h b/include/json/reader.h index be0d7676a..46975d86f 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -23,7 +23,8 @@ #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma pack(push, 8) +#pragma pack(push) +#pragma pack() namespace Json { diff --git a/include/json/value.h b/include/json/value.h index 0edeb050c..57ecb13f5 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -53,7 +53,8 @@ #pragma warning(disable : 4251 4275) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma pack(push, 8) +#pragma pack(push) +#pragma pack() /** \brief JSON (JavaScript Object Notation). */ diff --git a/include/json/writer.h b/include/json/writer.h index 03f99065f..7d8cf4d63 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -20,7 +20,8 @@ #pragma warning(disable : 4251) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma pack(push, 8) +#pragma pack(push) +#pragma pack() namespace Json { From 8190e061bc2d95da37479a638aa2c9e483e58ec6 Mon Sep 17 00:00:00 2001 From: mwestphal Date: Thu, 14 Jul 2022 23:57:37 +0200 Subject: [PATCH 086/196] Fix wrong usage of doxygen groups (#1417) --- include/json/value.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 57ecb13f5..15c517e12 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -437,7 +437,7 @@ class JSON_API Value { /// \post type() is arrayValue void resize(ArrayIndex newSize); - //@{ + ///@{ /// Access an array element (zero based index). If the array contains less /// than index element, then null value are inserted in the array so that /// its size is index+1. @@ -445,15 +445,15 @@ class JSON_API Value { /// this from the operator[] which takes a string.) Value& operator[](ArrayIndex index); Value& operator[](int index); - //@} + ///@} - //@{ + ///@{ /// Access an array element (zero based index). /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) const Value& operator[](ArrayIndex index) const; const Value& operator[](int index) const; - //@} + ///@} /// If the array contains at least index+1 elements, returns the element /// value, otherwise returns defaultValue. From 3d9bf8ee54855396e20b4e221ad28f71625bb76c Mon Sep 17 00:00:00 2001 From: Jakob Widauer Date: Wed, 7 Jun 2023 18:11:01 +0200 Subject: [PATCH 087/196] feat: adds front and back methods to Value type (#1458) Value::front and Value::back --- include/json/value.h | 24 ++++++++++++++++++++++++ src/test_lib_json/main.cpp | 14 ++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/include/json/value.h b/include/json/value.h index 15c517e12..9a302c161 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -585,6 +585,22 @@ class JSON_API Value { iterator begin(); iterator end(); + /// \brief Returns a reference to the first element in the `Value`. + /// Requires that this value holds an array or json object, with at least one element. + const Value& front() const; + + /// \brief Returns a reference to the first element in the `Value`. + /// Requires that this value holds an array or json object, with at least one element. + Value& front(); + + /// \brief Returns a reference to the last element in the `Value`. + /// Requires that value holds an array or json object, with at least one element. + const Value& back() const; + + /// \brief Returns a reference to the last element in the `Value`. + /// Requires that this value holds an array or json object, with at least one element. + Value& back(); + // Accessors for the [start, limit) range of bytes within the JSON text from // which this value was parsed, if any. void setOffsetStart(ptrdiff_t start); @@ -925,6 +941,14 @@ class JSON_API ValueIterator : public ValueIteratorBase { inline void swap(Value& a, Value& b) { a.swap(b); } +inline const Value& Value::front() const { return *begin(); } + +inline Value& Value::front() { return *begin(); } + +inline const Value& Value::back() const { return *(--end()); } + +inline Value& Value::back() { return *(--end()); } + } // namespace Json #pragma pack(pop) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index d0f5364ac..a6f21c45a 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -310,10 +310,14 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrays) { const Json::Value& constArray = array1_; JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[index0]); JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[0]); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray.front()); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray.back()); // Access through non-const reference JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[index0]); JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[0]); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_.front()); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_.back()); array1_[2] = Json::Value(17); JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]); @@ -356,6 +360,8 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, resizePopulatesAllMissingElements) { v.resize(n); JSONTEST_ASSERT_EQUAL(n, v.size()); JSONTEST_ASSERT_EQUAL(n, std::distance(v.begin(), v.end())); + JSONTEST_ASSERT_EQUAL(v.front(), Json::Value{}); + JSONTEST_ASSERT_EQUAL(v.back(), Json::Value{}); for (const Json::Value& e : v) JSONTEST_ASSERT_EQUAL(e, Json::Value{}); } @@ -406,6 +412,8 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) { JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[0]); // check append JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[1]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[2]); + JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array.front()); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array.back()); // insert lvalue at the head JSONTEST_ASSERT(array.insert(0, str1)); @@ -413,6 +421,8 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) { JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]); JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[2]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[3]); + JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array.front()); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array.back()); // checking address for (Json::ArrayIndex i = 0; i < 3; i++) { JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); @@ -425,6 +435,8 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) { JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]); JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]); + JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array.front()); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array.back()); // checking address for (Json::ArrayIndex i = 0; i < 4; i++) { JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); @@ -438,6 +450,8 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) { JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]); JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array[5]); + JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array.front()); + JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array.back()); // checking address for (Json::ArrayIndex i = 0; i < 5; i++) { JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); From 69098a18b9af0c47549d9a271c054d13ca92b006 Mon Sep 17 00:00:00 2001 From: Mykola Date: Tue, 27 Jun 2023 16:42:38 +0200 Subject: [PATCH 088/196] Avoid using cmake glob vars if we are a subproject (#1459) If jsoncpp is a subproject (like a git submodule), setting the global cmake variables affect the entire project (changes the structure of the output folders) and these changes prevent it. --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fd8bcf2b2..8920544a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,10 +96,12 @@ option(BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON) # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir.") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir.") -set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.") +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir.") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir.") + set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.") +endif() set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL") From cd8173c6d3076dd06e2d0e62a4b55b995c498515 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 11:39:17 -0700 Subject: [PATCH 089/196] Create c-cpp.yml --- .github/workflows/c-cpp.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/c-cpp.yml diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 000000000..fbf32ec92 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,23 @@ +name: C/C++ CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: configure + run: ./configure + - name: make + run: make + - name: make check + run: make check + - name: make distcheck + run: make distcheck From 01b11d2e4b9cb81959dd567d35b4b363e8932e4e Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 11:40:13 -0700 Subject: [PATCH 090/196] Create meson_build_and_run (#1553) --- .github/workflows/meson_build_and_run | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/meson_build_and_run diff --git a/.github/workflows/meson_build_and_run b/.github/workflows/meson_build_and_run new file mode 100644 index 000000000..98df7a85a --- /dev/null +++ b/.github/workflows/meson_build_and_run @@ -0,0 +1,29 @@ +name: Meson Build +uses: BSFishy/meson-build@v1.0.3 + +run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 +on: [push] + +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo " The job was automatically triggered by a ${{ github.event_name }} event." + - uses: actions/checkout@v4 + - uses: actions/setup-python@v1 + - uses: BSFishy/meson-build@v1.0.3 + with: + action: build + action: test + action: tidy + + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v4 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - run: echo "🍏 This job's status is ${{ job.status }}." From 79ade9024889ef9be0eb4833711f4eb0d0dec62b Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 11:46:57 -0700 Subject: [PATCH 091/196] Rename meson_build_and_run to meson.yml --- .github/workflows/{meson_build_and_run => meson.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{meson_build_and_run => meson.yml} (100%) diff --git a/.github/workflows/meson_build_and_run b/.github/workflows/meson.yml similarity index 100% rename from .github/workflows/meson_build_and_run rename to .github/workflows/meson.yml From 6668fa51eecd0b3caac657e3e1252b446f543bc6 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 11:50:31 -0700 Subject: [PATCH 092/196] Delete .github/workflows/c-cpp.yml --- .github/workflows/c-cpp.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/workflows/c-cpp.yml diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml deleted file mode 100644 index fbf32ec92..000000000 --- a/.github/workflows/c-cpp.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: C/C++ CI - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: configure - run: ./configure - - name: make - run: make - - name: make check - run: make check - - name: make distcheck - run: make distcheck From 5c003ecaccbf84550cfa055e9b9f524403854953 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 15:48:18 -0700 Subject: [PATCH 093/196] Fix clang format issues (#1555) --- include/json/allocator.h | 4 +++- include/json/reader.h | 6 +++--- include/json/value.h | 12 ++++++++---- include/json/writer.h | 11 ++++------- src/lib_json/json_reader.cpp | 4 ++-- src/lib_json/json_writer.cpp | 5 +++-- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/json/allocator.h b/include/json/allocator.h index 75406428f..f4fcc1c68 100644 --- a/include/json/allocator.h +++ b/include/json/allocator.h @@ -69,7 +69,9 @@ template class SecureAllocator { // Boilerplate SecureAllocator() {} template SecureAllocator(const SecureAllocator&) {} - template struct rebind { using other = SecureAllocator; }; + template struct rebind { + using other = SecureAllocator; + }; }; template diff --git a/include/json/reader.h b/include/json/reader.h index 46975d86f..10c6a4ff4 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -51,12 +51,12 @@ class JSON_API Reader { }; /** \brief Constructs a Reader allowing all features for parsing. - * \deprecated Use CharReader and CharReaderBuilder. + * \deprecated Use CharReader and CharReaderBuilder. */ Reader(); /** \brief Constructs a Reader allowing the specified feature set for parsing. - * \deprecated Use CharReader and CharReaderBuilder. + * \deprecated Use CharReader and CharReaderBuilder. */ Reader(const Features& features); @@ -272,7 +272,7 @@ class JSON_API CharReader { */ virtual CharReader* newCharReader() const = 0; }; // Factory -}; // CharReader +}; // CharReader /** \brief Build a CharReader implementation. * diff --git a/include/json/value.h b/include/json/value.h index 9a302c161..120dea890 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -586,19 +586,23 @@ class JSON_API Value { iterator end(); /// \brief Returns a reference to the first element in the `Value`. - /// Requires that this value holds an array or json object, with at least one element. + /// Requires that this value holds an array or json object, with at least one + /// element. const Value& front() const; /// \brief Returns a reference to the first element in the `Value`. - /// Requires that this value holds an array or json object, with at least one element. + /// Requires that this value holds an array or json object, with at least one + /// element. Value& front(); /// \brief Returns a reference to the last element in the `Value`. - /// Requires that value holds an array or json object, with at least one element. + /// Requires that value holds an array or json object, with at least one + /// element. const Value& back() const; /// \brief Returns a reference to the last element in the `Value`. - /// Requires that this value holds an array or json object, with at least one element. + /// Requires that this value holds an array or json object, with at least one + /// element. Value& back(); // Accessors for the [start, limit) range of bytes within the JSON text from diff --git a/include/json/writer.h b/include/json/writer.h index 7d8cf4d63..655ebfffb 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -64,7 +64,7 @@ class JSON_API StreamWriter { */ virtual StreamWriter* newStreamWriter() const = 0; }; // Factory -}; // StreamWriter +}; // StreamWriter /** \brief Write into stringstream, then return string, for convenience. * A StreamWriter will be created from the factory, used, and then deleted. @@ -168,8 +168,7 @@ class JSON_API Writer { #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSON_API FastWriter - : public Writer { +class JSON_API FastWriter : public Writer { public: FastWriter(); ~FastWriter() override = default; @@ -228,8 +227,7 @@ class JSON_API FastWriter #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSON_API - StyledWriter : public Writer { +class JSON_API StyledWriter : public Writer { public: StyledWriter(); ~StyledWriter() override = default; @@ -297,8 +295,7 @@ class JSON_API #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSON_API - StyledStreamWriter { +class JSON_API StyledStreamWriter { public: /** * \param indentation Each level will be indented by this amount extra. diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 1ac5e81ab..8dcd2b52e 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -608,7 +608,7 @@ bool Reader::decodeDouble(Token& token, Value& decoded) { value = -std::numeric_limits::infinity(); else if (!std::isinf(value)) return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); + "'" + String(token.start_, token.end_) + "' is not a number.", token); } decoded = value; return true; @@ -1660,7 +1660,7 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { value = -std::numeric_limits::infinity(); else if (!std::isinf(value)) return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); + "'" + String(token.start_, token.end_) + "' is not a number.", token); } decoded = value; return true; diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 0dd160e45..239c429a1 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -132,8 +132,9 @@ String valueToString(double value, bool useSpecialFloats, if (!isfinite(value)) { static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, {"null", "-1e+9999", "1e+9999"}}; - return reps[useSpecialFloats ? 0 : 1] - [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + return reps[useSpecialFloats ? 0 : 1][isnan(value) ? 0 + : (value < 0) ? 1 + : 2]; } String buffer(size_t(36), '\0'); From d2a9495fda6a2c1eb668faf7c997515462dde5d7 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 15:50:23 -0700 Subject: [PATCH 094/196] Delete .travis.yml (#1557) --- .travis.yml | 71 ----------------------------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 23acd4e57..000000000 --- a/.travis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# Build matrix / environment variables are explained on: -# http://about.travis-ci.com/docs/user/build-configuration/ -# This file can be validated on: http://www.yamllint.com/ -# Or using the Ruby based travel command line tool: -# gem install travis --no-rdoc --no-ri -# travis lint .travis.yml -language: cpp -sudo: false -addons: - homebrew: - packages: - - clang-format - - meson - - ninja - update: false # do not update homebrew by default - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 - packages: - - clang-format-8 - - clang-8 - - valgrind -matrix: - include: - - name: Mac clang meson static release testing - os: osx - osx_image: xcode11 - compiler: clang - env: - CXX="clang++" - CC="clang" - LIB_TYPE=static - BUILD_TYPE=release - script: ./.travis_scripts/meson_builder.sh - - name: Linux xenial clang meson static release testing - os: linux - dist: xenial - compiler: clang - env: - CXX="clang++" - CC="clang" - LIB_TYPE=static - BUILD_TYPE=release - PYTHONUSERBASE="$(pwd)/LOCAL" - PATH="$PYTHONUSERBASE/bin:$PATH" - # before_install and install steps only needed for linux meson builds - before_install: - - source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh - install: - - source ./.travis_scripts/travis.install.${TRAVIS_OS_NAME}.sh - script: ./.travis_scripts/meson_builder.sh - - name: Linux xenial gcc cmake coverage - os: linux - dist: xenial - compiler: gcc - env: - CXX=g++ - CC=gcc - DO_Coverage=ON - BUILD_TOOL="Unix Makefiles" - BUILD_TYPE=Debug - LIB_TYPE=shared - DESTDIR=/tmp/cmake_json_cpp - before_install: - - pip install --user cpp-coveralls - script: ./.travis_scripts/cmake_builder.sh - after_success: - - coveralls --include src/lib_json --include include -notifications: - email: false From 73c94501edfb06e8d6503853ae432d6315b1a26c Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 15:50:39 -0700 Subject: [PATCH 095/196] Delete .travis_scripts directory (#1556) --- .travis_scripts/cmake_builder.sh | 130 ------- .travis_scripts/meson_builder.sh | 83 ---- .travis_scripts/run-clang-format.py | 356 ------------------ .travis_scripts/run-clang-format.sh | 4 - .../travis.before_install.linux.sh | 8 - .travis_scripts/travis.before_install.osx.sh | 0 .travis_scripts/travis.install.linux.sh | 5 - .travis_scripts/travis.install.osx.sh | 1 - 8 files changed, 587 deletions(-) delete mode 100755 .travis_scripts/cmake_builder.sh delete mode 100755 .travis_scripts/meson_builder.sh delete mode 100755 .travis_scripts/run-clang-format.py delete mode 100755 .travis_scripts/run-clang-format.sh delete mode 100644 .travis_scripts/travis.before_install.linux.sh delete mode 100644 .travis_scripts/travis.before_install.osx.sh delete mode 100644 .travis_scripts/travis.install.linux.sh delete mode 100644 .travis_scripts/travis.install.osx.sh diff --git a/.travis_scripts/cmake_builder.sh b/.travis_scripts/cmake_builder.sh deleted file mode 100755 index f3d4e46b6..000000000 --- a/.travis_scripts/cmake_builder.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env sh -# This script can be used on the command line directly to configure several -# different build environments. -# This is called by `.travis.yml` via Travis CI. -# Travis supplies $TRAVIS_OS_NAME. -# http://docs.travis-ci.com/user/multi-os/ -# Our .travis.yml also defines: - -# - BUILD_TYPE=Release/Debug -# - LIB_TYPE=static/shared -# -# Optional environmental variables -# - DESTDIR <- used for setting the install prefix -# - BUILD_TOOL=["Unix Makefile"|"Ninja"] -# - BUILDNAME <- how to identify this build on the dashboard -# - DO_MemCheck <- if set, try to use valgrind -# - DO_Coverage <- if set, try to do dashboard coverage testing -# - -env_set=1 -if ${BUILD_TYPE+false}; then - echo "BUILD_TYPE not set in environment." - env_set=0 -fi -if ${LIB_TYPE+false}; then - echo "LIB_TYPE not set in environment." - env_set=0 -fi -if ${CXX+false}; then - echo "CXX not set in environment." - env_set=0 -fi - - -if [ ${env_set} -eq 0 ]; then - echo "USAGE: CXX=$(which clang++) BUILD_TYPE=[Release|Debug] LIB_TYPE=[static|shared] $0" - echo "" - echo "Examples:" - echo " CXX=$(which clang++) BUILD_TYPE=Release LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0" - echo " CXX=$(which clang++) BUILD_TYPE=Debug LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0" - echo " CXX=$(which clang++) BUILD_TYPE=Release LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0" - echo " CXX=$(which clang++) BUILD_TYPE=Debug LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0" - - echo " CXX=$(which g++) BUILD_TYPE=Release LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0" - echo " CXX=$(which g++) BUILD_TYPE=Debug LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0" - echo " CXX=$(which g++) BUILD_TYPE=Release LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0" - echo " CXX=$(which g++) BUILD_TYPE=Debug LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0" - - exit -1 -fi - -if ${DESTDIR+false}; then - DESTDIR="/usr/local" -fi - -# -e: fail on error -# -v: show commands -# -x: show expanded commands -set -vex - -env | sort - -which cmake -cmake --version - -echo ${CXX} -${CXX} --version -_COMPILER_NAME=`basename ${CXX}` -if [ "${LIB_TYPE}" = "shared" ]; then - _CMAKE_BUILD_SHARED_LIBS=ON -else - _CMAKE_BUILD_SHARED_LIBS=OFF -fi - -CTEST_TESTING_OPTION="-D ExperimentalTest" -# - DO_MemCheck <- if set, try to use valgrind -if ! ${DO_MemCheck+false}; then - valgrind --version - CTEST_TESTING_OPTION="-D ExperimentalMemCheck" -else -# - DO_Coverage <- if set, try to do dashboard coverage testing - if ! ${DO_Coverage+false}; then - export CXXFLAGS="-fprofile-arcs -ftest-coverage" - export LDFLAGS="-fprofile-arcs -ftest-coverage" - CTEST_TESTING_OPTION="-D ExperimentalTest -D ExperimentalCoverage" - #gcov --version - fi -fi - -# Ninja = Generates build.ninja files. -if ${BUILD_TOOL+false}; then - BUILD_TOOL="Ninja" - export _BUILD_EXE=ninja - which ninja - ninja --version -else -# Unix Makefiles = Generates standard UNIX makefiles. - export _BUILD_EXE=make -fi - -_BUILD_DIR_NAME="build-cmake_${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}_${_BUILD_EXE}" -mkdir -p ${_BUILD_DIR_NAME} -cd "${_BUILD_DIR_NAME}" - if ${BUILDNAME+false}; then - _HOSTNAME=`hostname -s` - BUILDNAME="${_HOSTNAME}_${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}_${_BUILD_EXE}" - fi - cmake \ - -G "${BUILD_TOOL}" \ - -DBUILDNAME:STRING="${BUILDNAME}" \ - -DCMAKE_CXX_COMPILER:PATH=${CXX} \ - -DCMAKE_BUILD_TYPE:STRING=${BUILD_TYPE} \ - -DBUILD_SHARED_LIBS:BOOL=${_CMAKE_BUILD_SHARED_LIBS} \ - -DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR} \ - ../ - - ctest -C ${BUILD_TYPE} -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild ${CTEST_TESTING_OPTION} -D ExperimentalSubmit - # Final step is to verify that installation succeeds - cmake --build . --config ${BUILD_TYPE} --target install - - if [ "${DESTDIR}" != "/usr/local" ]; then - ${_BUILD_EXE} install - fi -cd - - -if ${CLEANUP+false}; then - echo "Skipping cleanup: build directory will persist." -else - rm -r "${_BUILD_DIR_NAME}" -fi diff --git a/.travis_scripts/meson_builder.sh b/.travis_scripts/meson_builder.sh deleted file mode 100755 index bc74732f6..000000000 --- a/.travis_scripts/meson_builder.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env sh -# This script can be used on the command line directly to configure several -# different build environments. -# This is called by `.travis.yml` via Travis CI. -# Travis supplies $TRAVIS_OS_NAME. -# http://docs.travis-ci.com/user/multi-os/ -# Our .travis.yml also defines: - -# - BUILD_TYPE=release/debug -# - LIB_TYPE=static/shared - -env_set=1 -if ${BUILD_TYPE+false}; then - echo "BUILD_TYPE not set in environment." - env_set=0 -fi -if ${LIB_TYPE+false}; then - echo "LIB_TYPE not set in environment." - env_set=0 -fi -if ${CXX+false}; then - echo "CXX not set in environment." - env_set=0 -fi - - -if [ ${env_set} -eq 0 ]; then - echo "USAGE: CXX=$(which clang++) BUILD_TYPE=[release|debug] LIB_TYPE=[static|shared] $0" - echo "" - echo "Examples:" - echo " CXX=$(which clang++) BUILD_TYPE=release LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0" - echo " CXX=$(which clang++) BUILD_TYPE=debug LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0" - echo " CXX=$(which clang++) BUILD_TYPE=release LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0" - echo " CXX=$(which clang++) BUILD_TYPE=debug LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0" - - echo " CXX=$(which g++) BUILD_TYPE=release LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0" - echo " CXX=$(which g++) BUILD_TYPE=debug LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0" - echo " CXX=$(which g++) BUILD_TYPE=release LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0" - echo " CXX=$(which g++) BUILD_TYPE=debug LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0" - - exit -1 -fi - -if ${DESTDIR+false}; then - DESTDIR="/usr/local" -fi - -# -e: fail on error -# -v: show commands -# -x: show expanded commands -set -vex - - -env | sort - -which python3 -which meson -which ninja -echo ${CXX} -${CXX} --version -python3 --version -meson --version -ninja --version -_COMPILER_NAME=`basename ${CXX}` -_BUILD_DIR_NAME="build-${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}" - -#./.travis_scripts/run-clang-format.sh -meson --fatal-meson-warnings --werror --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . "${_BUILD_DIR_NAME}" -ninja -v -j 2 -C "${_BUILD_DIR_NAME}" - -cd "${_BUILD_DIR_NAME}" - meson test --no-rebuild --print-errorlogs - - if [ "${DESTDIR}" != "/usr/local" ]; then - ninja install - fi -cd - - -if ${CLEANUP+false}; then - echo "Skipping cleanup: build directory will persist." -else - rm -r "${_BUILD_DIR_NAME}" -fi diff --git a/.travis_scripts/run-clang-format.py b/.travis_scripts/run-clang-format.py deleted file mode 100755 index 605b5aad1..000000000 --- a/.travis_scripts/run-clang-format.py +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env python -"""A wrapper script around clang-format, suitable for linting multiple files -and to use for continuous integration. -This is an alternative API for the clang-format command line. -It runs over multiple files and directories in parallel. -A diff output is produced and a sensible exit code is returned. - -NOTE: pulled from https://github.com/Sarcasm/run-clang-format, which is -licensed under the MIT license. -""" - -from __future__ import print_function, unicode_literals - -import argparse -import codecs -import difflib -import fnmatch -import io -import multiprocessing -import os -import signal -import subprocess -import sys -import traceback - -from functools import partial - -try: - from subprocess import DEVNULL # py3k -except ImportError: - DEVNULL = open(os.devnull, "wb") - - -DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx' - - -class ExitStatus: - SUCCESS = 0 - DIFF = 1 - TROUBLE = 2 - - -def list_files(files, recursive=False, extensions=None, exclude=None): - if extensions is None: - extensions = [] - if exclude is None: - exclude = [] - - out = [] - for file in files: - if recursive and os.path.isdir(file): - for dirpath, dnames, fnames in os.walk(file): - fpaths = [os.path.join(dirpath, fname) for fname in fnames] - for pattern in exclude: - # os.walk() supports trimming down the dnames list - # by modifying it in-place, - # to avoid unnecessary directory listings. - dnames[:] = [ - x for x in dnames - if - not fnmatch.fnmatch(os.path.join(dirpath, x), pattern) - ] - fpaths = [ - x for x in fpaths if not fnmatch.fnmatch(x, pattern) - ] - for f in fpaths: - ext = os.path.splitext(f)[1][1:] - if ext in extensions: - out.append(f) - else: - out.append(file) - return out - - -def make_diff(file, original, reformatted): - return list( - difflib.unified_diff( - original, - reformatted, - fromfile='{}\t(original)'.format(file), - tofile='{}\t(reformatted)'.format(file), - n=3)) - - -class DiffError(Exception): - def __init__(self, message, errs=None): - super(DiffError, self).__init__(message) - self.errs = errs or [] - - -class UnexpectedError(Exception): - def __init__(self, message, exc=None): - super(UnexpectedError, self).__init__(message) - self.formatted_traceback = traceback.format_exc() - self.exc = exc - - -def run_clang_format_diff_wrapper(args, file): - try: - ret = run_clang_format_diff(args, file) - return ret - except DiffError: - raise - except Exception as e: - raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__, - e), e) - - -def run_clang_format_diff(args, file): - try: - with io.open(file, 'r', encoding='utf-8') as f: - original = f.readlines() - except IOError as exc: - raise DiffError(str(exc)) - invocation = [args.clang_format_executable, file] - - # Use of utf-8 to decode the process output. - # - # Hopefully, this is the correct thing to do. - # - # It's done due to the following assumptions (which may be incorrect): - # - clang-format will returns the bytes read from the files as-is, - # without conversion, and it is already assumed that the files use utf-8. - # - if the diagnostics were internationalized, they would use utf-8: - # > Adding Translations to Clang - # > - # > Not possible yet! - # > Diagnostic strings should be written in UTF-8, - # > the client can translate to the relevant code page if needed. - # > Each translation completely replaces the format string - # > for the diagnostic. - # > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation - # - # It's not pretty, due to Python 2 & 3 compatibility. - encoding_py3 = {} - if sys.version_info[0] >= 3: - encoding_py3['encoding'] = 'utf-8' - - try: - proc = subprocess.Popen( - invocation, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - **encoding_py3) - except OSError as exc: - raise DiffError( - "Command '{}' failed to start: {}".format( - subprocess.list2cmdline(invocation), exc - ) - ) - proc_stdout = proc.stdout - proc_stderr = proc.stderr - if sys.version_info[0] < 3: - # make the pipes compatible with Python 3, - # reading lines should output unicode - encoding = 'utf-8' - proc_stdout = codecs.getreader(encoding)(proc_stdout) - proc_stderr = codecs.getreader(encoding)(proc_stderr) - # hopefully the stderr pipe won't get full and block the process - outs = list(proc_stdout.readlines()) - errs = list(proc_stderr.readlines()) - proc.wait() - if proc.returncode: - raise DiffError( - "Command '{}' returned non-zero exit status {}".format( - subprocess.list2cmdline(invocation), proc.returncode - ), - errs, - ) - return make_diff(file, original, outs), errs - - -def bold_red(s): - return '\x1b[1m\x1b[31m' + s + '\x1b[0m' - - -def colorize(diff_lines): - def bold(s): - return '\x1b[1m' + s + '\x1b[0m' - - def cyan(s): - return '\x1b[36m' + s + '\x1b[0m' - - def green(s): - return '\x1b[32m' + s + '\x1b[0m' - - def red(s): - return '\x1b[31m' + s + '\x1b[0m' - - for line in diff_lines: - if line[:4] in ['--- ', '+++ ']: - yield bold(line) - elif line.startswith('@@ '): - yield cyan(line) - elif line.startswith('+'): - yield green(line) - elif line.startswith('-'): - yield red(line) - else: - yield line - - -def print_diff(diff_lines, use_color): - if use_color: - diff_lines = colorize(diff_lines) - if sys.version_info[0] < 3: - sys.stdout.writelines((l.encode('utf-8') for l in diff_lines)) - else: - sys.stdout.writelines(diff_lines) - - -def print_trouble(prog, message, use_colors): - error_text = 'error:' - if use_colors: - error_text = bold_red(error_text) - print("{}: {} {}".format(prog, error_text, message), file=sys.stderr) - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - '--clang-format-executable', - metavar='EXECUTABLE', - help='path to the clang-format executable', - default='clang-format') - parser.add_argument( - '--extensions', - help='comma separated list of file extensions (default: {})'.format( - DEFAULT_EXTENSIONS), - default=DEFAULT_EXTENSIONS) - parser.add_argument( - '-r', - '--recursive', - action='store_true', - help='run recursively over directories') - parser.add_argument('files', metavar='file', nargs='+') - parser.add_argument( - '-q', - '--quiet', - action='store_true') - parser.add_argument( - '-j', - metavar='N', - type=int, - default=0, - help='run N clang-format jobs in parallel' - ' (default number of cpus + 1)') - parser.add_argument( - '--color', - default='auto', - choices=['auto', 'always', 'never'], - help='show colored diff (default: auto)') - parser.add_argument( - '-e', - '--exclude', - metavar='PATTERN', - action='append', - default=[], - help='exclude paths matching the given glob-like pattern(s)' - ' from recursive search') - - args = parser.parse_args() - - # use default signal handling, like diff return SIGINT value on ^C - # https://bugs.python.org/issue14229#msg156446 - signal.signal(signal.SIGINT, signal.SIG_DFL) - try: - signal.SIGPIPE - except AttributeError: - # compatibility, SIGPIPE does not exist on Windows - pass - else: - signal.signal(signal.SIGPIPE, signal.SIG_DFL) - - colored_stdout = False - colored_stderr = False - if args.color == 'always': - colored_stdout = True - colored_stderr = True - elif args.color == 'auto': - colored_stdout = sys.stdout.isatty() - colored_stderr = sys.stderr.isatty() - - version_invocation = [args.clang_format_executable, str("--version")] - try: - subprocess.check_call(version_invocation, stdout=DEVNULL) - except subprocess.CalledProcessError as e: - print_trouble(parser.prog, str(e), use_colors=colored_stderr) - return ExitStatus.TROUBLE - except OSError as e: - print_trouble( - parser.prog, - "Command '{}' failed to start: {}".format( - subprocess.list2cmdline(version_invocation), e - ), - use_colors=colored_stderr, - ) - return ExitStatus.TROUBLE - - retcode = ExitStatus.SUCCESS - files = list_files( - args.files, - recursive=args.recursive, - exclude=args.exclude, - extensions=args.extensions.split(',')) - - if not files: - return - - njobs = args.j - if njobs == 0: - njobs = multiprocessing.cpu_count() + 1 - njobs = min(len(files), njobs) - - if njobs == 1: - # execute directly instead of in a pool, - # less overhead, simpler stacktraces - it = (run_clang_format_diff_wrapper(args, file) for file in files) - pool = None - else: - pool = multiprocessing.Pool(njobs) - it = pool.imap_unordered( - partial(run_clang_format_diff_wrapper, args), files) - while True: - try: - outs, errs = next(it) - except StopIteration: - break - except DiffError as e: - print_trouble(parser.prog, str(e), use_colors=colored_stderr) - retcode = ExitStatus.TROUBLE - sys.stderr.writelines(e.errs) - except UnexpectedError as e: - print_trouble(parser.prog, str(e), use_colors=colored_stderr) - sys.stderr.write(e.formatted_traceback) - retcode = ExitStatus.TROUBLE - # stop at the first unexpected error, - # something could be very wrong, - # don't process all files unnecessarily - if pool: - pool.terminate() - break - else: - sys.stderr.writelines(errs) - if outs == []: - continue - if not args.quiet: - print_diff(outs, use_color=colored_stdout) - if retcode == ExitStatus.SUCCESS: - retcode = ExitStatus.DIFF - return retcode - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/.travis_scripts/run-clang-format.sh b/.travis_scripts/run-clang-format.sh deleted file mode 100755 index ded76aaf5..000000000 --- a/.travis_scripts/run-clang-format.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -python $DIR/run-clang-format.py -r $DIR/../src/**/ $DIR/../include/**/ diff --git a/.travis_scripts/travis.before_install.linux.sh b/.travis_scripts/travis.before_install.linux.sh deleted file mode 100644 index 9b556de15..000000000 --- a/.travis_scripts/travis.before_install.linux.sh +++ /dev/null @@ -1,8 +0,0 @@ -set -vex - -# Preinstalled versions of python are dependent on which Ubuntu distribution -# you are running. The below version needs to be updated whenever we roll -# the Ubuntu version used in Travis. -# https://docs.travis-ci.com/user/languages/python/ - -pyenv global 3.7.1 diff --git a/.travis_scripts/travis.before_install.osx.sh b/.travis_scripts/travis.before_install.osx.sh deleted file mode 100644 index e69de29bb..000000000 diff --git a/.travis_scripts/travis.install.linux.sh b/.travis_scripts/travis.install.linux.sh deleted file mode 100644 index 6495fefe9..000000000 --- a/.travis_scripts/travis.install.linux.sh +++ /dev/null @@ -1,5 +0,0 @@ -set -vex - -pip3 install --user meson ninja -which meson -which ninja diff --git a/.travis_scripts/travis.install.osx.sh b/.travis_scripts/travis.install.osx.sh deleted file mode 100644 index 5d83c0c71..000000000 --- a/.travis_scripts/travis.install.osx.sh +++ /dev/null @@ -1 +0,0 @@ -# NOTHING TO DO HERE From c8166ddf1c21f4daa3fb975f51e62d1bdf36e76e Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 16:30:33 -0700 Subject: [PATCH 096/196] add comment space directive (#1558) --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 2a8066958..b7cf99793 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,4 @@ BasedOnStyle: LLVM DerivePointerAlignment: false PointerAlignment: Left - +SpacesBeforeTrailingComments: 1 From 255ebc54af0ebc940ac7d80b789ee77864c8b936 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 16:52:59 -0700 Subject: [PATCH 097/196] Create clang-format.yml --- .github/workflows/clang-format.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/clang-format.yml diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 000000000..50f471696 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,19 @@ +name: clang-format Check +on: [push, pull_request] +jobs: + formatting-check: + name: Formatting Check + runs-on: ubuntu-latest + strategy: + matrix: + path: + - 'src' + - 'examples' + - 'include' + steps: + - uses: actions/checkout@v4 + - name: Run clang-format style check for C/C++/Protobuf programs. + uses: jidicula/clang-format-action@v4.13.0 + with: + clang-format-version: '13' + check-path: ${{ matrix.path }} From cc28be059046a43e631977690efe06472e1477b7 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 16:54:56 -0700 Subject: [PATCH 098/196] Update clang-format.yml --- .github/workflows/clang-format.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 50f471696..a413ecab9 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,8 +1,8 @@ -name: clang-format Check +name: clang-format check on: [push, pull_request] jobs: formatting-check: - name: Formatting Check + name: formatting check runs-on: ubuntu-latest strategy: matrix: @@ -12,7 +12,7 @@ jobs: - 'include' steps: - uses: actions/checkout@v4 - - name: Run clang-format style check for C/C++/Protobuf programs. + - name: runs clang-format style check for C/C++/Protobuf programs. uses: jidicula/clang-format-action@v4.13.0 with: clang-format-version: '13' From 4290915354de66f99ec3e80b4e319f2d6b11c299 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 16:56:02 -0700 Subject: [PATCH 099/196] Update clang-format.yml --- .github/workflows/clang-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index a413ecab9..5f078ff00 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -15,5 +15,5 @@ jobs: - name: runs clang-format style check for C/C++/Protobuf programs. uses: jidicula/clang-format-action@v4.13.0 with: - clang-format-version: '13' + clang-format-version: '18' check-path: ${{ matrix.path }} From ccea7db6c3336ac0410d3f988fbf823f5d2d77da Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 17:07:11 -0700 Subject: [PATCH 100/196] Clang format updates (#1560) * add comment space directive * Fix clang format issue * wrap in clang-format off --- src/test_lib_json/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index a6f21c45a..1ef33bb5a 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3632,12 +3632,12 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { for (const auto& td : test_data) { bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(), &root, &errs); - JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n" - << " expected: {" - << "ok:" << td.ok << ", in:\'" << td.in << "\'" - << "}\n" - << " actual: {" - << "ok:" << ok << "}\n"; + // clang-format off + JSONTEST_ASSERT(td.ok == ok) << + "line:" << td.line << "\n " << + "expected: {ok:" << td.ok << ", in:\'" << td.in << "\'}\n " << + "actual: {ok:" << ok << "}\n"; + // clang-format on } { From 65d92a43136c2b950c0f30425231097678b067f6 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 17:10:48 -0700 Subject: [PATCH 101/196] Update meson.yml (#1554) * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml Switch to clang-format-check * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml Add multilple OSes * Update meson.yml Add ninja version * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml --- .github/workflows/meson.yml | 48 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index 98df7a85a..fbe8138dd 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -1,29 +1,33 @@ -name: Meson Build -uses: BSFishy/meson-build@v1.0.3 - -run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 +name: meson build and test +run-name: update pushed to ${{ github.ref }} on: [push] jobs: - Explore-GitHub-Actions: - runs-on: ubuntu-latest + publish: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + steps: - - run: echo " The job was automatically triggered by a ${{ github.event_name }} event." - - uses: actions/checkout@v4 - - uses: actions/setup-python@v1 - - uses: BSFishy/meson-build@v1.0.3 + - name: checkout repository + uses: actions/checkout@v4 + + - name: setup python + uses: actions/setup-python@v5 + + - name: meson build + uses: BSFishy/meson-build@v1.0.3 with: + meson-version: 1.5.1 + ninja-version: 1.11.1.1 action: build + + - name: meson test + uses: BSFishy/meson-build@v1.0.3 + with: + meson-version: 1.5.1 + ninja-version: 1.11.1.1 action: test - action: tidy - - - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - name: Check out repository code - uses: actions/checkout@v4 - - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - - run: echo "🖥️ The workflow is now ready to test your code on the runner." - - name: List files in the repository - run: | - ls ${{ github.workspace }} - - run: echo "🍏 This job's status is ${{ job.status }}." From 073ad7e96e1b45c7c82ee330da239714f1ac51d4 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 17:19:04 -0700 Subject: [PATCH 102/196] Update meson.yml --- .github/workflows/meson.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index fbe8138dd..8314dbc13 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -1,6 +1,6 @@ name: meson build and test run-name: update pushed to ${{ github.ref }} -on: [push] +on: [check_run, pull_request, push] jobs: publish: From c3a986600f9975a33e3573d85b48db63011d3711 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 17:19:14 -0700 Subject: [PATCH 103/196] Update clang-format.yml --- .github/workflows/clang-format.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 5f078ff00..221f8b839 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,5 +1,6 @@ name: clang-format check -on: [push, pull_request] +on: [check_run, pull_request, push] + jobs: formatting-check: name: formatting check From 0a9b9d9c6ea04847af83c32930176ec42ba6c842 Mon Sep 17 00:00:00 2001 From: vslashg Date: Mon, 9 Sep 2024 20:30:16 -0400 Subject: [PATCH 104/196] Fix a parser bug where tokens are misidentified as commas. (#1502) * Fix a parser bug where tokens are misidentified as commas. In the old and new readers, when parsing an object, a comment followed by any non-`}` token is treated as a comma. The new unit test required changing the runjsontests.py flag regime so that failure tests could be run with default settings. * Honor allowComments==false mode. Much of the comment handling in the parsers is bespoke, and does not honor this flag. By unfiying it under a common API, the parser is simplified and strict mode is now more correctly strict. Note that allowComments mode does not allow for comments in arbitrary locations; they are allowed only in certain positions. Rectifying this is a bigger effort, since collectComments mode requires storing the comments somewhere, and it's not immediately clear where in the DOM all such comments should live. --------- Co-authored-by: Jordan Bayles --- include/json/reader.h | 2 +- src/jsontestrunner/main.cpp | 7 ++- src/lib_json/json_reader.cpp | 74 +++++++++------------------ test/data/fail_strict_comment_01.json | 4 ++ test/data/fail_strict_comment_02.json | 4 ++ test/data/fail_strict_comment_03.json | 3 ++ test/data/fail_test_object_02.json | 1 + test/runjsontests.py | 9 ++-- 8 files changed, 49 insertions(+), 55 deletions(-) create mode 100644 test/data/fail_strict_comment_01.json create mode 100644 test/data/fail_strict_comment_02.json create mode 100644 test/data/fail_strict_comment_03.json create mode 100644 test/data/fail_test_object_02.json diff --git a/include/json/reader.h b/include/json/reader.h index 10c6a4ff4..85539d161 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -190,6 +190,7 @@ class JSON_API Reader { using Errors = std::deque; bool readToken(Token& token); + bool readTokenSkippingComments(Token& token); void skipSpaces(); bool match(const Char* pattern, int patternLength); bool readComment(); @@ -221,7 +222,6 @@ class JSON_API Reader { int& column) const; String getLocationLineAndColumn(Location location) const; void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); static bool containsNewLine(Location begin, Location end); static String normalizeEOL(Location begin, Location end); diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp index df717ffd5..ab6a80039 100644 --- a/src/jsontestrunner/main.cpp +++ b/src/jsontestrunner/main.cpp @@ -240,11 +240,14 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) { return printUsage(argv); } int index = 1; - if (Json::String(argv[index]) == "--json-checker") { - opts->features = Json::Features::strictMode(); + if (Json::String(argv[index]) == "--parse-only") { opts->parseOnly = true; ++index; } + if (Json::String(argv[index]) == "--strict") { + opts->features = Json::Features::strictMode(); + ++index; + } if (Json::String(argv[index]) == "--json-config") { printConfig(); return 3; diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 8dcd2b52e..b12c6b837 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -129,7 +129,7 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, bool successful = readValue(); Token token; - skipCommentTokens(token); + readTokenSkippingComments(token); if (collectComments_ && !commentsBefore_.empty()) root.setComment(commentsBefore_, commentAfter); if (features_.strictRoot_) { @@ -157,7 +157,7 @@ bool Reader::readValue() { throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; - skipCommentTokens(token); + readTokenSkippingComments(token); bool successful = true; if (collectComments_ && !commentsBefore_.empty()) { @@ -225,14 +225,14 @@ bool Reader::readValue() { return successful; } -void Reader::skipCommentTokens(Token& token) { +bool Reader::readTokenSkippingComments(Token& token) { + bool success = readToken(token); if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); + while (success && token.type_ == tokenComment) { + success = readToken(token); + } } + return success; } bool Reader::readToken(Token& token) { @@ -446,12 +446,7 @@ bool Reader::readObject(Token& token) { Value init(objectValue); currentValue().swapPayload(init); currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; + while (readTokenSkippingComments(tokenName)) { if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object return true; name.clear(); @@ -480,15 +475,11 @@ bool Reader::readObject(Token& token) { return recoverFromError(tokenObjectEnd); Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { + if (!readTokenSkippingComments(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) { return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd); } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); if (comma.type_ == tokenObjectEnd) return true; } @@ -518,10 +509,7 @@ bool Reader::readArray(Token& token) { Token currentToken; // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } + ok = readTokenSkippingComments(currentToken); bool badTokenType = (currentToken.type_ != tokenArraySeparator && currentToken.type_ != tokenArrayEnd); if (!ok || badTokenType) { @@ -943,6 +931,7 @@ class OurReader { using Errors = std::deque; bool readToken(Token& token); + bool readTokenSkippingComments(Token& token); void skipSpaces(); void skipBom(bool skipBom); bool match(const Char* pattern, int patternLength); @@ -976,7 +965,6 @@ class OurReader { int& column) const; String getLocationLineAndColumn(Location location) const; void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); static String normalizeEOL(Location begin, Location end); static bool containsNewLine(Location begin, Location end); @@ -1030,7 +1018,7 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, bool successful = readValue(); nodes_.pop(); Token token; - skipCommentTokens(token); + readTokenSkippingComments(token); if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { addError("Extra non-whitespace after JSON value.", token); return false; @@ -1058,7 +1046,7 @@ bool OurReader::readValue() { if (nodes_.size() > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; - skipCommentTokens(token); + readTokenSkippingComments(token); bool successful = true; if (collectComments_ && !commentsBefore_.empty()) { @@ -1145,14 +1133,14 @@ bool OurReader::readValue() { return successful; } -void OurReader::skipCommentTokens(Token& token) { +bool OurReader::readTokenSkippingComments(Token& token) { + bool success = readToken(token); if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); + while (success && token.type_ == tokenComment) { + success = readToken(token); + } } + return success; } bool OurReader::readToken(Token& token) { @@ -1449,12 +1437,7 @@ bool OurReader::readObject(Token& token) { Value init(objectValue); currentValue().swapPayload(init); currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; + while (readTokenSkippingComments(tokenName)) { if (tokenName.type_ == tokenObjectEnd && (name.empty() || features_.allowTrailingCommas_)) // empty object or trailing comma @@ -1491,15 +1474,11 @@ bool OurReader::readObject(Token& token) { return recoverFromError(tokenObjectEnd); Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { + if (!readTokenSkippingComments(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) { return addErrorAndRecover("Missing ',' or '}' in object declaration", comma, tokenObjectEnd); } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); if (comma.type_ == tokenObjectEnd) return true; } @@ -1533,10 +1512,7 @@ bool OurReader::readArray(Token& token) { Token currentToken; // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } + ok = readTokenSkippingComments(currentToken); bool badTokenType = (currentToken.type_ != tokenArraySeparator && currentToken.type_ != tokenArrayEnd); if (!ok || badTokenType) { diff --git a/test/data/fail_strict_comment_01.json b/test/data/fail_strict_comment_01.json new file mode 100644 index 000000000..b7e0a5e75 --- /dev/null +++ b/test/data/fail_strict_comment_01.json @@ -0,0 +1,4 @@ +{ + "a": "aaa", + "b": "bbb" // comments not allowed in strict mode +} diff --git a/test/data/fail_strict_comment_02.json b/test/data/fail_strict_comment_02.json new file mode 100644 index 000000000..699a7f731 --- /dev/null +++ b/test/data/fail_strict_comment_02.json @@ -0,0 +1,4 @@ +{ + "a": "aaa", // comments not allowed in strict mode + "b": "bbb" +} diff --git a/test/data/fail_strict_comment_03.json b/test/data/fail_strict_comment_03.json new file mode 100644 index 000000000..5f0fabf1f --- /dev/null +++ b/test/data/fail_strict_comment_03.json @@ -0,0 +1,3 @@ +{ + "array" : [1, 2, 3 /* comments not allowed in strict mode */] +} diff --git a/test/data/fail_test_object_02.json b/test/data/fail_test_object_02.json new file mode 100644 index 000000000..afe62c5b5 --- /dev/null +++ b/test/data/fail_test_object_02.json @@ -0,0 +1 @@ +{"one": 1 /* } */ { "two" : 2 } diff --git a/test/runjsontests.py b/test/runjsontests.py index 5496e2c58..49cc7a960 100644 --- a/test/runjsontests.py +++ b/test/runjsontests.py @@ -97,14 +97,17 @@ def runAllTests(jsontest_executable_path, input_dir = None, valgrind_path = use_valgrind and VALGRIND_CMD or '' for input_path in tests + test_jsonchecker: expect_failure = os.path.basename(input_path).startswith('fail') - is_json_checker_test = (input_path in test_jsonchecker) or expect_failure + is_json_checker_test = input_path in test_jsonchecker + is_parse_only = is_json_checker_test or expect_failure + is_strict_test = ('_strict_' in os.path.basename(input_path)) or is_json_checker_test print('TESTING:', input_path, end=' ') - options = is_json_checker_test and '--json-checker' or '' + options = is_parse_only and '--parse-only' or '' + options += is_strict_test and ' --strict' or '' options += ' --json-writer %s'%writerClass cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options, input_path) status, process_output = getStatusOutput(cmd) - if is_json_checker_test: + if is_parse_only: if expect_failure: if not status: print('FAILED') From 3c2205cd97838d3c4143107992967e23f0c958b8 Mon Sep 17 00:00:00 2001 From: vslashg Date: Mon, 9 Sep 2024 20:32:17 -0400 Subject: [PATCH 105/196] Fix out-of-bounds read. (#1503) getLocationLIneAndColumn would read past the end of the provided buffer if generating an error message at the end of the stream, if the final character was `\r`. Co-authored-by: Jordan Bayles --- src/lib_json/json_reader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index b12c6b837..86ed030a3 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -761,7 +761,7 @@ void Reader::getLocationLineAndColumn(Location location, int& line, while (current < location && current != end_) { Char c = *current++; if (c == '\r') { - if (*current == '\n') + if (current != end_ && *current == '\n') ++current; lastLineStart = current; ++line; @@ -1801,7 +1801,7 @@ void OurReader::getLocationLineAndColumn(Location location, int& line, while (current < location && current != end_) { Char c = *current++; if (c == '\r') { - if (*current == '\n') + if (current != end_ && *current == '\n') ++current; lastLineStart = current; ++line; From e1a3c64fef7351b49ad612c8b355a42666a7ff44 Mon Sep 17 00:00:00 2001 From: vslashg Date: Mon, 9 Sep 2024 20:34:55 -0400 Subject: [PATCH 106/196] Fix asserts in Value::setComment (#1445) The existing asserts seem to not be what was intended; they appear to have been mistranslated in pull/877. The first assert for `comment.empty()` was previously a check that a provided `const char*` parameter was not null. The function this replaced accepted empty strings, and the if() statement at the start of this function handles them. The second assert for `comment[0] == '\0'` was written when `comment` was a `const char*`, and was testing for empty c-string input. This PR replaces it with `comment.empty()` to match the original intent. Co-authored-by: Jordan Bayles --- src/lib_json/json_value.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index aa2b744ca..26cd843cc 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1410,9 +1410,8 @@ void Value::setComment(String comment, CommentPlacement placement) { // Always discard trailing newline, to aid indentation. comment.pop_back(); } - JSON_ASSERT(!comment.empty()); JSON_ASSERT_MESSAGE( - comment[0] == '\0' || comment[0] == '/', + comment.empty() || comment[0] == '/', "in Json::Value::setComment(): Comments must start with /"); comments_.set(placement, std::move(comment)); } From 034976a19dbd7ffe37aa1c3821855d4cde868fcb Mon Sep 17 00:00:00 2001 From: Philip Top Date: Mon, 9 Sep 2024 17:38:22 -0700 Subject: [PATCH 107/196] add a valueToQuotedString overload (#1397) * add a valueToQuotedString overload to take a string length to support things like a string_view more directly. * Apply suggestions from code review Co-authored-by: Billy Donahue --------- Co-authored-by: Billy Donahue Co-authored-by: Jordan Bayles --- include/json/writer.h | 1 + src/lib_json/json_writer.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/json/writer.h b/include/json/writer.h index 655ebfffb..7c56a2107 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -351,6 +351,7 @@ String JSON_API valueToString( PrecisionType precisionType = PrecisionType::significantDigits); String JSON_API valueToString(bool value); String JSON_API valueToQuotedString(const char* value); +String JSON_API valueToQuotedString(const char* value, size_t length); /// \brief Output using the StyledStreamWriter. /// \see Json::operator>>() diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 239c429a1..5bb5dd117 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -354,6 +354,10 @@ String valueToQuotedString(const char* value) { return valueToQuotedStringN(value, strlen(value)); } +String valueToQuotedString(const char* value, size_t length) { + return valueToQuotedStringN(value, length); +} + // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() = default; @@ -491,7 +495,7 @@ void StyledWriter::writeValue(const Value& value) { const String& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); + writeWithIndent(valueToQuotedString(name.c_str(), name.size())); document_ += " : "; writeValue(childValue); if (++it == members.end()) { @@ -709,7 +713,7 @@ void StyledStreamWriter::writeValue(const Value& value) { const String& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); + writeWithIndent(valueToQuotedString(name.c_str(), name.size())); *document_ << " : "; writeValue(childValue); if (++it == members.end()) { From 78893d396180bc558dc3b204fae929f0714748a6 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 18:19:48 -0700 Subject: [PATCH 108/196] Update clang-format.yml --- .github/workflows/clang-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 221f8b839..497b9d64e 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,5 +1,5 @@ name: clang-format check -on: [check_run, pull_request, push] +on: [check_run, push] jobs: formatting-check: From 57de64bf69f3e8fc715bfeb4dbe0bca27b6c4862 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 18:29:28 -0700 Subject: [PATCH 109/196] Add code coverage (#1561) * Add code coverage * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml * Update meson.yml --- .github/workflows/meson.yml | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index 8314dbc13..1899470f2 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -1,6 +1,6 @@ name: meson build and test run-name: update pushed to ${{ github.ref }} -on: [check_run, pull_request, push] +on: [check_run, push] jobs: publish: @@ -31,3 +31,35 @@ jobs: meson-version: 1.5.1 ninja-version: 1.11.1.1 action: test + + coverage: + runs-on: ubuntu-latest + + steps: + - name: checkout repository + uses: actions/checkout@v4 + + - name: setup python + uses: actions/setup-python@v5 + + - name: meson build + uses: BSFishy/meson-build@v1.0.3 + with: + meson-version: 1.5.1 + ninja-version: 1.11.1.1 + setup-options: -Db_coverage=true + action: build + + - name: meson test + uses: BSFishy/meson-build@v1.0.3 + with: + meson-version: 1.5.1 + ninja-version: 1.11.1.1 + setup-options: -Db_coverage=true + action: test + + - name: generate code coverage report + uses: threeal/gcovr-action@v1.0.0 + with: + coveralls-send: true + github-token: ${{ secrets.GITHUB_TOKEN }} From caf5fb0742e99c35abdfb127dde749138adc2715 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 18:35:36 -0700 Subject: [PATCH 110/196] Update meson.yml (#1562) --- .github/workflows/meson.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index 1899470f2..48d496c73 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -1,6 +1,6 @@ name: meson build and test run-name: update pushed to ${{ github.ref }} -on: [check_run, push] +on: [check_run, push, pull_request] jobs: publish: From badbbc7185cde8270e6005bcdb6686363fe00557 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 18:35:49 -0700 Subject: [PATCH 111/196] Update clang-format.yml --- .github/workflows/clang-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 497b9d64e..221f8b839 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,5 +1,5 @@ name: clang-format check -on: [check_run, push] +on: [check_run, pull_request, push] jobs: formatting-check: From fd1abe4cca7f496438f92d797371dabe14e49373 Mon Sep 17 00:00:00 2001 From: Andrea Pappacoda Date: Tue, 10 Sep 2024 03:42:23 +0200 Subject: [PATCH 112/196] build(meson): use find_program('python3') (#1386) If you really want to be sure to always find python3 when running Meson (and not some other implementation like [Muon](https://muon.build)) it is a bit better to use `find_program('python3')`, as described in https://mesonbuild.com/Reference-manual_functions.html#find_program : "if the "python3" program is requested and it is not found in the system, Meson will return its current interpreter Co-authored-by: Jordan Bayles --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index f68db30dd..fb2b47cd9 100644 --- a/meson.build +++ b/meson.build @@ -73,7 +73,7 @@ if meson.is_subproject() or not get_option('tests') subdir_done() endif -python = import('python').find_installation() +python = find_program('python3') jsoncpp_test = executable( 'jsoncpp_test', files([ From d39b0dff0c5673ed6b21a7808773cd45b661aae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20R=C3=B6hling?= Date: Tue, 10 Sep 2024 03:42:54 +0200 Subject: [PATCH 113/196] Bump CMake policy version to avoid deprecation warning (#1499) Starting with CMake 3.27, there will be a warning for compat levels below CMake 3.5. Co-authored-by: Jordan Bayles --- jsoncppConfig.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in index 76570bc30..fdd9fea6b 100644 --- a/jsoncppConfig.cmake.in +++ b/jsoncppConfig.cmake.in @@ -1,5 +1,5 @@ cmake_policy(PUSH) -cmake_policy(VERSION 3.0) +cmake_policy(VERSION 3.0...3.26) @PACKAGE_INIT@ From c857395951c1d5e80b0ac62f760d698f03b209f2 Mon Sep 17 00:00:00 2001 From: NotWearingPants <26556598+NotWearingPants@users.noreply.github.com> Date: Tue, 10 Sep 2024 04:43:32 +0300 Subject: [PATCH 114/196] Update link in amalgamate.py (#1335) --- amalgamate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/amalgamate.py b/amalgamate.py index 4a328ab5a..1d1e48810 100755 --- a/amalgamate.py +++ b/amalgamate.py @@ -63,7 +63,7 @@ def amalgamate_source(source_top_dir=None, """ print("Amalgamating header...") header = AmalgamationFile(source_top_dir) - header.add_text("/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/).") + header.add_text("/// Json-cpp amalgamated header (https://github.com/open-source-parsers/jsoncpp/).") header.add_text('/// It is intended to be used with #include "%s"' % header_include_path) header.add_file("LICENSE", wrap_in_comment=True) header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED") @@ -90,7 +90,7 @@ def amalgamate_source(source_top_dir=None, forward_header_include_path = base + "-forwards" + ext print("Amalgamating forward header...") header = AmalgamationFile(source_top_dir) - header.add_text("/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).") + header.add_text("/// Json-cpp amalgamated forward header (https://github.com/open-source-parsers/jsoncpp/).") header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path) header.add_text("/// This header provides forward declaration for all JsonCpp types.") header.add_file("LICENSE", wrap_in_comment=True) @@ -112,7 +112,7 @@ def amalgamate_source(source_top_dir=None, print("Amalgamating source...") source = AmalgamationFile(source_top_dir) - source.add_text("/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).") + source.add_text("/// Json-cpp amalgamated source (https://github.com/open-source-parsers/jsoncpp/).") source.add_text('/// It is intended to be used with #include "%s"' % header_include_path) source.add_file("LICENSE", wrap_in_comment=True) source.add_text("") From c04c0c2131e2c0e90eb731b58877eef39bcf8e47 Mon Sep 17 00:00:00 2001 From: martinduffy1 <106178409+martinduffy1@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:48:54 -0400 Subject: [PATCH 115/196] CharReader: Add StructuredError (#1409) * CharReader: Add Structured Error Add getStructuredError to CharReader * run clang format --------- Co-authored-by: Jordan Bayles Co-authored-by: Jordan Bayles --- include/json/reader.h | 27 +++++++++++++++- src/lib_json/json_reader.cpp | 60 ++++++++++++++++++++++++------------ src/test_lib_json/main.cpp | 30 ++++++++++++++++++ 3 files changed, 97 insertions(+), 20 deletions(-) diff --git a/include/json/reader.h b/include/json/reader.h index 85539d161..38b9360cf 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -244,6 +244,12 @@ class JSON_API Reader { */ class JSON_API CharReader { public: + struct JSON_API StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + virtual ~CharReader() = default; /** \brief Read a Value from a JSON * document. The document must be a UTF-8 encoded string containing the @@ -262,7 +268,12 @@ class JSON_API CharReader { * error occurred. */ virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) = 0; + String* errs); + + /** \brief Returns a vector of structured errors encountered while parsing. + * Each parse call resets the stored list of errors. + */ + std::vector getStructuredErrors() const; class JSON_API Factory { public: @@ -272,6 +283,20 @@ class JSON_API CharReader { */ virtual CharReader* newCharReader() const = 0; }; // Factory + +protected: + class Impl { + public: + virtual ~Impl() = default; + virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) = 0; + virtual std::vector getStructuredErrors() const = 0; + }; + + explicit CharReader(std::unique_ptr impl) : _impl(std::move(impl)) {} + +private: + std::unique_ptr _impl; }; // CharReader /** \brief Build a CharReader implementation. diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 86ed030a3..4ab4dffd3 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -878,17 +878,12 @@ class OurReader { public: using Char = char; using Location = const Char*; - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - String message; - }; explicit OurReader(OurFeatures const& features); bool parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments = true); String getFormattedErrorMessages() const; - std::vector getStructuredErrors() const; + std::vector getStructuredErrors() const; private: OurReader(OurReader const&); // no impl @@ -1836,10 +1831,11 @@ String OurReader::getFormattedErrorMessages() const { return formattedMessage; } -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; +std::vector +OurReader::getStructuredErrors() const { + std::vector allErrors; for (const auto& error : errors_) { - OurReader::StructuredError structured; + CharReader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; structured.message = error.message_; @@ -1849,20 +1845,36 @@ std::vector OurReader::getStructuredErrors() const { } class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; public: OurCharReader(bool collectComments, OurFeatures const& features) - : collectComments_(collectComments), reader_(features) {} - bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) override { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); + : CharReader( + std::unique_ptr(new OurImpl(collectComments, features))) {} + +protected: + class OurImpl : public Impl { + public: + OurImpl(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + + bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) override { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; } - return ok; - } + + std::vector + getStructuredErrors() const override { + return reader_.getStructuredErrors(); + } + + private: + bool const collectComments_; + OurReader reader_; + }; }; CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } @@ -1952,6 +1964,16 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) { //! [CharReaderBuilderDefaults] } +std::vector +CharReader::getStructuredErrors() const { + return _impl->getStructuredErrors(); +} + +bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) { + return _impl->parse(beginDoc, endDoc, root, errs); +} + ////////////////////////////////// // global functions diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 1ef33bb5a..fa41d19ed 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3917,6 +3917,36 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) { example.size())); } +struct ParseWithStructuredErrorsTest : JsonTest::TestCase { + void testErrors( + const std::string& doc, bool success, + const std::vector& expectedErrors) { + Json::CharReaderBuilder b; + CharReaderPtr reader(b.newCharReader()); + Json::Value root; + JSONTEST_ASSERT_EQUAL( + reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr), + success); + auto actualErrors = reader->getStructuredErrors(); + JSONTEST_ASSERT_EQUAL(expectedErrors.size(), actualErrors.size()); + for (std::size_t i = 0; i < actualErrors.size(); i++) { + const auto& a = actualErrors[i]; + const auto& e = expectedErrors[i]; + JSONTEST_ASSERT_EQUAL(a.offset_start, e.offset_start); + JSONTEST_ASSERT_EQUAL(a.offset_limit, e.offset_limit); + JSONTEST_ASSERT_STRING_EQUAL(a.message, e.message); + } + } +}; + +JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) { + testErrors("{}", true, {}); +} + +JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) { + testErrors("{ 1 : 2 }", false, {{2, 3, "Missing '}' or object member name"}}); +} + int main(int argc, const char* argv[]) { JsonTest::Runner runner; From 483f1c310e36db6d53868f9a4f8b9c0f90faba5b Mon Sep 17 00:00:00 2001 From: Pavel Tsynk <36221942+TsynkPavel@users.noreply.github.com> Date: Tue, 10 Sep 2024 08:50:38 +0700 Subject: [PATCH 116/196] Fix compile on windows with clang (#1480) Co-authored-by: Jordan Bayles --- src/lib_json/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 3cf66eb34..ce8100b29 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -144,7 +144,7 @@ if(BUILD_STATIC_LIBS) # avoid name clashes on windows as the shared import lib is also named jsoncpp.lib if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) - if (MSVC) + if (WIN32) set(STATIC_SUFFIX "_static") else() set(STATIC_SUFFIX "") From 31754ce2e25056c0bbf6599c49059d2778e9109c Mon Sep 17 00:00:00 2001 From: Pavel Tsynk <36221942+TsynkPavel@users.noreply.github.com> Date: Tue, 10 Sep 2024 08:51:11 +0700 Subject: [PATCH 117/196] Fixed setting JSONCPP_USE_SECURE_MEMORY definition (#1479) * Fixed setting JSONCPP_USE_SECURE_MEMORY definition * fix indent * Fix passing from command line * simplified definition --------- Co-authored-by: Jordan Bayles --- CMakeLists.txt | 4 +++- include/json/version.h | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8920544a3..ac0a8eda2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,9 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.") endif() -set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL") +if(JSONCPP_USE_SECURE_MEMORY) + add_definitions("-DJSONCPP_USE_SECURE_MEMORY=1") +endif() configure_file("${PROJECT_SOURCE_DIR}/version.in" "${PROJECT_BINARY_DIR}/version" diff --git a/include/json/version.h b/include/json/version.h index e931d0383..9e9541191 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -18,10 +18,9 @@ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ (JSONCPP_VERSION_PATCH << 8)) -#ifdef JSONCPP_USING_SECURE_MEMORY -#undef JSONCPP_USING_SECURE_MEMORY -#endif +#if !defined(JSONCPP_USE_SECURE_MEMORY) #define JSONCPP_USING_SECURE_MEMORY 0 +#endif // If non-zero, the library zeroes any memory that it has allocated before // it frees its memory. From 742c645ab31088f95edd112ffc65eca839cdf8ff Mon Sep 17 00:00:00 2001 From: Kapandaria Date: Tue, 10 Sep 2024 04:51:35 +0300 Subject: [PATCH 118/196] Update readFromString.cpp (#1477) Print the error to screen Co-authored-by: Jordan Bayles --- example/readFromString/readFromString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/readFromString/readFromString.cpp b/example/readFromString/readFromString.cpp index 0b29a4e86..878f9eb92 100644 --- a/example/readFromString/readFromString.cpp +++ b/example/readFromString/readFromString.cpp @@ -25,7 +25,7 @@ int main() { const std::unique_ptr reader(builder.newCharReader()); if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, &err)) { - std::cout << "error" << std::endl; + std::cout << "error: " << err << std::endl; return EXIT_FAILURE; } } From 62f7f3efe650dde5f6075a8dcecbfe358ba530e8 Mon Sep 17 00:00:00 2001 From: Pedro Kaj Kjellerup Nacht Date: Mon, 9 Sep 2024 22:53:23 -0300 Subject: [PATCH 119/196] Add security policy (#1484) Signed-off-by: Pedro Kaj Kjellerup Nacht --- SECURITY.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..67af8830b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it +privately. **Do not disclose it as a public issue.** This gives us time to work with you +to fix the issue before public exposure, reducing the chance that the exploit will be +used before a patch is released. + +Please submit the report by filling out +[this form](https://github.com/open-source-parsers/jsoncpp/security/advisories/new). + +Please provide the following information in your report: + +- A description of the vulnerability and its impact +- How to reproduce the issue + +This project is maintained by volunteers on a reasonable-effort basis. As such, +we ask that you give us 90 days to work on a fix before public exposure. From a4a083c30751a178b7cdfe1bee685d0ec1c2ed28 Mon Sep 17 00:00:00 2001 From: SpaceIm <30052553+SpaceIm@users.noreply.github.com> Date: Tue, 10 Sep 2024 03:57:51 +0200 Subject: [PATCH 120/196] remove ccache micro management (#1448) Co-authored-by: Jordan Bayles --- CMakeLists.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac0a8eda2..a37e726f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,16 +54,6 @@ endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -# --------------------------------------------------------------------------- -# use ccache if found, has to be done before project() -# --------------------------------------------------------------------------- -find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin) -if(CCACHE_EXECUTABLE) - message(STATUS "use ccache") - set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) - set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) -endif() - project(jsoncpp # Note: version must be updated in three places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the From d791737ccd74beb4c6bf3f0fa499db74c2791192 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 19:05:11 -0700 Subject: [PATCH 121/196] Create cmake.yml (#1563) * Create cmake.yml * Update cmake.yml * Update cmake.yml --- .github/workflows/cmake.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/cmake.yml diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 000000000..675493b8f --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,18 @@ +name: cmake +on: [push] +jobs: + publish: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: checkout project + uses: actions/checkout@v4 + + - name: build project + uses: threeal/cmake-action@v2.0.0 + From d13801e83239924c281119316aefb8f611d9bfd0 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 19:06:30 -0700 Subject: [PATCH 122/196] Update meson.yml (#1564) --- .github/workflows/meson.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index 48d496c73..22fe32f72 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -3,7 +3,7 @@ run-name: update pushed to ${{ github.ref }} on: [check_run, push, pull_request] jobs: - publish: + meson-publish: runs-on: ${{ matrix.os }} strategy: @@ -32,7 +32,7 @@ jobs: ninja-version: 1.11.1.1 action: test - coverage: + meson-coverage: runs-on: ubuntu-latest steps: From 8d1ea7054f4a0984fc84e406f9253b9cafacd64a Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Sep 2024 19:07:04 -0700 Subject: [PATCH 123/196] Update cmake.yml --- .github/workflows/cmake.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 675493b8f..91f387a50 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -1,7 +1,7 @@ name: cmake -on: [push] +on: [check_run, push, pull_request] jobs: - publish: + cmake-publish: runs-on: ${{ matrix.os }} strategy: From fdb529bd0613308591352ac1d4e765c4d33710c9 Mon Sep 17 00:00:00 2001 From: jedav Date: Mon, 9 Sep 2024 19:53:56 -0700 Subject: [PATCH 124/196] Move removeIndex's result instead of copying (#1516) Currently removeIndex copies the removed value into removed and then destructs the original, which can cause significant performance overhead. Co-authored-by: Jordan Bayles --- src/lib_json/json_value.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 26cd843cc..a5e2dd8e4 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1205,7 +1205,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) { return false; } if (removed) - *removed = it->second; + *removed = std::move(it->second); ArrayIndex oldSize = size(); // shift left all items left, into the place of the "removed" for (ArrayIndex i = index; i < (oldSize - 1); ++i) { From 2072e2b4e394f90ca9cbea32db53231900c01618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Tue, 10 Sep 2024 04:56:37 +0200 Subject: [PATCH 125/196] Use current source / binary dir when assuring out of source builds (#1527) Co-authored-by: Jordan Bayles --- include/PreventInSourceBuilds.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/PreventInSourceBuilds.cmake b/include/PreventInSourceBuilds.cmake index 7ddda546a..be5d0dd41 100644 --- a/include/PreventInSourceBuilds.cmake +++ b/include/PreventInSourceBuilds.cmake @@ -2,8 +2,8 @@ # This function will prevent in-source builds function(AssureOutOfSourceBuilds) # make sure the user doesn't play dirty with symlinks - get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) - get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + get_filename_component(srcdir "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_CURRENT_BINARY_DIR}" REALPATH) # disallow in-source builds if("${srcdir}" STREQUAL "${bindir}") From 48d2e106a71b91a1259127ae0ca4d759e11ea890 Mon Sep 17 00:00:00 2001 From: Bartosz Brachaczek Date: Tue, 10 Sep 2024 05:00:06 +0200 Subject: [PATCH 126/196] Opportunistically take advantage of C++20 move-in/out-of stringstream (#1457) * Opportunistically take advantage of C++20 move-out-of stringstream * Opportunistically take advantage of C++20 move-in/out-of stringstream --------- Co-authored-by: Jordan Bayles --- src/lib_json/json_reader.cpp | 8 +++----- src/lib_json/json_writer.cpp | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 4ab4dffd3..8ef29f07c 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -587,8 +587,7 @@ bool Reader::decodeDouble(Token& token) { bool Reader::decodeDouble(Token& token, Value& decoded) { double value = 0; - String buffer(token.start_, token.end_); - IStringStream is(buffer); + IStringStream is(String(token.start_, token.end_)); if (!(is >> value)) { if (value == std::numeric_limits::max()) value = std::numeric_limits::infinity(); @@ -1622,8 +1621,7 @@ bool OurReader::decodeDouble(Token& token) { bool OurReader::decodeDouble(Token& token, Value& decoded) { double value = 0; - const String buffer(token.start_, token.end_); - IStringStream is(buffer); + IStringStream is(String(token.start_, token.end_)); if (!(is >> value)) { if (value == std::numeric_limits::max()) value = std::numeric_limits::infinity(); @@ -1981,7 +1979,7 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, String* errs) { OStringStream ssin; ssin << sin.rdbuf(); - String doc = ssin.str(); + String doc = std::move(ssin).str(); char const* begin = doc.data(); char const* end = begin + doc.size(); // Note that we do not actually need a null-terminator. diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 5bb5dd117..ee45c43ba 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -1251,7 +1251,7 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) { OStringStream sout; StreamWriterPtr const writer(factory.newStreamWriter()); writer->write(root, &sout); - return sout.str(); + return std::move(sout).str(); } OStream& operator<<(OStream& sout, Value const& root) { From fa0dff18fdef3dc7cd0ab0376a2aa19f878dbbc2 Mon Sep 17 00:00:00 2001 From: Roelof Oomen Date: Tue, 10 Sep 2024 05:02:24 +0200 Subject: [PATCH 127/196] Protect target JsonCpp::JsonCpp against multi-include (#1435) * Protect target JsonCpp::JsonCpp against multi-include Fixes #1356 * Simplify (@BillyDonahue) --------- Co-authored-by: Jordan Bayles --- jsoncpp-namespaced-targets.cmake | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/jsoncpp-namespaced-targets.cmake b/jsoncpp-namespaced-targets.cmake index ac1504e00..70a79ee7f 100644 --- a/jsoncpp-namespaced-targets.cmake +++ b/jsoncpp-namespaced-targets.cmake @@ -1,7 +1,9 @@ -if (TARGET jsoncpp_static) - add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) - set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_static") -elseif (TARGET jsoncpp_lib) - add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) - set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_lib") -endif () \ No newline at end of file +if (NOT TARGET JsonCpp::JsonCpp) + if (TARGET jsoncpp_static) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_static") + elseif (TARGET jsoncpp_lib) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_lib") + endif () +endif () From f4590227862e62264b98b88fd8c82558002f9df7 Mon Sep 17 00:00:00 2001 From: matthieugleg <156894466+matthieugleg@users.noreply.github.com> Date: Tue, 10 Sep 2024 05:06:22 +0200 Subject: [PATCH 128/196] Update CMakeLists.txt (#1528) Remove build directory from include Co-authored-by: Jordan Bayles --- src/lib_json/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index ce8100b29..152635348 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -132,7 +132,6 @@ if(BUILD_SHARED_LIBS) target_include_directories(${SHARED_LIB} PUBLIC $ $ - $ ) list(APPEND CMAKE_TARGETS ${SHARED_LIB}) @@ -166,7 +165,6 @@ if(BUILD_STATIC_LIBS) target_include_directories(${STATIC_LIB} PUBLIC $ $ - $ ) list(APPEND CMAKE_TARGETS ${STATIC_LIB}) @@ -193,7 +191,6 @@ if(BUILD_OBJECT_LIBS) target_include_directories(${OBJECT_LIB} PUBLIC $ $ - $ ) list(APPEND CMAKE_TARGETS ${OBJECT_LIB}) From 4b1bd4405e0d5ebfcc6252f0246e28d56290611e Mon Sep 17 00:00:00 2001 From: Woodrow Douglass Date: Mon, 9 Sep 2024 23:08:12 -0400 Subject: [PATCH 129/196] Create a jsoncppConfig.cmake file, even if building under meson (#1486) * Create a jsoncppConfig.cmake file, even if building under meson * Hardcode many fewer things in the meson-generated cmake files * use join_paths for constructing paths in the output Config.cmake --------- Co-authored-by: Jordan Bayles --- jsoncppConfig.cmake.meson.in | 8 ++++++++ meson.build | 39 +++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 jsoncppConfig.cmake.meson.in diff --git a/jsoncppConfig.cmake.meson.in b/jsoncppConfig.cmake.meson.in new file mode 100644 index 000000000..0f4866d6d --- /dev/null +++ b/jsoncppConfig.cmake.meson.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +@MESON_SHARED_TARGET@ +@MESON_STATIC_TARGET@ + +include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" ) + +check_required_components(JsonCpp) diff --git a/meson.build b/meson.build index fb2b47cd9..80703618f 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ project( 'cpp_std=c++11', 'warning_level=1'], license : 'Public Domain', - meson_version : '>= 0.49.0') + meson_version : '>= 0.54.0') jsoncpp_headers = files([ @@ -62,6 +62,43 @@ import('pkgconfig').generate( filebase : 'jsoncpp', description : 'A C++ library for interacting with JSON') +cmakeconf = configuration_data() +cmakeconf.set('MESON_LIB_DIR', get_option('libdir')) +cmakeconf.set('MESON_INCLUDE_DIR', get_option('includedir')) + +fs = import('fs') +if get_option('default_library') == 'shared' + shared_name = fs.name(jsoncpp_lib.full_path()) +endif +if get_option('default_library') == 'static' + static_name = fs.name(jsoncpp_lib.full_path()) +endif +if get_option('default_library') == 'both' + shared_name = fs.name(jsoncpp_lib.get_shared_lib().full_path()) + static_name = fs.name(jsoncpp_lib.get_static_lib().full_path()) +endif + +if get_option('default_library') == 'shared' or get_option('default_library') == 'both' + cmakeconf.set('MESON_SHARED_TARGET', ''' +add_library(jsoncpp_lib IMPORTED SHARED) +set_target_properties(jsoncpp_lib PROPERTIES + IMPORTED_LOCATION "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('libdir'), shared_name) + '''" + INTERFACE_INCLUDE_DIRECTORIES "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('includedir')) + '")') +endif +if get_option('default_library') == 'static' or get_option('default_library') == 'both' + cmakeconf.set('MESON_STATIC_TARGET', ''' +add_library(jsoncpp_static IMPORTED STATIC) +set_target_properties(jsoncpp_static PROPERTIES + IMPORTED_LOCATION "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('libdir'), static_name) + '''" + INTERFACE_INCLUDE_DIRECTORIES "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('includedir')) + '")') +endif + +import('cmake').configure_package_config_file( + name: 'jsoncpp', + input: 'jsoncppConfig.cmake.meson.in', + configuration: cmakeconf) +install_data('jsoncpp-namespaced-targets.cmake', install_dir : join_paths(get_option('libdir'), 'cmake', jsoncpp_lib.name())) + # for libraries bundling jsoncpp jsoncpp_dep = declare_dependency( include_directories : jsoncpp_include_directories, From 162ead383d1fc920a01b2f333e6e69fa089c2541 Mon Sep 17 00:00:00 2001 From: Kerem TAN <56820099+KeremTAN@users.noreply.github.com> Date: Tue, 10 Sep 2024 06:08:55 +0300 Subject: [PATCH 130/196] include/json/value.h is changed (#1462) Co-authored-by: Jordan Bayles --- include/json/value.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 120dea890..f1232c47f 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -3,8 +3,8 @@ // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE -#ifndef JSON_H_INCLUDED -#define JSON_H_INCLUDED +#ifndef JSON_VALUE_H_INCLUDED +#define JSON_VALUE_H_INCLUDED #if !defined(JSON_IS_AMALGAMATION) #include "forwards.h" From 99e8ca69b129ff0b65bded458404820c6a35d898 Mon Sep 17 00:00:00 2001 From: Rudi Heitbaum Date: Tue, 10 Sep 2024 13:09:10 +1000 Subject: [PATCH 131/196] meson.build: fix the version number (#1432) Co-authored-by: Jordan Bayles --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 80703618f..e6ba08c47 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - version : '1.9.4', + version : '1.9.5', default_options : [ 'buildtype=release', 'cpp_std=c++11', From 3aa1192a0071ba640f249566c1d4ba2cf391a21c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 10 Sep 2024 05:11:44 +0200 Subject: [PATCH 132/196] Introduce CharReaderBuilder::ecma404Mode (#1333) * Introduce CharReaderBuilder::ecma404Mode * Bump micro version --------- Co-authored-by: Jordan Bayles Co-authored-by: Billy Donahue Co-authored-by: Jordan Bayles --- CMakeLists.txt | 4 ++-- include/json/reader.h | 6 ++++++ include/json/version.h | 4 ++-- meson.build | 4 ++-- src/lib_json/json_reader.cpp | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a37e726f7..f11425c08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,11 +62,11 @@ project(jsoncpp # 2. ./include/json/version.h # 3. ./CMakeLists.txt # IMPORTANT: also update the PROJECT_SOVERSION!! - VERSION 1.9.5 # [.[.[.]]] + VERSION 1.9.6 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(PROJECT_SOVERSION 25) +set(PROJECT_SOVERSION 26) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) diff --git a/include/json/reader.h b/include/json/reader.h index 38b9360cf..d745378fc 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -385,6 +385,12 @@ class JSON_API CharReaderBuilder : public CharReader::Factory { * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode */ static void strictMode(Json::Value* settings); + /** ECMA-404 mode. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode + */ + static void ecma404Mode(Json::Value* settings); }; /** Consume entire stream and use its begin/end. diff --git a/include/json/version.h b/include/json/version.h index 9e9541191..38faedf11 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -9,10 +9,10 @@ // 3. /CMakeLists.txt // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "1.9.5" +#define JSONCPP_VERSION_STRING "1.9.6" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 5 +#define JSONCPP_VERSION_PATCH 6 #define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ diff --git a/meson.build b/meson.build index e6ba08c47..561b41ce7 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - version : '1.9.5', + version : '1.9.6', default_options : [ 'buildtype=release', 'cpp_std=c++11', @@ -50,7 +50,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 25, + soversion : 26, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 8ef29f07c..10c97aecb 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -1961,6 +1961,22 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) { (*settings)["skipBom"] = true; //! [CharReaderBuilderDefaults] } +// static +void CharReaderBuilder::ecma404Mode(Json::Value* settings) { + //! [CharReaderBuilderECMA404Mode] + (*settings)["allowComments"] = false; + (*settings)["allowTrailingCommas"] = false; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; + (*settings)["skipBom"] = false; + //! [CharReaderBuilderECMA404Mode] +} std::vector CharReader::getStructuredErrors() const { From 2067f66d662ef0925733ba95595a3cf988a2d32d Mon Sep 17 00:00:00 2001 From: zeroxia Date: Tue, 10 Sep 2024 11:14:17 +0800 Subject: [PATCH 133/196] cmake export configuration: allow repeating find_package(jsoncpp) calls (#1491) In jsoncpp-namspaced-targets.cmake, it creates JsonCpp::JsonCpp imported library without first checking whether it was already created by former call to find_package(JsonCpp). As CMake allows repeated call to find_package(), the error of "another target with the same name already exists" should be fixed. Co-authored-by: xiazuoling.xzl Co-authored-by: Jordan Bayles From 7f36cdb3ead60cdc77ec4e6a104bd2f653730b30 Mon Sep 17 00:00:00 2001 From: Timofey <45315126+petukhovtd@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:14:36 +0700 Subject: [PATCH 134/196] Added Value::find with String key (#1467) * Added Value::find with String key * Fix codestyle --------- Co-authored-by: Jordan Bayles Co-authored-by: Petukhov Timofey --- include/json/value.h | 3 +++ src/lib_json/json_value.cpp | 5 ++++- src/test_lib_json/main.cpp | 9 +++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/json/value.h b/include/json/value.h index f1232c47f..c8e1aae2e 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -513,6 +513,9 @@ class JSON_API Value { /// and operator[]const /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + Value const* find(const String& key) const; /// Most general and efficient version of object-mutators. /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index a5e2dd8e4..5bd8d9a27 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1092,6 +1092,9 @@ Value const* Value::find(char const* begin, char const* end) const { return nullptr; return &(*it).second; } +Value const* Value::find(const String& key) const { + return find(key.data(), key.data() + key.length()); +} Value* Value::demand(char const* begin, char const* end) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::demand(begin, end): requires " @@ -1105,7 +1108,7 @@ const Value& Value::operator[](const char* key) const { return *found; } Value const& Value::operator[](const String& key) const { - Value const* found = find(key.data(), key.data() + key.length()); + Value const* found = find(key); if (!found) return nullSingleton(); return *found; diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index fa41d19ed..55ab2241d 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -220,11 +220,20 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) { JSONTEST_ASSERT(foundId != nullptr); JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId); + const std::string stringIdKey = "id"; + const Json::Value* stringFoundId = object1_.find(stringIdKey); + JSONTEST_ASSERT(stringFoundId != nullptr); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), *stringFoundId); + const char unknownIdKey[] = "unknown id"; const Json::Value* foundUnknownId = object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey)); JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId); + const std::string stringUnknownIdKey = "unknown id"; + const Json::Value* stringFoundUnknownId = object1_.find(stringUnknownIdKey); + JSONTEST_ASSERT_EQUAL(nullptr, stringFoundUnknownId); + // Access through demand() const char yetAnotherIdKey[] = "yet another id"; const Json::Value* foundYetAnotherId = From 89e2973c754a9c02a49974d839779b151e95afd6 Mon Sep 17 00:00:00 2001 From: Scotty1701 <37419120+Scotty1701@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:18:29 -0700 Subject: [PATCH 135/196] Don't use build dir build interfaces (#1419) Do not export a location in the build directory as a build interface. This location is not created until the build step is run and can interfere with the CMake configuration step if including in another project. Co-authored-by: Jordan Bayles From 76ff1db84d5f3b7515eb3934126b78d178057af9 Mon Sep 17 00:00:00 2001 From: Paolo Monteverde Date: Thu, 12 Sep 2024 01:47:59 +0200 Subject: [PATCH 136/196] Fixes PreventInSourceBuilds.cmake to work with add_subdirectory (#1383) Co-authored-by: Jordan Bayles From 54fc4e28ed98ecaa8ce79d39d72bc9e3f8b35c13 Mon Sep 17 00:00:00 2001 From: YaalLek <140312422+YaalLek@users.noreply.github.com> Date: Thu, 12 Sep 2024 02:53:22 +0300 Subject: [PATCH 137/196] json_value.cpp bug in the edges of uint/int (#1519) * json_value.cpp bug in the edges of uint/int Fixing bug of sending a number that is a bit bigger than max it returns 0: https://stackoverflow.com/questions/77261400/jsoncpp-do-not-protect-from-uint64-overflow-and-have-weird-behavior/77261716#77261716 * Update json_value.cpp Fixing bug of sending a number that is a bit bigger than max it returns 0: https://stackoverflow.com/questions/77261400/jsoncpp-do-not-protect-from-uint64-overflow-and-have-weird-behavior/77261716#77261716 * Update test cases * json_value.cpp bug in the edges of uint/int Fixing bug of sending a number that is a bit bigger than max it returns 0: https://stackoverflow.com/questions/77261400/jsoncpp-do-not-protect-from-uint64-overflow-and-have-weird-behavior/77261716#77261716 * Run clang tidy --------- Co-authored-by: Jordan Bayles --- src/lib_json/json_value.cpp | 25 ++++++++++++++++++++----- src/test_lib_json/main.cpp | 8 ++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 5bd8d9a27..72ba8e59f 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -87,7 +87,8 @@ template static inline bool InRange(double d, T min, U max) { // The casts can lose precision, but we are looking only for // an approximate range. Might fail on edge cases though. ~cdunn - return d >= static_cast(min) && d <= static_cast(max); + return d >= static_cast(min) && d <= static_cast(max) && + !(static_cast(d) == min && d != static_cast(min)); } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { @@ -101,7 +102,8 @@ template static inline double integerToDouble(T value) { template static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); + return d >= integerToDouble(min) && d <= integerToDouble(max) && + !(static_cast(d) == min && d != integerToDouble(min)); } #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) @@ -705,6 +707,11 @@ Value::Int64 Value::asInt64() const { JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); return Int64(value_.uint_); case realValue: + // If the double value is in proximity to minInt64, it will be rounded to + // minInt64. The correct value in this scenario is indeterminable + JSON_ASSERT_MESSAGE( + value_.real_ != minInt64, + "Double value is minInt64, precise value cannot be determined"); JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range"); return Int64(value_.real_); @@ -1311,8 +1318,12 @@ bool Value::isInt64() const { // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a // double, so double(maxInt64) will be rounded up to 2^63. Therefore we // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + // minInt64 is -2^63 which can be represented as a double, but since double + // values in its proximity are also rounded to -2^63, we require the value + // to be strictly greater than the limit to avoid returning 'true' for + // values that are not in the range + return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) && + IsIntegral(value_.real_); default: break; } @@ -1350,7 +1361,11 @@ bool Value::isIntegral() const { // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && + // minInt64 is -2^63 which can be represented as a double, but since double + // values in its proximity are also rounded to -2^63, we require the value + // to be strictly greater than the limit to avoid returning 'true' for + // values that are not in the range + return value_.real_ > double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); #else return value_.real_ >= minInt && value_.real_ <= maxUInt && diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 55ab2241d..5a0ce01ce 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -1191,15 +1191,13 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) { JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_STRING_EQUAL("-9223372036854775808", val.asString()); - // int64 min (floating point constructor). Note that kint64min *is* exactly - // representable as a double. + // int64 min (floating point constructor). Since double values in proximity of + // kint64min are rounded to kint64min, we don't check for conversion to int64. val = Json::Value(double(kint64min)); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); checks = IsCheck(); - checks.isInt64_ = true; - checks.isIntegral_ = true; checks.isDouble_ = true; checks.isNumeric_ = true; JSONTEST_ASSERT_PRED(checkIs(val, checks)); @@ -1208,8 +1206,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) { JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); - JSONTEST_ASSERT_EQUAL(kint64min, val.asInt64()); - JSONTEST_ASSERT_EQUAL(kint64min, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); From 871f0cc43bbd9ccf4e4a67df5a7751f53b49d99e Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Wed, 11 Sep 2024 17:01:27 -0700 Subject: [PATCH 138/196] Release 1.9.6 and move versions to 1.9.7 (#1566) * Release 1.9.6 and move versions to 1.9.7 This patch updates versions to be for version 1.9.7. * remove log.txt --- CMakeLists.txt | 4 ++-- include/json/version.h | 4 ++-- meson.build | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f11425c08..c958250e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,11 +62,11 @@ project(jsoncpp # 2. ./include/json/version.h # 3. ./CMakeLists.txt # IMPORTANT: also update the PROJECT_SOVERSION!! - VERSION 1.9.6 # [.[.[.]]] + VERSION 1.9.7 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(PROJECT_SOVERSION 26) +set(PROJECT_SOVERSION 27) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) diff --git a/include/json/version.h b/include/json/version.h index 38faedf11..25745cce1 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -9,10 +9,10 @@ // 3. /CMakeLists.txt // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "1.9.6" +#define JSONCPP_VERSION_STRING "1.9.7" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 6 +#define JSONCPP_VERSION_PATCH 7 #define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ diff --git a/meson.build b/meson.build index 561b41ce7..8e8d57e3c 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - version : '1.9.6', + version : '1.9.7', default_options : [ 'buildtype=release', 'cpp_std=c++11', @@ -50,7 +50,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 26, + soversion : 27, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) From 07e3d1b076aff1700daf188cd8a00b25b9712af9 Mon Sep 17 00:00:00 2001 From: Pavel Tsynk <36221942+TsynkPavel@users.noreply.github.com> Date: Thu, 12 Sep 2024 07:43:25 +0700 Subject: [PATCH 139/196] Fix deallocate for working on old compiers (#1478) Co-authored-by: Jordan Bayles --- CMakeLists.txt | 6 ++++++ include/json/allocator.h | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c958250e7..6104c5ce5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,12 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.") endif() +include(CheckFunctionExists) +check_function_exists(memset_s HAVE_MEMSET_S) +if(HAVE_MEMSET_S) + add_definitions("-DHAVE_MEMSET_S=1") +endif() + if(JSONCPP_USE_SECURE_MEMORY) add_definitions("-DJSONCPP_USE_SECURE_MEMORY=1") endif() diff --git a/include/json/allocator.h b/include/json/allocator.h index f4fcc1c68..459c34c61 100644 --- a/include/json/allocator.h +++ b/include/json/allocator.h @@ -6,6 +6,7 @@ #ifndef JSON_ALLOCATOR_H_INCLUDED #define JSON_ALLOCATOR_H_INCLUDED +#include #include #include @@ -38,8 +39,16 @@ template class SecureAllocator { * The memory block is filled with zeroes before being released. */ void deallocate(pointer p, size_type n) { - // memset_s is used because memset may be optimized away by the compiler + // These constructs will not be removed by the compiler during optimization, + // unlike memset. +#if defined(HAVE_MEMSET_S) memset_s(p, n * sizeof(T), 0, n * sizeof(T)); +#elif defined(_WIN32) + RtlSecureZeroMemory(p, n * sizeof(T)); +#else + std::fill_n(reinterpret_cast(p), n, 0); +#endif + // free using "global operator delete" ::operator delete(p); } From 8214f717e7c7d361f002b6c3d1b1086ddd096315 Mon Sep 17 00:00:00 2001 From: Jacek Galowicz Date: Thu, 12 Sep 2024 19:58:39 +0200 Subject: [PATCH 140/196] Fix typo in JSONCPP_USE_SECURE_MEMORY vs JSONCPP_USING_SECURE_MEMORY (#1567) --- include/json/config.h | 2 +- include/json/value.h | 2 +- include/json/version.h | 2 +- src/lib_json/json_value.cpp | 8 ++++---- src/test_lib_json/jsontest.cpp | 2 +- src/test_lib_json/jsontest.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/json/config.h b/include/json/config.h index 6359273a2..7f6e2431b 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -127,7 +127,7 @@ using LargestUInt = UInt64; template using Allocator = - typename std::conditional, + typename std::conditional, std::allocator>::type; using String = std::basic_string, Allocator>; using IStringStream = diff --git a/include/json/value.h b/include/json/value.h index c8e1aae2e..073ed30d9 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -375,7 +375,7 @@ class JSON_API Value { int compare(const Value& other) const; const char* asCString() const; ///< Embedded zeroes could cause you trouble! -#if JSONCPP_USING_SECURE_MEMORY +#if JSONCPP_USE_SECURE_MEMORY unsigned getCStringLength() const; // Allows you to understand the length of // the CString #endif diff --git a/include/json/version.h b/include/json/version.h index 25745cce1..42e8780a3 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -19,7 +19,7 @@ (JSONCPP_VERSION_PATCH << 8)) #if !defined(JSONCPP_USE_SECURE_MEMORY) -#define JSONCPP_USING_SECURE_MEMORY 0 +#define JSONCPP_USE_SECURE_MEMORY 0 #endif // If non-zero, the library zeroes any memory that it has allocated before // it frees its memory. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 72ba8e59f..e53643a6d 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -165,7 +165,7 @@ inline static void decodePrefixedString(bool isPrefixed, char const* prefixed, /** Free the string duplicated by * duplicateStringValue()/duplicateAndPrefixStringValue(). */ -#if JSONCPP_USING_SECURE_MEMORY +#if JSONCPP_USE_SECURE_MEMORY static inline void releasePrefixedStringValue(char* value) { unsigned length = 0; char const* valueDecoded; @@ -180,10 +180,10 @@ static inline void releaseStringValue(char* value, unsigned length) { memset(value, 0, size); free(value); } -#else // !JSONCPP_USING_SECURE_MEMORY +#else // !JSONCPP_USE_SECURE_MEMORY static inline void releasePrefixedStringValue(char* value) { free(value); } static inline void releaseStringValue(char* value, unsigned) { free(value); } -#endif // JSONCPP_USING_SECURE_MEMORY +#endif // JSONCPP_USE_SECURE_MEMORY } // namespace Json @@ -601,7 +601,7 @@ const char* Value::asCString() const { return this_str; } -#if JSONCPP_USING_SECURE_MEMORY +#if JSONCPP_USE_SECURE_MEMORY unsigned Value::getCStringLength() const { JSON_ASSERT_MESSAGE(type() == stringValue, "in Json::Value::asCString(): requires stringValue"); diff --git a/src/test_lib_json/jsontest.cpp b/src/test_lib_json/jsontest.cpp index 0b7d12b97..508067a77 100644 --- a/src/test_lib_json/jsontest.cpp +++ b/src/test_lib_json/jsontest.cpp @@ -410,7 +410,7 @@ Json::String ToJsonString(const char* toConvert) { Json::String ToJsonString(Json::String in) { return in; } -#if JSONCPP_USING_SECURE_MEMORY +#if JSONCPP_USE_SECURE_MEMORY Json::String ToJsonString(std::string in) { return Json::String(in.data(), in.data() + in.length()); } diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h index a2385fa3f..69e3264b9 100644 --- a/src/test_lib_json/jsontest.h +++ b/src/test_lib_json/jsontest.h @@ -185,7 +185,7 @@ TestResult& checkEqual(TestResult& result, T expected, U actual, Json::String ToJsonString(const char* toConvert); Json::String ToJsonString(Json::String in); -#if JSONCPP_USING_SECURE_MEMORY +#if JSONCPP_USE_SECURE_MEMORY Json::String ToJsonString(std::string in); #endif From bd25fc5ea0e14d19e1451632205c8b99ec0b1c09 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Mon, 30 Sep 2024 18:23:00 -0400 Subject: [PATCH 141/196] fix(build): remove `check_required_components` for meson build (#1570) Signed-off-by: Rui Chen --- jsoncppConfig.cmake.meson.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/jsoncppConfig.cmake.meson.in b/jsoncppConfig.cmake.meson.in index 0f4866d6d..be8852d0c 100644 --- a/jsoncppConfig.cmake.meson.in +++ b/jsoncppConfig.cmake.meson.in @@ -4,5 +4,3 @@ @MESON_STATIC_TARGET@ include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" ) - -check_required_components(JsonCpp) From 2b3815c90d163d34bed75dbc657f9545cb3d382f Mon Sep 17 00:00:00 2001 From: Alexandre Detiste Date: Tue, 3 Dec 2024 08:00:25 +0100 Subject: [PATCH 142/196] the cgi module was removed from Python3.13 (#1578) --- devtools/batchbuild.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devtools/batchbuild.py b/devtools/batchbuild.py index 0eb0690e8..bf8be48df 100644 --- a/devtools/batchbuild.py +++ b/devtools/batchbuild.py @@ -9,7 +9,7 @@ import string import subprocess import sys -import cgi +import html class BuildDesc: def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None): @@ -195,12 +195,12 @@ def generate_html_report(html_report_path, builds): for variable in variables: build_types = sorted(build_types_by_variable[variable]) nb_build_type = len(build_types_by_variable[variable]) - th_vars.append('%s' % (nb_build_type, cgi.escape(' '.join(variable)))) + th_vars.append('%s' % (nb_build_type, html.escape(' '.join(variable)))) for build_type in build_types: - th_build_types.append('%s' % cgi.escape(build_type)) + th_build_types.append('%s' % html.escape(build_type)) tr_builds = [] for generator in sorted(builds_by_generator): - tds = [ '%s\n' % cgi.escape(generator) ] + tds = [ '%s\n' % html.escape(generator) ] for variable in variables: build_types = sorted(build_types_by_variable[variable]) for build_type in build_types: From 3f86349128b044598ce9a19c1ef92f2b7f4131bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=BCtzel?= Date: Tue, 3 Dec 2024 08:19:05 +0100 Subject: [PATCH 143/196] Fix name of static library when targeting MinGW. (#1579) Co-authored-by: Jordan Bayles --- src/lib_json/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 152635348..3037eb020 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -143,7 +143,7 @@ if(BUILD_STATIC_LIBS) # avoid name clashes on windows as the shared import lib is also named jsoncpp.lib if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) - if (WIN32) + if (MSVC OR ("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")) set(STATIC_SUFFIX "_static") else() set(STATIC_SUFFIX "") From dca8a24cf8da1fc61b5cf0422cad03474124196c Mon Sep 17 00:00:00 2001 From: Jens Mertelmeyer Date: Thu, 5 Dec 2024 07:28:16 +0100 Subject: [PATCH 144/196] Fix comparison warnings caused by 54fc4e2 (#1575) Co-authored-by: Jordan Bayles --- src/lib_json/json_value.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index e53643a6d..d9dee50cb 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -684,7 +684,7 @@ Value::UInt Value::asUInt() const { JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); return UInt(value_.uint_); case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt), "double out of UInt range"); return UInt(value_.real_); case nullValue: @@ -733,7 +733,7 @@ Value::UInt64 Value::asUInt64() const { case uintValue: return UInt64(value_.uint_); case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64), "double out of UInt64 range"); return UInt64(value_.real_); case nullValue: @@ -844,7 +844,7 @@ bool Value::isConvertibleTo(ValueType other) const { type() == booleanValue || type() == nullValue; case uintValue: return isUInt() || - (type() == realValue && InRange(value_.real_, 0, maxUInt)) || + (type() == realValue && InRange(value_.real_, 0u, maxUInt)) || type() == booleanValue || type() == nullValue; case realValue: return isNumeric() || type() == booleanValue || type() == nullValue; From 07a8fe6a235a91e9ad9bd69fae25a3ed07162ac0 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Fri, 10 Jan 2025 18:17:00 -0500 Subject: [PATCH 145/196] Drop pre-C++11 alternatives (#1593) * Assume C++11 We already assume C++11 elsewhere, so all pre-11 `#ifdef` branches are dead code at this point. Fixes issue #1591 because we can just use `std::isfinite` etc. assume C++11 in json_reader.cpp as well apply clang-format * valueToString: simplify lookup of special float name --- AUTHORS | 2 +- src/lib_json/json_reader.cpp | 11 ----- src/lib_json/json_writer.cpp | 79 ++++-------------------------------- 3 files changed, 9 insertions(+), 83 deletions(-) diff --git a/AUTHORS b/AUTHORS index e1fa0fc3a..7a3def276 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,7 +16,7 @@ Baruch Siach Ben Boeckel Benjamin Knecht Bernd Kuhls -Billy Donahue +Billy Donahue Braden McDorman Brandon Myers Brendan Drew diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 10c97aecb..5b6299906 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -23,13 +23,6 @@ #include #include -#if __cplusplus >= 201103L - -#if !defined(sscanf) -#define sscanf std::sscanf -#endif - -#endif //__cplusplus #if defined(_MSC_VER) #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) @@ -53,11 +46,7 @@ static size_t const stackLimit_g = namespace Json { -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) using CharReaderPtr = std::unique_ptr; -#else -using CharReaderPtr = std::auto_ptr; -#endif // Implementation of class Features // //////////////////////////////// diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index ee45c43ba..ac14eb11f 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,67 +19,6 @@ #include #include -#if __cplusplus >= 201103L -#include -#include - -#if !defined(isnan) -#define isnan std::isnan -#endif - -#if !defined(isfinite) -#define isfinite std::isfinite -#endif - -#else -#include -#include - -#if defined(_MSC_VER) -#if !defined(isnan) -#include -#define isnan _isnan -#endif - -#if !defined(isfinite) -#include -#define isfinite _finite -#endif - -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - -#endif //_MSC_VER - -#if defined(__sun) && defined(__SVR4) // Solaris -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#endif - -#if defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) \ - ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) -#endif -#endif -#endif - -#if !defined(isnan) -// IEEE standard states that NaN values will not compare to themselves -#define isnan(x) ((x) != (x)) -#endif - -#if !defined(__APPLE__) -#if !defined(isfinite) -#define isfinite finite -#endif -#endif -#endif - #if defined(_MSC_VER) // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) @@ -85,11 +26,7 @@ namespace Json { -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) using StreamWriterPtr = std::unique_ptr; -#else -using StreamWriterPtr = std::auto_ptr; -#endif String valueToString(LargestInt value) { UIntToStringBuffer buffer; @@ -129,12 +66,12 @@ String valueToString(double value, bool useSpecialFloats, // Print into the buffer. We need not request the alternative representation // that always has a decimal point because JSON doesn't distinguish the // concepts of reals and integers. - if (!isfinite(value)) { - static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, - {"null", "-1e+9999", "1e+9999"}}; - return reps[useSpecialFloats ? 0 : 1][isnan(value) ? 0 - : (value < 0) ? 1 - : 2]; + if (!std::isfinite(value)) { + if (std::isnan(value)) + return useSpecialFloats ? "NaN" : "null"; + if (value < 0) + return useSpecialFloats ? "-Infinity" : "-1e+9999"; + return useSpecialFloats ? "Infinity" : "1e+9999"; } String buffer(size_t(36), '\0'); From 60ccc1f5deb671e95d2a6cc761f6d03f3c8ade07 Mon Sep 17 00:00:00 2001 From: evalon32 <34560232+evalon32@users.noreply.github.com> Date: Fri, 10 Jan 2025 18:25:25 -0500 Subject: [PATCH 146/196] feat: support std::string_view in Value API (#1584) This adds direct support for `std::string_view` when available (C++17 and above). The current API can be used with `std::string_view` via the low-level two-pointer methods, but is not ergonomic. E.g., compare: ``` Json::Value node; std::string foo, bar, baz; std::string_view foo_sv, bar_sv, baz_sv; // Efficient & readable: node[foo][bar][baz]; // Less efficient, less readable: node[std::string(foo_sv)][std::string(bar_sv)][std::string(baz_sv)]; // Efficient, but a lot less readable: *node.demand(foo_sv.data(), foo_sv.data() + foo_sv.size()) ->demand(bar_sv.data(), bar_sv.data() + bar_sv.size()) ->demand(baz_sv.data(), baz_sv.data() + baz_sv.size()) // After this change, efficient & readable: node[foo_sv][bar_sv][baz_sv]; ``` * The constructor can take a `std::string_view` parameter. The existing overloads taking `const std::string&` and `const char*` are still necessary to support assignment from those types. * `operator[]`, `get()`, `isMember()` and `removeMember()` take a `std::string_view` parameter. This supersedes the overloads taking `const std::string&` and `const char*`. The overloads taking a pair of pointers (begin, end) are preserved for source compatibility. * `getString()` has an overload with a `std::string_view` output parameter. The one with a pair of pointers is preserved for source compatibility. Signed-off-by: Lev Kandel Co-authored-by: Jordan Bayles --- include/json/value.h | 61 +++++++++++++++++++++++++++---- src/lib_json/json_value.cpp | 71 +++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 7 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 073ed30d9..307493298 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -39,6 +39,10 @@ #endif #endif +#if __cplusplus >= 201703L +#define JSONCPP_HAS_STRING_VIEW 1 +#endif + #include #include #include @@ -46,6 +50,10 @@ #include #include +#ifdef JSONCPP_HAS_STRING_VIEW +#include +#endif + // Disable warning C4251: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -342,6 +350,9 @@ class JSON_API Value { */ Value(const StaticString& value); Value(const String& value); +#ifdef JSONCPP_HAS_STRING_VIEW + Value(std::string_view value); +#endif Value(bool value); Value(std::nullptr_t ptr) = delete; Value(const Value& other); @@ -384,6 +395,12 @@ class JSON_API Value { * \return false if !string. (Seg-fault if str or end are NULL.) */ bool getString(char const** begin, char const** end) const; +#ifdef JSONCPP_HAS_STRING_VIEW + /** Get string_view of string-value. + * \return false if !string. (Seg-fault if str is NULL.) + */ + bool getString(std::string_view* str) const; +#endif Int asInt() const; UInt asUInt() const; #if defined(JSON_HAS_INT64) @@ -470,6 +487,15 @@ class JSON_API Value { bool insert(ArrayIndex index, const Value& newValue); bool insert(ArrayIndex index, Value&& newValue); +#ifdef JSONCPP_HAS_STRING_VIEW + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](std::string_view key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](std::string_view key) const; +#else /// Access an object value by name, create a null member if it does not exist. /// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// Exceeding that will cause an exception. @@ -484,6 +510,7 @@ class JSON_API Value { /// that name. /// \param key may contain embedded nulls. const Value& operator[](const String& key) const; +#endif /** \brief Access an object value by name, create a null member if it does not * exist. * @@ -497,18 +524,24 @@ class JSON_API Value { * \endcode */ Value& operator[](const StaticString& key); +#ifdef JSONCPP_HAS_STRING_VIEW /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy - Value get(const char* key, const Value& defaultValue) const; + Value get(std::string_view key, const Value& defaultValue) const; +#else /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy - /// \note key may contain embedded nulls. - Value get(const char* begin, const char* end, - const Value& defaultValue) const; + Value get(const char* key, const Value& defaultValue) const; /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy /// \param key may contain embedded nulls. Value get(const String& key, const Value& defaultValue) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, + const Value& defaultValue) const; /// Most general and efficient version of isMember()const, get()const, /// and operator[]const /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 @@ -525,20 +558,28 @@ class JSON_API Value { /// Do nothing if it did not exist. /// \pre type() is objectValue or nullValue /// \post type() is unchanged +#if JSONCPP_HAS_STRING_VIEW + void removeMember(std::string_view key); +#else void removeMember(const char* key); /// Same as removeMember(const char*) /// \param key may contain embedded nulls. void removeMember(const String& key); - /// Same as removeMember(const char* begin, const char* end, Value* removed), - /// but 'key' is null-terminated. - bool removeMember(const char* key, Value* removed); +#endif /** \brief Remove the named map member. * * Update 'removed' iff removed. * \param key may contain embedded nulls. * \return true iff removed (no exceptions) */ +#if JSONCPP_HAS_STRING_VIEW + bool removeMember(std::string_view key, Value* removed); +#else bool removeMember(String const& key, Value* removed); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); +#endif /// Same as removeMember(String const& key, Value* removed) bool removeMember(const char* begin, const char* end, Value* removed); /** \brief Remove the indexed array element. @@ -549,12 +590,18 @@ class JSON_API Value { */ bool removeIndex(ArrayIndex index, Value* removed); +#ifdef JSONCPP_HAS_STRING_VIEW + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(std::string_view key) const; +#else /// Return true if the object has a member named key. /// \note 'key' must be null-terminated. bool isMember(const char* key) const; /// Return true if the object has a member named key. /// \param key may contain embedded nulls. bool isMember(const String& key) const; +#endif /// Same as isMember(String const& key)const bool isMember(const char* begin, const char* end) const; diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index d9dee50cb..527d716f2 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -17,6 +17,10 @@ #include #include +#ifdef JSONCPP_HAS_STRING_VIEW +#include +#endif + // Provide implementation equivalent of std::snprintf for older _MSC compilers #if defined(_MSC_VER) && _MSC_VER < 1900 #include @@ -420,6 +424,14 @@ Value::Value(const String& value) { value.data(), static_cast(value.length())); } +#ifdef JSONCPP_HAS_STRING_VIEW +Value::Value(std::string_view value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast(value.length())); +} +#endif + Value::Value(const StaticString& value) { initBasic(stringValue); value_.string_ = const_cast(value.c_str()); @@ -627,6 +639,21 @@ bool Value::getString(char const** begin, char const** end) const { return true; } +#ifdef JSONCPP_HAS_STRING_VIEW +bool Value::getString(std::string_view* str) const { + if (type() != stringValue) + return false; + if (value_.string_ == nullptr) + return false; + const char* begin; + unsigned length; + decodePrefixedString(this->isAllocated(), this->value_.string_, &length, + &begin); + *str = std::string_view(begin, length); + return true; +} +#endif + String Value::asString() const { switch (type()) { case nullValue: @@ -1108,6 +1135,17 @@ Value* Value::demand(char const* begin, char const* end) { "objectValue or nullValue"); return &resolveReference(begin, end); } +#ifdef JSONCPP_HAS_STRING_VIEW +const Value& Value::operator[](std::string_view key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; +} +Value& Value::operator[](std::string_view key) { + return resolveReference(key.data(), key.data() + key.length()); +} +#else const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); if (!found) @@ -1128,6 +1166,7 @@ Value& Value::operator[](const char* key) { Value& Value::operator[](const String& key) { return resolveReference(key.data(), key.data() + key.length()); } +#endif Value& Value::operator[](const StaticString& key) { return resolveReference(key.c_str()); @@ -1167,12 +1206,18 @@ Value Value::get(char const* begin, char const* end, Value const* found = find(begin, end); return !found ? defaultValue : *found; } +#ifdef JSONCPP_HAS_STRING_VIEW +Value Value::get(std::string_view key, const Value& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); +} +#else Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } Value Value::get(String const& key, Value const& defaultValue) const { return get(key.data(), key.data() + key.length(), defaultValue); } +#endif bool Value::removeMember(const char* begin, const char* end, Value* removed) { if (type() != objectValue) { @@ -1188,12 +1233,31 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) { value_.map_->erase(it); return true; } +#ifdef JSONCPP_HAS_STRING_VIEW +bool Value::removeMember(std::string_view key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); +} +#else bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } bool Value::removeMember(String const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } +#endif + +#ifdef JSONCPP_HAS_STRING_VIEW +void Value::removeMember(std::string_view key) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type() == nullValue) + return; + + CZString actualKey(key.data(), unsigned(key.length()), + CZString::noDuplication); + value_.map_->erase(actualKey); +} +#else void Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::removeMember(): requires objectValue"); @@ -1204,6 +1268,7 @@ void Value::removeMember(const char* key) { value_.map_->erase(actualKey); } void Value::removeMember(const String& key) { removeMember(key.c_str()); } +#endif bool Value::removeIndex(ArrayIndex index, Value* removed) { if (type() != arrayValue) { @@ -1233,12 +1298,18 @@ bool Value::isMember(char const* begin, char const* end) const { Value const* value = find(begin, end); return nullptr != value; } +#ifdef JSONCPP_HAS_STRING_VIEW +bool Value::isMember(std::string_view key) const { + return isMember(key.data(), key.data() + key.length()); +} +#else bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } bool Value::isMember(String const& key) const { return isMember(key.data(), key.data() + key.length()); } +#endif Value::Members Value::getMemberNames() const { JSON_ASSERT_MESSAGE( From ba004477a6f260dedbe6ef6470b3760192e8d232 Mon Sep 17 00:00:00 2001 From: SwintonStreet Date: Fri, 10 Jan 2025 23:38:47 +0000 Subject: [PATCH 147/196] Added Value::findType with String key (#1574) This adds a convenience function to return a member if it has a specific json type. All isType values are supported. Co-authored-by: Jordan Bayles --- include/json/value.h | 23 ++++++++++ src/lib_json/json_value.cpp | 38 ++++++++++++++++ src/test_lib_json/main.cpp | 86 +++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/include/json/value.h b/include/json/value.h index 307493298..5f6544329 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -549,6 +549,29 @@ class JSON_API Value { /// Most general and efficient version of isMember()const, get()const, /// and operator[]const Value const* find(const String& key) const; + + /// Calls find and only returns a valid pointer if the type is found + template + Value const* findValue(const String& key) const { + Value const* found = find(key); + if (!found || !(found->*TMemFn)()) + return nullptr; + return found; + } + + Value const* findNull(const String& key) const; + Value const* findBool(const String& key) const; + Value const* findInt(const String& key) const; + Value const* findInt64(const String& key) const; + Value const* findUInt(const String& key) const; + Value const* findUInt64(const String& key) const; + Value const* findIntegral(const String& key) const; + Value const* findDouble(const String& key) const; + Value const* findNumeric(const String& key) const; + Value const* findString(const String& key) const; + Value const* findArray(const String& key) const; + Value const* findObject(const String& key) const; + /// Most general and efficient version of object-mutators. /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 527d716f2..a875d28b2 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1129,6 +1129,44 @@ Value const* Value::find(char const* begin, char const* end) const { Value const* Value::find(const String& key) const { return find(key.data(), key.data() + key.length()); } + +Value const* Value::findNull(const String& key) const { + return findValue(key); +} +Value const* Value::findBool(const String& key) const { + return findValue(key); +} +Value const* Value::findInt(const String& key) const { + return findValue(key); +} +Value const* Value::findInt64(const String& key) const { + return findValue(key); +} +Value const* Value::findUInt(const String& key) const { + return findValue(key); +} +Value const* Value::findUInt64(const String& key) const { + return findValue(key); +} +Value const* Value::findIntegral(const String& key) const { + return findValue(key); +} +Value const* Value::findDouble(const String& key) const { + return findValue(key); +} +Value const* Value::findNumeric(const String& key) const { + return findValue(key); +} +Value const* Value::findString(const String& key) const { + return findValue(key); +} +Value const* Value::findArray(const String& key) const { + return findValue(key); +} +Value const* Value::findObject(const String& key) const { + return findValue(key); +} + Value* Value::demand(char const* begin, char const* end) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::demand(begin, end): requires " diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 5a0ce01ce..60f149d5e 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -76,6 +76,8 @@ struct ValueTest : JsonTest::TestCase { Json::Value float_{0.00390625f}; Json::Value array1_; Json::Value object1_; + Json::Value object2_; + Json::Value object3_; Json::Value emptyString_{""}; Json::Value string1_{"a"}; Json::Value string_{"sometext with space"}; @@ -85,6 +87,34 @@ struct ValueTest : JsonTest::TestCase { ValueTest() { array1_.append(1234); object1_["id"] = 1234; + + // object2 with matching values + object2_["null"] = Json::nullValue; + object2_["bool"] = true; + object2_["int"] = Json::Int{Json::Value::maxInt}; + object2_["int64"] = Json::Int64{Json::Value::maxInt64}; + object2_["uint"] = Json::UInt{Json::Value::maxUInt}; + object2_["uint64"] = Json::UInt64{Json::Value::maxUInt64}; + object2_["integral"] = 1234; + object2_["double"] = 1234.56789; + object2_["numeric"] = 0.12345f; + object2_["string"] = "string"; + object2_["array"] = Json::arrayValue; + object2_["object"] = Json::objectValue; + + // object3 with not matching values + object3_["object"] = Json::nullValue; + object3_["null"] = true; + object3_["bool"] = Json::Int{Json::Value::maxInt}; + object3_["int"] = "not_an_int"; + object3_["int64"] = "not_an_int64"; + object3_["uint"] = "not_an_uint"; + object3_["uin64"] = "not_an_uint64"; + object3_["integral"] = 1234.56789; + object3_["double"] = false; + object3_["numeric"] = "string"; + object3_["string"] = Json::arrayValue; + object3_["array"] = Json::objectValue; } struct IsCheck { @@ -234,6 +264,62 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) { const Json::Value* stringFoundUnknownId = object1_.find(stringUnknownIdKey); JSONTEST_ASSERT_EQUAL(nullptr, stringFoundUnknownId); + // Access through find() + const Json::Value* nullFound = object2_.findNull("null"); + JSONTEST_ASSERT(nullFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::nullValue, *nullFound); + JSONTEST_ASSERT(object3_.findNull("null") == nullptr); + + const Json::Value* boolFound = object2_.findBool("bool"); + JSONTEST_ASSERT(boolFound != nullptr); + JSONTEST_ASSERT_EQUAL(true, *boolFound); + JSONTEST_ASSERT(object3_.findBool("bool") == nullptr); + + const Json::Value* intFound = object2_.findInt("int"); + JSONTEST_ASSERT(intFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::Int{Json::Value::maxInt}, *intFound); + JSONTEST_ASSERT(object3_.findInt("int") == nullptr); + + const Json::Value* int64Found = object2_.findInt64("int64"); + JSONTEST_ASSERT(int64Found != nullptr); + JSONTEST_ASSERT_EQUAL(Json::Int64{Json::Value::maxInt64}, *int64Found); + JSONTEST_ASSERT(object3_.findInt64("int64") == nullptr); + + const Json::Value* uintFound = object2_.findUInt("uint"); + JSONTEST_ASSERT(uintFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::UInt{Json::Value::maxUInt}, *uintFound); + JSONTEST_ASSERT(object3_.findUInt("uint") == nullptr); + + const Json::Value* uint64Found = object2_.findUInt64("uint64"); + JSONTEST_ASSERT(uint64Found != nullptr); + JSONTEST_ASSERT_EQUAL(Json::UInt64{Json::Value::maxUInt64}, *uint64Found); + JSONTEST_ASSERT(object3_.findUInt64("uint64") == nullptr); + + const Json::Value* integralFound = object2_.findIntegral("integral"); + JSONTEST_ASSERT(integralFound != nullptr); + JSONTEST_ASSERT_EQUAL(1234, *integralFound); + JSONTEST_ASSERT(object3_.findIntegral("integral") == nullptr); + + const Json::Value* doubleFound = object2_.findDouble("double"); + JSONTEST_ASSERT(doubleFound != nullptr); + JSONTEST_ASSERT_EQUAL(1234.56789, *doubleFound); + JSONTEST_ASSERT(object3_.findDouble("double") == nullptr); + + const Json::Value* numericFound = object2_.findNumeric("numeric"); + JSONTEST_ASSERT(numericFound != nullptr); + JSONTEST_ASSERT_EQUAL(0.12345f, *numericFound); + JSONTEST_ASSERT(object3_.findNumeric("numeric") == nullptr); + + const Json::Value* stringFound = object2_.findString("string"); + JSONTEST_ASSERT(stringFound != nullptr); + JSONTEST_ASSERT_EQUAL(std::string{"string"}, *stringFound); + JSONTEST_ASSERT(object3_.findString("string") == nullptr); + + const Json::Value* arrayFound = object2_.findArray("array"); + JSONTEST_ASSERT(arrayFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::arrayValue, *arrayFound); + JSONTEST_ASSERT(object3_.findArray("array") == nullptr); + // Access through demand() const char yetAnotherIdKey[] = "yet another id"; const Json::Value* foundYetAnotherId = From 037752d9a1e48c8b7e5a62ee895a352166df03e3 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:57:16 -0700 Subject: [PATCH 148/196] Set up for Bazel module builds. (#1597) * Set up for Bazel module builds. Note: the MODULE.bazel is copied from https://github.com/bazelbuild/bazel-central-registry/blob/main/modules/jsoncpp/1.9.6/MODULE.bazel * More tweaks to .gitignore --- .gitignore | 4 ++++ CMakeLists.txt | 3 ++- MODULE.bazel | 14 ++++++++++++++ include/json/version.h | 3 ++- meson.build | 3 ++- 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 MODULE.bazel diff --git a/.gitignore b/.gitignore index 9682782fa..69868f413 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,7 @@ compile_commands.json # temps /version + +# Bazel output paths +/bazel-* +/MODULE.bazel.lock diff --git a/CMakeLists.txt b/CMakeLists.txt index 6104c5ce5..5ab9c52a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,12 +55,13 @@ endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") project(jsoncpp - # Note: version must be updated in three places when doing a release. This + # Note: version must be updated in four places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the # correct version. # 1. ./meson.build # 2. ./include/json/version.h # 3. ./CMakeLists.txt + # 4. ./MODULE.bazel # IMPORTANT: also update the PROJECT_SOVERSION!! VERSION 1.9.7 # [.[.[.]]] LANGUAGES CXX) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..03f192dd4 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,14 @@ +module( + name = "jsoncpp", + + # Note: version must be updated in four places when doing a release. This + # annoying process ensures that amalgamate, CMake, and meson all report the + # correct version. + # 1. /meson.build + # 2. /include/json/version.h + # 3. /CMakeLists.txt + # 4. /MODULE.bazel + # IMPORTANT: also update the SOVERSION!! + version = "1.9.7", + compatibility_level = 1, +) diff --git a/include/json/version.h b/include/json/version.h index 42e8780a3..555152c8c 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -1,12 +1,13 @@ #ifndef JSON_VERSION_H_INCLUDED #define JSON_VERSION_H_INCLUDED -// Note: version must be updated in three places when doing a release. This +// Note: version must be updated in four places when doing a release. This // annoying process ensures that amalgamate, CMake, and meson all report the // correct version. // 1. /meson.build // 2. /include/json/version.h // 3. /CMakeLists.txt +// 4. /MODULE.bazel // IMPORTANT: also update the SOVERSION!! #define JSONCPP_VERSION_STRING "1.9.7" diff --git a/meson.build b/meson.build index 8e8d57e3c..2648c3071 100644 --- a/meson.build +++ b/meson.build @@ -2,12 +2,13 @@ project( 'jsoncpp', 'cpp', - # Note: version must be updated in three places when doing a release. This + # Note: version must be updated in four places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the # correct version. # 1. /meson.build # 2. /include/json/version.h # 3. /CMakeLists.txt + # 4. /MODULE.bazel # IMPORTANT: also update the SOVERSION!! version : '1.9.7', default_options : [ From ca98c98457b1163cca1f7d8db62827c115fec6d1 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:15:37 -0700 Subject: [PATCH 149/196] Add a BUILD.bazel file for //example. (#1602) --- example/BUILD.bazel | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 example/BUILD.bazel diff --git a/example/BUILD.bazel b/example/BUILD.bazel new file mode 100644 index 000000000..38e7dfcf7 --- /dev/null +++ b/example/BUILD.bazel @@ -0,0 +1,33 @@ +cc_binary( + name = "readFromStream_ok", + srcs = ["readFromStream/readFromStream.cpp"], + deps = ["//:jsoncpp"], + args = ["$(location :readFromStream/withComment.json)"], + data = ["readFromStream/withComment.json"], +) + +cc_binary( + name = "readFromStream_err", + srcs = ["readFromStream/readFromStream.cpp"], + deps = ["//:jsoncpp"], + args = ["$(location :readFromStream/errorFormat.json)"], + data = ["readFromStream/errorFormat.json"], +) + +cc_binary( + name = "readFromString", + srcs = ["readFromString/readFromString.cpp"], + deps = ["//:jsoncpp"], +) + +cc_binary( + name = "streamWrite", + srcs = ["streamWrite/streamWrite.cpp"], + deps = ["//:jsoncpp"], +) + +cc_binary( + name = "stringWrite", + srcs = ["stringWrite/stringWrite.cpp"], + deps = ["//:jsoncpp"], +) From 9af09c4a4abe5928d1f7a6e7ec1c73a565bb362e Mon Sep 17 00:00:00 2001 From: Victor Vianna Date: Mon, 10 Nov 2025 17:51:20 -0800 Subject: [PATCH 150/196] Fix "include what you use" issue (#1625) Fix IWYU for istreambuf_iterator. Co-authored-by: Victor Hugo Vianna Silva --- src/lib_json/json_reader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 5b6299906..93bb82240 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include From 6f6aca167fb016a47d6bb320e6bcce8e4bfe5708 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Tue, 11 Nov 2025 23:58:32 -0800 Subject: [PATCH 151/196] Make the build configuration under Bazel more correct. (#1600) * Expose JSON_USE_EXCEPTION and JSON_HAS_INT64 as Bazel config flags with defaults that match the existing Bazel build. Switch //:jsoncpp from using copts ro defines for JSON_USE_EXCEPTION and JSON_HAS_INT64 so that rules that depend on it get the same config. Make src/test_lib_json/fuzz.cpp respect JSON_USE_EXCEPTION. * #ifdef stuff that should only be used with JSON_USE_EXCEPTION. --------- Co-authored-by: Jordan Bayles --- BUILD.bazel | 33 +++++++++++++++++++++++++++++---- MODULE.bazel | 5 +++++ src/test_lib_json/fuzz.cpp | 8 ++++---- src/test_lib_json/jsontest.h | 4 ++++ src/test_lib_json/main.cpp | 10 +++++++++- 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 6d7ac3da9..2227fee23 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,7 +1,29 @@ licenses(["unencumbered"]) # Public Domain or MIT +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") + exports_files(["LICENSE"]) +bool_flag( + name = "use_exception", + build_setting_default = False, +) + +config_setting( + name = "use_exception_cfg", + flag_values = {":use_exception": "true"}, +) + +bool_flag( + name = "has_int64", + build_setting_default = True, +) + +config_setting( + name = "has_int64_cfg", + flag_values = {":has_int64": "true"}, +) + cc_library( name = "jsoncpp", srcs = [ @@ -22,10 +44,13 @@ cc_library( "include/json/version.h", "include/json/writer.h", ], - copts = [ - "-DJSON_USE_EXCEPTION=0", - "-DJSON_HAS_INT64", - ], + defines = select({ + ":use_exception_cfg": ["JSON_USE_EXCEPTION=1"], + "//conditions:default": ["JSON_USE_EXCEPTION=0"], + }) + select({ + ":has_int64_cfg": ["JSON_HAS_INT64"], + "//conditions:default": [], + }), includes = ["include"], visibility = ["//visibility:public"], deps = [":private"], diff --git a/MODULE.bazel b/MODULE.bazel index 03f192dd4..e60fa06d1 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -12,3 +12,8 @@ module( version = "1.9.7", compatibility_level = 1, ) + +bazel_dep( + name = "bazel_skylib", + version = "1.7.1", +) diff --git a/src/test_lib_json/fuzz.cpp b/src/test_lib_json/fuzz.cpp index 5b75c22e6..3679a95ec 100644 --- a/src/test_lib_json/fuzz.cpp +++ b/src/test_lib_json/fuzz.cpp @@ -11,10 +11,6 @@ #include #include -namespace Json { -class Exception; -} - extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { Json::CharReaderBuilder builder; @@ -45,10 +41,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { Json::Value root; const auto data_str = reinterpret_cast(data); +#if JSON_USE_EXCEPTION try { +#endif // JSON_USE_EXCEPTION reader->parse(data_str, data_str + size, &root, nullptr); +#if JSON_USE_EXCEPTION } catch (Json::Exception const&) { } +#endif // JSON_USE_EXCEPTION // Whether it succeeded or not doesn't matter. return 0; } diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h index 69e3264b9..3652c4029 100644 --- a/src/test_lib_json/jsontest.h +++ b/src/test_lib_json/jsontest.h @@ -228,6 +228,8 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, JsonTest::ToJsonString(actual), __FILE__, \ __LINE__, #expected " == " #actual) +#if JSON_USE_EXCEPTION + /// \brief Asserts that a given expression throws an exception #define JSONTEST_ASSERT_THROWS(expr) \ do { \ @@ -242,6 +244,8 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, "expected exception thrown: " #expr); \ } while (0) +#endif // JSON_USE_EXCEPTION + /// \brief Begin a fixture test case. #define JSONTEST_FIXTURE(FixtureType, name) \ class Test##FixtureType##name : public FixtureType { \ diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 60f149d5e..e20723498 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -1888,7 +1888,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, typeChecksThrowExceptions) { JSONTEST_ASSERT_THROWS(objVal.asBool()); JSONTEST_ASSERT_THROWS(arrVal.asBool()); -#endif +#endif // JSON_USE_EXCEPTION } JSONTEST_FIXTURE_LOCAL(ValueTest, offsetAccessors) { @@ -3323,6 +3323,8 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { +#if JSON_USE_EXCEPTION + Json::CharReaderBuilder b; Json::Value root; char const doc[] = R"({ "property" : "value" })"; @@ -3342,6 +3344,8 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { JSONTEST_ASSERT_THROWS( reader->parse(doc, doc + std::strlen(doc), &root, &errs)); } + +#endif // JSON_USE_EXCEPTION } JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) { @@ -3961,6 +3965,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, indexes) { } JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) { +#if JSON_USE_EXCEPTION + Json::Value const v; JSONTEST_ASSERT_THROWS( Json::Value::iterator it(v.begin())); // Compile, but throw. @@ -3982,6 +3988,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) { } Json::String expected = R"(" 9","10","11",)"; JSONTEST_ASSERT_STRING_EQUAL(expected, out.str()); + +#endif // JSON_USE_EXCEPTION } struct RValueTest : JsonTest::TestCase {}; From 4bcbc6ac0509cc8b0d0d84618cfd518dd945c114 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Wed, 12 Nov 2025 00:01:15 -0800 Subject: [PATCH 152/196] Add Bazel tests (#1601) * Expose JSON_USE_EXCEPTION and JSON_HAS_INT64 as Bazel config flags with defaults that match the existing Bazel build. Switch //:jsoncpp from using copts ro defines for JSON_USE_EXCEPTION and JSON_HAS_INT64 so that rules that depend on it get the same config. Make src/test_lib_json/fuzz.cpp respect JSON_USE_EXCEPTION. * #ifdef stuff that should only be used with JSON_USE_EXCEPTION. * Modify runjsontests.py to allow passing a single test case file. * Add tests to the Bazel builds. * Reverse the polarity to fix a bug. --------- Co-authored-by: Jordan Bayles --- src/jsontestrunner/BUILD.bazel | 6 ++++ src/test_lib_json/BUILD.bazel | 11 ++++++ test/BUILD.bazel | 20 +++++++++++ test/runjsontests.py | 61 +++++++++++++++++++++------------- 4 files changed, 74 insertions(+), 24 deletions(-) create mode 100644 src/jsontestrunner/BUILD.bazel create mode 100644 src/test_lib_json/BUILD.bazel create mode 100644 test/BUILD.bazel diff --git a/src/jsontestrunner/BUILD.bazel b/src/jsontestrunner/BUILD.bazel new file mode 100644 index 000000000..543bc5d88 --- /dev/null +++ b/src/jsontestrunner/BUILD.bazel @@ -0,0 +1,6 @@ +cc_binary( + name = "jsontestrunner", + srcs = ["main.cpp"], + deps = ["//:jsoncpp"], + visibility = ["//test:__pkg__"], +) diff --git a/src/test_lib_json/BUILD.bazel b/src/test_lib_json/BUILD.bazel new file mode 100644 index 000000000..7e83f5219 --- /dev/null +++ b/src/test_lib_json/BUILD.bazel @@ -0,0 +1,11 @@ +cc_test( + name = "jsoncpp_test", + srcs = [ + "jsontest.cpp", + "jsontest.h", + "main.cpp", + "fuzz.h", + "fuzz.cpp", + ], + deps = ["//:jsoncpp"], +) diff --git a/test/BUILD.bazel b/test/BUILD.bazel new file mode 100644 index 000000000..269cd8646 --- /dev/null +++ b/test/BUILD.bazel @@ -0,0 +1,20 @@ +filegroup( + name = "expected", + srcs = glob(["data/**", "jsonchecker/**"], exclude=["**/*.json"]), +) + +[py_test( + name = "runjson_%s_test" % "_".join(f.split("/")), + srcs = ["runjsontests.py"], + main = "runjsontests.py", + args = [ + "--with-json-checker", + "$(location //src/jsontestrunner:jsontestrunner)", + "$(location :%s)" % f, + ], + data = [ + "//src/jsontestrunner:jsontestrunner", + ":expected", + ":%s" % f, + ], +) for f in glob(["**/*.json"])] diff --git a/test/runjsontests.py b/test/runjsontests.py index 49cc7a960..14275ec22 100644 --- a/test/runjsontests.py +++ b/test/runjsontests.py @@ -66,38 +66,51 @@ class FailError(Exception): def __init__(self, msg): super(Exception, self).__init__(msg) -def runAllTests(jsontest_executable_path, input_dir = None, +def runAllTests(jsontest_executable_path, input_path = None, use_valgrind=False, with_json_checker=False, writerClass='StyledWriter'): - if not input_dir: - input_dir = os.path.join(os.getcwd(), 'data') - tests = glob(os.path.join(input_dir, '*.json')) - if with_json_checker: - all_tests = glob(os.path.join(input_dir, '../jsonchecker', '*.json')) - # These tests fail with strict json support, but pass with JsonCPP's - # extra leniency features. When adding a new exclusion to this list, - # remember to add the test's number and reasoning here: - known = ["fail{}.json".format(n) for n in [ - 4, 9, # fail because we allow trailing commas - 7, # fails because we allow commas after close - 8, # fails because we allow extra close - 10, # fails because we allow extra values after close - 13, # fails because we allow leading zeroes in numbers - 18, # fails because we allow deeply nested values - 25, # fails because we allow tab characters in strings - 27, # fails because we allow string line breaks - ]] - test_jsonchecker = [ test for test in all_tests - if os.path.basename(test) not in known] + if not input_path: + input_path = os.path.join(os.getcwd(), 'data') + if os.path.isdir(input_path): + tests = [ + os.path.normpath(os.path.abspath(test)) + for test in glob(os.path.join(input_path, '*.json')) + ] + + if with_json_checker: + tests += [ + os.path.normpath(os.path.abspath(test)) + for test in glob(os.path.join(input_path, '../jsonchecker', '*.json')) + ] else: - test_jsonchecker = [] + tests = [input_path] + + # These tests fail with strict json support, but pass with JsonCPP's + # extra leniency features. When adding a new exclusion to this list, + # remember to add the test's number and reasoning here: + known = ["fail{}.json".format(n) for n in [ + 4, 9, # fail because we allow trailing commas + 7, # fails because we allow commas after close + 8, # fails because we allow extra close + 10, # fails because we allow extra values after close + 13, # fails because we allow leading zeroes in numbers + 18, # fails because we allow deeply nested values + 25, # fails because we allow tab characters in strings + 27, # fails because we allow string line breaks + ]] + + tests = [ + test for test in tests + if os.path.basename(test) not in known or + os.path.basename(os.path.dirname(test)) != "jsonchecker" + ] failed_tests = [] valgrind_path = use_valgrind and VALGRIND_CMD or '' - for input_path in tests + test_jsonchecker: + for input_path in tests: expect_failure = os.path.basename(input_path).startswith('fail') - is_json_checker_test = input_path in test_jsonchecker + is_json_checker_test = os.path.basename(os.path.dirname(input_path)) == "jsonchecker" is_parse_only = is_json_checker_test or expect_failure is_strict_test = ('_strict_' in os.path.basename(input_path)) or is_json_checker_test print('TESTING:', input_path, end=' ') From 30e7528001e17d0a03e33797010b146ae1ec2d89 Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Wed, 12 Nov 2025 00:07:06 -0800 Subject: [PATCH 153/196] Return false in Reader::readValue when stack limit is exceeded (#1619) jsoncpp, as a shared library, should not call `abort` merely because there's an error reading a value. See https://en.cppreference.com/w/c/program/abort, `abort` should only be called to **abnormally** cause the program to exit. Functions inserted by `atexit` are also not called, meaning that the host program may have not cleaned up resources properly. But here, exceeding stack limit isn't a sign of abnormalty. `exit` is not a good substitute either, see the `exit-in-shared-library` from Debian: https://lintian.debian.org/tags/exit-in-shared-library.html Fix #1618 In this case, returning false seems like a better idea. Co-authored-by: Jordan Bayles --- src/lib_json/json_reader.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 93bb82240..265b03054 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -144,7 +144,12 @@ bool Reader::readValue() { // after calling readValue(). parse() executes one nodes_.push(), so > instead // of >=. if (nodes_.size() > stackLimit_g) +#if JSON_USE_EXCEPTION throwRuntimeError("Exceeded stackLimit in readValue()."); +#else + // throwRuntimeError aborts. Don't abort here. + return false; +#endif Token token; readTokenSkippingComments(token); From e16663cc02ac1dc38f59e8a61d00fd5bcc24bc7d Mon Sep 17 00:00:00 2001 From: bmagistro Date: Wed, 12 Nov 2025 03:10:33 -0500 Subject: [PATCH 154/196] Remove deprecated/removed clang-tidy key AnalyzeTemporaryDtors (#1614) (#1615) Co-authored-by: Ben Magistro Co-authored-by: Jordan Bayles --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 99e914df9..75da71785 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,7 +2,6 @@ Checks: 'google-readability-casting,modernize-deprecated-headers,modernize-loop-convert,modernize-use-auto,modernize-use-default-member-init,modernize-use-using,readability-else-after-return,readability-redundant-member-init,readability-redundant-string-cstr' WarningsAsErrors: '' HeaderFilterRegex: '' -AnalyzeTemporaryDtors: false FormatStyle: none CheckOptions: - key: modernize-use-using.IgnoreMacros From b511d9e64956db998b74909df112ac8c8f41d6ff Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 12 Nov 2025 09:14:04 +0100 Subject: [PATCH 155/196] [docs] Consuming JSONCpp via Conan package manager (#1622) * Fix Conan badge URL Signed-off-by: Uilian Ries * Add Conan instructions in README Signed-off-by: Uilian Ries * Add build missing Signed-off-by: Uilian Ries --------- Signed-off-by: Uilian Ries Co-authored-by: Jordan Bayles --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bff8dca2..c8b42a9be 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # JsonCpp -[![badge](https://img.shields.io/badge/conan.io-jsoncpp%2F1.8.0-green.svg?logo=data:image/png;base64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAA1VBMVEUAAABhlctjlstkl8tlmMtlmMxlmcxmmcxnmsxpnMxpnM1qnc1sn85voM91oM11oc1xotB2oc56pNF6pNJ2ptJ8ptJ8ptN9ptN8p9N5qNJ9p9N9p9R8qtOBqdSAqtOAqtR%2BrNSCrNJ/rdWDrNWCsNWCsNaJs9eLs9iRvNuVvdyVv9yXwd2Zwt6axN6dxt%2Bfx%2BChyeGiyuGjyuCjyuGly%2BGlzOKmzOGozuKoz%2BKqz%2BOq0OOv1OWw1OWw1eWx1eWy1uay1%2Baz1%2Baz1%2Bez2Oe02Oe12ee22ujUGwH3AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBQkREyOxFIh/AAAAiklEQVQI12NgAAMbOwY4sLZ2NtQ1coVKWNvoc/Eq8XDr2wB5Ig62ekza9vaOqpK2TpoMzOxaFtwqZua2Bm4makIM7OzMAjoaCqYuxooSUqJALjs7o4yVpbowvzSUy87KqSwmxQfnsrPISyFzWeWAXCkpMaBVIC4bmCsOdgiUKwh3JojLgAQ4ZCE0AMm2D29tZwe6AAAAAElFTkSuQmCC)](https://bintray.com/theirix/conan-repo/jsoncpp%3Atheirix) +[![Conan Center](https://img.shields.io/conan/v/jsoncpp)](https://conan.io/center/recipes/jsoncpp) [![badge](https://img.shields.io/badge/license-MIT-blue)](https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE) [![badge](https://img.shields.io/badge/document-doxygen-brightgreen)](http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html) [![Coverage Status](https://coveralls.io/repos/github/open-source-parsers/jsoncpp/badge.svg?branch=master)](https://coveralls.io/github/open-source-parsers/jsoncpp?branch=master) @@ -52,6 +52,14 @@ You can download and install JsonCpp using the [vcpkg](https://github.com/Micros The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. +### Conan package manager + +You can download and install JsonCpp using the [Conan](https://conan.io/) package manager: + + conan install -r conancenter --requires="jsoncpp/[*]" --build=missing + +The JsonCpp package in Conan Center is kept up to date by [ConanCenterIndex](https://github.com/conan-io/conan-center-index) contributors. If the version is out of date, please create an issue or pull request on the Conan Center Index repository. + ### Amalgamated source https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated-(Possibly-outdated) From 32f924ffb01abf7efb0b56f100932505e882c099 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Feb 2026 12:58:19 -0800 Subject: [PATCH 156/196] Cleanup README.md, fix broken link. (#1633) * Cleanup README.md, fix broken link. * cleanup readme vcpkg notes --- README.md | 99 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c8b42a9be..fbdd0bee6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ [![badge](https://img.shields.io/badge/document-doxygen-brightgreen)](http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html) [![Coverage Status](https://coveralls.io/repos/github/open-source-parsers/jsoncpp/badge.svg?branch=master)](https://coveralls.io/github/open-source-parsers/jsoncpp?branch=master) - [JSON][json-org] is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value pairs. @@ -14,10 +13,9 @@ pairs. JsonCpp is a C++ library that allows manipulating JSON values, including serialization and deserialization to and from strings. It can also preserve -existing comment in unserialization/serialization steps, making it a convenient +existing comment in deserialization/serialization steps, making it a convenient format to store user input files. - ## Documentation [JsonCpp documentation][JsonCpp-documentation] is generated using [Doxygen][]. @@ -25,7 +23,6 @@ format to store user input files. [JsonCpp-documentation]: http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html [Doxygen]: http://www.doxygen.org - ## A note on backward-compatibility * `1.y.z` is built with C++11. @@ -34,42 +31,106 @@ format to store user input files. * Major versions maintain binary-compatibility. ### Special note -The branch `00.11.z`is a new branch, its major version number `00` is to show that it is -different from `0.y.z` and `1.y.z`, the main purpose of this branch is to make a balance -between the other two branches. Thus, users can use some new features in this new branch -that introduced in 1.y.z, but can hardly applied into 0.y.z. + +The branch `00.11.z`is a new branch, its major version number `00` is to show +that it is different from `0.y.z` and `1.y.z`, the main purpose of this branch +is to make a balance between the other two branches. Thus, users can use some +new features in this new branch that introduced in 1.y.z, but can hardly applied +into 0.y.z. ## Using JsonCpp in your project ### The vcpkg dependency manager -You can download and install JsonCpp using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: +You can download and install JsonCpp using the [vcpkg](https://github.com/Microsoft/vcpkg/) +dependency manager, which has installation instruction dependent on your +build system. For example, if you are in a CMake project, the +[CMake install tutorial](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started?pivots=shell-powershell) +suggests the follow installation method. + +First, clone and set up `vcpkg`. + +```sh git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh - ./vcpkg integrate install - ./vcpkg install jsoncpp +``` + +Then, create a [vcpkg.json manifest](https://learn.microsoft.com/en-us/vcpkg/reference/vcpkg-json), +enabling manifest mode and adding JsonCpp to the manifest's dependencies list. + +```sh + vcpkg new --application + vcpkg add port jsoncpp +``` + +> [!NOTE]: you can use vcpkg in either classic mode or manifest mode (recommended). + +#### Classic mode -The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. +If your project does not have a `vcpkg.json`, +your project is in [Classic mode](https://learn.microsoft.com/en-us/vcpkg/concepts/classic-mode) +you can install JsonCpp by directly invoking the `install` command: + +```sh + vcpkg install jsoncpp +``` + +### Manifest mode + +If your project *does* have a vcpkg.json manifest, your project is in [Manifest mode](https://learn.microsoft.com/en-us/vcpkg/concepts/manifest-mode) +and you need to add JsonCpp to your package manifest dependencies, then invoke +install with no arguments. + +```sh + vcpkg add port jsoncpp + vcpkg install +``` + +Example manifest: + +```sh +{ + "name": "best-app-ever", + "dependencies": [ "jsoncpp" ], +} +``` + +> [!NOTE] The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. +> If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) +> on the vcpkg repository. ### Conan package manager -You can download and install JsonCpp using the [Conan](https://conan.io/) package manager: +You can download and install JsonCpp using the [Conan](https://conan.io/) +package manager: +```sh conan install -r conancenter --requires="jsoncpp/[*]" --build=missing +``` -The JsonCpp package in Conan Center is kept up to date by [ConanCenterIndex](https://github.com/conan-io/conan-center-index) contributors. If the version is out of date, please create an issue or pull request on the Conan Center Index repository. +The JsonCpp package in Conan Center is kept up to date by [ConanCenterIndex](https://github.com/conan-io/conan-center-index) +contributors. If the version is out of date, please create an issue or pull request on the +Conan Center Index repository. ### Amalgamated source -https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated-(Possibly-outdated) + +See the [Wiki entry on Amalgamated Source](https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated-(Possibly-outdated)). ### The Meson Build System -If you are using the [Meson Build System](http://mesonbuild.com), then you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/jsoncpp), or simply use `meson wrap install jsoncpp`. + +If you are using the [Meson Build System](http://mesonbuild.com), then you can +get a wrap file by downloading it from [Meson WrapDB](https://mesonbuild.com/Wrapdb-projects.html), +or simply use `meson wrap install jsoncpp`. ### Other ways -If you have trouble, see the [Wiki](https://github.com/open-source-parsers/jsoncpp/wiki), or post a question as an Issue. + +If you have trouble, see the +[Wiki](https://github.com/open-source-parsers/jsoncpp/wiki), or post a question +as an Issue. ## License -See the `LICENSE` file for details. In summary, JsonCpp is licensed under the -MIT license, or public domain if desired and recognized in your jurisdiction. +See the [LICENSE](./LICENSE) file for details. In summary, JsonCpp is licensed +under the MIT license, or public domain if desired and recognized in your +jurisdiction. From e799ca052df0f859d8d4133211344581c211b925 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Tue, 3 Feb 2026 11:54:59 -0800 Subject: [PATCH 157/196] Add gcovr.cfg to fix CI coverage merge errors (#1635) Configures gcovr to use 'merge-mode-functions = separate', resolving the GcovrMergeAssertionError caused by strict merging of header-only functions in `jsontest.h`. Also adds source filtering to focus reports on `src/lib_json/` and `include/json/`, and excludes throw branches to reduce false positives. --- gcovr.cfg | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 gcovr.cfg diff --git a/gcovr.cfg b/gcovr.cfg new file mode 100644 index 000000000..ffbea3656 --- /dev/null +++ b/gcovr.cfg @@ -0,0 +1,22 @@ +# Newer versions of gcovr have strict function merging by default, which +# can cause issues with header-only functions or macros (like in jsontest.h). +# 'separate' mode keeps them distinct, fixing the GcovrMergeAssertionError. +merge-mode-functions = separate + +# --- Filtering --- +# Only include the library sources in the coverage report. +# This ensures coverage stats reflect the library quality and ignores test code. +filter = src/lib_json/ +filter = include/json/ + +# Exclude the build directory to avoid processing generated files +exclude-directories = build + +# --- Noise Reduction --- +# Ignore branches that are generated by the compiler (e.g., exception handling) +# This drastically reduces "false positives" for missing branch coverage. +exclude-throw-branches = yes + +# --- CI Visibility --- +# Print a small summary table to the console logs. +print-summary = yes From 2b3cc5a6ebd63ee8ee5e5b25e50947d3de35e6a4 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 17:37:00 -0800 Subject: [PATCH 158/196] Remove build directory exclusion from gcovr config (#1640) Remove exclusion of the build directory from coverage. --- gcovr.cfg | 3 --- 1 file changed, 3 deletions(-) diff --git a/gcovr.cfg b/gcovr.cfg index ffbea3656..621e71053 100644 --- a/gcovr.cfg +++ b/gcovr.cfg @@ -9,9 +9,6 @@ merge-mode-functions = separate filter = src/lib_json/ filter = include/json/ -# Exclude the build directory to avoid processing generated files -exclude-directories = build - # --- Noise Reduction --- # Ignore branches that are generated by the compiler (e.g., exception handling) # This drastically reduces "false positives" for missing branch coverage. From 4188925158cd4d88105ba36ec5b4d56cf098085b Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:11:03 -0800 Subject: [PATCH 159/196] Add workflow for version bumping --- .github/workflows/version-bump | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/version-bump diff --git a/.github/workflows/version-bump b/.github/workflows/version-bump new file mode 100644 index 000000000..b60c7b967 --- /dev/null +++ b/.github/workflows/version-bump @@ -0,0 +1,60 @@ +name: "Bump Project Version" + +on: + workflow_dispatch: + inputs: + version_base: + description: 'Target Version (e.g., 1.9.7)' + required: true + default: '1.9.7' + +jobs: + bump-version: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Construct Version String + id: get_ver + run: | + BASE="${{ github.event.inputs.version_base }}" + RUN_NUM="${{ github.run_number }}" + FULL_VER="$BASE.$RUN_NUM" + + echo "full_version=$FULL_VER" >> $GITHUB_OUTPUT + echo "base_version=$BASE" >> $GITHUB_OUTPUT + + - name: Update Project Files + run: | + VER="${{ steps.get_ver.outputs.full_version }}" + echo "Bumping all files to $VER" + + # 1. CMakeLists.txt (Matches 'VERSION X.Y.Z.W' or 'X.Y.Z') + sed -i "s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt + + # 2. meson.build + sed -i "s/version : '[0-9.]*'/version : '$VER'/" meson.build + + # 3. vcpkg.json + jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json + + # 4. include/json/version.h + # We parse the base version for the numeric macros (MAJOR.MINOR.PATCH) + # while the 4-part string goes into JSONCPP_VERSION_STRING. + IFS='.' read -r MAJOR MINOR PATCH <<< "${{ steps.get_ver.outputs.base_version }}" + + sed -i "s/# define JSONCPP_VERSION_STRING \"[^\"]*\"/# define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h + sed -i "s/# define JSONCPP_VERSION_MAJOR [0-9]*/# define JSONCPP_VERSION_MAJOR $MAJOR/" include/json/version.h + sed -i "s/# define JSONCPP_VERSION_MINOR [0-9]*/# define JSONCPP_VERSION_MINOR $MINOR/" include/json/version.h + sed -i "s/# define JSONCPP_VERSION_PATCH [0-9]*/# define JSONCPP_VERSION_PATCH $PATCH/" include/json/version.h + + - name: Commit and Push + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "chore: bump version to ${{ steps.get_ver.outputs.full_version }} (Run #${{ github.run_number }})" + git push From 257e15aa31885d6f378b1be5094da759326efb5e Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:11:42 -0800 Subject: [PATCH 160/196] Add version-bump workflow configuration --- .github/workflows/{version-bump => version-bump.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{version-bump => version-bump.yml} (100%) diff --git a/.github/workflows/version-bump b/.github/workflows/version-bump.yml similarity index 100% rename from .github/workflows/version-bump rename to .github/workflows/version-bump.yml From 3b8f743eeca2e164fc80a32f6ee3078f12aa39fc Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:18:31 -0800 Subject: [PATCH 161/196] Rename version-bump.yml to update-project-version.yml --- .github/workflows/update-project-version.yml | 59 +++++++++++++++++++ .github/workflows/version-bump.yml | 60 -------------------- 2 files changed, 59 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/update-project-version.yml delete mode 100644 .github/workflows/version-bump.yml diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml new file mode 100644 index 000000000..fc4d48689 --- /dev/null +++ b/.github/workflows/update-project-version.yml @@ -0,0 +1,59 @@ +name: "update project version" + +on: + workflow_dispatch: + inputs: + target_version: + description: 'Next Version (e.g., 1.9.7)' + required: true + default: '1.9.7' + +jobs: + create-bump-pr: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Update Project Files + id: update_files + run: | + VER="${{ github.event.inputs.target_version }}" + echo "Updating files to $VER" + + # 1. CMakeLists.txt + sed -i "s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt + + # 2. meson.build + sed -i "s/version : '[0-9.]*'/version : '$VER'/" meson.build + + # 3. vcpkg.json (Using jq for safety) + jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json + + # 4. include/json/version.h + # Parse X.Y.Z into separate variables + IFS='.' read -r MAJOR MINOR PATCH <<< "$VER" + sed -i "s/# define JSONCPP_VERSION_STRING \"[^\"]*\"/# define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h + sed -i "s/# define JSONCPP_VERSION_MAJOR [0-9]*/# define JSONCPP_VERSION_MAJOR $MAJOR/" include/json/version.h + sed -i "s/# define JSONCPP_VERSION_MINOR [0-9]*/# define JSONCPP_VERSION_MINOR $MINOR/" include/json/version.h + sed -i "s/# define JSONCPP_VERSION_PATCH [0-9]*/# define JSONCPP_VERSION_PATCH $PATCH/" include/json/version.h + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: bump version to ${{ github.event.inputs.target_version }}" + branch: "bump-to-${{ github.event.inputs.target_version }}" + title: "chore: bump version to ${{ github.event.inputs.target_version }}" + body: | + Manual version bump to `${{ github.event.inputs.target_version }}` to start the next development cycle. + + **Files updated:** + - `CMakeLists.txt` + - `meson.build` + - `vcpkg.json` + - `include/json/version.h` + labels: "maintenance" diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml deleted file mode 100644 index b60c7b967..000000000 --- a/.github/workflows/version-bump.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: "Bump Project Version" - -on: - workflow_dispatch: - inputs: - version_base: - description: 'Target Version (e.g., 1.9.7)' - required: true - default: '1.9.7' - -jobs: - bump-version: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Construct Version String - id: get_ver - run: | - BASE="${{ github.event.inputs.version_base }}" - RUN_NUM="${{ github.run_number }}" - FULL_VER="$BASE.$RUN_NUM" - - echo "full_version=$FULL_VER" >> $GITHUB_OUTPUT - echo "base_version=$BASE" >> $GITHUB_OUTPUT - - - name: Update Project Files - run: | - VER="${{ steps.get_ver.outputs.full_version }}" - echo "Bumping all files to $VER" - - # 1. CMakeLists.txt (Matches 'VERSION X.Y.Z.W' or 'X.Y.Z') - sed -i "s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt - - # 2. meson.build - sed -i "s/version : '[0-9.]*'/version : '$VER'/" meson.build - - # 3. vcpkg.json - jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json - - # 4. include/json/version.h - # We parse the base version for the numeric macros (MAJOR.MINOR.PATCH) - # while the 4-part string goes into JSONCPP_VERSION_STRING. - IFS='.' read -r MAJOR MINOR PATCH <<< "${{ steps.get_ver.outputs.base_version }}" - - sed -i "s/# define JSONCPP_VERSION_STRING \"[^\"]*\"/# define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h - sed -i "s/# define JSONCPP_VERSION_MAJOR [0-9]*/# define JSONCPP_VERSION_MAJOR $MAJOR/" include/json/version.h - sed -i "s/# define JSONCPP_VERSION_MINOR [0-9]*/# define JSONCPP_VERSION_MINOR $MINOR/" include/json/version.h - sed -i "s/# define JSONCPP_VERSION_PATCH [0-9]*/# define JSONCPP_VERSION_PATCH $PATCH/" include/json/version.h - - - name: Commit and Push - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add . - git commit -m "chore: bump version to ${{ steps.get_ver.outputs.full_version }} (Run #${{ github.run_number }})" - git push From fb3e7504ac9749c27c5510ccfff9089bd062d51d Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:22:46 -0800 Subject: [PATCH 162/196] Refactor version bump workflow for clarity and functionality Updated the workflow name and added target_soversion input. Modified version update commands for CMakeLists.txt, meson.build, and include/json/version.h. --- .github/workflows/update-project-version.yml | 59 +++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index fc4d48689..6e284b151 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -1,4 +1,4 @@ -name: "update project version" +name: "Manual Version Bump" on: workflow_dispatch: @@ -7,9 +7,12 @@ on: description: 'Next Version (e.g., 1.9.7)' required: true default: '1.9.7' + target_soversion: + description: 'Next SOVERSION (e.g., 28). Leave blank to keep current.' + required: false jobs: - create-bump-pr: + bump-and-verify: runs-on: ubuntu-latest permissions: contents: write @@ -22,38 +25,26 @@ jobs: id: update_files run: | VER="${{ github.event.inputs.target_version }}" - echo "Updating files to $VER" - - # 1. CMakeLists.txt - sed -i "s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt - - # 2. meson.build - sed -i "s/version : '[0-9.]*'/version : '$VER'/" meson.build - - # 3. vcpkg.json (Using jq for safety) + SOVER="${{ github.event.inputs.target_soversion }}" + echo "Bumping version to $VER" + + # 1. CMakeLists.txt: Match only the project declaration + # This prevents touching comments, policies, or SOVERSION + sed -i "s/project(jsoncpp VERSION [0-9.]*/project(jsoncpp VERSION $VER/" CMakeLists.txt + + # Only update SOVERSION if provided + if [ -n "$SOVER" ]; then + echo "Bumping SOVERSION to $SOVER" + sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt + fi + + # 2. meson.build: Match the project line specifically + sed -i "s/project('jsoncpp', 'cpp', version : '[0-9.]*'/project('jsoncpp', 'cpp', version : '$VER'/" meson.build + + # 3. vcpkg.json: Using jq for syntax safety jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json - # 4. include/json/version.h - # Parse X.Y.Z into separate variables + # 4. include/json/version.h: Match specific #define macros IFS='.' read -r MAJOR MINOR PATCH <<< "$VER" - sed -i "s/# define JSONCPP_VERSION_STRING \"[^\"]*\"/# define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h - sed -i "s/# define JSONCPP_VERSION_MAJOR [0-9]*/# define JSONCPP_VERSION_MAJOR $MAJOR/" include/json/version.h - sed -i "s/# define JSONCPP_VERSION_MINOR [0-9]*/# define JSONCPP_VERSION_MINOR $MINOR/" include/json/version.h - sed -i "s/# define JSONCPP_VERSION_PATCH [0-9]*/# define JSONCPP_VERSION_PATCH $PATCH/" include/json/version.h - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "chore: bump version to ${{ github.event.inputs.target_version }}" - branch: "bump-to-${{ github.event.inputs.target_version }}" - title: "chore: bump version to ${{ github.event.inputs.target_version }}" - body: | - Manual version bump to `${{ github.event.inputs.target_version }}` to start the next development cycle. - - **Files updated:** - - `CMakeLists.txt` - - `meson.build` - - `vcpkg.json` - - `include/json/version.h` - labels: "maintenance" + sed -i "s/#define JSONCPP_VERSION_STRING \"[^\"]*\"/#define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h + sed -i "s/#define JSONCPP_VERSION_MAJOR [0-9]*/ From e7324155432f0c20200ee12178c73d35f96afb05 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:23:43 -0800 Subject: [PATCH 163/196] Rename workflow and update descriptions --- .github/workflows/update-project-version.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index 6e284b151..a72486eb5 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -1,14 +1,14 @@ -name: "Manual Version Bump" +name: "update project version" on: workflow_dispatch: inputs: target_version: - description: 'Next Version (e.g., 1.9.7)' + description: 'next version (e.g., 1.9.7)' required: true default: '1.9.7' target_soversion: - description: 'Next SOVERSION (e.g., 28). Leave blank to keep current.' + description: 'next SOVERSION (e.g., 28) - leave blank to keep current.' required: false jobs: @@ -18,10 +18,10 @@ jobs: contents: write pull-requests: write steps: - - name: Checkout code + - name: checkout code uses: actions/checkout@v4 - - name: Update Project Files + - name: update project files id: update_files run: | VER="${{ github.event.inputs.target_version }}" From 3b558716d00c28a51da2d0cf551b94da936171ec Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:26:01 -0800 Subject: [PATCH 164/196] Enhance version update workflow with input validation Updated descriptions for workflow inputs and added checks for file existence before updating version files. --- .github/workflows/update-project-version.yml | 70 +++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index a72486eb5..35caeef23 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -4,11 +4,11 @@ on: workflow_dispatch: inputs: target_version: - description: 'next version (e.g., 1.9.7)' + description: 'Next Version (e.g., 1.9.7)' required: true default: '1.9.7' target_soversion: - description: 'next SOVERSION (e.g., 28) - leave blank to keep current.' + description: 'Next SOVERSION (e.g., 28). Leave blank to keep current.' required: false jobs: @@ -28,23 +28,57 @@ jobs: SOVER="${{ github.event.inputs.target_soversion }}" echo "Bumping version to $VER" - # 1. CMakeLists.txt: Match only the project declaration - # This prevents touching comments, policies, or SOVERSION - sed -i "s/project(jsoncpp VERSION [0-9.]*/project(jsoncpp VERSION $VER/" CMakeLists.txt - - # Only update SOVERSION if provided - if [ -n "$SOVER" ]; then - echo "Bumping SOVERSION to $SOVER" - sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt + # 1. CMakeLists.txt + if [ -f CMakeLists.txt ]; then + echo "updating cmakelists.txt" + sed -i "s/project(jsoncpp VERSION [0-9.]*/project(jsoncpp VERSION $VER/" CMakeLists.txt + if [ -n "$SOVER" ]; then + sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt + fi fi - # 2. meson.build: Match the project line specifically - sed -i "s/project('jsoncpp', 'cpp', version : '[0-9.]*'/project('jsoncpp', 'cpp', version : '$VER'/" meson.build + # 2. meson.build + if [ -f meson.build ]; then + echo "updating meson.build" + sed -i "s/project('jsoncpp', 'cpp', version : '[0-9.]*'/project('jsoncpp', 'cpp', version : '$VER'/" meson.build + fi + + # 3. vcpkg.json + if [ -f vcpkg.json ]; then + echo "updating vcpkg.json" + jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json + else + echo "vcpkg.json not found, skipping" + fi - # 3. vcpkg.json: Using jq for syntax safety - jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json + # 4. include/json/version.h + if [ -f include/json/version.h ]; then + echo "updating version.h" + IFS='.' read -r MAJOR MINOR PATCH <<< "$VER" + # Using '|' as delimiter to prevent shell escaping issues + sed -i "s|#define JSONCPP_VERSION_STRING \"[^\"]*\"|#define JSONCPP_VERSION_STRING \"$VER\"|" include/json/version.h + sed -i "s|#define JSONCPP_VERSION_MAJOR [0-9]*|#define JSONCPP_VERSION_MAJOR $MAJOR|" include/json/version.h + sed -i "s|#define JSONCPP_VERSION_MINOR [0-9]*|#define JSONCPP_VERSION_MINOR $MINOR|" include/json/version.h + sed -i "s|#define JSONCPP_VERSION_PATCH [0-9]*|#define JSONCPP_VERSION_PATCH $PATCH|" include/json/version.h + fi + + - name: sanity check (cmake configure) + run: | + if [ -f CMakeLists.txt ]; then + mkdir build_check + cd build_check + cmake .. -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF + fi - # 4. include/json/version.h: Match specific #define macros - IFS='.' read -r MAJOR MINOR PATCH <<< "$VER" - sed -i "s/#define JSONCPP_VERSION_STRING \"[^\"]*\"/#define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h - sed -i "s/#define JSONCPP_VERSION_MAJOR [0-9]*/ + - name: create pull request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: bump version to ${{ github.event.inputs.target_version }}" + branch: "bump-to-${{ github.event.inputs.target_version }}" + title: "chore: bump version to ${{ github.event.inputs.target_version }}" + body: | + automated version bump. + - new version: `${{ github.event.inputs.target_version }}` + - new soversion: `${{ github.event.inputs.target_soversion || 'no change' }}` + labels: "maintenance" From 50dbfd6ffb5006952ceaddf4733ddadfaf9ba1c8 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:30:20 -0800 Subject: [PATCH 165/196] Update version input descriptions and handling --- .github/workflows/update-project-version.yml | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index 35caeef23..afbf78e65 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: target_version: - description: 'Next Version (e.g., 1.9.7)' + description: 'Next Version (e.g., 1.9.7 or 1.9.7.123)' required: true default: '1.9.7' target_soversion: @@ -26,7 +26,7 @@ jobs: run: | VER="${{ github.event.inputs.target_version }}" SOVER="${{ github.event.inputs.target_soversion }}" - echo "Bumping version to $VER" + echo "bumping version to $VER" # 1. CMakeLists.txt if [ -f CMakeLists.txt ]; then @@ -47,19 +47,25 @@ jobs: if [ -f vcpkg.json ]; then echo "updating vcpkg.json" jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json - else - echo "vcpkg.json not found, skipping" fi # 4. include/json/version.h if [ -f include/json/version.h ]; then echo "updating version.h" - IFS='.' read -r MAJOR MINOR PATCH <<< "$VER" - # Using '|' as delimiter to prevent shell escaping issues + # Split version into components (handles 3 or 4 parts) + IFS='.' read -r MAJOR MINOR PATCH QUALIFIER <<< "$VER" + sed -i "s|#define JSONCPP_VERSION_STRING \"[^\"]*\"|#define JSONCPP_VERSION_STRING \"$VER\"|" include/json/version.h sed -i "s|#define JSONCPP_VERSION_MAJOR [0-9]*|#define JSONCPP_VERSION_MAJOR $MAJOR|" include/json/version.h sed -i "s|#define JSONCPP_VERSION_MINOR [0-9]*|#define JSONCPP_VERSION_MINOR $MINOR|" include/json/version.h sed -i "s|#define JSONCPP_VERSION_PATCH [0-9]*|#define JSONCPP_VERSION_PATCH $PATCH|" include/json/version.h + + # If QUALIFIER exists, append it; otherwise, leave macro empty + if [ -n "$QUALIFIER" ]; then + sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER $QUALIFIER|" include/json/version.h + else + sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER|" include/json/version.h + fi fi - name: sanity check (cmake configure) @@ -68,6 +74,9 @@ jobs: mkdir build_check cd build_check cmake .. -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF + cd .. + # CRITICAL: Remove the build folder so it isn't included in the PR + rm -rf build_check fi - name: create pull request From 4bf4e7fcb4c1181be6ae0e3a32ba7e2b7cee1a99 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:37:44 -0800 Subject: [PATCH 166/196] Update version descriptions and improve sed commands --- .github/workflows/update-project-version.yml | 24 ++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index afbf78e65..b112ce3ae 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -4,11 +4,11 @@ on: workflow_dispatch: inputs: target_version: - description: 'Next Version (e.g., 1.9.7 or 1.9.7.123)' + description: 'next version (e.g., 1.9.7 or 1.9.7.123)' required: true default: '1.9.7' target_soversion: - description: 'Next SOVERSION (e.g., 28). Leave blank to keep current.' + description: 'next soversion (e.g., 28). leave blank to keep current.' required: false jobs: @@ -28,19 +28,25 @@ jobs: SOVER="${{ github.event.inputs.target_soversion }}" echo "bumping version to $VER" - # 1. CMakeLists.txt + # 1. CMakeLists.txt (handles multi-line project() call) if [ -f CMakeLists.txt ]; then echo "updating cmakelists.txt" - sed -i "s/project(jsoncpp VERSION [0-9.]*/project(jsoncpp VERSION $VER/" CMakeLists.txt + # match VERSION only if it follows 'project(jsoncpp' + sed -i "/project(jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt if [ -n "$SOVER" ]; then sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt fi fi - # 2. meson.build + # 2. meson.build (handles multi-line project() and lowercase soversion) if [ -f meson.build ]; then echo "updating meson.build" - sed -i "s/project('jsoncpp', 'cpp', version : '[0-9.]*'/project('jsoncpp', 'cpp', version : '$VER'/" meson.build + # update version in project() + sed -i "/project('jsoncpp'/,/)/ s/version : '[0-9.]*'/version : '$VER'/" meson.build + if [ -n "$SOVER" ]; then + # update soversion in library() + sed -i "s/soversion : [0-9]*/soversion : $SOVER/" meson.build + fi fi # 3. vcpkg.json @@ -52,7 +58,8 @@ jobs: # 4. include/json/version.h if [ -f include/json/version.h ]; then echo "updating version.h" - # Split version into components (handles 3 or 4 parts) + # split version into components (e.g., 1.9.7.123 -> MAJOR=1, MINOR=9, PATCH=7, QUALIFIER=123) + # if 1.9.7 -> QUALIFIER is empty IFS='.' read -r MAJOR MINOR PATCH QUALIFIER <<< "$VER" sed -i "s|#define JSONCPP_VERSION_STRING \"[^\"]*\"|#define JSONCPP_VERSION_STRING \"$VER\"|" include/json/version.h @@ -60,7 +67,7 @@ jobs: sed -i "s|#define JSONCPP_VERSION_MINOR [0-9]*|#define JSONCPP_VERSION_MINOR $MINOR|" include/json/version.h sed -i "s|#define JSONCPP_VERSION_PATCH [0-9]*|#define JSONCPP_VERSION_PATCH $PATCH|" include/json/version.h - # If QUALIFIER exists, append it; otherwise, leave macro empty + # handle qualifier macro if [ -n "$QUALIFIER" ]; then sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER $QUALIFIER|" include/json/version.h else @@ -75,7 +82,6 @@ jobs: cd build_check cmake .. -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF cd .. - # CRITICAL: Remove the build folder so it isn't included in the PR rm -rf build_check fi From b52dce4e2ba4bc55d268523b4cd405990109a3ad Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:42:21 -0800 Subject: [PATCH 167/196] Update versioning logic in workflow configuration --- .github/workflows/update-project-version.yml | 22 +++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index b112ce3ae..9a00d255f 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: target_version: - description: 'next version (e.g., 1.9.7 or 1.9.7.123)' + description: 'next version (e.g., 1.9.7 or 1.9.7.12)' required: true default: '1.9.7' target_soversion: @@ -28,24 +28,24 @@ jobs: SOVER="${{ github.event.inputs.target_soversion }}" echo "bumping version to $VER" - # 1. CMakeLists.txt (handles multi-line project() call) + # 1. CMakeLists.txt if [ -f CMakeLists.txt ]; then echo "updating cmakelists.txt" - # match VERSION only if it follows 'project(jsoncpp' - sed -i "/project(jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt + # match VERSION only within the project block + sed -i "/project[[:space:]]*([[:space:]]*jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt if [ -n "$SOVER" ]; then sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt fi fi - # 2. meson.build (handles multi-line project() and lowercase soversion) + # 2. meson.build if [ -f meson.build ]; then echo "updating meson.build" - # update version in project() - sed -i "/project('jsoncpp'/,/)/ s/version : '[0-9.]*'/version : '$VER'/" meson.build + # match version : 'x.y.z' with flexible quotes and spacing + sed -i "s/version[[:space:]]*:[[:space:]]*['\"][0-9.]*['\"]/version : '$VER'/" meson.build if [ -n "$SOVER" ]; then - # update soversion in library() - sed -i "s/soversion : [0-9]*/soversion : $SOVER/" meson.build + # matches soversion : '26' + sed -i "s/soversion[[:space:]]*:[[:space:]]*['\"][0-9]*['\"]/soversion : '$SOVER'/" meson.build fi fi @@ -58,8 +58,7 @@ jobs: # 4. include/json/version.h if [ -f include/json/version.h ]; then echo "updating version.h" - # split version into components (e.g., 1.9.7.123 -> MAJOR=1, MINOR=9, PATCH=7, QUALIFIER=123) - # if 1.9.7 -> QUALIFIER is empty + # 1.9.7.12 -> MAJOR=1, MINOR=9, PATCH=7, QUALIFIER=12 IFS='.' read -r MAJOR MINOR PATCH QUALIFIER <<< "$VER" sed -i "s|#define JSONCPP_VERSION_STRING \"[^\"]*\"|#define JSONCPP_VERSION_STRING \"$VER\"|" include/json/version.h @@ -67,7 +66,6 @@ jobs: sed -i "s|#define JSONCPP_VERSION_MINOR [0-9]*|#define JSONCPP_VERSION_MINOR $MINOR|" include/json/version.h sed -i "s|#define JSONCPP_VERSION_PATCH [0-9]*|#define JSONCPP_VERSION_PATCH $PATCH|" include/json/version.h - # handle qualifier macro if [ -n "$QUALIFIER" ]; then sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER $QUALIFIER|" include/json/version.h else From c4a1e4ccf8f2d7e3d8801b04eae1c76700900383 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:45:47 -0800 Subject: [PATCH 168/196] Update versioning in update-project-version.yml --- .github/workflows/update-project-version.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index 9a00d255f..7f153919f 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -31,7 +31,6 @@ jobs: # 1. CMakeLists.txt if [ -f CMakeLists.txt ]; then echo "updating cmakelists.txt" - # match VERSION only within the project block sed -i "/project[[:space:]]*([[:space:]]*jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt if [ -n "$SOVER" ]; then sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt @@ -41,24 +40,28 @@ jobs: # 2. meson.build if [ -f meson.build ]; then echo "updating meson.build" - # match version : 'x.y.z' with flexible quotes and spacing sed -i "s/version[[:space:]]*:[[:space:]]*['\"][0-9.]*['\"]/version : '$VER'/" meson.build if [ -n "$SOVER" ]; then - # matches soversion : '26' sed -i "s/soversion[[:space:]]*:[[:space:]]*['\"][0-9]*['\"]/soversion : '$SOVER'/" meson.build fi fi - # 3. vcpkg.json + # 3. MODULE.bazel + if [ -f MODULE.bazel ]; then + echo "updating MODULE.bazel" + # matches: version = "1.9.6" + sed -i "s/version[[:space:]]*=[[:space:]]*['\"][0-9.]*['\"]/version = \"$VER\"/" MODULE.bazel + fi + + # 4. vcpkg.json if [ -f vcpkg.json ]; then echo "updating vcpkg.json" jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json fi - # 4. include/json/version.h + # 5. include/json/version.h if [ -f include/json/version.h ]; then echo "updating version.h" - # 1.9.7.12 -> MAJOR=1, MINOR=9, PATCH=7, QUALIFIER=12 IFS='.' read -r MAJOR MINOR PATCH QUALIFIER <<< "$VER" sed -i "s|#define JSONCPP_VERSION_STRING \"[^\"]*\"|#define JSONCPP_VERSION_STRING \"$VER\"|" include/json/version.h @@ -66,6 +69,7 @@ jobs: sed -i "s|#define JSONCPP_VERSION_MINOR [0-9]*|#define JSONCPP_VERSION_MINOR $MINOR|" include/json/version.h sed -i "s|#define JSONCPP_VERSION_PATCH [0-9]*|#define JSONCPP_VERSION_PATCH $PATCH|" include/json/version.h + # set qualifier to the number if 4th part exists, otherwise leave blank if [ -n "$QUALIFIER" ]; then sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER $QUALIFIER|" include/json/version.h else From 728ad03790d21d31140b530c97dfcce6234ed993 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:48:27 -0800 Subject: [PATCH 169/196] Clarify version update comments in workflow script Updated comments in the version bumping script to clarify that only the version inside the project() or module() blocks is updated for CMakeLists.txt, meson.build, and MODULE.bazel. Removed unnecessary version updates for include/json/version.h and related sanity checks. --- .github/workflows/update-project-version.yml | 59 +++----------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index 7f153919f..16a413dbc 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -28,7 +28,7 @@ jobs: SOVER="${{ github.event.inputs.target_soversion }}" echo "bumping version to $VER" - # 1. CMakeLists.txt + # 1. CMakeLists.txt: Only update version inside the project() block if [ -f CMakeLists.txt ]; then echo "updating cmakelists.txt" sed -i "/project[[:space:]]*([[:space:]]*jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt @@ -37,65 +37,24 @@ jobs: fi fi - # 2. meson.build + # 2. meson.build: Only update version inside the project() block if [ -f meson.build ]; then echo "updating meson.build" - sed -i "s/version[[:space:]]*:[[:space:]]*['\"][0-9.]*['\"]/version : '$VER'/" meson.build + sed -i "/project('jsoncpp'/,/)/ s/version[[:space:]]*:[[:space:]]*['\"][0-9.]*['\"]/version : '$VER'/" meson.build if [ -n "$SOVER" ]; then + # update soversion only within the library() or where defined sed -i "s/soversion[[:space:]]*:[[:space:]]*['\"][0-9]*['\"]/soversion : '$SOVER'/" meson.build fi fi - # 3. MODULE.bazel + # 3. MODULE.bazel: Only update version inside the module() block if [ -f MODULE.bazel ]; then echo "updating MODULE.bazel" - # matches: version = "1.9.6" - sed -i "s/version[[:space:]]*=[[:space:]]*['\"][0-9.]*['\"]/version = \"$VER\"/" MODULE.bazel + # match range from 'module(' to the first ')' + sed -i "/module(/,/)/ s/version[[:space:]]*=[[:space:]]*['\"][0-9.]*['\"]/version = \"$VER\"/" MODULE.bazel fi - # 4. vcpkg.json + # 4. vcpkg.json: jq is inherently surgical if [ -f vcpkg.json ]; then echo "updating vcpkg.json" - jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json.tmp vcpkg.json - fi - - # 5. include/json/version.h - if [ -f include/json/version.h ]; then - echo "updating version.h" - IFS='.' read -r MAJOR MINOR PATCH QUALIFIER <<< "$VER" - - sed -i "s|#define JSONCPP_VERSION_STRING \"[^\"]*\"|#define JSONCPP_VERSION_STRING \"$VER\"|" include/json/version.h - sed -i "s|#define JSONCPP_VERSION_MAJOR [0-9]*|#define JSONCPP_VERSION_MAJOR $MAJOR|" include/json/version.h - sed -i "s|#define JSONCPP_VERSION_MINOR [0-9]*|#define JSONCPP_VERSION_MINOR $MINOR|" include/json/version.h - sed -i "s|#define JSONCPP_VERSION_PATCH [0-9]*|#define JSONCPP_VERSION_PATCH $PATCH|" include/json/version.h - - # set qualifier to the number if 4th part exists, otherwise leave blank - if [ -n "$QUALIFIER" ]; then - sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER $QUALIFIER|" include/json/version.h - else - sed -i "s|#define JSONCPP_VERSION_QUALIFIER.*|#define JSONCPP_VERSION_QUALIFIER|" include/json/version.h - fi - fi - - - name: sanity check (cmake configure) - run: | - if [ -f CMakeLists.txt ]; then - mkdir build_check - cd build_check - cmake .. -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF - cd .. - rm -rf build_check - fi - - - name: create pull request - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "chore: bump version to ${{ github.event.inputs.target_version }}" - branch: "bump-to-${{ github.event.inputs.target_version }}" - title: "chore: bump version to ${{ github.event.inputs.target_version }}" - body: | - automated version bump. - - new version: `${{ github.event.inputs.target_version }}` - - new soversion: `${{ github.event.inputs.target_soversion || 'no change' }}` - labels: "maintenance" + jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json. From acf3b5dbaca090a53e3bc3f21a52c0052d37c10f Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 18:50:47 -0800 Subject: [PATCH 170/196] Add test for allowDroppedNullPlaceholders (#1648) --- src/test_lib_json/main.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index e20723498..5d5b971f8 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3095,6 +3095,17 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, allowNumericKeysTest) { checkParse(R"({ 123 : "abc" })"); } +JSONTEST_FIXTURE_LOCAL(ReaderTest, allowDroppedNullPlaceholders) { + Json::Features features; + features.allowDroppedNullPlaceholders_ = true; + setFeatures(features); + checkParse(R"([1,,2])"); + JSONTEST_ASSERT_EQUAL(3, root.size()); + JSONTEST_ASSERT_EQUAL(1, root[0].asInt()); + JSONTEST_ASSERT(root[1].isNull()); + JSONTEST_ASSERT_EQUAL(2, root[2].asInt()); +} + struct CharReaderTest : JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) { From 1d5b0b1abecb1b00694a069a8160dc02ab667c06 Mon Sep 17 00:00:00 2001 From: Martin Chang Date: Tue, 3 Mar 2026 10:59:37 +0800 Subject: [PATCH 171/196] prevent test colision when running in parallel via RESOURCE_LOCK (#1637) Co-authored-by: Jordan Bayles --- src/jsontestrunner/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jsontestrunner/CMakeLists.txt b/src/jsontestrunner/CMakeLists.txt index 1fc71ea87..7f536d318 100644 --- a/src/jsontestrunner/CMakeLists.txt +++ b/src/jsontestrunner/CMakeLists.txt @@ -48,4 +48,9 @@ if(PYTHONINTERP_FOUND) COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $ "${TEST_DIR}/data" WORKING_DIRECTORY "${TEST_DIR}/data" ) + + # Both tests write .actual/.actual-rewrite along with test data, need to prevent collision when running tests via ctest -j + set_tests_properties(jsoncpp_readerwriter jsoncpp_readerwriter_json_checker + PROPERTIES RESOURCE_LOCK "test_data_files" + ) endif() From dc45da884eb49636e53329d4776a6be9d80a0b22 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 2 Mar 2026 19:19:30 -0800 Subject: [PATCH 172/196] fixup project version updater (#1649) * fixup project version updater * Enhance version bumping workflow in YAML Updated the versioning script to handle version bumps in various files, including CMakeLists.txt, meson.build, MODULE.bazel, vcpkg.json, and include/json/version.h. Improved echo statements and jq command usage. * fix meson inclusion probably. * Refactor update-project-version workflow Removed sanity check and pull request creation steps from the workflow. * Add version verification and pull request creation steps * Simplify version update workflow Refactor version update logic and remove unnecessary checks. * Refactor version extraction in workflow script * Enhance workflow with CMake sanity check and version bump Add sanity check for CMake configuration and automate version bump process. * Fix regex patterns for version updates in YAML * Refactor version update script for clarity and efficiency * Fix label formatting in update-project-version.yml --- .github/workflows/update-project-version.yml | 96 ++++++++++++++++---- 1 file changed, 80 insertions(+), 16 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index 16a413dbc..af03a5566 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -22,39 +22,103 @@ jobs: uses: actions/checkout@v4 - name: update project files - id: update_files run: | VER="${{ github.event.inputs.target_version }}" SOVER="${{ github.event.inputs.target_soversion }}" - echo "bumping version to $VER" + echo "bumping to $VER" - # 1. CMakeLists.txt: Only update version inside the project() block + # 1. cmakelists.txt if [ -f CMakeLists.txt ]; then - echo "updating cmakelists.txt" - sed -i "/project[[:space:]]*([[:space:]]*jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt + sed -i "/project.*jsoncpp/,/)/ s/VERSION [0-9.]*/VERSION $VER/" CMakeLists.txt if [ -n "$SOVER" ]; then sed -i "s/set(PROJECT_SOVERSION [0-9]*/set(PROJECT_SOVERSION $SOVER/" CMakeLists.txt fi fi - # 2. meson.build: Only update version inside the project() block + # 2. meson.build if [ -f meson.build ]; then - echo "updating meson.build" - sed -i "/project('jsoncpp'/,/)/ s/version[[:space:]]*:[[:space:]]*['\"][0-9.]*['\"]/version : '$VER'/" meson.build + # targeting the version line directly + sed -i "s/version[[:space:]]*:[[:space:]]*['\"][0-9.]*['\"]/version : '$VER'/" meson.build if [ -n "$SOVER" ]; then - # update soversion only within the library() or where defined sed -i "s/soversion[[:space:]]*:[[:space:]]*['\"][0-9]*['\"]/soversion : '$SOVER'/" meson.build fi fi - # 3. MODULE.bazel: Only update version inside the module() block + # 3. module.bazel if [ -f MODULE.bazel ]; then - echo "updating MODULE.bazel" - # match range from 'module(' to the first ')' - sed -i "/module(/,/)/ s/version[[:space:]]*=[[:space:]]*['\"][0-9.]*['\"]/version = \"$VER\"/" MODULE.bazel + # match only the first 'version' occurrence in the file (the module version) + sed -i "0,/version[[:space:]]*=[[:space:]]*['\"][0-9.]*['\"]/s//version = \"$VER\"/" MODULE.bazel fi - # 4. vcpkg.json: jq is inherently surgical + # 4. vcpkg.json if [ -f vcpkg.json ]; then - echo "updating vcpkg.json" - jq ".version = \"$VER\"" vcpkg.json > vcpkg.json.tmp && mv vcpkg.json. + jq --arg ver "$VER" '.version = $ver' vcpkg.json > tmp.json && mv tmp.json vcpkg.json + fi + + # 5. include/json/version.h + if [ -f include/json/version.h ]; then + MAJOR=$(echo "$VER" | cut -d. -f1) + MINOR=$(echo "$VER" | cut -d. -f2) + PATCH=$(echo "$VER" | cut -d. -f3) + QUALIFIER=$(echo "$VER" | cut -d. -f4 -s) + + sed -i "s/#define JSONCPP_VERSION_STRING \".*\"/#define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h + sed -i "s/#define JSONCPP_VERSION_MAJOR [0-9]*/#define JSONCPP_VERSION_MAJOR $MAJOR/" include/json/version.h + sed -i "s/#define JSONCPP_VERSION_MINOR [0-9]*/#define JSONCPP_VERSION_MINOR $MINOR/" include/json/version.h + sed -i "s/#define JSONCPP_VERSION_PATCH [0-9]*/#define JSONCPP_VERSION_PATCH $PATCH/" include/json/version.h + + if [ -n "$QUALIFIER" ]; then + sed -i "s/#define JSONCPP_VERSION_QUALIFIER.*/#define JSONCPP_VERSION_QUALIFIER $QUALIFIER/" include/json/version.h + else + sed -i "s/#define JSONCPP_VERSION_QUALIFIER.*/#define JSONCPP_VERSION_QUALIFIER/" include/json/version.h + fi + fi + + - name: verify version macros + id: verify + run: | + FILE="include/json/version.h" + if [ -f "$FILE" ]; then + # extract clean values by stripping everything except digits and dots + V_STR=$(grep "JSONCPP_VERSION_STRING" "$FILE" | head -n 1 | cut -d '"' -f 2) + V_MAJ=$(grep "JSONCPP_VERSION_MAJOR" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') + V_MIN=$(grep "JSONCPP_VERSION_MINOR" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') + V_PAT=$(grep "JSONCPP_VERSION_PATCH" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') + V_QUA=$(grep "JSONCPP_VERSION_QUALIFIER" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') + + # create a unique delimiter for the multi-line output + DELIM=$(dd if=/dev/urandom bs=15 count=1 2>/dev/null | base64) + echo "report<<$DELIM" >> $GITHUB_OUTPUT + echo "| Macro | Value |" >> $GITHUB_OUTPUT + echo "| :--- | :--- |" >> $GITHUB_OUTPUT + echo "| STRING | \`$V_STR\` |" >> $GITHUB_OUTPUT + echo "| MAJOR | \`$V_MAJ\` |" >> $GITHUB_OUTPUT + echo "| MINOR | \`$V_MIN\` |" >> $GITHUB_OUTPUT + echo "| PATCH | \`$V_PAT\` |" >> $GITHUB_OUTPUT + echo "| QUALIFIER | \`${V_QUA:-empty}\` |" >> $GITHUB_OUTPUT + echo "$DELIM" >> $GITHUB_OUTPUT + fi + + - name: sanity check (cmake configure) + run: | + if [ -f CMakeLists.txt ]; then + mkdir build_check && cd build_check + cmake .. -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF + cd .. && rm -rf build_check + fi + + - name: create pull request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: bump version to ${{ github.event.inputs.target_version }}" + branch: "bump-to-${{ github.event.inputs.target_version }}" + title: "chore: bump version to ${{ github.event.inputs.target_version }}" + body: | + automated version bump. + - new version: `${{ github.event.inputs.target_version }}` + - new soversion: `${{ github.event.inputs.target_soversion || 'no change' }}` + + ### header verification + ${{ steps.verify.outputs.report }} + labels: "maintenance" From 87139ddc8614767e36969838c18483227dd15318 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Mon, 9 Mar 2026 12:15:08 -0700 Subject: [PATCH 173/196] Update README with project status and focus (#1639) * Update README with project status and focus Add project status and focus areas to README * Update README.md * docs: Restore maintainer disclaimers and fix Conan instructions This commit adds back the warning about community-maintained package managers and the warning about the Amalgamated Source being possibly outdated to prevent misdirected issues. It also includes the necessary generators for Conan 2 in the README's Conan section to resolve issue #1629 while preserving the brevity of the new layout. --- README.md | 130 ++++++++++++++++++++---------------------------------- 1 file changed, 49 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index fbdd0bee6..25b2d2b83 100644 --- a/README.md +++ b/README.md @@ -16,121 +16,89 @@ serialization and deserialization to and from strings. It can also preserve existing comment in deserialization/serialization steps, making it a convenient format to store user input files. -## Documentation +## Project Status -[JsonCpp documentation][JsonCpp-documentation] is generated using [Doxygen][]. +JsonCpp is a mature project in maintenance mode. Our priority is providing a stable, +reliable JSON library for the long tail of C++ development. -[JsonCpp-documentation]: http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html -[Doxygen]: http://www.doxygen.org +### Current Focus -## A note on backward-compatibility +* **Security:** Addressing vulnerabilities and fuzzing results. +* **Compatibility:** Ensuring the library builds without warnings on the latest versions of GCC, +Clang, and MSVC. +* **Reliability:** Fixing regressions and critical logical bugs. -* `1.y.z` is built with C++11. -* `0.y.z` can be used with older compilers. -* `00.11.z` can be used both in old and new compilers. -* Major versions maintain binary-compatibility. +### Out of Scope -### Special note +* **Performance:** We are not competing with SIMD-accelerated or reflection-based parsers. +* **Features:** We are generally not accepting requests for new data formats or major API changes. -The branch `00.11.z`is a new branch, its major version number `00` is to show -that it is different from `0.y.z` and `1.y.z`, the main purpose of this branch -is to make a balance between the other two branches. Thus, users can use some -new features in this new branch that introduced in 1.y.z, but can hardly applied -into 0.y.z. +JsonCpp remains a primary choice for developers who require comment preservation and support for +legacy toolchains where modern C++ standards are unavailable. The library is intended to be a +reliable dependency that does not require frequent updates or major migration efforts. -## Using JsonCpp in your project +## A note on backward-compatibility -### The vcpkg dependency manager +* **`1.y.z` (master):** Actively maintained. Requires C++11. -You can download and install JsonCpp using the [vcpkg](https://github.com/Microsoft/vcpkg/) -dependency manager, which has installation instruction dependent on your -build system. For example, if you are in a CMake project, the -[CMake install tutorial](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started?pivots=shell-powershell) -suggests the follow installation method. +* **`0.y.z`:** Legacy support for pre-C++11 compilers. Maintenance is limited to critical security fixes. -First, clone and set up `vcpkg`. +* **`00.11.z`:** Discontinued. -```sh - git clone https://github.com/Microsoft/vcpkg.git - cd vcpkg - ./bootstrap-vcpkg.sh -``` +Major versions maintain binary compatibility. Critical security fixes are accepted for both the `master` and `0.y.z` branches. -Then, create a [vcpkg.json manifest](https://learn.microsoft.com/en-us/vcpkg/reference/vcpkg-json), -enabling manifest mode and adding JsonCpp to the manifest's dependencies list. +## Integration -```sh - vcpkg new --application - vcpkg add port jsoncpp -``` - -> [!NOTE]: you can use vcpkg in either classic mode or manifest mode (recommended). - -#### Classic mode +> [!NOTE] +> Package manager ports (vcpkg, Conan, etc.) are community-maintained. Please report outdated versions or missing generators to their respective repositories. -If your project does not have a `vcpkg.json`, -your project is in [Classic mode](https://learn.microsoft.com/en-us/vcpkg/concepts/classic-mode) -you can install JsonCpp by directly invoking the `install` command: +### vcpkg +Add `jsoncpp` to your `vcpkg.json` manifest: -```sh - vcpkg install jsoncpp +```json +{ + "dependencies": ["jsoncpp"] +} ``` -### Manifest mode +Or install via classic mode: `vcpkg install jsoncpp`. -If your project *does* have a vcpkg.json manifest, your project is in [Manifest mode](https://learn.microsoft.com/en-us/vcpkg/concepts/manifest-mode) -and you need to add JsonCpp to your package manifest dependencies, then invoke -install with no arguments. +### Conan ```sh - vcpkg add port jsoncpp - vcpkg install +conan install --requires="jsoncpp/[*]" --build=missing ``` -Example manifest: - -```sh -{ - "name": "best-app-ever", - "dependencies": [ "jsoncpp" ], -} -``` +If you are using a `conanfile.txt` in a Conan 2 project, ensure you use the appropriate generators: -> [!NOTE] The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. -> If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) -> on the vcpkg repository. +```ini +[requires] +jsoncpp/[*] -### Conan package manager +[generators] +CMakeToolchain +CMakeDeps +``` -You can download and install JsonCpp using the [Conan](https://conan.io/) -package manager: +### Meson ```sh - conan install -r conancenter --requires="jsoncpp/[*]" --build=missing +meson wrap install jsoncpp ``` -The JsonCpp package in Conan Center is kept up to date by [ConanCenterIndex](https://github.com/conan-io/conan-center-index) -contributors. If the version is out of date, please create an issue or pull request on the -Conan Center Index repository. - ### Amalgamated source -See the [Wiki entry on Amalgamated Source](https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated-(Possibly-outdated)). +> [!NOTE] +> This approach may be outdated. -### The Meson Build System +For projects requiring a single-header approach, see the [Wiki entry](https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated-(Possibly-outdated)). -If you are using the [Meson Build System](http://mesonbuild.com), then you can -get a wrap file by downloading it from [Meson WrapDB](https://mesonbuild.com/Wrapdb-projects.html), -or simply use `meson wrap install jsoncpp`. - -### Other ways +## Documentation -If you have trouble, see the -[Wiki](https://github.com/open-source-parsers/jsoncpp/wiki), or post a question -as an Issue. +Documentation is generated via [Doxygen](http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html). +Additional information is available on the [Project Wiki](https://github.com/open-source-parsers/jsoncpp/wiki). ## License -See the [LICENSE](./LICENSE) file for details. In summary, JsonCpp is licensed -under the MIT license, or public domain if desired and recognized in your -jurisdiction. +JsonCpp is licensed under the MIT license, or public domain where recognized. +See [LICENSE](./LICENSE) for details. From dbd0850e9ac2b18b91fa5588b1243bbc0eb037c6 Mon Sep 17 00:00:00 2001 From: nv-jdeligiannis <84378738+nv-jdeligiannis@users.noreply.github.com> Date: Tue, 10 Mar 2026 01:33:25 +0100 Subject: [PATCH 174/196] Adding a cmake option to exclude the jsoncpp files from install. (#1596) * Adding a cmake option to exclude the jsoncpp files from install. Useful when used used as a submodule * Updaing help text --------- Co-authored-by: Jordan Bayles --- CMakeLists.txt | 1 + include/CMakeLists.txt | 3 +++ src/lib_json/CMakeLists.txt | 3 +++ 3 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ab9c52a2..4eb4499a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ option(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C option(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON) option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON) option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF) +option(JSONCPP_WITH_INSTALL "Include JsonCpp header and binaries in the install target" ON) option(JSONCPP_STATIC_WINDOWS_RUNTIME "Use static (MT/MTd) Windows runtime" OFF) option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." ON) option(BUILD_STATIC_LIBS "Build jsoncpp_lib as a static library." ON) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index dc40d95e8..bbd640559 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,5 +1,8 @@ +if (JSONCPP_WITH_INSTALL) + file(GLOB INCLUDE_FILES "json/*.h") install(FILES ${INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/json) +endif() \ No newline at end of file diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 3037eb020..86722ac8d 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -196,6 +196,8 @@ if(BUILD_OBJECT_LIBS) list(APPEND CMAKE_TARGETS ${OBJECT_LIB}) endif() +if (JSONCPP_WITH_INSTALL) + install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -203,3 +205,4 @@ install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT} OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} ) +endif() From 715735abbe29ee973049b34a7b6336b93d321284 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 13:57:22 -0700 Subject: [PATCH 175/196] Change stack depth limit to 256 (#1657) * Change stack depth limit to 256 * run clang format --- src/lib_json/json_reader.cpp | 8 ++++---- src/test_lib_json/main.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 265b03054..0697132b0 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -39,7 +39,7 @@ // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile // time to change the stack limit #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) -#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#define JSONCPP_DEPRECATED_STACK_LIMIT 256 #endif static size_t const stackLimit_g = @@ -1932,7 +1932,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings) { (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; + (*settings)["stackLimit"] = 256; (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; (*settings)["allowSpecialFloats"] = false; @@ -1949,7 +1949,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) { (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; + (*settings)["stackLimit"] = 256; (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; (*settings)["allowSpecialFloats"] = false; @@ -1965,7 +1965,7 @@ void CharReaderBuilder::ecma404Mode(Json::Value* settings) { (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; + (*settings)["stackLimit"] = 256; (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = false; (*settings)["allowSpecialFloats"] = false; diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 5d5b971f8..f19ca2fb4 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3355,6 +3355,16 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { JSONTEST_ASSERT_THROWS( reader->parse(doc, doc + std::strlen(doc), &root, &errs)); } + // Default stack limit should reject deeply nested input (regression test for + // stack exhaustion from fuzz input like [[[[...]]]]) + { + Json::CharReaderBuilder defaultBuilder; + Json::String nested(300, '['); + CharReaderPtr reader(defaultBuilder.newCharReader()); + Json::String errs; + JSONTEST_ASSERT_THROWS(reader->parse( + nested.data(), nested.data() + nested.size(), &root, &errs)); + } #endif // JSON_USE_EXCEPTION } From 134138d0eb404eedd7b421609e795c858895c0ab Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 16:33:53 -0700 Subject: [PATCH 176/196] Fix uninitialized CMake variable in version.in (#1658) CMake's project() command sets jsoncpp_VERSION (lowercase prefix), not JSONCPP_VERSION. The wrong variable caused the generated version file to be empty. Fixes #1656 Co-authored-by: Claude Sonnet 4.6 --- version.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.in b/version.in index bfc03f7dd..f1e333570 100644 --- a/version.in +++ b/version.in @@ -1 +1 @@ -@JSONCPP_VERSION@ +@jsoncpp_VERSION@ From ef0877151eb14f2d75fea139b5de34a048733e8b Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 17:54:08 -0700 Subject: [PATCH 177/196] Fix CMake deprecation warning for compatibility with CMake < 3.10 (#1659) * Fix uninitialized CMake variable in version.in CMake's project() command sets jsoncpp_VERSION (lowercase prefix), not JSONCPP_VERSION. The wrong variable caused the generated version file to be empty. Fixes #1656 Co-Authored-By: Claude Sonnet 4.6 * Fix CMake deprecation warning for compatibility with CMake < 3.10 Bump JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION from 3.8.0 to 3.10.0 to silence the CMake 3.31 deprecation warning. Fixes #1598 --------- Co-authored-by: Claude Sonnet 4.6 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4eb4499a2..cfd1a4e1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ # CMake versions greater than the JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION policies will # continue to generate policy warnings "CMake Warning (dev)...Policy CMP0XXX is not set:" # -set(JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION "3.8.0") +set(JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION "3.10.0") set(JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION "3.13.2") cmake_minimum_required(VERSION ${JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION}) if("${CMAKE_VERSION}" VERSION_LESS "${JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION}") From 215b0258171aef90a708a7e4a2c40ba19a74a13a Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 17:57:42 -0700 Subject: [PATCH 178/196] Scope JSON_DLL_BUILD to shared lib target only (#1660) Replaced directory-wide add_compile_definitions/add_definitions with target_compile_definitions PRIVATE on the shared lib target, so JSON_DLL_BUILD is not incorrectly applied to static and object libs. Fixes #1634 --- src/lib_json/CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 86722ac8d..965894158 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -107,12 +107,6 @@ list(APPEND REQUIRED_FEATURES if(BUILD_SHARED_LIBS) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions(JSON_DLL_BUILD) - else() - add_definitions(-DJSON_DLL_BUILD) - endif() - set(SHARED_LIB ${PROJECT_NAME}_lib) add_library(${SHARED_LIB} SHARED ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) set_target_properties(${SHARED_LIB} PROPERTIES @@ -122,6 +116,8 @@ if(BUILD_SHARED_LIBS) POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} ) + target_compile_definitions(${SHARED_LIB} PRIVATE JSON_DLL_BUILD) + # Set library's runtime search path on OSX if(APPLE) set_target_properties(${SHARED_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") From 8661f9e5fb51ae6bd839c635ba325f0fe7ba4974 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 22:33:54 -0700 Subject: [PATCH 179/196] Fix number parsing failing under non-C locales (#1662) IStringStream inherits the global locale, so parsing doubles with operator>> fails when the locale uses ',' as the decimal separator (e.g. de_DE). Imbue the stream with std::locale::classic() in both Reader::decodeDouble and OurReader::decodeDouble. The writer already handles this correctly via fixNumericLocale(). Fixes #1565 --- RELEASE_1.9.7.md | 52 ++++++++++++++++++++++++++++++++++++ src/lib_json/json_reader.cpp | 2 ++ 2 files changed, 54 insertions(+) create mode 100644 RELEASE_1.9.7.md diff --git a/RELEASE_1.9.7.md b/RELEASE_1.9.7.md new file mode 100644 index 000000000..3607998d7 --- /dev/null +++ b/RELEASE_1.9.7.md @@ -0,0 +1,52 @@ +# jsoncpp 1.9.7 Release Work + +Issues to fix before tagging 1.9.7, each in a separate CL. + +--- + +## Done + +- [x] **#1656** — Fix uninitialized CMake variable `JSONCPP_VERSION` in `version.in` + → Change `@JSONCPP_VERSION@` to `@jsoncpp_VERSION@` + +--- + +## To Do + +### Security / Memory Safety + +- [ ] **#1626** — MemorySanitizer: use-of-uninitialized-value in `Json::Value::resolveReference` + → Uninitialized value detected by MSan in `json_value.cpp`. Need to identify and zero-initialize the offending member. + +- [ ] **#1623** — Use-after-free: `Json::Reader::parse` stores raw pointers into input string + → `Reader` stores `begin_`/`end_` pointers that dangle after the input `std::string` goes out of scope. `getFormattedErrorMessages()` then reads freed memory. + → Fix: copy the input document internally, or clearly document the lifetime requirement (the simpler option given the old Reader API is deprecated). + +### Correctness + +- [x] **#1565** — Number parsing breaks when user sets a non-C locale (e.g. `de_DE`) + → `istringstream`/`ostringstream` used for number parsing/writing inherit the global locale, which may use `,` as decimal separator instead of `.`. + → Fix: imbue streams with `std::locale::classic()` in `json_reader.cpp` and `json_writer.cpp`. + +- [ ] **#1546** — Control characters below 0x20 not rejected during parsing + → JSON spec requires rejecting unescaped control characters. jsoncpp currently accepts them. + +### Build / CMake + +- [ ] **#1634** — `JSON_DLL_BUILD` compile definition applied globally instead of per-target + → `add_compile_definitions` scopes it to all targets; should use `target_compile_definitions` scoped to the shared lib only. + +- [x] **#1598** — CMake 3.31 deprecation warning about compatibility with CMake < 3.10 + → Update `cmake_minimum_required` to use `...` version range syntax, e.g. `cmake_minimum_required(VERSION 3.10...3.31)`. + +- [x] **#1595** — Linker errors with `string_view` API when jsoncpp built as C++11 but consumer uses C++17 + → Root cause: `JSONCPP_HAS_STRING_VIEW` is not defined when building the library (forced C++11), but consumer with C++17 sees the `string_view` overloads in headers and tries to link them. + → Fix options: (a) export `JSONCPP_HAS_STRING_VIEW` in the CMake config so consumers see the same value, or (b) drop `CMAKE_CXX_STANDARD` force and use `target_compile_features(cxx_std_11)` instead. + +--- + +## Skipped (not bugs) + +- **#1548** — "Memory leak" after parsing large files: confirmed to be normal allocator behavior (OS doesn't immediately reclaim heap). Not a library bug. +- **#1533** — `clear()` then adding values fails: `clear()` preserves the value type by design. Confirmed user error. +- **#1547** — Trailing commas/garbage not rejected: existing behavior, controllable via `strictMode()`. Not a regression. diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 0697132b0..b0b6eb02f 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -583,6 +583,7 @@ bool Reader::decodeDouble(Token& token) { bool Reader::decodeDouble(Token& token, Value& decoded) { double value = 0; IStringStream is(String(token.start_, token.end_)); + is.imbue(std::locale::classic()); if (!(is >> value)) { if (value == std::numeric_limits::max()) value = std::numeric_limits::infinity(); @@ -1617,6 +1618,7 @@ bool OurReader::decodeDouble(Token& token) { bool OurReader::decodeDouble(Token& token, Value& decoded) { double value = 0; IStringStream is(String(token.start_, token.end_)); + is.imbue(std::locale::classic()); if (!(is >> value)) { if (value == std::numeric_limits::max()) value = std::numeric_limits::infinity(); From 94aee4f71552afcb8968ca8c7c1631471afa7ad8 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 22:36:14 -0700 Subject: [PATCH 180/196] Reject unescaped control characters in JSON strings (#1663) RFC 8259 requires that control characters (U+0000-U+001F) be escaped when they appear inside strings. jsoncpp previously accepted them silently. Add a check in Reader::decodeString and OurReader::decodeString to return an error when an unescaped control character is encountered. Fixes #1546 --- src/lib_json/json_reader.cpp | 4 ++++ test/data/fail_test_control_char_01.json | 1 + 2 files changed, 5 insertions(+) create mode 100644 test/data/fail_test_control_char_01.json diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index b0b6eb02f..3faa2028f 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -655,6 +655,8 @@ bool Reader::decodeString(Token& token, String& decoded) { return addError("Bad escape sequence in string", token, current); } } else { + if (static_cast(c) < 0x20) + return addError("Control character in string", token, current - 1); decoded += c; } } @@ -1690,6 +1692,8 @@ bool OurReader::decodeString(Token& token, String& decoded) { return addError("Bad escape sequence in string", token, current); } } else { + if (static_cast(c) < 0x20) + return addError("Control character in string", token, current - 1); decoded += c; } } diff --git a/test/data/fail_test_control_char_01.json b/test/data/fail_test_control_char_01.json new file mode 100644 index 000000000..1f6835573 --- /dev/null +++ b/test/data/fail_test_control_char_01.json @@ -0,0 +1 @@ +"" \ No newline at end of file From d4742c2b4550d4ee516f065c87315c756ac2430f Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 22:36:29 -0700 Subject: [PATCH 181/196] Fix MSAN issue in #1626 (#1654) * Fix MSAN issue in #1626 This patch fixes an MSAN issue by changing CZString initialization. * add test * expand tests * fix build * Export CZString with JSON_API to fix Windows DLL linker errors --- include/json/value.h | 6 +++- src/lib_json/json_value.cpp | 47 ++++++++++++++++++++---------- src/test_lib_json/main.cpp | 58 +++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 5f6544329..a7a39a1a7 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -50,6 +50,9 @@ #include #include +// Forward declaration for testing. +struct ValueTest; + #ifdef JSONCPP_HAS_STRING_VIEW #include #endif @@ -201,6 +204,7 @@ class JSON_API StaticString { */ class JSON_API Value { friend class ValueIteratorBase; + friend struct ::ValueTest; public: using Members = std::vector; @@ -266,7 +270,7 @@ class JSON_API Value { private: #endif #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - class CZString { + class JSON_API CZString { public: enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; CZString(ArrayIndex index); diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index a875d28b2..74f77896f 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -253,20 +253,29 @@ Value::CZString::CZString(const CZString& other) { cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr ? duplicateStringValue(other.cstr_, other.storage_.length_) : other.cstr_); - storage_.policy_ = - static_cast( - other.cstr_ - ? (static_cast(other.storage_.policy_) == - noDuplication - ? noDuplication - : duplicate) - : static_cast(other.storage_.policy_)) & - 3U; - storage_.length_ = other.storage_.length_; -} - -Value::CZString::CZString(CZString&& other) noexcept - : cstr_(other.cstr_), index_(other.index_) { + if (other.cstr_) { + storage_.policy_ = + static_cast( + other.cstr_ + ? (static_cast(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast(other.storage_.policy_)) & + 3U; + storage_.length_ = other.storage_.length_; + } else { + index_ = other.index_; + } +} + +Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_) { + if (other.cstr_) { + storage_.policy_ = other.storage_.policy_; + storage_.length_ = other.storage_.length_; + } else { + index_ = other.index_; + } other.cstr_ = nullptr; } @@ -292,8 +301,16 @@ Value::CZString& Value::CZString::operator=(const CZString& other) { } Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { + if (cstr_ && storage_.policy_ == duplicate) { + releasePrefixedStringValue(const_cast(cstr_)); + } cstr_ = other.cstr_; - index_ = other.index_; + if (other.cstr_) { + storage_.policy_ = other.storage_.policy_; + storage_.length_ = other.storage_.length_; + } else { + index_ = other.index_; + } other.cstr_ = nullptr; return *this; } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index f19ca2fb4..d6938c1d0 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -150,6 +150,8 @@ struct ValueTest : JsonTest::TestCase { /// Normalize the representation of floating-point number by stripped leading /// 0 in exponent. static Json::String normalizeFloatingPointStr(const Json::String& s); + + void runCZStringTests(); }; Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) { @@ -167,6 +169,44 @@ Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) { return normalized + exponent; } +void ValueTest::runCZStringTests() { + // 1. Copy Constructor (Index) + Json::Value::CZString idx1(123); + Json::Value::CZString idx2(idx1); + JSONTEST_ASSERT_EQUAL(idx2.index(), 123); + + // 2. Move Constructor (Index) + Json::Value::CZString idx3(std::move(idx1)); + JSONTEST_ASSERT_EQUAL(idx3.index(), 123); + + // 3. Move Assignment (Index) + Json::Value::CZString idx4(456); + idx4 = std::move(idx3); + JSONTEST_ASSERT_EQUAL(idx4.index(), 123); + + // 4. Copy Constructor (String) + Json::Value::CZString str1("param", 5, + Json::Value::CZString::duplicateOnCopy); + Json::Value::CZString str2((str1)); // copy makes it duplicate (owning) + JSONTEST_ASSERT_STRING_EQUAL(str2.data(), "param"); + + // 5. Move Constructor (String) + // Move from Owning string (str2) + Json::Value::CZString str3(std::move(str2)); + JSONTEST_ASSERT_STRING_EQUAL(str3.data(), "param"); + + // 6. Move Assignment (String) + Json::Value::CZString str4("other", 5, + Json::Value::CZString::duplicateOnCopy); + Json::Value::CZString str5((str4)); // owning "other" + // Move-assign owning "param" (str3) into owning "other" (str5) + // This verifies we don't leak "other" (if fixed) and correctly take "param" + str5 = std::move(str3); + JSONTEST_ASSERT_STRING_EQUAL(str5.data(), "param"); +} + +JSONTEST_FIXTURE_LOCAL(ValueTest, CZStringCoverage) { runCZStringTests(); } + JSONTEST_FIXTURE_LOCAL(ValueTest, checkNormalizeFloatingPointStr) { struct TestData { std::string in; @@ -449,6 +489,24 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, resizeArray) { } } +JSONTEST_FIXTURE_LOCAL(ValueTest, copyMoveArray) { + Json::Value array; + array.append("item1"); + array.append("item2"); + + // Test Copy Constructor (covers CZString(const CZString&) with index) + Json::Value copy(array); + JSONTEST_ASSERT_EQUAL(copy.size(), 2); + JSONTEST_ASSERT_EQUAL(Json::Value("item1"), copy[0]); + JSONTEST_ASSERT_EQUAL(Json::Value("item2"), copy[1]); + + // Test Move Constructor (covers CZString(CZString&&) with index) + Json::Value moved(std::move(copy)); + JSONTEST_ASSERT_EQUAL(moved.size(), 2); + JSONTEST_ASSERT_EQUAL(Json::Value("item1"), moved[0]); + JSONTEST_ASSERT_EQUAL(Json::Value("item2"), moved[1]); +} + JSONTEST_FIXTURE_LOCAL(ValueTest, resizePopulatesAllMissingElements) { Json::ArrayIndex n = 10; Json::Value v; From 9a5bbec0d63804de9cf028a9fbc69f8fa0dc901e Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 22:38:17 -0700 Subject: [PATCH 182/196] Fix string_view ABI mismatch between library and consumers (#1661) The library was forced to build with CMAKE_CXX_STANDARD 11, so JSONCPP_HAS_STRING_VIEW was never defined at compile time. Consumers building with C++17 would see the string_view APIs in the header but fail to link them. Fix: - Remove the global CMAKE_CXX_STANDARD 11 override; the existing target_compile_features(cxx_std_11) already enforces the minimum. - Detect string_view support at configure time with check_cxx_source_compiles and export JSONCPP_HAS_STRING_VIEW as a PUBLIC compile definition on all library targets, so consumers always see the same value the library was built with. - Guard the __cplusplus fallback in value.h so it does not override the CMake-set define. Fixes #1595 --- CMakeLists.txt | 6 ------ include/json/value.h | 2 ++ src/lib_json/CMakeLists.txt | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd1a4e1c..bc8575fd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,12 +40,6 @@ foreach(pold "") # Currently Empty endif() endforeach() -# Build the library with C++11 standard support, independent from other including -# software which may use a different CXX_STANDARD or CMAKE_CXX_STANDARD. -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - # Ensure that CMAKE_BUILD_TYPE has a value specified for single configuration generators. if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING diff --git a/include/json/value.h b/include/json/value.h index a7a39a1a7..f32f45609 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -39,9 +39,11 @@ #endif #endif +#ifndef JSONCPP_HAS_STRING_VIEW #if __cplusplus >= 201703L #define JSONCPP_HAS_STRING_VIEW 1 #endif +#endif #include #include diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 965894158..03e933552 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -7,6 +7,7 @@ include(CheckIncludeFileCXX) include(CheckTypeSize) include(CheckStructHasMember) include(CheckCXXSymbolExists) +include(CheckCXXSourceCompiles) check_include_file_cxx(clocale HAVE_CLOCALE) check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV) @@ -25,6 +26,11 @@ if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALEC endif() endif() +check_cxx_source_compiles( + "#include + int main() { std::string_view sv; return 0; }" + JSONCPP_HAS_STRING_VIEW) + set(JSONCPP_INCLUDE_DIR ../../include) set(PUBLIC_HEADERS @@ -125,6 +131,10 @@ if(BUILD_SHARED_LIBS) target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) + if(JSONCPP_HAS_STRING_VIEW) + target_compile_definitions(${SHARED_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) + endif() + target_include_directories(${SHARED_LIB} PUBLIC $ $ @@ -158,6 +168,10 @@ if(BUILD_STATIC_LIBS) target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) + if(JSONCPP_HAS_STRING_VIEW) + target_compile_definitions(${STATIC_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) + endif() + target_include_directories(${STATIC_LIB} PUBLIC $ $ @@ -184,6 +198,10 @@ if(BUILD_OBJECT_LIBS) target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) + if(JSONCPP_HAS_STRING_VIEW) + target_compile_definitions(${OBJECT_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) + endif() + target_include_directories(${OBJECT_LIB} PUBLIC $ $ From 02e903a847fb30366491007b45cf8e90ac871114 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 22:45:14 -0700 Subject: [PATCH 183/196] Revert "Fix number parsing failing under non-C locales" (#1664) * Revert "Fix number parsing failing under non-C locales (#1662)" This reverts commit 8661f9e5fb51ae6bd839c635ba325f0fe7ba4974. * readd json reader changes --- RELEASE_1.9.7.md | 52 ------------------------------------------------ 1 file changed, 52 deletions(-) delete mode 100644 RELEASE_1.9.7.md diff --git a/RELEASE_1.9.7.md b/RELEASE_1.9.7.md deleted file mode 100644 index 3607998d7..000000000 --- a/RELEASE_1.9.7.md +++ /dev/null @@ -1,52 +0,0 @@ -# jsoncpp 1.9.7 Release Work - -Issues to fix before tagging 1.9.7, each in a separate CL. - ---- - -## Done - -- [x] **#1656** — Fix uninitialized CMake variable `JSONCPP_VERSION` in `version.in` - → Change `@JSONCPP_VERSION@` to `@jsoncpp_VERSION@` - ---- - -## To Do - -### Security / Memory Safety - -- [ ] **#1626** — MemorySanitizer: use-of-uninitialized-value in `Json::Value::resolveReference` - → Uninitialized value detected by MSan in `json_value.cpp`. Need to identify and zero-initialize the offending member. - -- [ ] **#1623** — Use-after-free: `Json::Reader::parse` stores raw pointers into input string - → `Reader` stores `begin_`/`end_` pointers that dangle after the input `std::string` goes out of scope. `getFormattedErrorMessages()` then reads freed memory. - → Fix: copy the input document internally, or clearly document the lifetime requirement (the simpler option given the old Reader API is deprecated). - -### Correctness - -- [x] **#1565** — Number parsing breaks when user sets a non-C locale (e.g. `de_DE`) - → `istringstream`/`ostringstream` used for number parsing/writing inherit the global locale, which may use `,` as decimal separator instead of `.`. - → Fix: imbue streams with `std::locale::classic()` in `json_reader.cpp` and `json_writer.cpp`. - -- [ ] **#1546** — Control characters below 0x20 not rejected during parsing - → JSON spec requires rejecting unescaped control characters. jsoncpp currently accepts them. - -### Build / CMake - -- [ ] **#1634** — `JSON_DLL_BUILD` compile definition applied globally instead of per-target - → `add_compile_definitions` scopes it to all targets; should use `target_compile_definitions` scoped to the shared lib only. - -- [x] **#1598** — CMake 3.31 deprecation warning about compatibility with CMake < 3.10 - → Update `cmake_minimum_required` to use `...` version range syntax, e.g. `cmake_minimum_required(VERSION 3.10...3.31)`. - -- [x] **#1595** — Linker errors with `string_view` API when jsoncpp built as C++11 but consumer uses C++17 - → Root cause: `JSONCPP_HAS_STRING_VIEW` is not defined when building the library (forced C++11), but consumer with C++17 sees the `string_view` overloads in headers and tries to link them. - → Fix options: (a) export `JSONCPP_HAS_STRING_VIEW` in the CMake config so consumers see the same value, or (b) drop `CMAKE_CXX_STANDARD` force and use `target_compile_features(cxx_std_11)` instead. - ---- - -## Skipped (not bugs) - -- **#1548** — "Memory leak" after parsing large files: confirmed to be normal allocator behavior (OS doesn't immediately reclaim heap). Not a library bug. -- **#1533** — `clear()` then adding values fails: `clear()` preserves the value type by design. Confirmed user error. -- **#1547** — Trailing commas/garbage not rejected: existing behavior, controllable via `strictMode()`. Not a regression. From ce757bee45b84a42885af06897e378247ccecb94 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Sun, 15 Mar 2026 22:51:09 -0700 Subject: [PATCH 184/196] Fix use-after-free in Reader::parse(std::istream&) (#1665) The istream overload stored the document in a local String then passed raw pointers into it to parse(const char*, const char*), which kept those pointers in begin_/end_. After parse() returned the local String was destroyed, leaving begin_/end_ dangling. Any subsequent call to getFormattedErrorMessages() would then read freed memory. Fix by reading the stream into the member document_ instead, matching the behavior of parse(const std::string&). Also document the lifetime requirement on parse(const char*, const char*): the caller's buffer must outlive the Reader if error-reporting methods are used after parsing. Fixes #1623 --- include/json/reader.h | 5 ++++- src/lib_json/json_reader.cpp | 13 ++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/json/reader.h b/include/json/reader.h index d745378fc..7aa227188 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -81,7 +81,10 @@ class JSON_API Reader { * document. * * \param beginDoc Pointer on the beginning of the UTF-8 encoded - * string of the document to read. + * string of the document to read. The pointed-to + * buffer must outlive this Reader if error + * methods (e.g. getFormattedErrorMessages()) are + * called after parse() returns. * \param endDoc Pointer on the end of the UTF-8 encoded string * of the document to read. Must be >= beginDoc. * \param[out] root Contains the root value of the document if it diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 3faa2028f..83743f73b 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -88,15 +88,10 @@ bool Reader::parse(const std::string& document, Value& root, } bool Reader::parse(std::istream& is, Value& root, bool collectComments) { - // std::istream_iterator begin(is); - // std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since String is reference-counted, this at least does not - // create an extra copy. - String doc(std::istreambuf_iterator(is), {}); - return parse(doc.data(), doc.data() + doc.size(), root, collectComments); + document_.assign(std::istreambuf_iterator(is), + std::istreambuf_iterator()); + return parse(document_.data(), document_.data() + document_.size(), root, + collectComments); } bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, From 3455302847cf1e4671f1d8f5fa953fd46a7b1404 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 16 Mar 2026 13:09:40 -0700 Subject: [PATCH 185/196] Update bazel config for 9.x (#1655) * Update bazel config for 9.x Bazel 9.x+ requires explicit load statements for things that were previously included in bazel. I automatically added these with `buildifier` and added some reasonable minimum versions to the MODULE.bazel file. * Fix tests for Bazel 9.x sandbox --------- Co-authored-by: Jordan Bayles Co-authored-by: Jordan Bayles --- BUILD.bazel | 7 ++++--- MODULE.bazel | 8 ++++++++ example/BUILD.bazel | 6 ++++-- src/jsontestrunner/BUILD.bazel | 4 +++- src/test_lib_json/BUILD.bazel | 8 +++++--- test/BUILD.bazel | 15 ++++++++++++--- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 2227fee23..45f7a21b3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,6 +1,7 @@ -licenses(["unencumbered"]) # Public Domain or MIT - load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +licenses(["unencumbered"]) # Public Domain or MIT exports_files(["LICENSE"]) @@ -36,9 +37,9 @@ cc_library( "include/json/allocator.h", "include/json/assertions.h", "include/json/config.h", - "include/json/json_features.h", "include/json/forwards.h", "include/json/json.h", + "include/json/json_features.h", "include/json/reader.h", "include/json/value.h", "include/json/version.h", diff --git a/MODULE.bazel b/MODULE.bazel index e60fa06d1..e29304fa6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,3 +17,11 @@ bazel_dep( name = "bazel_skylib", version = "1.7.1", ) +bazel_dep( + name = "rules_cc", + version = "0.0.17", +) +bazel_dep( + name = "rules_python", + version = "1.0.0", +) diff --git a/example/BUILD.bazel b/example/BUILD.bazel index 38e7dfcf7..ebbd0b58e 100644 --- a/example/BUILD.bazel +++ b/example/BUILD.bazel @@ -1,17 +1,19 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") + cc_binary( name = "readFromStream_ok", srcs = ["readFromStream/readFromStream.cpp"], - deps = ["//:jsoncpp"], args = ["$(location :readFromStream/withComment.json)"], data = ["readFromStream/withComment.json"], + deps = ["//:jsoncpp"], ) cc_binary( name = "readFromStream_err", srcs = ["readFromStream/readFromStream.cpp"], - deps = ["//:jsoncpp"], args = ["$(location :readFromStream/errorFormat.json)"], data = ["readFromStream/errorFormat.json"], + deps = ["//:jsoncpp"], ) cc_binary( diff --git a/src/jsontestrunner/BUILD.bazel b/src/jsontestrunner/BUILD.bazel index 543bc5d88..fa1f39510 100644 --- a/src/jsontestrunner/BUILD.bazel +++ b/src/jsontestrunner/BUILD.bazel @@ -1,6 +1,8 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") + cc_binary( name = "jsontestrunner", srcs = ["main.cpp"], - deps = ["//:jsoncpp"], visibility = ["//test:__pkg__"], + deps = ["//:jsoncpp"], ) diff --git a/src/test_lib_json/BUILD.bazel b/src/test_lib_json/BUILD.bazel index 7e83f5219..18b2a1801 100644 --- a/src/test_lib_json/BUILD.bazel +++ b/src/test_lib_json/BUILD.bazel @@ -1,11 +1,13 @@ +load("@rules_cc//cc:cc_test.bzl", "cc_test") + cc_test( name = "jsoncpp_test", srcs = [ + "fuzz.cpp", + "fuzz.h", "jsontest.cpp", "jsontest.h", "main.cpp", - "fuzz.h", - "fuzz.cpp", - ], + ], deps = ["//:jsoncpp"], ) diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 269cd8646..c1a3623a1 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -1,20 +1,29 @@ +load("@rules_python//python:defs.bzl", "py_test") + filegroup( name = "expected", - srcs = glob(["data/**", "jsonchecker/**"], exclude=["**/*.json"]), + srcs = glob( + [ + "data/**", + "jsonchecker/**", + ], + exclude = ["**/*.json"], + ), ) [py_test( name = "runjson_%s_test" % "_".join(f.split("/")), srcs = ["runjsontests.py"], - main = "runjsontests.py", args = [ "--with-json-checker", "$(location //src/jsontestrunner:jsontestrunner)", "$(location :%s)" % f, ], data = [ - "//src/jsontestrunner:jsontestrunner", ":expected", + "//src/jsontestrunner", ":%s" % f, ], + main = "runjsontests.py", + tags = ["no-sandbox"], ) for f in glob(["**/*.json"])] From 8e9b4e462bdd84e932a095190fead8ec39654f53 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 19 Mar 2026 17:38:44 -0700 Subject: [PATCH 186/196] Update version to 1.9.8, remove qualifier from version string (#1666) * improve qualifier support * move to va args * remove qualifier and focus on strict Semantic Versioning --- .github/workflows/update-project-version.yml | 13 ++----------- CMakeLists.txt | 4 ++-- MODULE.bazel | 2 +- include/json/version.h | 5 ++--- meson.build | 4 ++-- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index af03a5566..c00363837 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -4,9 +4,9 @@ on: workflow_dispatch: inputs: target_version: - description: 'next version (e.g., 1.9.7 or 1.9.7.12)' + description: 'next version (e.g., 1.9.8)' required: true - default: '1.9.7' + default: '1.9.8' target_soversion: description: 'next soversion (e.g., 28). leave blank to keep current.' required: false @@ -60,18 +60,11 @@ jobs: MAJOR=$(echo "$VER" | cut -d. -f1) MINOR=$(echo "$VER" | cut -d. -f2) PATCH=$(echo "$VER" | cut -d. -f3) - QUALIFIER=$(echo "$VER" | cut -d. -f4 -s) sed -i "s/#define JSONCPP_VERSION_STRING \".*\"/#define JSONCPP_VERSION_STRING \"$VER\"/" include/json/version.h sed -i "s/#define JSONCPP_VERSION_MAJOR [0-9]*/#define JSONCPP_VERSION_MAJOR $MAJOR/" include/json/version.h sed -i "s/#define JSONCPP_VERSION_MINOR [0-9]*/#define JSONCPP_VERSION_MINOR $MINOR/" include/json/version.h sed -i "s/#define JSONCPP_VERSION_PATCH [0-9]*/#define JSONCPP_VERSION_PATCH $PATCH/" include/json/version.h - - if [ -n "$QUALIFIER" ]; then - sed -i "s/#define JSONCPP_VERSION_QUALIFIER.*/#define JSONCPP_VERSION_QUALIFIER $QUALIFIER/" include/json/version.h - else - sed -i "s/#define JSONCPP_VERSION_QUALIFIER.*/#define JSONCPP_VERSION_QUALIFIER/" include/json/version.h - fi fi - name: verify version macros @@ -84,7 +77,6 @@ jobs: V_MAJ=$(grep "JSONCPP_VERSION_MAJOR" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') V_MIN=$(grep "JSONCPP_VERSION_MINOR" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') V_PAT=$(grep "JSONCPP_VERSION_PATCH" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') - V_QUA=$(grep "JSONCPP_VERSION_QUALIFIER" "$FILE" | head -n 1 | awk '{print $3}' | tr -cd '0-9') # create a unique delimiter for the multi-line output DELIM=$(dd if=/dev/urandom bs=15 count=1 2>/dev/null | base64) @@ -95,7 +87,6 @@ jobs: echo "| MAJOR | \`$V_MAJ\` |" >> $GITHUB_OUTPUT echo "| MINOR | \`$V_MIN\` |" >> $GITHUB_OUTPUT echo "| PATCH | \`$V_PAT\` |" >> $GITHUB_OUTPUT - echo "| QUALIFIER | \`${V_QUA:-empty}\` |" >> $GITHUB_OUTPUT echo "$DELIM" >> $GITHUB_OUTPUT fi diff --git a/CMakeLists.txt b/CMakeLists.txt index bc8575fd1..0cc34c98a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,11 +57,11 @@ project(jsoncpp # 3. ./CMakeLists.txt # 4. ./MODULE.bazel # IMPORTANT: also update the PROJECT_SOVERSION!! - VERSION 1.9.7 # [.[.[.]]] + VERSION 1.9.8 # [.[.[.]]] LANGUAGES CXX) message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(PROJECT_SOVERSION 27) +set(PROJECT_SOVERSION 28) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) diff --git a/MODULE.bazel b/MODULE.bazel index e29304fa6..25b8bfc8c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -9,7 +9,7 @@ module( # 3. /CMakeLists.txt # 4. /MODULE.bazel # IMPORTANT: also update the SOVERSION!! - version = "1.9.7", + version = "1.9.8", compatibility_level = 1, ) diff --git a/include/json/version.h b/include/json/version.h index 555152c8c..1579c7807 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -10,11 +10,10 @@ // 4. /MODULE.bazel // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "1.9.7" +#define JSONCPP_VERSION_STRING "1.9.8" #define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MINOR 9 -#define JSONCPP_VERSION_PATCH 7 -#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_PATCH 8 #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ (JSONCPP_VERSION_PATCH << 8)) diff --git a/meson.build b/meson.build index 2648c3071..efcbaa43b 100644 --- a/meson.build +++ b/meson.build @@ -10,7 +10,7 @@ project( # 3. /CMakeLists.txt # 4. /MODULE.bazel # IMPORTANT: also update the SOVERSION!! - version : '1.9.7', + version : '1.9.8', default_options : [ 'buildtype=release', 'cpp_std=c++11', @@ -51,7 +51,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 27, + soversion : 28, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) From cdc84831f1861c4372cc2ced8284f0b5d0bcec5a Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 19 Mar 2026 17:59:27 -0700 Subject: [PATCH 187/196] Revert soversion change -- unnecessary (#1667) --- CMakeLists.txt | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cc34c98a..c1de7aefc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ project(jsoncpp LANGUAGES CXX) message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(PROJECT_SOVERSION 28) +set(PROJECT_SOVERSION 27) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) diff --git a/meson.build b/meson.build index efcbaa43b..e08314bcd 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 28, + soversion : 27, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) From 19a794d79a5d6074e7d573e88e705b4543775edf Mon Sep 17 00:00:00 2001 From: Jie Luo Date: Tue, 7 Apr 2026 19:54:04 -0700 Subject: [PATCH 188/196] prevent macro redefined for JSON_HAS_INT64 (#1673) --- include/json/config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/json/config.h b/include/json/config.h index 7f6e2431b..6971fa656 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -122,7 +122,9 @@ using UInt64 = uint64_t; #endif // if defined(_MSC_VER) using LargestInt = Int64; using LargestUInt = UInt64; +#ifndef JSON_HAS_INT64 #define JSON_HAS_INT64 +#endif // ifndef JSON_HAS_INT64 #endif // if defined(JSON_NO_INT64) template From 87576c45e62c2365a1238d15057bd3e8a22173f7 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Tue, 7 Apr 2026 20:29:23 -0700 Subject: [PATCH 189/196] Fix CMake 4.0 compatibility in jsoncppConfig.cmake.in (#1671) CMake 4.0 has removed compatibility with policy versions below 3.5. This change updates the minimum policy version from 3.0 to 3.5 in `jsoncppConfig.cmake.in` to prevent a fatal configuration error when downstream projects use `find_package(jsoncpp)` with CMake 4.0+. --- jsoncppConfig.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in index fdd9fea6b..35fed3687 100644 --- a/jsoncppConfig.cmake.in +++ b/jsoncppConfig.cmake.in @@ -1,5 +1,5 @@ cmake_policy(PUSH) -cmake_policy(VERSION 3.0...3.26) +cmake_policy(VERSION 3.5...3.26) @PACKAGE_INIT@ From 2c2754f3c935bfb86af21b8b1636b16a98e793f6 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Tue, 7 Apr 2026 20:46:24 -0700 Subject: [PATCH 190/196] ci: suppress Node 20 deprecation and missing python-version warnings (#1674) - Injects `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true` in all workflows to opt-in to Node.js 24 and suppress the deprecation warnings from multiple GitHub Actions. - Specifies `python-version: '3.x'` for `actions/setup-python@v5` in `meson.yml` to fix the missing input warning. --- .github/workflows/clang-format.yml | 3 +++ .github/workflows/cmake.yml | 4 ++++ .github/workflows/meson.yml | 7 +++++++ .github/workflows/update-project-version.yml | 3 +++ 4 files changed, 17 insertions(+) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 221f8b839..eca3c31f5 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,6 +1,9 @@ name: clang-format check on: [check_run, pull_request, push] +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: formatting-check: name: formatting check diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 91f387a50..55452ac25 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -1,5 +1,9 @@ name: cmake on: [check_run, push, pull_request] + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: cmake-publish: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index 22fe32f72..92d04862f 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -2,6 +2,9 @@ name: meson build and test run-name: update pushed to ${{ github.ref }} on: [check_run, push, pull_request] +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: meson-publish: runs-on: ${{ matrix.os }} @@ -17,6 +20,8 @@ jobs: - name: setup python uses: actions/setup-python@v5 + with: + python-version: '3.x' - name: meson build uses: BSFishy/meson-build@v1.0.3 @@ -41,6 +46,8 @@ jobs: - name: setup python uses: actions/setup-python@v5 + with: + python-version: '3.x' - name: meson build uses: BSFishy/meson-build@v1.0.3 diff --git a/.github/workflows/update-project-version.yml b/.github/workflows/update-project-version.yml index c00363837..c47e53790 100644 --- a/.github/workflows/update-project-version.yml +++ b/.github/workflows/update-project-version.yml @@ -11,6 +11,9 @@ on: description: 'next soversion (e.g., 28). leave blank to keep current.' required: false +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: bump-and-verify: runs-on: ubuntu-latest From c67034e4b4c722579ee15fddb8e4af8f04252b08 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 9 Apr 2026 10:37:08 -0700 Subject: [PATCH 191/196] Fix C++11 ABI breakage when compiled with C++17 #1668 (#1675) * ci: suppress Node 20 deprecation and missing python-version warnings - Injects `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true` in all workflows to opt-in to Node.js 24 and suppress the deprecation warnings from multiple GitHub Actions. - Specifies `python-version: '3.x'` for `actions/setup-python@v5` in `meson.yml` to fix the missing input warning. * Fix C++11 ABI breakage when compiled with C++17 (#1668) When JSONCPP_HAS_STRING_VIEW was defined, the library dropped the `const char*` and `const String&` overloads for `operator[]`, `get`, `removeMember`, and `isMember`, breaking ABI compatibility for projects consuming the library with C++11. This change unconditionally declares and defines the legacy overloads so they are always exported, restoring compatibility. * ci: add ABI compatibility matrix workflow This adds a new GitHub Actions workflow to verify ABI compatibility across C++ standard boundaries. It explicitly tests the scenario where JsonCpp is built with one standard (e.g., C++11) and consumed by an application built with a newer one (e.g., C++23), and vice versa. To facilitate testing the specific `std::string_view` boundary that is conditionally compiled, a new `stringView` demo application has been added to the `example/` directory and is consumed directly by the CI matrix to ensure standard library symbols link correctly across standard versions, build types (shared/static), and operating systems. * fix: inline std::string_view methods to prevent ABI breaks This commit completely eliminates the ABI breakage that occurs across C++ standard boundaries when using `std::string_view`. Previously, when the library was built with C++17+, CMake would leak `JSONCPP_HAS_STRING_VIEW=1` as a PUBLIC definition. A C++11 consumer would receive this definition, attempt to parse the header, and fail with compiler errors because `std::string_view` is not available in their environment. Conversely, if the library was built in C++11 (without `string_view` symbols), a C++17 consumer would naturally define `JSONCPP_HAS_STRING_VIEW` based on `__cplusplus` inside `value.h`. The consumer would then call the declared `string_view` methods, resulting in linker errors because the methods weren't compiled into the library. By moving all `std::string_view` overloads directly into `value.h` as `inline` methods that delegate to the fundamental `const char*, const char*` methods: 1. The consumer's compiler dictates whether the overloads are visible (via `__cplusplus >= 201703L`). 2. The consumer compiles the inline wrappers locally, removing any reliance on the library's exported symbols for `std::string_view`. 3. CMake no longer needs to pollute the consumer's environment with PUBLIC compile definitions. * run clang format * finish clang format --- .github/workflows/abi-compatibility.yml | 79 +++++++++++++++++++++++++ example/BUILD.bazel | 6 ++ example/CMakeLists.txt | 1 + example/stringView/stringView.cpp | 29 +++++++++ include/json/value.h | 54 +++++++++++------ src/lib_json/CMakeLists.txt | 9 --- src/lib_json/json_value.cpp | 66 --------------------- 7 files changed, 151 insertions(+), 93 deletions(-) create mode 100644 .github/workflows/abi-compatibility.yml create mode 100644 example/stringView/stringView.cpp diff --git a/.github/workflows/abi-compatibility.yml b/.github/workflows/abi-compatibility.yml new file mode 100644 index 000000000..881c4e8e0 --- /dev/null +++ b/.github/workflows/abi-compatibility.yml @@ -0,0 +1,79 @@ +name: ABI Compatibility + +on: [check_run, push, pull_request] + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + abi-compatibility: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + shared_libs: [ON, OFF] + include: + - jsoncpp_std: 11 + app_std: 23 + - jsoncpp_std: 23 + app_std: 11 + + steps: + - name: checkout project + uses: actions/checkout@v4 + + - name: build and install JsonCpp (C++${{ matrix.jsoncpp_std }}) + shell: bash + run: | + mkdir build-jsoncpp + cd build-jsoncpp + cmake .. -DCMAKE_CXX_STANDARD=${{ matrix.jsoncpp_std }} \ + -DCMAKE_CXX_STANDARD_REQUIRED=ON \ + -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-jsoncpp \ + -DBUILD_SHARED_LIBS=${{ matrix.shared_libs }} \ + -DJSONCPP_WITH_TESTS=OFF + cmake --build . --config Release + cmake --install . --config Release + + - name: create example app + shell: bash + run: | + mkdir example-app + cat << 'EOF' > example-app/CMakeLists.txt + cmake_minimum_required(VERSION 3.10) + project(abi_test) + + find_package(jsoncpp REQUIRED CONFIG) + + add_executable(abi_test stringView.cpp) + target_link_libraries(abi_test PRIVATE JsonCpp::JsonCpp) + EOF + + cp $GITHUB_WORKSPACE/example/stringView/stringView.cpp example-app/stringView.cpp + + - name: build example app (C++${{ matrix.app_std }}) + shell: bash + run: | + cd example-app + mkdir build + cd build + cmake .. -DCMAKE_CXX_STANDARD=${{ matrix.app_std }} \ + -DCMAKE_CXX_STANDARD_REQUIRED=ON \ + -DCMAKE_PREFIX_PATH=$GITHUB_WORKSPACE/install-jsoncpp + cmake --build . --config Release + + - name: run example app + shell: bash + run: | + if [ "$RUNNER_OS" == "Windows" ]; then + export PATH=$GITHUB_WORKSPACE/install-jsoncpp/bin:$PATH + ./example-app/build/Release/abi_test.exe + elif [ "$RUNNER_OS" == "macOS" ]; then + export DYLD_LIBRARY_PATH=$GITHUB_WORKSPACE/install-jsoncpp/lib:$DYLD_LIBRARY_PATH + ./example-app/build/abi_test + else + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install-jsoncpp/lib:$LD_LIBRARY_PATH + ./example-app/build/abi_test + fi diff --git a/example/BUILD.bazel b/example/BUILD.bazel index ebbd0b58e..35813085b 100644 --- a/example/BUILD.bazel +++ b/example/BUILD.bazel @@ -33,3 +33,9 @@ cc_binary( srcs = ["stringWrite/stringWrite.cpp"], deps = ["//:jsoncpp"], ) + +cc_binary( + name = "stringView", + srcs = ["stringView/stringView.cpp"], + deps = ["//:jsoncpp"], +) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 230d1bd7b..0666db763 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -4,6 +4,7 @@ set(EXAMPLES readFromStream stringWrite streamWrite + stringView ) add_definitions(-D_GLIBCXX_USE_CXX11_ABI) diff --git a/example/stringView/stringView.cpp b/example/stringView/stringView.cpp new file mode 100644 index 000000000..b5e33e9fd --- /dev/null +++ b/example/stringView/stringView.cpp @@ -0,0 +1,29 @@ +#include "json/json.h" +#include +#include + +#if defined(JSONCPP_HAS_STRING_VIEW) +#include +#endif + +/** + * \brief Example using std::string_view with JsonCpp. + */ +int main() { + Json::Value root; + root["key"] = "value"; + +#if defined(JSONCPP_HAS_STRING_VIEW) + std::cout << "Has string_view support" << std::endl; + std::string_view sv("key"); + if (root.isMember(sv)) { + std::cout << root[sv].asString() << std::endl; + } +#else + std::cout << "No string_view support" << std::endl; + if (root.isMember("key")) { + std::cout << root["key"].asString() << std::endl; + } +#endif + return EXIT_SUCCESS; +} diff --git a/include/json/value.h b/include/json/value.h index f32f45609..2007e6b42 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -357,7 +357,8 @@ class JSON_API Value { Value(const StaticString& value); Value(const String& value); #ifdef JSONCPP_HAS_STRING_VIEW - Value(std::string_view value); + inline Value(std::string_view value) + : Value(value.data(), value.data() + value.length()) {} #endif Value(bool value); Value(std::nullptr_t ptr) = delete; @@ -405,7 +406,14 @@ class JSON_API Value { /** Get string_view of string-value. * \return false if !string. (Seg-fault if str is NULL.) */ - bool getString(std::string_view* str) const; + inline bool getString(std::string_view* str) const { + char const* begin; + char const* end; + if (!getString(&begin, &end)) + return false; + *str = std::string_view(begin, static_cast(end - begin)); + return true; + } #endif Int asInt() const; UInt asUInt() const; @@ -496,12 +504,19 @@ class JSON_API Value { #ifdef JSONCPP_HAS_STRING_VIEW /// Access an object value by name, create a null member if it does not exist. /// \param key may contain embedded nulls. - Value& operator[](std::string_view key); + inline Value& operator[](std::string_view key) { + return resolveReference(key.data(), key.data() + key.length()); + } /// Access an object value by name, returns null if there is no member with /// that name. /// \param key may contain embedded nulls. - const Value& operator[](std::string_view key) const; -#else + inline const Value& operator[](std::string_view key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; + } +#endif /// Access an object value by name, create a null member if it does not exist. /// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// Exceeding that will cause an exception. @@ -516,7 +531,6 @@ class JSON_API Value { /// that name. /// \param key may contain embedded nulls. const Value& operator[](const String& key) const; -#endif /** \brief Access an object value by name, create a null member if it does not * exist. * @@ -533,8 +547,10 @@ class JSON_API Value { #ifdef JSONCPP_HAS_STRING_VIEW /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy - Value get(std::string_view key, const Value& defaultValue) const; -#else + inline Value get(std::string_view key, const Value& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); + } +#endif /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy Value get(const char* key, const Value& defaultValue) const; @@ -542,7 +558,6 @@ class JSON_API Value { /// \note deep copy /// \param key may contain embedded nulls. Value get(const String& key, const Value& defaultValue) const; -#endif /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy /// \note key may contain embedded nulls. @@ -588,13 +603,14 @@ class JSON_API Value { /// \pre type() is objectValue or nullValue /// \post type() is unchanged #if JSONCPP_HAS_STRING_VIEW - void removeMember(std::string_view key); -#else + inline void removeMember(std::string_view key) { + removeMember(key.data(), key.data() + key.length(), nullptr); + } +#endif void removeMember(const char* key); /// Same as removeMember(const char*) /// \param key may contain embedded nulls. void removeMember(const String& key); -#endif /** \brief Remove the named map member. * * Update 'removed' iff removed. @@ -602,13 +618,14 @@ class JSON_API Value { * \return true iff removed (no exceptions) */ #if JSONCPP_HAS_STRING_VIEW - bool removeMember(std::string_view key, Value* removed); -#else + inline bool removeMember(std::string_view key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); + } +#endif bool removeMember(String const& key, Value* removed); /// Same as removeMember(const char* begin, const char* end, Value* removed), /// but 'key' is null-terminated. bool removeMember(const char* key, Value* removed); -#endif /// Same as removeMember(String const& key, Value* removed) bool removeMember(const char* begin, const char* end, Value* removed); /** \brief Remove the indexed array element. @@ -622,15 +639,16 @@ class JSON_API Value { #ifdef JSONCPP_HAS_STRING_VIEW /// Return true if the object has a member named key. /// \param key may contain embedded nulls. - bool isMember(std::string_view key) const; -#else + inline bool isMember(std::string_view key) const { + return isMember(key.data(), key.data() + key.length()); + } +#endif /// Return true if the object has a member named key. /// \note 'key' must be null-terminated. bool isMember(const char* key) const; /// Return true if the object has a member named key. /// \param key may contain embedded nulls. bool isMember(const String& key) const; -#endif /// Same as isMember(String const& key)const bool isMember(const char* begin, const char* end) const; diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 03e933552..a0695e9eb 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -131,9 +131,6 @@ if(BUILD_SHARED_LIBS) target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) - if(JSONCPP_HAS_STRING_VIEW) - target_compile_definitions(${SHARED_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) - endif() target_include_directories(${SHARED_LIB} PUBLIC $ @@ -168,9 +165,6 @@ if(BUILD_STATIC_LIBS) target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) - if(JSONCPP_HAS_STRING_VIEW) - target_compile_definitions(${STATIC_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) - endif() target_include_directories(${STATIC_LIB} PUBLIC $ @@ -198,9 +192,6 @@ if(BUILD_OBJECT_LIBS) target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) - if(JSONCPP_HAS_STRING_VIEW) - target_compile_definitions(${OBJECT_LIB} PUBLIC JSONCPP_HAS_STRING_VIEW=1) - endif() target_include_directories(${OBJECT_LIB} PUBLIC $ diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 74f77896f..a8eb72d6b 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -441,14 +441,6 @@ Value::Value(const String& value) { value.data(), static_cast(value.length())); } -#ifdef JSONCPP_HAS_STRING_VIEW -Value::Value(std::string_view value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue( - value.data(), static_cast(value.length())); -} -#endif - Value::Value(const StaticString& value) { initBasic(stringValue); value_.string_ = const_cast(value.c_str()); @@ -656,21 +648,6 @@ bool Value::getString(char const** begin, char const** end) const { return true; } -#ifdef JSONCPP_HAS_STRING_VIEW -bool Value::getString(std::string_view* str) const { - if (type() != stringValue) - return false; - if (value_.string_ == nullptr) - return false; - const char* begin; - unsigned length; - decodePrefixedString(this->isAllocated(), this->value_.string_, &length, - &begin); - *str = std::string_view(begin, length); - return true; -} -#endif - String Value::asString() const { switch (type()) { case nullValue: @@ -1190,17 +1167,6 @@ Value* Value::demand(char const* begin, char const* end) { "objectValue or nullValue"); return &resolveReference(begin, end); } -#ifdef JSONCPP_HAS_STRING_VIEW -const Value& Value::operator[](std::string_view key) const { - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) - return nullSingleton(); - return *found; -} -Value& Value::operator[](std::string_view key) { - return resolveReference(key.data(), key.data() + key.length()); -} -#else const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); if (!found) @@ -1221,7 +1187,6 @@ Value& Value::operator[](const char* key) { Value& Value::operator[](const String& key) { return resolveReference(key.data(), key.data() + key.length()); } -#endif Value& Value::operator[](const StaticString& key) { return resolveReference(key.c_str()); @@ -1261,18 +1226,12 @@ Value Value::get(char const* begin, char const* end, Value const* found = find(begin, end); return !found ? defaultValue : *found; } -#ifdef JSONCPP_HAS_STRING_VIEW -Value Value::get(std::string_view key, const Value& defaultValue) const { - return get(key.data(), key.data() + key.length(), defaultValue); -} -#else Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } Value Value::get(String const& key, Value const& defaultValue) const { return get(key.data(), key.data() + key.length(), defaultValue); } -#endif bool Value::removeMember(const char* begin, const char* end, Value* removed) { if (type() != objectValue) { @@ -1288,31 +1247,13 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) { value_.map_->erase(it); return true; } -#ifdef JSONCPP_HAS_STRING_VIEW -bool Value::removeMember(std::string_view key, Value* removed) { - return removeMember(key.data(), key.data() + key.length(), removed); -} -#else bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } bool Value::removeMember(String const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } -#endif - -#ifdef JSONCPP_HAS_STRING_VIEW -void Value::removeMember(std::string_view key) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type() == nullValue) - return; - CZString actualKey(key.data(), unsigned(key.length()), - CZString::noDuplication); - value_.map_->erase(actualKey); -} -#else void Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::removeMember(): requires objectValue"); @@ -1323,7 +1264,6 @@ void Value::removeMember(const char* key) { value_.map_->erase(actualKey); } void Value::removeMember(const String& key) { removeMember(key.c_str()); } -#endif bool Value::removeIndex(ArrayIndex index, Value* removed) { if (type() != arrayValue) { @@ -1353,18 +1293,12 @@ bool Value::isMember(char const* begin, char const* end) const { Value const* value = find(begin, end); return nullptr != value; } -#ifdef JSONCPP_HAS_STRING_VIEW -bool Value::isMember(std::string_view key) const { - return isMember(key.data(), key.data() + key.length()); -} -#else bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } bool Value::isMember(String const& key) const { return isMember(key.data(), key.data() + key.length()); } -#endif Value::Members Value::getMemberNames() const { JSON_ASSERT_MESSAGE( From 36f94b68d60774d2a5870a6881a92de02ed76eb1 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 9 Apr 2026 11:01:46 -0700 Subject: [PATCH 192/196] chore: remove leftover CMake checks for std::string_view (#1676) * ci: suppress Node 20 deprecation and missing python-version warnings - Injects `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true` in all workflows to opt-in to Node.js 24 and suppress the deprecation warnings from multiple GitHub Actions. - Specifies `python-version: '3.x'` for `actions/setup-python@v5` in `meson.yml` to fix the missing input warning. * Fix C++11 ABI breakage when compiled with C++17 (#1668) When JSONCPP_HAS_STRING_VIEW was defined, the library dropped the `const char*` and `const String&` overloads for `operator[]`, `get`, `removeMember`, and `isMember`, breaking ABI compatibility for projects consuming the library with C++11. This change unconditionally declares and defines the legacy overloads so they are always exported, restoring compatibility. * ci: add ABI compatibility matrix workflow This adds a new GitHub Actions workflow to verify ABI compatibility across C++ standard boundaries. It explicitly tests the scenario where JsonCpp is built with one standard (e.g., C++11) and consumed by an application built with a newer one (e.g., C++23), and vice versa. To facilitate testing the specific `std::string_view` boundary that is conditionally compiled, a new `stringView` demo application has been added to the `example/` directory and is consumed directly by the CI matrix to ensure standard library symbols link correctly across standard versions, build types (shared/static), and operating systems. * fix: inline std::string_view methods to prevent ABI breaks This commit completely eliminates the ABI breakage that occurs across C++ standard boundaries when using `std::string_view`. Previously, when the library was built with C++17+, CMake would leak `JSONCPP_HAS_STRING_VIEW=1` as a PUBLIC definition. A C++11 consumer would receive this definition, attempt to parse the header, and fail with compiler errors because `std::string_view` is not available in their environment. Conversely, if the library was built in C++11 (without `string_view` symbols), a C++17 consumer would naturally define `JSONCPP_HAS_STRING_VIEW` based on `__cplusplus` inside `value.h`. The consumer would then call the declared `string_view` methods, resulting in linker errors because the methods weren't compiled into the library. By moving all `std::string_view` overloads directly into `value.h` as `inline` methods that delegate to the fundamental `const char*, const char*` methods: 1. The consumer's compiler dictates whether the overloads are visible (via `__cplusplus >= 201703L`). 2. The consumer compiles the inline wrappers locally, removing any reliance on the library's exported symbols for `std::string_view`. 3. CMake no longer needs to pollute the consumer's environment with PUBLIC compile definitions. * run clang format * finish clang format * chore: remove leftover CMake checks for std::string_view Fixes #1669 This removes the final vestige of the JSONCPP_HAS_STRING_VIEW build system logic. As of the previous commit (inlining std::string_view methods into value.h to fix ABI breaks), the library no longer relies on the build system (CMake or Meson) to check for and define JSONCPP_HAS_STRING_VIEW. The header value.h automatically activates std::string_view overloads purely by checking the consumer`s __cplusplus >= 201703L. Since none of the actual std::string_view symbols are compiled into the .so / .a library anymore, Meson (and CMake) builds are identical regardless of whether string_view is supported by the compiler building the library. * format spacing better --- src/lib_json/CMakeLists.txt | 6 ------ src/lib_json/json_value.cpp | 4 ---- 2 files changed, 10 deletions(-) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index a0695e9eb..7197ba793 100644 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -7,7 +7,6 @@ include(CheckIncludeFileCXX) include(CheckTypeSize) include(CheckStructHasMember) include(CheckCXXSymbolExists) -include(CheckCXXSourceCompiles) check_include_file_cxx(clocale HAVE_CLOCALE) check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV) @@ -26,11 +25,6 @@ if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALEC endif() endif() -check_cxx_source_compiles( - "#include - int main() { std::string_view sv; return 0; }" - JSONCPP_HAS_STRING_VIEW) - set(JSONCPP_INCLUDE_DIR ../../include) set(PUBLIC_HEADERS diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index a8eb72d6b..a812ea4d3 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -17,10 +17,6 @@ #include #include -#ifdef JSONCPP_HAS_STRING_VIEW -#include -#endif - // Provide implementation equivalent of std::snprintf for older _MSC compilers #if defined(_MSC_VER) && _MSC_VER < 1900 #include From 217973062e42de90f29f7788d8a657b02c57a80d Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 9 Apr 2026 11:05:57 -0700 Subject: [PATCH 193/196] docs: update amalgamation instructions and add github action (#1677) The amalgamation approach is not outdated and works perfectly out-of-the-box. This updates the README to remove the 'possibly-outdated' warning and replaces it with direct, simple instructions for generating the amalgamated source files. A new GitHub Action workflow (`.github/workflows/amalgamate.yml`) has also been added to ensure the `amalgamate.py` script is run on every commit and that the resulting amalgamated C++ source files successfully compile, preventing any future regressions in the single-header distribution method. --- .github/workflows/amalgamate.yml | 39 ++++++++++++++++++++++++++++++++ README.md | 11 ++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/amalgamate.yml diff --git a/.github/workflows/amalgamate.yml b/.github/workflows/amalgamate.yml new file mode 100644 index 000000000..e8a55d428 --- /dev/null +++ b/.github/workflows/amalgamate.yml @@ -0,0 +1,39 @@ +name: Amalgamation + +on: [check_run, push, pull_request] + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + amalgamation: + runs-on: ubuntu-latest + + steps: + - name: checkout project + uses: actions/checkout@v4 + + - name: setup python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: run amalgamate script + run: | + python amalgamate.py + + - name: test compile amalgamated source + run: | + cat << 'EOF' > test_amalgamation.cpp + #include "json/json.h" + #include + + int main() { + Json::Value root; + root["hello"] = "world"; + std::cout << root.toStyledString() << std::endl; + return 0; + } + EOF + c++ -std=c++11 -I dist dist/jsoncpp.cpp test_amalgamation.cpp -o test_amalgamation + ./test_amalgamation \ No newline at end of file diff --git a/README.md b/README.md index 25b2d2b83..fe2b4f956 100644 --- a/README.md +++ b/README.md @@ -88,10 +88,15 @@ meson wrap install jsoncpp ### Amalgamated source -> [!NOTE] -> This approach may be outdated. +For projects requiring a single-header approach, JsonCpp provides a script to generate an amalgamated source and header file. + +You can generate the amalgamated files by running the following Python script from the top-level directory: + +```sh +python3 amalgamate.py +``` -For projects requiring a single-header approach, see the [Wiki entry](https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated-(Possibly-outdated)). +This will generate a `dist` directory containing `jsoncpp.cpp`, `json/json.h`, and `json/json-forwards.h`. You can then drop these files directly into your project's source tree and compile `jsoncpp.cpp` alongside your other source files. ## Documentation From 941802d466ff6117508e326025720b74d67636f0 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 9 Apr 2026 11:42:28 -0700 Subject: [PATCH 194/196] feat: add Json::version() to expose runtime version (#1531) (#1678) This adds a runtime function `Json::version()` that returns the `JSONCPP_VERSION_STRING`. This allows a program using jsoncpp to display the version information of the runtime linked shared library, or check at runtime that the version of the shared library is compatible with what the program expects. Fixes #1531 --- include/json/config.h | 1 + src/lib_json/json_value.cpp | 2 ++ src/test_lib_json/main.cpp | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/include/json/config.h b/include/json/config.h index 6971fa656..4619e93bd 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -105,6 +105,7 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { +JSON_API const char* version(); using Int = int; using UInt = unsigned int; #if defined(JSON_NO_INT64) diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index a812ea4d3..168251ee1 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1704,4 +1704,6 @@ Value& Path::make(Value& root) const { return *node; } +const char* version() { return JSONCPP_VERSION_STRING; } + } // namespace Json diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index d6938c1d0..4c000fa9b 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -4188,6 +4188,11 @@ JSONTEST_FIXTURE_LOCAL(VersionTest, VersionNumbersMatch) { JSONTEST_ASSERT_EQUAL(vstr.str(), std::string(JSONCPP_VERSION_STRING)); } +JSONTEST_FIXTURE_LOCAL(VersionTest, RuntimeVersionString) { + JSONTEST_ASSERT_EQUAL(std::string(JSONCPP_VERSION_STRING), + std::string(Json::version())); +} + #if defined(__GNUC__) #pragma GCC diagnostic pop #endif From 64f54a4cfe4af4db1567672e24b033e051706536 Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 23 Apr 2026 16:20:58 -0700 Subject: [PATCH 195/196] feat: add .members() iterator adapter for range-based for loops (#288) (#1679) * feat: add .members() iterator adapter for range-based for loops (#288) This adds a zero-allocation iterator adapter to `Json::Value` that enables idiomatic range-based for loops over object members. This allows iterating over key-value pairs without allocating a vector of keys via `getMemberNames()`, and cleanly supports C++17 structured bindings (e.g. `for (const auto& [name, val] : obj.members())`). Fixes #288 * run ninja format --- .github/workflows/abi-compatibility.yml | 13 ++- .github/workflows/cmake.yml | 3 + include/json/forwards.h | 2 + include/json/value.h | 130 ++++++++++++++++++++++++ src/test_lib_json/main.cpp | 48 +++++++++ 5 files changed, 194 insertions(+), 2 deletions(-) diff --git a/.github/workflows/abi-compatibility.yml b/.github/workflows/abi-compatibility.yml index 881c4e8e0..1351c09d4 100644 --- a/.github/workflows/abi-compatibility.yml +++ b/.github/workflows/abi-compatibility.yml @@ -15,10 +15,18 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] shared_libs: [ON, OFF] include: + - jsoncpp_std: 11 + app_std: 17 + - jsoncpp_std: 17 + app_std: 11 - jsoncpp_std: 11 app_std: 23 - jsoncpp_std: 23 app_std: 11 + - jsoncpp_std: 17 + app_std: 23 + - jsoncpp_std: 23 + app_std: 17 steps: - name: checkout project @@ -47,11 +55,12 @@ jobs: find_package(jsoncpp REQUIRED CONFIG) - add_executable(abi_test stringView.cpp) + add_executable(abi_test jsontest.cpp fuzz.cpp main.cpp) target_link_libraries(abi_test PRIVATE JsonCpp::JsonCpp) EOF - cp $GITHUB_WORKSPACE/example/stringView/stringView.cpp example-app/stringView.cpp + cp src/test_lib_json/*.cpp example-app/ + cp src/test_lib_json/*.h example-app/ - name: build example app (C++${{ matrix.app_std }}) shell: bash diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 55452ac25..2b2666d36 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -12,6 +12,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] + cxx_standard: [11, 17] steps: - name: checkout project @@ -19,4 +20,6 @@ jobs: - name: build project uses: threeal/cmake-action@v2.0.0 + with: + options: CMAKE_CXX_STANDARD=${{ matrix.cxx_standard }} diff --git a/include/json/forwards.h b/include/json/forwards.h index affe33a7f..2887bdd78 100644 --- a/include/json/forwards.h +++ b/include/json/forwards.h @@ -37,6 +37,8 @@ class Value; class ValueIteratorBase; class ValueIterator; class ValueConstIterator; +class ValueMembersView; +class ValueConstMembersView; } // namespace Json diff --git a/include/json/value.h b/include/json/value.h index 2007e6b42..f14a71ce5 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -682,6 +682,11 @@ class JSON_API Value { iterator begin(); iterator end(); + // \brief Returns a view of member pairs for range-based for loops. + ValueMembersView members(); + // \brief Returns a view of member pairs for range-based for loops. + ValueConstMembersView members() const; + /// \brief Returns a reference to the first element in the `Value`. /// Requires that this value holds an array or json object, with at least one /// element. @@ -1040,6 +1045,131 @@ class JSON_API ValueIterator : public ValueIteratorBase { pointer operator->() const { return const_cast(&deref()); } }; +/** \brief Proxy struct to enable range-based for loops over object members. + */ +struct MemberProxy { + const String name; + Value& value; +}; + +/** \brief Proxy struct to enable range-based for loops over const object + * members. + */ +struct ConstMemberProxy { + const String name; + const Value& value; +}; + +/** \brief Iterator adapter for range-based for loops. + */ +class ValueMembersIterator { +public: + using iterator_category = std::forward_iterator_tag; + using value_type = MemberProxy; + using difference_type = int; + using pointer = MemberProxy*; + using reference = MemberProxy; + + ValueMembersIterator() = default; + explicit ValueMembersIterator(ValueIterator const& iter) : it_(iter) {} + + ValueMembersIterator& operator++() { + ++it_; + return *this; + } + ValueMembersIterator operator++(int) { + ValueMembersIterator temp(*this); + ++*this; + return temp; + } + bool operator==(ValueMembersIterator const& other) const { + return it_ == other.it_; + } + bool operator!=(ValueMembersIterator const& other) const { + return it_ != other.it_; + } + MemberProxy operator*() const { return MemberProxy{it_.name(), *it_}; } + +private: + ValueIterator it_; +}; + +/** \brief Iterator adapter for range-based for loops. + */ +class ValueConstMembersIterator { +public: + using iterator_category = std::forward_iterator_tag; + using value_type = ConstMemberProxy; + using difference_type = int; + using pointer = ConstMemberProxy*; + using reference = ConstMemberProxy; + + ValueConstMembersIterator() = default; + explicit ValueConstMembersIterator(ValueConstIterator const& iter) + : it_(iter) {} + + ValueConstMembersIterator& operator++() { + ++it_; + return *this; + } + ValueConstMembersIterator operator++(int) { + ValueConstMembersIterator temp(*this); + ++*this; + return temp; + } + bool operator==(ValueConstMembersIterator const& other) const { + return it_ == other.it_; + } + bool operator!=(ValueConstMembersIterator const& other) const { + return it_ != other.it_; + } + ConstMemberProxy operator*() const { + return ConstMemberProxy{it_.name(), *it_}; + } + +private: + ValueConstIterator it_; +}; + +/** \brief Range-based for loop adapter for object members. + */ +class ValueMembersView { +public: + ValueMembersView(ValueIterator begin, ValueIterator end) + : begin_(begin), end_(end) {} + ValueMembersIterator begin() const { return ValueMembersIterator(begin_); } + ValueMembersIterator end() const { return ValueMembersIterator(end_); } + +private: + ValueIterator begin_; + ValueIterator end_; +}; + +/** \brief Range-based for loop adapter for object members. + */ +class ValueConstMembersView { +public: + ValueConstMembersView(ValueConstIterator begin, ValueConstIterator end) + : begin_(begin), end_(end) {} + ValueConstMembersIterator begin() const { + return ValueConstMembersIterator(begin_); + } + ValueConstMembersIterator end() const { + return ValueConstMembersIterator(end_); + } + +private: + ValueConstIterator begin_; + ValueConstIterator end_; +}; + +inline ValueMembersView Value::members() { + return ValueMembersView(begin(), end()); +} +inline ValueConstMembersView Value::members() const { + return ValueConstMembersView(begin(), end()); +} + inline void swap(Value& a, Value& b) { a.swap(b); } inline const Value& Value::front() const { return *begin(); } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 4c000fa9b..501aba10e 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3924,6 +3924,54 @@ JSONTEST_FIXTURE_LOCAL(BomTest, notSkipBom) { struct IteratorTest : JsonTest::TestCase {}; +JSONTEST_FIXTURE_LOCAL(IteratorTest, members) { + Json::Value j; + j["k1"] = "a"; + j["k2"] = "b"; + + std::vector keys; + std::vector values; + + for (const auto& member : j.members()) { + keys.push_back(member.name); + values.push_back(member.value.asString()); + } + + JSONTEST_ASSERT((keys == std::vector{"k1", "k2"})); + JSONTEST_ASSERT((values == std::vector{"a", "b"})); + + // Test modification through value reference + for (const auto& member : j.members()) { + member.value = "c"; + } + + JSONTEST_ASSERT(j["k1"].asString() == "c"); + + // Test const members + const Json::Value& cj = j; + keys.clear(); + values.clear(); + + for (const auto& member : cj.members()) { + keys.push_back(member.name); + values.push_back(member.value.asString()); + } + + JSONTEST_ASSERT((keys == std::vector{"k1", "k2"})); + JSONTEST_ASSERT((values == std::vector{"c", "c"})); + +#if __cplusplus >= 201703L + keys.clear(); + values.clear(); + for (auto const& [k, v] : cj.members()) { + keys.push_back(k); + values.push_back(v.asString()); + } + JSONTEST_ASSERT((keys == std::vector{"k1", "k2"})); + JSONTEST_ASSERT((values == std::vector{"c", "c"})); +#endif +} + JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) { Json::Value j; const Json::Value& cj = j; From 755d0a69d7109d465db6196a3c7e1c6f3c62a48f Mon Sep 17 00:00:00 2001 From: Jordan Bayles Date: Thu, 23 Apr 2026 16:34:58 -0700 Subject: [PATCH 196/196] Improve formatting (#1680) * style: format the entire library using clang-format Updated `reformat.sh` to include the `include` and `example` directories, as well as `.inl` files, and ran it across the repository to ensure consistent code styling throughout the library. * ci: fix directory name in clang-format workflow The workflow was checking the `examples` directory, but the directory is actually named `example`. This updates the matrix path to ensure the example files are properly checked during CI. --- .github/workflows/clang-format.yml | 2 +- reformat.sh | 2 +- src/lib_json/json_valueiterator.inl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index eca3c31f5..ae3096302 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -12,7 +12,7 @@ jobs: matrix: path: - 'src' - - 'examples' + - 'example' - 'include' steps: - uses: actions/checkout@v4 diff --git a/reformat.sh b/reformat.sh index cdc03b1ea..86bc066f1 100755 --- a/reformat.sh +++ b/reformat.sh @@ -1 +1 @@ -find src -name '*.cpp' -or -name '*.h' | xargs clang-format -i +find src include example -name '*.cpp' -or -name '*.h' -or -name '*.inl' | xargs clang-format -i diff --git a/src/lib_json/json_valueiterator.inl b/src/lib_json/json_valueiterator.inl index d6128b8ed..4e77f368b 100644 --- a/src/lib_json/json_valueiterator.inl +++ b/src/lib_json/json_valueiterator.inl @@ -122,8 +122,8 @@ ValueConstIterator::ValueConstIterator( ValueConstIterator::ValueConstIterator(ValueIterator const& other) : ValueIteratorBase(other) {} -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { +ValueConstIterator& +ValueConstIterator::operator=(const ValueIteratorBase& other) { copy(other); return *this; }