Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion include/json/reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion include/json/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@
#endif
#endif

#ifndef JSONCPP_HAS_STRING_VIEW
#if __cplusplus >= 201703L
#define JSONCPP_HAS_STRING_VIEW 1
#endif
#endif

#include <array>
#include <exception>
Expand All @@ -50,6 +52,9 @@
#include <string>
#include <vector>

// Forward declaration for testing.
struct ValueTest;

#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
Expand Down Expand Up @@ -201,6 +206,7 @@ class JSON_API StaticString {
*/
class JSON_API Value {
friend class ValueIteratorBase;
friend struct ::ValueTest;

public:
using Members = std::vector<String>;
Expand Down Expand Up @@ -266,7 +272,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);
Expand Down
26 changes: 20 additions & 6 deletions src/lib_json/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 <string_view>
int main() { std::string_view sv; return 0; }"
JSONCPP_HAS_STRING_VIEW)

set(JSONCPP_INCLUDE_DIR ../../include)

set(PUBLIC_HEADERS
Expand Down Expand Up @@ -107,12 +113,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
Expand All @@ -122,13 +122,19 @@ 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/.")
endif()

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
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
Expand Down Expand Up @@ -162,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
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
Expand All @@ -188,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
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
Expand Down
19 changes: 10 additions & 9 deletions src/lib_json/json_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<char> begin(is);
// std::istream_iterator<char> 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<char>(is), {});
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
document_.assign(std::istreambuf_iterator<char>(is),
std::istreambuf_iterator<char>());
return parse(document_.data(), document_.data() + document_.size(), root,
collectComments);
}

bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
Expand Down Expand Up @@ -583,6 +578,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<double>::max())
value = std::numeric_limits<double>::infinity();
Expand Down Expand Up @@ -654,6 +650,8 @@ bool Reader::decodeString(Token& token, String& decoded) {
return addError("Bad escape sequence in string", token, current);
}
} else {
if (static_cast<unsigned char>(c) < 0x20)
return addError("Control character in string", token, current - 1);
decoded += c;
}
}
Expand Down Expand Up @@ -1617,6 +1615,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<double>::max())
value = std::numeric_limits<double>::infinity();
Expand Down Expand Up @@ -1688,6 +1687,8 @@ bool OurReader::decodeString(Token& token, String& decoded) {
return addError("Bad escape sequence in string", token, current);
}
} else {
if (static_cast<unsigned char>(c) < 0x20)
return addError("Control character in string", token, current - 1);
decoded += c;
}
}
Expand Down
47 changes: 32 additions & 15 deletions src/lib_json/json_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned>(
other.cstr_
? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
noDuplication
? noDuplication
: duplicate)
: static_cast<DuplicationPolicy>(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<unsigned>(
other.cstr_
? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
noDuplication
? noDuplication
: duplicate)
: static_cast<DuplicationPolicy>(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;
}

Expand All @@ -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<char*>(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;
}
Expand Down
58 changes: 58 additions & 0 deletions src/test_lib_json/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions test/data/fail_test_control_char_01.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
""
Loading