Merge branch 'master' into value_find_String_key

This commit is contained in:
Jordan Bayles 2024-09-09 20:12:31 -07:00 committed by GitHub
commit 62cd357e7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 238 additions and 71 deletions

18
.github/workflows/cmake.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: cmake
on: [check_run, push, pull_request]
jobs:
cmake-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

View File

@ -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:

View File

@ -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
@ -72,11 +62,11 @@ project(jsoncpp
# 2. ./include/json/version.h
# 3. ./CMakeLists.txt
# IMPORTANT: also update the PROJECT_SOVERSION!!
VERSION 1.9.5 # <major>[.<minor>[.<patch>[.<tweak>]]]
VERSION 1.9.6 # <major>[.<minor>[.<patch>[.<tweak>]]]
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)
@ -103,7 +93,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"

17
SECURITY.md Normal file
View File

@ -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.

View File

@ -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("")

View File

@ -25,7 +25,7 @@ int main() {
const std::unique_ptr<Json::CharReader> 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;
}
}

View File

@ -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}")

View File

@ -244,6 +244,12 @@ private:
*/
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 <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the
@ -262,7 +268,12 @@ public:
* 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<StructuredError> getStructuredErrors() const;
class JSON_API Factory {
public:
@ -272,6 +283,20 @@ public:
*/
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<StructuredError> getStructuredErrors() const = 0;
};
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
private:
std::unique_ptr<Impl> _impl;
}; // CharReader
/** \brief Build a CharReader implementation.
@ -360,6 +385,12 @@ public:
* \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.

View File

@ -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"

View File

@ -9,19 +9,18 @@
// 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) | \
(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.

View File

@ -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 ()
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 ()

View File

@ -1,5 +1,5 @@
cmake_policy(PUSH)
cmake_policy(VERSION 3.0)
cmake_policy(VERSION 3.0...3.26)
@PACKAGE_INIT@

View File

@ -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)

View File

@ -9,13 +9,13 @@ project(
# 2. /include/json/version.h
# 3. /CMakeLists.txt
# IMPORTANT: also update the SOVERSION!!
version : '1.9.4',
version : '1.9.6',
default_options : [
'buildtype=release',
'cpp_std=c++11',
'warning_level=1'],
license : 'Public Domain',
meson_version : '>= 0.49.0')
meson_version : '>= 0.54.0')
jsoncpp_headers = files([
@ -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)
@ -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,
@ -73,7 +110,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([

View File

@ -132,7 +132,6 @@ if(BUILD_SHARED_LIBS)
target_include_directories(${SHARED_LIB} PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
)
list(APPEND CMAKE_TARGETS ${SHARED_LIB})
@ -144,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 (MSVC)
if (WIN32)
set(STATIC_SUFFIX "_static")
else()
set(STATIC_SUFFIX "")
@ -166,7 +165,6 @@ if(BUILD_STATIC_LIBS)
target_include_directories(${STATIC_LIB} PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
)
list(APPEND CMAKE_TARGETS ${STATIC_LIB})
@ -193,7 +191,6 @@ if(BUILD_OBJECT_LIBS)
target_include_directories(${OBJECT_LIB} PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
)
list(APPEND CMAKE_TARGETS ${OBJECT_LIB})

View File

@ -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<double>::max())
value = std::numeric_limits<double>::infinity();
@ -878,17 +877,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<StructuredError> getStructuredErrors() const;
std::vector<CharReader::StructuredError> getStructuredErrors() const;
private:
OurReader(OurReader const&); // no impl
@ -1627,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<double>::max())
value = std::numeric_limits<double>::infinity();
@ -1836,10 +1829,11 @@ String OurReader::getFormattedErrorMessages() const {
return formattedMessage;
}
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
std::vector<OurReader::StructuredError> allErrors;
std::vector<CharReader::StructuredError>
OurReader::getStructuredErrors() const {
std::vector<CharReader::StructuredError> 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 +1843,36 @@ std::vector<OurReader::StructuredError> 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<OurImpl>(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<CharReader::StructuredError>
getStructuredErrors() const override {
return reader_.getStructuredErrors();
}
private:
bool const collectComments_;
OurReader reader_;
};
};
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
@ -1951,6 +1961,32 @@ 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::StructuredError>
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
@ -1959,7 +1995,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.

View File

@ -1208,7 +1208,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) {

View File

@ -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) {

View File

@ -3926,6 +3926,36 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
example.size()));
}
struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
void testErrors(
const std::string& doc, bool success,
const std::vector<Json::CharReader::StructuredError>& 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;