Compare commits

..

172 Commits

Author SHA1 Message Date
bcsgh
ca98c98457 Add a BUILD.bazel file for //example. (#1602) 2025-03-18 16:15:37 -07:00
bcsgh
037752d9a1 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
2025-03-12 15:57:16 -07:00
SwintonStreet
ba004477a6 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 <bayles.jordan@gmail.com>
2025-01-10 15:38:47 -08:00
evalon32
60ccc1f5de 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 <lmakhlis@google.com>
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2025-01-10 15:25:25 -08:00
Billy Donahue
07a8fe6a23 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
2025-01-10 15:17:00 -08:00
Jens Mertelmeyer
dca8a24cf8 Fix comparison warnings caused by 54fc4e2 (#1575)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-12-04 22:28:16 -08:00
Markus Mützel
3f86349128 Fix name of static library when targeting MinGW. (#1579)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-12-02 23:19:05 -08:00
Alexandre Detiste
2b3815c90d the cgi module was removed from Python3.13 (#1578) 2024-12-02 23:00:25 -08:00
Rui Chen
bd25fc5ea0 fix(build): remove check_required_components for meson build (#1570)
Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-09-30 15:23:00 -07:00
Jacek Galowicz
8214f717e7 Fix typo in JSONCPP_USE_SECURE_MEMORY vs JSONCPP_USING_SECURE_MEMORY (#1567) 2024-09-12 10:58:39 -07:00
Pavel Tsynk
07e3d1b076 Fix deallocate for working on old compiers (#1478)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-11 17:43:25 -07:00
Jordan Bayles
871f0cc43b 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
2024-09-11 17:01:27 -07:00
YaalLek
54fc4e28ed 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<uint64_t> 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<uint64_t> 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<uint64_t> 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 <bayles.jordan@gmail.com>
2024-09-11 16:53:22 -07:00
Paolo Monteverde
76ff1db84d Fixes PreventInSourceBuilds.cmake to work with add_subdirectory (#1383)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-11 16:47:59 -07:00
Scotty1701
89e2973c75 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 <bayles.jordan@gmail.com>
2024-09-09 20:18:29 -07:00
Timofey
7f36cdb3ea Added Value::find with String key (#1467)
* Added Value::find with String key

* Fix codestyle

---------

Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
Co-authored-by: Petukhov Timofey <Timofey.Petukhov@infotecs.ru>
2024-09-09 20:14:36 -07:00
zeroxia
2067f66d66 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 <xiazuoling.xzl@alibaba-inc.com>
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 20:14:17 -07:00
Alex Beregszaszi
3aa1192a00 Introduce CharReaderBuilder::ecma404Mode (#1333)
* Introduce CharReaderBuilder::ecma404Mode

* Bump micro version

---------

Co-authored-by: Jordan Bayles <jophba@chromium.org>
Co-authored-by: Billy Donahue <BillyDonahue@users.noreply.github.com>
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 20:11:44 -07:00
Rudi Heitbaum
99e8ca69b1 meson.build: fix the version number (#1432)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 20:09:10 -07:00
Kerem TAN
162ead383d include/json/value.h is changed (#1462)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 20:08:55 -07:00
Woodrow Douglass
4b1bd4405e 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 <bayles.jordan@gmail.com>
2024-09-09 20:08:12 -07:00
matthieugleg
f459022786 Update CMakeLists.txt (#1528)
Remove build directory from include

Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 20:06:22 -07:00
Roelof Oomen
fa0dff18fd Protect target JsonCpp::JsonCpp against multi-include (#1435)
* Protect target JsonCpp::JsonCpp against multi-include

Fixes #1356

* Simplify (@BillyDonahue)

---------

Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 20:02:24 -07:00
Bartosz Brachaczek
48d2e106a7 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 <bayles.jordan@gmail.com>
2024-09-09 20:00:06 -07:00
Lars Müller
2072e2b4e3 Use current source / binary dir when assuring out of source builds (#1527)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 19:56:37 -07:00
jedav
fdb529bd06 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 <bayles.jordan@gmail.com>
2024-09-09 19:53:56 -07:00
Jordan Bayles
8d1ea7054f Update cmake.yml 2024-09-09 19:07:04 -07:00
Jordan Bayles
d13801e832 Update meson.yml (#1564) 2024-09-09 19:06:30 -07:00
Jordan Bayles
d791737ccd Create cmake.yml (#1563)
* Create cmake.yml

* Update cmake.yml

* Update cmake.yml
2024-09-09 19:05:11 -07:00
SpaceIm
a4a083c307 remove ccache micro management (#1448)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 18:57:51 -07:00
Pedro Kaj Kjellerup Nacht
62f7f3efe6 Add security policy (#1484)
Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
2024-09-09 18:53:23 -07:00
Kapandaria
742c645ab3 Update readFromString.cpp (#1477)
Print the error to screen

Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 18:51:35 -07:00
Pavel Tsynk
31754ce2e2 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 <bayles.jordan@gmail.com>
2024-09-09 18:51:11 -07:00
Pavel Tsynk
483f1c310e Fix compile on windows with clang (#1480)
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 18:50:38 -07:00
martinduffy1
c04c0c2131 CharReader: Add StructuredError (#1409)
* CharReader: Add Structured Error

Add getStructuredError to CharReader

* run clang format

---------

Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
Co-authored-by: Jordan Bayles <jophba@chromium.org>
2024-09-09 18:48:54 -07:00
NotWearingPants
c857395951 Update link in amalgamate.py (#1335) 2024-09-09 18:43:32 -07:00
Timo Röhling
d39b0dff0c 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 <bayles.jordan@gmail.com>
2024-09-09 18:42:54 -07:00
Andrea Pappacoda
fd1abe4cca 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 <bayles.jordan@gmail.com>
2024-09-09 18:42:23 -07:00
Jordan Bayles
badbbc7185 Update clang-format.yml 2024-09-09 18:35:49 -07:00
Jordan Bayles
caf5fb0742 Update meson.yml (#1562) 2024-09-09 18:35:36 -07:00
Jordan Bayles
57de64bf69 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
2024-09-09 18:29:28 -07:00
Jordan Bayles
78893d3961 Update clang-format.yml 2024-09-09 18:19:48 -07:00
Philip Top
034976a19d 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 <BillyDonahue@users.noreply.github.com>

---------

Co-authored-by: Billy Donahue <BillyDonahue@users.noreply.github.com>
Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com>
2024-09-09 17:38:22 -07:00
vslashg
e1a3c64fef 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 <bayles.jordan@gmail.com>
2024-09-09 17:34:55 -07:00
vslashg
3c2205cd97 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 <bayles.jordan@gmail.com>
2024-09-09 17:32:17 -07:00
vslashg
0a9b9d9c6e 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 <bayles.jordan@gmail.com>
2024-09-09 17:30:16 -07:00
Jordan Bayles
c3a986600f Update clang-format.yml 2024-09-09 17:19:14 -07:00
Jordan Bayles
073ad7e96e Update meson.yml 2024-09-09 17:19:04 -07:00
Jordan Bayles
65d92a4313 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
2024-09-09 17:10:48 -07:00
Jordan Bayles
ccea7db6c3 Clang format updates (#1560)
* add comment space directive

* Fix clang format issue

* wrap in clang-format off
2024-09-09 17:07:11 -07:00
Jordan Bayles
4290915354 Update clang-format.yml 2024-09-09 16:56:02 -07:00
Jordan Bayles
cc28be0590 Update clang-format.yml 2024-09-09 16:54:56 -07:00
Jordan Bayles
255ebc54af Create clang-format.yml 2024-09-09 16:52:59 -07:00
Jordan Bayles
c8166ddf1c add comment space directive (#1558) 2024-09-09 16:30:33 -07:00
Jordan Bayles
73c94501ed Delete .travis_scripts directory (#1556) 2024-09-09 15:50:39 -07:00
Jordan Bayles
d2a9495fda Delete .travis.yml (#1557) 2024-09-09 15:50:23 -07:00
Jordan Bayles
5c003ecacc Fix clang format issues (#1555) 2024-09-09 15:48:18 -07:00
Jordan Bayles
6668fa51ee Delete .github/workflows/c-cpp.yml 2024-09-09 11:50:31 -07:00
Jordan Bayles
79ade90248 Rename meson_build_and_run to meson.yml 2024-09-09 11:46:57 -07:00
Jordan Bayles
01b11d2e4b Create meson_build_and_run (#1553) 2024-09-09 11:40:13 -07:00
Jordan Bayles
cd8173c6d3 Create c-cpp.yml 2024-09-09 11:39:17 -07:00
Mykola
69098a18b9 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.
2023-06-27 10:42:38 -04:00
Jakob Widauer
3d9bf8ee54 feat: adds front and back methods to Value type (#1458)
Value::front and Value::back
2023-06-07 12:11:01 -04:00
mwestphal
8190e061bc Fix wrong usage of doxygen groups (#1417) 2022-07-14 17:57:37 -04:00
Jessica Clarke
42e892d96e 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.
2022-01-12 16:27:16 -05:00
luzpaz
a1f1613bdd Fix various typos (#1350)
Found via `codespell -q 3 -L alue,alse`

Co-authored-by: Christopher Dunn <cdunn2001@gmail.com>
Co-authored-by: Jordan Bayles <jophba@chromium.org>
2021-12-14 18:04:47 -08:00
Tero Kinnunen
2d55c7445f 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 <tero.kinnunen@vaisala.com>

Co-authored-by: Tero Kinnunen <tero.kinnunen@vaisala.com>
2021-12-14 18:00:28 -08:00
Christopher Dunn
5defb4ed1a Merge pull request #1351 from open-source-parsers/drop-deprecation-warnings
Drop compile-time deprecation warning
2021-11-03 12:53:28 -05:00
Christopher Dunn
c4904b2c0d Bump micro version 2021-11-03 11:39:54 -05:00
Christopher Dunn
54a5432c01 Drop compile-time deprecation warning 2021-11-03 11:35:15 -05:00
Christopher Dunn
b22302e560 Merge pull request #1347 from fjtrujy/position_independent_code
Fix POSITION_INDEPENDENT_CODE
2021-11-03 10:41:12 -05:00
Francisco Javier Trujillo Mata
29f9853455 Fix cmake config for POSITION_INDEPENDENT_CODE enabling it just when BUILD_SHARED_LIBS is ON 2021-10-29 10:41:41 +02:00
Christopher Dunn
fa747b1ae3 clang-format is not available by default 2021-10-28 13:38:53 -05:00
Alex Beregszaszi
94a6220f7c Document skipBom in CharReaderBuilder (#1332) 2021-09-21 01:55:25 -04:00
Jack Ullery
c39fbdac0f minor fix for code examples (#1317) 2021-08-12 17:08:46 -04:00
Frank Dana
65bb1b1c1d 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.
2021-06-23 11:03:44 -07:00
Mariusz Glebocki
375a1119f8 Add support for Bazel build system (#1275)
Co-authored-by: Christopher Dunn <cdunn2001@gmail.com>
2021-05-05 21:03:02 -05:00
SpaceIm
5fabc5e6d2 conversion errors only if warnings as errors enabled (#1284) 2021-05-05 20:55:25 -05:00
Christopher Dunn
ed1ab7ac45 Avoid getline(s, EOF)
Fixes #1288
2021-05-05 01:21:22 -05:00
Christopher Dunn
bb34617267 Merge branch 'cmake-config-improvements' #1271
(creating merge-commit late, after accidental "rebase-and-merge")
2021-05-04 23:49:10 -05:00
Sergey Rachev
993e4e2828 - isolated namespace targets into separate file 2021-05-04 23:34:28 -05:00
Sergey Rachev
2af4a4c6c8 - workaround for CMake < 3.18 ALIAS target limitation to not point to non-GLOBAL IMPORTED target 2021-05-04 23:34:28 -05:00
Sergey Rachev
a3914b792f - narrowed lines to be aligned with overall file line width 2021-05-04 23:34:28 -05:00
Sergey Rachev
cee42e0bd7 - empty line at end of file 2021-05-04 23:34:28 -05:00
Sergey Rachev
62f3e03475 - 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
2021-05-04 23:34:28 -05:00
Sergey Rachev
b640795571 - 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.
2021-05-04 23:34:28 -05:00
Billy Donahue
94cda30dbd 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
2021-03-18 05:22:35 -04:00
PinkD
1ee39a6752 add comment for emitUTF8 in header 2021-03-06 01:33:15 -06:00
Billy Donahue
b1bd848241 fix sign-conversion warning (#1268)
Use ArrayIndex instead of int.  Fixes #1266
2021-02-20 16:07:34 -05:00
Sven Köhler
09c5ecd84f only append _static suffix for microsoft toolchains 2021-02-20 13:40:52 -06:00
Billy Donahue
fda274ddd2 Fix Value::resize to fill all array elements (#1265)
* Fix Value::resize to fill all array elements

Fixes #1264
2021-02-09 23:50:37 -05:00
Yixing Lao
da9e17d257 allow selection of Windows MSVC runtime 2021-02-03 14:29:20 -06:00
Derick Vigne
ac2870298e Fixed pkg-config Version 2021-02-03 13:40:56 -06:00
GermanAizek
c9a976238b minor fixes for 64 bits and refactor code 2021-01-15 11:49:10 -05:00
Riccardo Corsi
eab8ebe644 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. 2021-01-10 00:50:48 -06:00
Billy Donahue
fe9663e7ed Json::ValueIterator operators * and -> need to be const
Fixes #1249.
2021-01-10 00:40:21 -06:00
Christopher Dunn
5c4219b8ae 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
2021-01-10 00:18:59 -06:00
Christopher Dunn
be4a512887 Remove trailing space characters (#1256)
Also add two newlines

(rebased from `aaronfranke/formatting`)

resolves #1220

Co-authored-by: Aaron Franke <arnfranke@yahoo.com>
2021-01-09 22:39:07 -06:00
Lei
940982438d Fix a precision bug of valueToString, prevent to give an error result… (#1246)
* 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 <dlilei@126.com>
2020-12-15 11:08:05 -08:00
Hans Johnson
8954092f0a 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 <jophba@chromium.org>
2020-11-06 13:35:51 -08:00
Marcel Opprecht
ceae0e3867 Fix clang-tidy warnings (#1231)
* Fix clang-tidy warnings

Signed-off-by: Marcel Opprecht <marcel.opprecht@scandit.com>

* Fixup/clang-format

Co-authored-by: Marcel Opprecht <marcel.opprecht@scandit.com>
Co-authored-by: Jordan Bayles <jophba@chromium.org>
2020-11-06 13:22:26 -08:00
Christian Ledergerber
30170d651c Fix c++20 compilation problem for clang10 and fix potential bug due to compiler optimization 2020-11-02 10:51:39 -05:00
Christopher Dunn
5f4e10462f Merge pull request #1229 from open-source-parsers/pypi
Try meson/ninja from pypi
2020-10-10 11:30:19 -05:00
Christopher Dunn
bb9db78fe2 Do not allow failures on osx 2020-10-10 11:20:19 -05:00
Christopher Dunn
1664b6bbf8 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
2020-10-10 11:19:28 -05:00
Christopher Dunn
5d1cb30e40 clang-format 2020-10-10 11:10:09 -05:00
Ben Boeckel
c60ebf787a test: ensure the version numbers agree 2020-10-03 23:09:25 -05:00
Ben Boeckel
72db276986 version.h: fix the version number in the header
Fixes: #1224
2020-10-03 23:09:25 -05:00
Jordan Bayles
9059f5cad0 Roll version numbers for 1.9.4 release (#1223) 2020-09-25 19:19:16 -07:00
Daniel Engberg
45733df96c 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 <daniel.engberg.lists@pyret.net>
2020-09-01 23:02:57 -05:00
Ben Wolsieffer
5be07bdc5e Fix generation of pkg-config file with absolute includedir/libdir. (#1199) 2020-07-20 20:36:30 +08:00
Chen
bf0cfa5b46 hot fix for building static lib (#1203)
Fix #1197
2020-07-14 16:37:22 +08:00
Chen
cfc1ad72ad 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.
2020-07-13 20:33:58 +08:00
nathanruiz
c8453d39d1 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.
2020-06-23 14:52:28 -07:00
Billy Donahue
632044ad95 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 <thestorm.nik@gmail.com>
2020-06-11 18:14:03 -04:00
Billy Donahue
b3189a0800 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!)
2020-06-11 17:43:44 -04:00
Jordan Bayles
9be5895985 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
2020-05-30 20:20:20 -07:00
kabeer27
6aba23f4a8 Fixes Oss-Fuzz issue: 21916 (#1180)
* Fix heap-buffer-overflow in json_reader
2020-05-29 21:50:26 +08:00
Billy Donahue
c161f4ac69 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.
2020-05-21 11:30:59 -04:00
Billy Donahue
75b360af4a spot fix #1171: isprint argument must be representable as unsigned char (#1173) 2020-05-13 18:37:02 -04:00
Rosen Penev
e36cff19f0 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 <rosenp@gmail.com>

* optimize JsonWriter::validate #1171

* do the same for json_reader

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* use std::any_of

Also simplified two loops.

Signed-off-by: Rosen Penev <rosenp@gmail.com>

Co-authored-by: Billy Donahue <billy.donahue@gmail.com>
2020-05-12 19:19:36 -04:00
Edward Brey
b8cb8889aa Added current dir specifier for PowerShell (#1169)
The `./` is needed before `vcpkg install jsoncpp` when installing with PowerShell.
2020-05-08 09:00:12 +08:00
Chen
d2d4c74a03 Update README.md and add dota17 to AUTHORS list. (#1168)
* update README

* add dota17 to AUTHORS list
2020-04-30 18:05:17 +08:00
Chen
8b7ea09b80 Bump soversion to 24 (#1167) 2020-04-30 17:58:07 +08:00
xkszltl
a4fb5db543 Put ".exe" and ".dll" together to make test usable in build dir. (#1166) 2020-04-30 10:31:54 +08:00
Christopher Dunn
d517d598a7 Merge pull request #1165 from mrjoel/mrjoel/cmake-updates
Improve CMake correctness and handling
2020-04-29 08:27:43 -05:00
Joel Johnson
e9b0b96be6 Remove redundant cmake_minimum_required from example
This is already covered by the toplevel CMake, which also serves to
provide a consistent minimum version.
2020-04-28 15:21:16 -06:00
Joel Johnson
3f0d63b5a9 Use internal CMake compiler version directly 2020-04-28 15:21:16 -06:00
Joel Johnson
524234e479 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.
2020-04-28 15:21:16 -06:00
Joel Johnson
9abf11935c 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.
2020-04-28 15:21:16 -06:00
Joel Johnson
8a5e792f20 Add Clang support, be explicit about MSVC flags 2020-04-28 15:21:16 -06:00
Joel Johnson
30eb5ce128 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.
2020-04-28 15:21:16 -06:00
Joel Johnson
12ceb01485 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.
2020-04-28 15:21:16 -06:00
Joel Johnson
edc6239f39 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.
2020-04-28 15:21:16 -06:00
Joel Johnson
5a0152ae1b Only set CMAKE_BUILD_TYPE for single config generators 2020-04-28 15:21:16 -06:00
Joel Johnson
c648b0378a Consolidate setting of jsoncpp target properties 2020-04-28 15:21:16 -06:00
Joel Johnson
a3afd74b80 Don't use unique variable for postfix
The more general CMake way to handle library suffixing is to set
CMAKE_<CONFIG>_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.
2020-04-28 15:21:16 -06:00
Chen
2cb16b35dc allowBom -> skipBom (#1162) 2020-04-28 17:30:08 +08:00
Chen
83946a28db Ignore byte order mark in the head of UTF-8 text. (#1149)
* Ignore bom at the beginning of the UTF-8 text
2020-04-28 15:16:05 +08:00
bcsgh
91f1553f2c Make throwRuntimeError/throwLogicError print msg when built with JSON_USE_EXCEPTION=0 2020-04-24 13:40:51 -05:00
Christopher Dunn
5813ab1bc1 Merge branch 'fixup-tests' into 'master' (#1102) 2020-04-24 13:06:44 -05:00
Christopher Dunn
a0b8c3ecb4 Do not run colliding tests at same time 2020-04-24 12:43:17 -05:00
Jordan Bayles
b349221938 Cleanup test configurations 2020-04-24 12:43:17 -05:00
Jordan Bayles
9e23f66f61 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.
2020-04-24 12:43:17 -05:00
Christopher Dunn
411d88fae8 Stop checking status; raise instead 2020-04-24 12:43:17 -05:00
Christopher Dunn
1ff6bb65a0 ninja test 2020-04-24 12:43:17 -05:00
Ben Boeckel
8b20b7a317 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.
2020-04-23 23:22:10 -05:00
Stefano Fiorentino
2e54e8ff1c adding myself to AUTHORS as per commits (#1109)
commits:
ff923658c4
5907cef86c
2020-04-23 22:52:56 -05:00
Rosen Penev
90ca694e46 clang-tidy fixes again (#1155)
* [clang-tidy] remove redundant string initialization

Found with readability-redundant-string-init

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* [clang-tidy] switch to raw strings

Easier to read.

Found with modernize-raw-string-literal

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* [clang-tidy] fix performance issues

Found with performance*

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* fix extra comma warnings

Found with clang's -Wextra-semi-stmt

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* remove JSONCPP_OP_EXPLICIT

This codebase in C++11. No need for compatibility with C++98.

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* remove JSONCPP_NOEXCEPT

This codebase is C++11 now. No need for this macro.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-04-12 01:26:04 -04:00
Chen
3beb37ea14 revert trailing comma in old Reader (#1126) 2020-02-13 13:25:08 -08:00
David Gobbi
dc180eb25e 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<bool>' follows non-inline definition
  inline declaration of 'is<bool>' 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.
2020-02-13 13:22:49 -08:00
Claus Klein
a6fe8e27d8 Use ccache right (#1139)
* Prevent cmakelint warnings

Use 4 spaces for indent, no tabs

* Use ccache right

fix indents too at CMakeLists.txt
2020-02-13 13:20:46 -08:00
Rosen Penev
edf528edfa clang-tidy fixes again (#1087)
* [clang-tidy] Do not use else after return

Found with readability-else-after-return

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* [clang-tidy] Convert several loops to be range based

Found with modernize-loop-convert

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* [clang-tidy] Replace deprecated C headers

Found with modernize-deprecated-headers

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* [clang-tidy] Use auto where applicable

Found with modernize-use-auto

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* .clang-tidy: Add these checks
2020-02-02 23:03:45 -05:00
Chen
6317f9a406 fix compile warnning using cmake (#1132) 2020-01-20 17:12:35 +08:00
David Seifert
6bc55ec35d 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.
2020-01-07 09:23:50 +08:00
Andrew Childs
f11611c878 json_writer: fix inverted sense in isAnyCharRequiredQuoting (#1120)
This bug is only affects platforms where `char` is unsigned.

When char is a signed type, values >= 0x80 are also considered < 0,
and hence require escaping due to the < ' ' condition.

When char is an unsigned type, values >= 0x80 match none of the
conditions and are considered safe to emit without escaping.

This shows up as a test failure:

* Detail of EscapeSequenceTest/writeEscapeSequence test failure:
/build/source/src/test_lib_json/main.cpp(3370): expected == result
  Expected: '["\"","\\","\b","\f","\n","\r","\t","\u0278","\ud852\udf62"]
  '
  Actual  : '["\"","\\","\b","\f","\n","\r","\t","ɸ","𤭢"]
  '
2019-12-28 15:04:24 +08:00
Chen
8f7f35c5cd Replace Raw Unicode in Testcase (#1127)
* use unicode code point

* change values' order, because JSONTEST_ASSERT_EQUAL(expected, actual)
2019-12-26 16:08:17 +08:00
theirix
7e5485ab5b Add option JSONCPP_WITH_EXAMPLE (#1099)
* Add option JSONCPP_WITH_EXAMPLE

Allows to conditionally build examples as
it has been done for tests.  Useful for packaging.

* Do not build example by default
2019-12-23 11:04:44 +08:00
Chen
92d90250f2 fix Reader bug and add testcase (#1122) 2019-12-23 10:56:54 +08:00
Billy Donahue
d6c4a8fb2d tweak to avoid implicit narrowing warning. (#1114)
* tweak to avoid implicit narrowing warning.

change an int to size_t #1113

* Update main.cpp
2019-12-11 12:12:37 -08:00
Chen
a3c8642886 Add test cases for Reader (#1108)
* update testcase for reader

* add a helper function

* refactor structured error testing
2019-12-04 10:24:52 +08:00
Chen
2983f5a89a Run Clang-tidy with modernize-use-auto (#1077)
* Run clang-tidy modify with modernize-use-auto
* Use using instead of typedef
2019-12-04 09:08:45 +08:00
Chen
a0bd9adfef Add an insert overload function (#1110) 2019-12-03 09:13:42 +08:00
Billy Donahue
9e0d70aa66 eliminate some redundancy in test_lib_json/main.cpp (#1104)
refactor test 'CharReaderAllowDropNullTest/issue178'
2019-11-15 09:18:32 -05:00
dota17
f200239d5b Add some testcases for charReader (#1095)
* update charReader test case

* remove C ++ compiler version switch for smart pointer

* remove comma test due to PR #1098
2019-11-15 14:51:43 +08:00
Christopher Dunn
cfc3e927fc Merge pull request #1101 from open-source-parsers/drop_cpptl_support
Issue 1100: Drop CPPTL support
2019-11-15 00:31:06 -06:00
Jordan Bayles
a481201af1 Readd some overzealously removed code 2019-11-14 10:21:15 -08:00
Jordan Bayles
9704cedb20 Issue 1100: Drop CPPTL support
CPPTL support is no longer relevant to JsonCpp, and can be removed from
the library. This patch removes all mentions of CPPTL, by removing all
definitions and code sections conditionally compiled only when JsonCpp
is used with CPPTL. Include guards are also renamed to not refer to
CPPTL where appropriate.
2019-11-14 09:38:11 -08:00
Christopher Dunn
781eec4da8 Merge pull request #1098 from cdunn2001/allow-trailing-commas
Allow trailing comma in objects and arrays
2019-11-14 00:21:18 -06:00
Jacob Bundgaard
1c8f7d8ae5 Run clang-format 2019-11-14 00:05:24 -06:00
Jacob Bundgaard
554d961625 Allow trailing comma in arrays if dropped null placeholders are not allowed 2019-11-14 00:05:24 -06:00
Jacob Bundgaard
01db7b7430 Allow trailing comma in objects 2019-11-14 00:05:24 -06:00
92 changed files with 2489 additions and 2114 deletions

View File

@@ -1,4 +1,4 @@
BasedOnStyle: LLVM
DerivePointerAlignment: false
PointerAlignment: Left
SpacesBeforeTrailingComments: 1

View File

@@ -1,10 +1,10 @@
---
Checks: 'google-readability-casting,modernize-use-default-member-init,modernize-use-using,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
FormatStyle: none
CheckOptions:
CheckOptions:
- key: modernize-use-using.IgnoreMacros
value: '0'
...

20
.github/workflows/clang-format.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: clang-format check
on: [check_run, pull_request, push]
jobs:
formatting-check:
name: formatting check
runs-on: ubuntu-latest
strategy:
matrix:
path:
- 'src'
- 'examples'
- 'include'
steps:
- uses: actions/checkout@v4
- name: runs clang-format style check for C/C++/Protobuf programs.
uses: jidicula/clang-format-action@v4.13.0
with:
clang-format-version: '18'
check-path: ${{ matrix.path }}

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

65
.github/workflows/meson.yml vendored Normal file
View File

@@ -0,0 +1,65 @@
name: meson build and test
run-name: update pushed to ${{ github.ref }}
on: [check_run, push, pull_request]
jobs:
meson-publish:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-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
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
meson-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 }}

10
.gitignore vendored
View File

@@ -10,6 +10,7 @@
/libs/
/doc/doxyfile
/dist/
/.cache/
# MSVC project files:
*.sln
@@ -28,9 +29,9 @@
# CMake-generated files:
CMakeFiles/
*.cmake
/pkg-config/jsoncpp.pc
jsoncpp_lib_static.dir/
compile_commands.json
# In case someone runs cmake in the root-dir:
/CMakeCache.txt
@@ -51,3 +52,10 @@ jsoncpp_lib_static.dir/
# DS_Store
.DS_Store
# temps
/version
# Bazel output paths
/bazel-*
/MODULE.bazel.lock

View File

@@ -1,71 +0,0 @@
# Build matrix / environment variables are explained on:
# http://about.travis-ci.org/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:
allow_failures:
- os: osx
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
# 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

View File

@@ -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 [ "${BUILD_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

View File

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

View File

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

View File

@@ -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/**/

View File

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

View File

@@ -1 +0,0 @@
# NOTHING TO DO HERE

View File

@@ -1,10 +0,0 @@
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}

View File

@@ -1 +0,0 @@
# NOTHING TO DO HERE

View File

@@ -16,11 +16,12 @@ Baruch Siach <baruch@tkos.co.il>
Ben Boeckel <mathstuf@gmail.com>
Benjamin Knecht <bknecht@logitech.com>
Bernd Kuhls <bernd.kuhls@t-online.de>
Billy Donahue <billydonahue@google.com>
Billy Donahue <billy.donahue@gmail.com>
Braden McDorman <bmcdorman@gmail.com>
Brandon Myers <bmyers1788@gmail.com>
Brendan Drew <brendan.drew@daqri.com>
chason <cxchao802@gmail.com>
chenguoping <chenguopingdota@163.com>
Chris Gilling <cgilling@iparadigms.com>
Christopher Dawes <christopher.dawes.1981@googlemail.com>
Christopher Dunn <cdunn2001@gmail.com>
@@ -97,6 +98,7 @@ selaselah <selah@outlook.com>
Sergiy80 <sil2004@gmail.com>
sergzub <sergzub@gmail.com>
Stefan Schweter <stefan@schweter.it>
Stefano Fiorentino <stefano.fiore84@gmail.com>
Steffen Kieß <Steffen.Kiess@ipvs.uni-stuttgart.de>
Steven Hahn <hahnse@ornl.gov>
Stuart Eichert <stuart@fivemicro.com>

37
BUILD.bazel Normal file
View File

@@ -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"],
)

View File

@@ -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
@@ -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
@@ -37,44 +40,37 @@ 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()
# 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)
#####
## 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()
# ====
# 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()
project(JSONCPP
# Note: version must be updated in three places when doing a release. This
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
project(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
# IMPORTANT: also update the SOVERSION!!
VERSION 1.9.2 # <major>[.<minor>[.<patch>[.<tweak>]]]
# 1. ./meson.build
# 2. ./include/json/version.h
# 3. ./CMakeLists.txt
# 4. ./MODULE.bazel
# IMPORTANT: also update the PROJECT_SOVERSION!!
VERSION 1.9.7 # <major>[.<minor>[.<patch>[.<tweak>]]]
LANGUAGES CXX)
message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
set( JSONCPP_SOVERSION 22 )
message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(PROJECT_SOVERSION 27)
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)
@@ -82,120 +78,100 @@ option(JSONCPP_WITH_WARNING_AS_ERROR "Force compilation to fail if a warning occ
option(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C and ISO C++" ON)
option(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON)
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()
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)
# 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")
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" )
include(CheckFunctionExists)
check_function_exists(memset_s HAVE_MEMSET_S)
if(HAVE_MEMSET_S)
add_definitions("-DHAVE_MEMSET_S=1")
endif()
configure_file( "${PROJECT_SOURCE_DIR}/version.in"
"${PROJECT_BINARY_DIR}/version"
NEWLINE_STYLE UNIX )
if(JSONCPP_USE_SECURE_MEMORY)
add_definitions("-DJSONCPP_USE_SECURE_MEMORY=1")
endif()
macro(UseCompilationWarningAsError)
configure_file("${PROJECT_SOURCE_DIR}/version.in"
"${PROJECT_BINARY_DIR}/version"
NEWLINE_STYLE UNIX)
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($<$<CONFIG:Debug>:/WX>)
else()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ")
endif()
add_compile_options($<$<CONFIG:Debug>:/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()
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($<$<CONFIG:Debug>:/W4>)
else()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
add_compile_options($<$<CONFIG:Debug>:/W4>)
if (JSONCPP_STATIC_WINDOWS_RUNTIME)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
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)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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
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(-pedantic)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
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()
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)
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(JSONCPP_WITH_WARNING_AS_ERROR)
add_compile_options(-Werror=conversion)
elseif(JSONCPP_WITH_STRICT_ISO)
add_compile_options(-Wpedantic)
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)
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"
@@ -205,27 +181,34 @@ 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 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 ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake
${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp-namespaced-targets.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
add_subdirectory( example )
if(JSONCPP_WITH_EXAMPLE)
add_subdirectory(example)
endif()

View File

@@ -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
@@ -27,9 +27,15 @@ 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
See https://github.com/open-source-parsers/jsoncpp/wiki/Building
@@ -71,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:
@@ -138,7 +144,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.

14
LICENSE
View File

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

14
MODULE.bazel Normal file
View File

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

View File

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

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)
@@ -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")
@@ -110,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

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

23
cmake/JoinPaths.cmake Normal file
View File

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

View File

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

View File

@@ -146,7 +146,7 @@ def glob(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)

View File

@@ -9,7 +9,7 @@ import shutil
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('<th colspan="%d">%s</th>' % (nb_build_type, cgi.escape(' '.join(variable))))
th_vars.append('<th colspan="%d">%s</th>' % (nb_build_type, html.escape(' '.join(variable))))
for build_type in build_types:
th_build_types.append('<th>%s</th>' % cgi.escape(build_type))
th_build_types.append('<th>%s</th>' % html.escape(build_type))
tr_builds = []
for generator in sorted(builds_by_generator):
tds = [ '<td>%s</td>\n' % cgi.escape(generator) ]
tds = [ '<td>%s</td>\n' % html.escape(generator) ]
for variable in variables:
build_types = sorted(build_types_by_variable[variable])
for build_type in build_types:

View File

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

View File

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

View File

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

33
example/BUILD.bazel Normal file
View File

@@ -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"],
)

View File

@@ -1,29 +1,27 @@
#vim: et ts =4 sts = 4 sw = 4 tw = 0
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)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Wall -Wextra)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
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})

View File

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

View File

@@ -1,5 +1,6 @@
#include "json/json.h"
#include <iostream>
#include <memory>
/**
* \brief Parse a raw string into Value object using the CharReaderBuilder
* class, or the legacy Reader class.
@@ -11,7 +12,7 @@
*/
int main() {
const std::string rawJson = R"({"Age": 20, "Name": "colin"})";
const int rawJsonLength = static_cast<int>(rawJson.length());
const auto rawJsonLength = static_cast<int>(rawJson.length());
constexpr bool shouldUseOldWay = false;
JSONCPP_STRING err;
Json::Value root;
@@ -24,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

@@ -1,5 +1,6 @@
#include "json/json.h"
#include <iostream>
#include <memory>
/** \brief Write the Value object to a stream.
* Example Usage:
* $g++ streamWrite.cpp -ljsoncpp -std=c++11 -o streamWrite

5
get_version.pl Normal file
View File

@@ -0,0 +1,5 @@
while (<>) {
if (/version : '(.+)',/) {
print "$1";
}
}

View File

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

View File

@@ -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_CURRENT_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_CURRENT_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()

View File

@@ -3,13 +3,15 @@
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED
#define CPPTL_JSON_ALLOCATOR_H_INCLUDED
#ifndef JSON_ALLOCATOR_H_INCLUDED
#define JSON_ALLOCATOR_H_INCLUDED
#include <algorithm>
#include <cstring>
#include <memory>
#pragma pack(push, 8)
#pragma pack(push)
#pragma pack()
namespace Json {
template <typename T> class SecureAllocator {
@@ -35,11 +37,18 @@ public:
* 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) {
// 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<volatile unsigned char*>(p), n, 0);
#endif
// free using "global operator delete"
::operator delete(p);
}
@@ -69,7 +78,9 @@ public:
// Boilerplate
SecureAllocator() {}
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
template <typename U> struct rebind { using other = SecureAllocator<U>; };
template <typename U> struct rebind {
using other = SecureAllocator<U>;
};
};
template <typename T, typename U>
@@ -86,4 +97,4 @@ bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
#pragma pack(pop)
#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED
#endif // JSON_ALLOCATOR_H_INCLUDED

View File

@@ -3,8 +3,8 @@
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
#ifndef JSON_ASSERTIONS_H_INCLUDED
#define JSON_ASSERTIONS_H_INCLUDED
#include <cstdlib>
#include <sstream>
@@ -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 // CPPTL_JSON_ASSERTIONS_H_INCLUDED
#endif // JSON_ASSERTIONS_H_INCLUDED

View File

@@ -1,25 +0,0 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_AUTOLINK_H_INCLUDED
#define JSON_AUTOLINK_H_INCLUDED
#include "config.h"
#ifdef JSON_IN_CPPTL
#include <cpptl/cpptl_autolink.h>
#endif
#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
!defined(JSON_IN_CPPTL)
#define CPPTL_AUTOLINK_NAME "json"
#undef CPPTL_AUTOLINK_DLL
#ifdef JSON_DLL
#define CPPTL_AUTOLINK_DLL
#endif
#include "autolink.h"
#endif
#endif // JSON_AUTOLINK_H_INCLUDED

View File

@@ -14,16 +14,6 @@
#include <string>
#include <type_traits>
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of
/// std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
@@ -40,28 +30,22 @@
/// Remarks: it is automatically defined in the generated amalgamated header.
// #define JSON_IS_AMALGAMATION
#ifdef JSON_IN_CPPTL
#include <cpptl/config.h>
#ifndef JSON_USE_CPPTL
#define JSON_USE_CPPTL 1
#endif
#endif
#ifdef JSON_IN_CPPTL
#define JSON_API CPPTL_API
#elif defined(JSON_DLL_BUILD)
// Export macros for DLL visibility
#if defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#elif defined(__GNUC__) || defined(__clang__)
#define JSON_API __attribute__((visibility("default")))
#endif // if defined(_MSC_VER)
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#endif // ifdef JSON_IN_CPPTL
#endif // ifdef JSON_DLL_BUILD
#if !defined(JSON_API)
#define JSON_API
#endif
@@ -90,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)))
@@ -135,29 +105,29 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
typedef int Int;
typedef unsigned int UInt;
using Int = int;
using UInt = unsigned int;
#if defined(JSON_NO_INT64)
typedef int LargestInt;
typedef unsigned int LargestUInt;
using LargestInt = int;
using LargestUInt = unsigned int;
#undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
using Int64 = __int64;
using UInt64 = unsigned __int64;
#else // if defined(_MSC_VER) // Other platforms, use long long
typedef int64_t Int64;
typedef uint64_t UInt64;
using Int64 = int64_t;
using UInt64 = uint64_t;
#endif // if defined(_MSC_VER)
typedef Int64 LargestInt;
typedef UInt64 LargestUInt;
using LargestInt = Int64;
using LargestUInt = UInt64;
#define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64)
template <typename T>
using Allocator =
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
typename std::conditional<JSONCPP_USE_SECURE_MEMORY, SecureAllocator<T>,
std::allocator<T>>::type;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using IStringStream =

View File

@@ -29,7 +29,7 @@ class CharReaderBuilder;
class Features;
// value.h
typedef unsigned int ArrayIndex;
using ArrayIndex = unsigned int;
class StaticString;
class Path;
class PathArgument;

View File

@@ -6,7 +6,7 @@
#ifndef JSON_JSON_H_INCLUDED
#define JSON_JSON_H_INCLUDED
#include "autolink.h"
#include "config.h"
#include "json_features.h"
#include "reader.h"
#include "value.h"

View File

@@ -3,14 +3,15 @@
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
#define CPPTL_JSON_FEATURES_H_INCLUDED
#ifndef JSON_FEATURES_H_INCLUDED
#define JSON_FEATURES_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#pragma pack(push, 8)
#pragma pack(push)
#pragma pack()
namespace Json {
@@ -58,4 +59,4 @@ public:
#pragma pack(pop)
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
#endif // JSON_FEATURES_H_INCLUDED

View File

@@ -3,8 +3,8 @@
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_READER_H_INCLUDED
#define CPPTL_JSON_READER_H_INCLUDED
#ifndef JSON_READER_H_INCLUDED
#define JSON_READER_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "json_features.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 {
@@ -33,11 +34,10 @@ namespace Json {
* \deprecated Use CharReader and CharReaderBuilder.
*/
class JSONCPP_DEPRECATED(
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
class JSON_API Reader {
public:
typedef char Char;
typedef const Char* Location;
using Char = char;
using Location = const Char*;
/** \brief An error tagged with where in the JSON text it was encountered.
*
@@ -51,13 +51,13 @@ public:
};
/** \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 <a HREF="http://www.json.org">JSON</a>
@@ -187,9 +187,10 @@ private:
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces();
bool match(const Char* pattern, int patternLength);
bool readComment();
@@ -221,12 +222,11 @@ private:
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);
typedef std::stack<Value*> Nodes;
using Nodes = std::stack<Value*>;
Nodes nodes_;
Errors errors_;
String document_;
@@ -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,7 +283,21 @@ public:
*/
virtual CharReader* newCharReader() const = 0;
}; // Factory
}; // CharReader
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.
*
@@ -299,6 +324,8 @@ public:
* if allowComments is false.
* - `"allowComments": false or true`
* - true if comments are allowed.
* - `"allowTrailingCommas": false or true`
* - true if trailing commas in objects and arrays are allowed.
* - `"strictRoot": false or true`
* - true if root must be either an array or an object value
* - `"allowDroppedNullPlaceholders": false or true`
@@ -322,6 +349,9 @@ public:
* - `"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.
@@ -355,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.
@@ -398,4 +434,4 @@ JSON_API IStream& operator>>(IStream&, Value&);
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // CPPTL_JSON_READER_H_INCLUDED
#endif // JSON_READER_H_INCLUDED

View File

@@ -3,8 +3,8 @@
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef CPPTL_JSON_H_INCLUDED
#define CPPTL_JSON_H_INCLUDED
#ifndef JSON_VALUE_H_INCLUDED
#define JSON_VALUE_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
@@ -21,29 +21,48 @@
#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
#if __cplusplus >= 201703L
#define JSONCPP_HAS_STRING_VIEW 1
#endif
#include <array>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <vector>
#ifndef JSON_USE_CPPTL_SMALLMAP
#include <map>
#else
#include <cpptl/smallmap.h>
#endif
#ifdef JSON_USE_CPPTL
#include <cpptl/forwards.h>
#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// 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)
#pragma pack(push)
#pragma pack()
/** \brief JSON (JavaScript Object Notation).
*/
@@ -57,8 +76,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_;
@@ -120,11 +139,6 @@ enum PrecisionType {
decimalPlaces ///< we set max number of digits after "." in string
};
//# ifdef JSON_USE_CPPTL
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
//# endif
/** \brief Lightweight wrapper to tag static string.
*
* Value constructor and objectValue member assignment takes advantage of the
@@ -189,21 +203,21 @@ class JSON_API Value {
friend class ValueIteratorBase;
public:
typedef std::vector<String> Members;
typedef ValueIterator iterator;
typedef ValueConstIterator const_iterator;
typedef Json::UInt UInt;
typedef Json::Int Int;
using Members = std::vector<String>;
using iterator = ValueIterator;
using const_iterator = ValueConstIterator;
using UInt = Json::UInt;
using Int = Json::Int;
#if defined(JSON_HAS_INT64)
typedef Json::UInt64 UInt64;
typedef Json::Int64 Int64;
using UInt64 = Json::UInt64;
using Int64 = Json::Int64;
#endif // defined(JSON_HAS_INT64)
typedef Json::LargestInt LargestInt;
typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex;
using LargestInt = Json::LargestInt;
using LargestUInt = Json::LargestUInt;
using ArrayIndex = Json::ArrayIndex;
// Required for boost integration, e. g. BOOST_TEST
typedef std::string value_type;
using value_type = std::string;
#if JSON_USE_NULLREF
// Binary compatibility kludges, do not use.
@@ -258,10 +272,10 @@ private:
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;
@@ -287,11 +301,7 @@ private:
};
public:
#ifndef JSON_USE_CPPTL_SMALLMAP
typedef std::map<CZString, Value> ObjectValues;
#else
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
public:
@@ -340,18 +350,19 @@ public:
*/
Value(const StaticString& value);
Value(const String& value);
#ifdef JSON_USE_CPPTL
Value(const CppTL::ConstString& 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);
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);
@@ -375,7 +386,7 @@ public:
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
@@ -384,8 +395,11 @@ public:
* \return false if !string. (Seg-fault if str or end are NULL.)
*/
bool getString(char const** begin, char const** end) const;
#ifdef JSON_USE_CPPTL
CppTL::ConstString asConstString() 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;
@@ -413,8 +427,8 @@ public:
bool isObject() const;
/// The `as<T>` and `is<T>` member function templates and specializations.
template <typename T> T as() const = delete;
template <typename T> bool is() const = delete;
template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;
bool isConvertibleTo(ValueType other) const;
@@ -426,7 +440,7 @@ public:
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
@@ -440,7 +454,7 @@ public:
/// \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.
@@ -448,15 +462,15 @@ public:
/// 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.
@@ -468,9 +482,20 @@ public:
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value);
Value& append(Value&& value);
/// \brief Insert value in array at specific index
bool insert(ArrayIndex index, Value newValue);
/// \brief Insert value in array at specific index
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.
@@ -485,6 +510,7 @@ public:
/// 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.
*
@@ -498,34 +524,54 @@ public:
* \endcode
*/
Value& operator[](const StaticString& key);
#ifdef JSON_USE_CPPTL
/// Access an object value by name, create a null member if it does not exist.
Value& operator[](const CppTL::ConstString& key);
/// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const CppTL::ConstString& key) const;
#endif
#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
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
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;
/// 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;
#ifdef JSON_USE_CPPTL
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
#endif
/// 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
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;
/// Calls find and only returns a valid pointer if the type is found
template <typename T, bool (T::*TMemFn)() const>
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.
@@ -535,20 +581,28 @@ public:
/// 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.
@@ -559,18 +613,20 @@ public:
*/
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;
#ifdef JSON_USE_CPPTL
/// Return true if the object has a member named key.
bool isMember(const CppTL::ConstString& key) const;
#endif
/// \brief Return a list of the member names.
///
@@ -579,11 +635,6 @@ public:
/// \post if type() was nullValue, it remains nullValue
Members getMemberNames() const;
//# ifdef JSON_USE_CPPTL
// EnumMemberNames enumMemberNames() const;
// EnumValues enumValues() const;
//# endif
/// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
void setComment(const char* comment, CommentPlacement placement) {
@@ -607,6 +658,26 @@ public:
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);
@@ -658,9 +729,9 @@ private:
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);
@@ -706,11 +777,6 @@ template <> inline float Value::as<float>() const { return asFloat(); }
template <> inline const char* Value::as<const char*>() const {
return asCString();
}
#ifdef JSON_USE_CPPTL
template <> inline CppTL::ConstString Value::as<CppTL::ConstString>() const {
return asConstString();
}
#endif
/** \brief Experimental and untested: represents an element of the "path" to
* access a node.
@@ -757,8 +823,8 @@ public:
Value& make(Value& root) const;
private:
typedef std::vector<const PathArgument*> InArgs;
typedef std::vector<PathArgument> Args;
using InArgs = std::vector<const PathArgument*>;
using Args = std::vector<PathArgument>;
void makePath(const String& path, const InArgs& in);
void addPathInArg(const String& path, const InArgs& in,
@@ -773,10 +839,10 @@ private:
*/
class JSON_API ValueIteratorBase {
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef unsigned int size_t;
typedef int difference_type;
typedef ValueIteratorBase SelfType;
using iterator_category = std::bidirectional_iterator_tag;
using size_t = unsigned int;
using difference_type = int;
using SelfType = ValueIteratorBase;
bool operator==(const SelfType& other) const { return isEqual(other); }
@@ -849,12 +915,12 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
friend class Value;
public:
typedef const Value value_type;
using value_type = const Value;
// typedef unsigned int size_t;
// typedef int difference_type;
typedef const Value& reference;
typedef const Value* pointer;
typedef ValueConstIterator SelfType;
using reference = const Value&;
using pointer = const Value*;
using SelfType = ValueConstIterator;
ValueConstIterator();
ValueConstIterator(ValueIterator const& other);
@@ -900,12 +966,12 @@ class JSON_API ValueIterator : public ValueIteratorBase {
friend class Value;
public:
typedef Value value_type;
typedef unsigned int size_t;
typedef int difference_type;
typedef Value& reference;
typedef Value* pointer;
typedef ValueIterator SelfType;
using value_type = Value;
using size_t = unsigned int;
using difference_type = int;
using reference = Value&;
using pointer = Value*;
using SelfType = ValueIterator;
ValueIterator();
explicit ValueIterator(const ValueConstIterator& other);
@@ -946,12 +1012,20 @@ public:
* 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<reference>(deref()); }
pointer operator->() const { return const_cast<pointer>(&deref()); }
};
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)
@@ -960,4 +1034,4 @@ inline void swap(Value& a, Value& b) { a.swap(b); }
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // CPPTL_JSON_H_INCLUDED
#endif // JSON_H_INCLUDED

View File

@@ -1,27 +1,27 @@
#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.2"
#define JSONCPP_VERSION_STRING "1.9.7"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 2
#define JSONCPP_VERSION_PATCH 7
#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
#if !defined(JSONCPP_USE_SECURE_MEMORY)
#define JSONCPP_USE_SECURE_MEMORY 0
#endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.

View File

@@ -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 {
@@ -63,7 +64,7 @@ public:
*/
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.
@@ -110,6 +111,8 @@ public:
* - 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
@@ -145,7 +148,7 @@ public:
/** \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();
@@ -165,8 +168,7 @@ public:
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
: public Writer {
class JSON_API FastWriter : public Writer {
public:
FastWriter();
~FastWriter() override = default;
@@ -215,7 +217,7 @@ private:
* - 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()
@@ -225,8 +227,7 @@ private:
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
StyledWriter : public Writer {
class JSON_API StyledWriter : public Writer {
public:
StyledWriter();
~StyledWriter() override = default;
@@ -252,7 +253,7 @@ private:
static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text);
typedef std::vector<String> ChildValues;
using ChildValues = std::vector<String>;
ChildValues childValues_;
String document_;
@@ -284,7 +285,7 @@ private:
* - 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()
@@ -294,8 +295,7 @@ private:
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
StyledStreamWriter {
class JSON_API StyledStreamWriter {
public:
/**
* \param indentation Each level will be indented by this amount extra.
@@ -326,7 +326,7 @@ private:
static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text);
typedef std::vector<String> ChildValues;
using ChildValues = std::vector<String>;
ChildValues childValues_;
OStream* document_;
@@ -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>>()

View File

@@ -0,0 +1,9 @@
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 ()

11
jsoncppConfig.cmake.in Normal file
View File

@@ -0,0 +1,11 @@
cmake_policy(PUSH)
cmake_policy(VERSION 3.0...3.26)
@PACKAGE_INIT@
include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-targets.cmake" )
include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" )
check_required_components(JsonCpp)
cmake_policy(POP)

View File

@@ -0,0 +1,6 @@
@PACKAGE_INIT@
@MESON_SHARED_TARGET@
@MESON_STATIC_TARGET@
include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" )

View File

@@ -2,26 +2,26 @@ 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.2',
version : '1.9.7',
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 = [
jsoncpp_headers = files([
'include/json/allocator.h',
'include/json/assertions.h',
'include/json/autolink.h',
'include/json/config.h',
'include/json/json_features.h',
'include/json/forwards.h',
@@ -29,7 +29,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(
@@ -45,13 +46,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 : 27,
install : true,
include_directories : jsoncpp_include_directories,
cpp_args: dll_export_flag)
@@ -63,22 +63,62 @@ 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,
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 = find_program('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,
@@ -101,5 +141,17 @@ 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',
python,
is_parallel : false,
args : [
'-B',
join_paths(meson.current_source_dir(), 'test/runjsontests.py'),
'--with-json-checker',
jsontestrunner,
join_paths(meson.current_source_dir(), 'test/data')],
workdir : join_paths(meson.current_source_dir(), 'test/data'),
)

5
meson_options.txt Normal file
View File

@@ -0,0 +1,5 @@
option(
'tests',
type : 'boolean',
value : true,
description : 'Enable building tests')

View File

@@ -1,11 +1,11 @@
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
Version: @JSONCPP_VERSION@
Version: @PROJECT_VERSION@
URL: https://github.com/open-source-parsers/jsoncpp
Libs: -L${libdir} -ljsoncpp
Cflags: -I${includedir}

1
reformat.sh Executable file
View File

@@ -0,0 +1 @@
find src -name '*.cpp' -or -name '*.h' | xargs clang-format -i

View File

@@ -1,26 +1,28 @@
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()
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)
@@ -32,18 +34,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}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
DEPENDS jsontestrunner_exe jsoncpp_test
)
"${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${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}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
WORKING_DIRECTORY "${TEST_DIR}/data"
COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
WORKING_DIRECTORY "${TEST_DIR}/data"
)
add_test(NAME jsoncpp_readerwriter_json_checker
COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
WORKING_DIRECTORY "${TEST_DIR}/data"
COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
WORKING_DIRECTORY "${TEST_DIR}/data"
)
endif()

View File

@@ -57,10 +57,10 @@ static Json::String readInputTestFile(const char* path) {
if (!file)
return "";
fseek(file, 0, SEEK_END);
long const size = ftell(file);
size_t const usize = static_cast<unsigned long>(size);
auto const size = ftell(file);
auto const usize = static_cast<size_t>(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)
@@ -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;
@@ -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;
@@ -335,6 +338,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__)

View File

@@ -1,13 +1,7 @@
if( CMAKE_COMPILER_IS_GNUCXX )
#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 )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
endif()
endif( CMAKE_COMPILER_IS_GNUCXX )
add_compile_options("-Werror=strict-aliasing")
endif()
include(CheckIncludeFileCXX)
include(CheckTypeSize)
@@ -17,33 +11,23 @@ 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")
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,49 +36,29 @@ 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)
set(JSONCPP_SOURCES
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 )
else()
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 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.
@@ -141,14 +105,101 @@ 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})
if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
target_include_directories( jsoncpp_lib PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>)
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 ${BUILD_SHARED_LIBS}
)
# 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})
target_include_directories(${SHARED_LIB} PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
)
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 also named jsoncpp.lib
if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
if (MSVC OR ("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC"))
set(STATIC_SUFFIX "_static")
else()
set(STATIC_SUFFIX "")
endif()
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(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES})
target_include_directories(${STATIC_LIB} PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
)
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 ${BUILD_SHARED_LIBS}
)
# 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})
target_include_directories(${OBJECT_LIB} PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
)
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}
)

View File

@@ -10,7 +10,9 @@
#include <json/reader.h>
#include <json/value.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <iostream>
#include <istream>
@@ -21,13 +23,6 @@
#include <utility>
#include <cstdio>
#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)
@@ -51,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<CharReader>;
#else
typedef std::auto_ptr<CharReader> CharReaderPtr;
#endif
// Implementation of class Features
// ////////////////////////////////
@@ -77,10 +68,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
@@ -106,8 +94,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<char> EOF);
String doc(std::istreambuf_iterator<char>(is), {});
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
}
@@ -131,7 +118,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_) {
@@ -159,7 +146,7 @@ bool Reader::readValue() {
throwRuntimeError("Exceeded stackLimit in readValue().");
Token token;
skipCommentTokens(token);
readTokenSkippingComments(token);
bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) {
@@ -227,14 +214,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) {
@@ -448,12 +435,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();
@@ -464,7 +446,7 @@ bool Reader::readObject(Token& token) {
Value numberName;
if (!decodeNumber(tokenName, numberName))
return recoverFromError(tokenObjectEnd);
name = String(numberName.asCString());
name = numberName.asString();
} else {
break;
}
@@ -482,15 +464,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;
}
@@ -520,10 +498,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) {
@@ -601,11 +576,16 @@ bool Reader::decodeDouble(Token& token) {
bool Reader::decodeDouble(Token& token, Value& decoded) {
double value = 0;
String buffer(token.start_, token.end_);
IStringStream is(buffer);
if (!(is >> value))
return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
IStringStream is(String(token.start_, token.end_));
if (!(is >> value)) {
if (value == std::numeric_limits<double>::max())
value = std::numeric_limits<double>::infinity();
else if (value == std::numeric_limits<double>::lowest())
value = -std::numeric_limits<double>::infinity();
else if (!std::isinf(value))
return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
}
decoded = value;
return true;
}
@@ -629,7 +609,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++;
@@ -769,7 +749,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;
@@ -863,6 +843,7 @@ class OurFeatures {
public:
static OurFeatures all();
bool allowComments_;
bool allowTrailingCommas_;
bool strictRoot_;
bool allowDroppedNullPlaceholders_;
bool allowNumericKeys_;
@@ -870,6 +851,7 @@ public:
bool failIfExtra_;
bool rejectDupKeys_;
bool allowSpecialFloats_;
bool skipBom_;
size_t stackLimit_;
}; // OurFeatures
@@ -884,17 +866,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
@@ -937,7 +914,9 @@ private:
using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces();
void skipBom(bool skipBom);
bool match(const Char* pattern, int patternLength);
bool readComment();
bool readCStyleComment(bool* containsNewLineResult);
@@ -969,7 +948,6 @@ private:
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);
@@ -995,10 +973,7 @@ private:
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) {}
@@ -1021,10 +996,12 @@ 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_.skipBom_);
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;
@@ -1052,7 +1029,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()) {
@@ -1139,14 +1116,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) {
@@ -1175,8 +1152,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();
@@ -1267,6 +1247,16 @@ void OurReader::skipSpaces() {
}
}
void OurReader::skipBom(bool skipBom) {
// The default behavior is to skip BOM.
if (skipBom) {
if ((end_ - begin_) >= 3 && 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;
@@ -1349,11 +1339,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() == '/';
@@ -1431,13 +1420,10 @@ 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;
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
while (readTokenSkippingComments(tokenName)) {
if (tokenName.type_ == tokenObjectEnd &&
(name.empty() ||
features_.allowTrailingCommas_)) // empty object or trailing comma
return true;
name.clear();
if (tokenName.type_ == tokenString) {
@@ -1471,15 +1457,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;
}
@@ -1491,15 +1473,19 @@ bool OurReader::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();
@@ -1509,10 +1495,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) {
@@ -1571,9 +1554,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 =
@@ -1587,10 +1570,10 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
if (c < '0' || c > '9')
return decodeDouble(token, decoded);
const Value::UInt digit(static_cast<Value::UInt>(c - '0'));
const auto digit(static_cast<Value::UInt>(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.
@@ -1604,7 +1587,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::UInt>(value % 10);
const auto last_digit = static_cast<Value::UInt>(value % 10);
decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
} else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
decoded = Value::LargestInt(value);
@@ -1627,11 +1610,15 @@ 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)) {
return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
if (value == std::numeric_limits<double>::max())
value = std::numeric_limits<double>::infinity();
else if (value == std::numeric_limits<double>::lowest())
value = -std::numeric_limits<double>::infinity();
else if (!std::isinf(value))
return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
}
decoded = value;
return true;
@@ -1654,9 +1641,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++;
@@ -1796,7 +1783,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;
@@ -1831,10 +1818,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_;
@@ -1844,20 +1832,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_); }
@@ -1866,6 +1870,7 @@ CharReader* CharReaderBuilder::newCharReader() const {
bool collectComments = settings_["collectComments"].asBool();
OurFeatures features = OurFeatures::all();
features.allowComments_ = settings_["allowComments"].asBool();
features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
features.strictRoot_ = settings_["strictRoot"].asBool();
features.allowDroppedNullPlaceholders_ =
settings_["allowDroppedNullPlaceholders"].asBool();
@@ -1878,38 +1883,37 @@ CharReader* CharReaderBuilder::newCharReader() const {
features.failIfExtra_ = settings_["failIfExtra"].asBool();
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
features.skipBom_ = settings_["skipBom"].asBool();
return new OurCharReader(collectComments, features);
}
static void getValidReaderKeys(std::set<String>* valid_keys) {
valid_keys->clear();
valid_keys->insert("collectComments");
valid_keys->insert("allowComments");
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");
}
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<String> 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<String>{
"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)[key] = *si;
else
return false;
}
return inv.empty();
return invalid ? invalid->empty() : true;
}
Value& CharReaderBuilder::operator[](const String& key) {
return settings_[key];
}
@@ -1917,6 +1921,7 @@ Value& CharReaderBuilder::operator[](const String& key) {
void CharReaderBuilder::strictMode(Json::Value* settings) {
//! [CharReaderBuilderStrictMode]
(*settings)["allowComments"] = false;
(*settings)["allowTrailingCommas"] = false;
(*settings)["strictRoot"] = true;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
@@ -1925,6 +1930,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings) {
(*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = true;
(*settings)["allowSpecialFloats"] = false;
(*settings)["skipBom"] = true;
//! [CharReaderBuilderStrictMode]
}
// static
@@ -1932,6 +1938,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
//! [CharReaderBuilderDefaults]
(*settings)["collectComments"] = true;
(*settings)["allowComments"] = true;
(*settings)["allowTrailingCommas"] = true;
(*settings)["strictRoot"] = false;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
@@ -1940,8 +1947,35 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
(*settings)["failIfExtra"] = false;
(*settings)["rejectDupKeys"] = false;
(*settings)["allowSpecialFloats"] = false;
(*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
@@ -1950,7 +1984,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

@@ -71,7 +71,7 @@ enum {
};
// Defines a char buffer for use with uintToString().
typedef char UIntToStringBuffer[uintToStringBufferSize];
using UIntToStringBuffer = char[uintToStringBufferSize];
/** Converts an unsigned integer to string.
* @param value Unsigned integer to convert to string
@@ -116,14 +116,18 @@ template <typename Iter> 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 <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
template <typename Iter>
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;

View File

@@ -8,16 +8,18 @@
#include <json/value.h>
#include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <sstream>
#include <utility>
#ifdef JSON_USE_CPPTL
#include <cpptl/conststring.h>
#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
#include <algorithm> // min()
#include <cstddef> // size_t
// Provide implementation equivalent of std::snprintf for older _MSC compilers
#if defined(_MSC_VER) && _MSC_VER < 1900
@@ -89,7 +91,8 @@ template <typename T, typename U>
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<double>(min) && d <= static_cast<double>(max);
return d >= static_cast<double>(min) && d <= static_cast<double>(max) &&
!(static_cast<U>(d) == min && d != static_cast<double>(min));
}
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
static inline double integerToDouble(Json::UInt64 value) {
@@ -103,7 +106,8 @@ template <typename T> static inline double integerToDouble(T value) {
template <typename T, typename U>
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<U>(d) == min && d != integerToDouble(min));
}
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
@@ -120,7 +124,7 @@ static inline char* duplicateStringValue(const char* value, size_t length) {
if (length >= static_cast<size_t>(Value::maxInt))
length = Value::maxInt - 1;
char* newString = static_cast<char*>(malloc(length + 1));
auto newString = static_cast<char*>(malloc(length + 1));
if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateStringValue(): "
"Failed to allocate string value buffer");
@@ -140,8 +144,8 @@ static inline char* duplicateAndPrefixStringValue(const char* value,
sizeof(unsigned) - 1U,
"in Json::Value::duplicateAndPrefixStringValue(): "
"length too big for prefixing");
unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
char* newString = static_cast<char*>(malloc(actualLength));
size_t actualLength = sizeof(length) + length + 1;
auto newString = static_cast<char*>(malloc(actualLength));
if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
"Failed to allocate string value buffer");
@@ -165,7 +169,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 +184,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
@@ -203,8 +207,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) {
@@ -214,8 +218,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
// //////////////////////////////////////////////////////////////////
@@ -255,7 +265,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;
}
@@ -281,7 +291,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;
@@ -414,19 +424,19 @@ Value::Value(const String& value) {
value.data(), static_cast<unsigned>(value.length()));
}
#ifdef JSONCPP_HAS_STRING_VIEW
Value::Value(std::string_view value) {
initBasic(stringValue, true);
value_.string_ = duplicateAndPrefixStringValue(
value.data(), static_cast<unsigned>(value.length()));
}
#endif
Value::Value(const StaticString& value) {
initBasic(stringValue);
value_.string_ = const_cast<char*>(value.c_str());
}
#ifdef JSON_USE_CPPTL
Value::Value(const CppTL::ConstString& value) {
initBasic(stringValue, true);
value_.string_ = duplicateAndPrefixStringValue(
value, static_cast<unsigned>(value.length()));
}
#endif
Value::Value(bool value) {
initBasic(booleanValue);
value_.bool_ = value;
@@ -437,7 +447,7 @@ Value::Value(const Value& other) {
dupMeta(other);
}
Value::Value(Value&& other) {
Value::Value(Value&& other) noexcept {
initBasic(nullValue);
swap(other);
}
@@ -452,7 +462,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;
}
@@ -529,9 +539,10 @@ bool Value::operator<(const Value& other) const {
}
case arrayValue:
case objectValue: {
int delta = int(value_.map_->size() - other.value_.map_->size());
if (delta)
return delta < 0;
auto thisSize = value_.map_->size();
auto otherSize = other.value_.map_->size();
if (thisSize != otherSize)
return thisSize < otherSize;
return (*value_.map_) < (*other.value_.map_);
}
default:
@@ -602,7 +613,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");
@@ -628,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:
@@ -654,15 +680,6 @@ String Value::asString() const {
}
}
#ifdef JSON_USE_CPPTL
CppTL::ConstString Value::asConstString() const {
unsigned len;
char const* str;
decodePrefixedString(isAllocated(), value_.string_, &len, &str);
return CppTL::ConstString(str, len);
}
#endif
Value::Int Value::asInt() const {
switch (type()) {
case intValue:
@@ -694,7 +711,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:
@@ -717,6 +734,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_);
@@ -738,7 +760,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:
@@ -849,7 +871,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;
@@ -894,8 +916,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(); }
@@ -925,7 +946,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);
@@ -1104,12 +1126,64 @@ 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 const* Value::findNull(const String& key) const {
return findValue<Value, &Value::isNull>(key);
}
Value const* Value::findBool(const String& key) const {
return findValue<Value, &Value::isBool>(key);
}
Value const* Value::findInt(const String& key) const {
return findValue<Value, &Value::isInt>(key);
}
Value const* Value::findInt64(const String& key) const {
return findValue<Value, &Value::isInt64>(key);
}
Value const* Value::findUInt(const String& key) const {
return findValue<Value, &Value::isUInt>(key);
}
Value const* Value::findUInt64(const String& key) const {
return findValue<Value, &Value::isUInt64>(key);
}
Value const* Value::findIntegral(const String& key) const {
return findValue<Value, &Value::isIntegral>(key);
}
Value const* Value::findDouble(const String& key) const {
return findValue<Value, &Value::isDouble>(key);
}
Value const* Value::findNumeric(const String& key) const {
return findValue<Value, &Value::isNumeric>(key);
}
Value const* Value::findString(const String& key) const {
return findValue<Value, &Value::isString>(key);
}
Value const* Value::findArray(const String& key) const {
return findValue<Value, &Value::isArray>(key);
}
Value const* Value::findObject(const String& key) const {
return findValue<Value, &Value::isObject>(key);
}
Value* Value::demand(char const* begin, char const* end) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::demand(begin, end): requires "
"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)
@@ -1117,7 +1191,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;
@@ -1130,23 +1204,12 @@ 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());
}
#ifdef JSON_USE_CPPTL
Value& Value::operator[](const CppTL::ConstString& key) {
return resolveReference(key.c_str(), key.end_c_str());
}
Value const& Value::operator[](CppTL::ConstString const& key) const {
Value const* found = find(key.c_str(), key.end_c_str());
if (!found)
return nullSingleton();
return *found;
}
#endif
Value& Value::append(const Value& value) { return append(Value(value)); }
Value& Value::append(Value&& value) {
@@ -1158,19 +1221,22 @@ Value& Value::append(Value&& value) {
return this->value_.map_->emplace(size(), std::move(value)).first->second;
}
bool Value::insert(ArrayIndex index, Value newValue) {
bool Value::insert(ArrayIndex index, const Value& newValue) {
return insert(index, Value(newValue));
}
bool Value::insert(ArrayIndex index, Value&& newValue) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::insert: requires arrayValue");
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,
@@ -1178,12 +1244,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) {
@@ -1199,12 +1271,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");
@@ -1215,6 +1306,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) {
@@ -1226,7 +1318,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) {
@@ -1240,28 +1332,21 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
return true;
}
#ifdef JSON_USE_CPPTL
Value Value::get(const CppTL::ConstString& key,
const Value& defaultValue) const {
return get(key.c_str(), key.end_c_str(), defaultValue);
}
#endif
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());
}
#ifdef JSON_USE_CPPTL
bool Value::isMember(const CppTL::ConstString& key) const {
return isMember(key.c_str(), key.end_c_str());
}
#endif
Value::Members Value::getMemberNames() const {
@@ -1279,31 +1364,6 @@ Value::Members Value::getMemberNames() const {
}
return members;
}
//
//# ifdef JSON_USE_CPPTL
// EnumMemberNames
// Value::enumMemberNames() const
//{
// if ( type() == objectValue )
// {
// return CppTL::Enum::any( CppTL::Enum::transform(
// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
// MemberNamesTransform() ) );
// }
// return EnumMemberNames();
//}
//
//
// EnumValues
// Value::enumValues() const
//{
// if ( type() == objectValue || type() == arrayValue )
// return CppTL::Enum::anyValues( *(value_.map_),
// CppTL::Type<const Value &>() );
// return EnumValues();
//}
//
//# endif
static bool IsIntegral(double d) {
double integral_part;
@@ -1367,8 +1427,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;
}
@@ -1406,7 +1470,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 &&
@@ -1433,14 +1501,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;
}
@@ -1456,13 +1525,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<Array>(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) {
@@ -1470,9 +1537,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));
}

View File

@@ -30,9 +30,6 @@ void ValueIteratorBase::decrement() { --current_; }
ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance(const SelfType& other) const {
#ifdef JSON_USE_CPPTL_SMALLMAP
return other.current_ - current_;
#else
// Iterator for null value are initialized using the default
// constructor, which initialize current_ to the default
// std::map::iterator. As begin() and end() are two instance
@@ -53,7 +50,6 @@ ValueIteratorBase::computeDistance(const SelfType& other) const {
++myDistance;
}
return myDistance;
#endif
}
bool ValueIteratorBase::isEqual(const SelfType& other) const {

View File

@@ -7,7 +7,11 @@
#include "json_tool.h"
#include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <memory>
@@ -15,67 +19,6 @@
#include <sstream>
#include <utility>
#if __cplusplus >= 201103L
#include <cmath>
#include <cstdio>
#if !defined(isnan)
#define isnan std::isnan
#endif
#if !defined(isfinite)
#define isfinite std::isfinite
#endif
#else
#include <cmath>
#include <cstdio>
#if defined(_MSC_VER)
#if !defined(isnan)
#include <float.h>
#define isnan _isnan
#endif
#if !defined(isfinite)
#include <float.h>
#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 <ieeefp.h>
#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)
@@ -83,11 +26,7 @@
namespace Json {
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using StreamWriterPtr = std::unique_ptr<StreamWriter>;
#else
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
#endif
String valueToString(LargestInt value) {
UIntToStringBuffer buffer;
@@ -127,11 +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');
@@ -152,16 +92,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
@@ -173,16 +115,12 @@ 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);
char const* const end = s + n;
for (char const* cur = s; cur < end; ++cur) {
if (*cur == '\\' || *cur == '\"' || *cur < ' ' ||
static_cast<unsigned char>(*cur) < 0x80)
return true;
}
return false;
return std::any_of(s, s + n, [](unsigned char c) {
return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
});
}
static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
@@ -264,12 +202,20 @@ static String toHex16Bit(unsigned int x) {
return result;
}
static String valueToQuotedStringN(const char* value, unsigned length,
static void appendRaw(String& result, unsigned ch) {
result += static_cast<char>(ch);
}
static void appendHex(String& result, unsigned ch) {
result.append("\\u").append(toHex16Bit(ch));
}
static String valueToQuotedStringN(const char* value, size_t length,
bool emitUTF8 = false) {
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.
@@ -312,29 +258,26 @@ static String valueToQuotedStringN(const char* value, unsigned length,
// sequence from occurring.
default: {
if (emitUTF8) {
result += *c;
unsigned codepoint = static_cast<unsigned char>(*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<char>(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;
@@ -345,7 +288,11 @@ static String valueToQuotedStringN(const char* value, unsigned length,
}
String valueToQuotedString(const char* value) {
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
return valueToQuotedStringN(value, strlen(value));
}
String valueToQuotedString(const char* value, size_t length) {
return valueToQuotedStringN(value, length);
}
// Class Writer
@@ -394,7 +341,7 @@ void FastWriter::writeValue(const Value& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
break;
}
case booleanValue:
@@ -417,8 +364,7 @@ void FastWriter::writeValue(const Value& value) {
const String& name = *it;
if (it != members.begin())
document_ += ',';
document_ += valueToQuotedStringN(name.data(),
static_cast<unsigned>(name.length()));
document_ += valueToQuotedStringN(name.data(), name.length());
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
writeValue(value[name]);
}
@@ -463,7 +409,7 @@ void StyledWriter::writeValue(const Value& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
else
pushValue("");
break;
@@ -486,7 +432,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()) {
@@ -504,7 +450,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 {
@@ -513,7 +459,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);
@@ -536,7 +482,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];
@@ -681,7 +627,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
else
pushValue("");
break;
@@ -704,7 +650,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()) {
@@ -955,8 +901,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
emitUTF8_));
pushValue(
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
else
pushValue("");
break;
@@ -979,8 +925,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
String const& name = *it;
Value const& childValue = value[name];
writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedStringN(
name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
writeWithIndent(
valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
*sout_ << colonSymbol_;
writeValue(childValue);
if (++it == members.end()) {
@@ -1197,34 +1143,30 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const {
endingLineFeedSymbol, usf, emitUTF8, pre,
precisionType);
}
static void getValidWriterKeys(std::set<String>* 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<String> 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<String>{
"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)[key] = *si;
else
return false;
}
return inv.empty();
return invalid ? invalid->empty() : true;
}
Value& StreamWriterBuilder::operator[](const String& key) {
return settings_[key];
}
@@ -1246,7 +1188,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

@@ -1,46 +1,39 @@
# 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()
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)
## 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} $<TARGET_FILE:jsoncpp_test>
)
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 $<TARGET_FILE:jsoncpp_lib> $<TARGET_FILE_DIR:jsoncpp_test>
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>)
else(BUILD_SHARED_LIBS)
# Just run the test executable.
add_custom_command( TARGET jsoncpp_test
POST_BUILD
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>)
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} $<TARGET_FILE:jsoncpp_test>
add_custom_command(TARGET jsoncpp_test
POST_BUILD
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>
)
endif()
set_target_properties(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)

View File

@@ -9,7 +9,6 @@
#include <json/config.h>
#include <json/json.h>
#include <memory>
#include <stdint.h>
#include <string>
namespace Json {
@@ -40,11 +39,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
builder.settings_["rejectDupKeys_"] = hash_settings & (1 << 7);
builder.settings_["allowSpecialFloats_"] = hash_settings & (1 << 8);
builder.settings_["collectComments"] = hash_settings & (1 << 9);
builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10);
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value root;
const char* data_str = reinterpret_cast<const char*>(data);
const auto data_str = reinterpret_cast<const char*>(data);
try {
reader->parse(data_str, data_str + size, &root, nullptr);
} catch (Json::Exception const&) {

View File

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

View File

@@ -42,7 +42,7 @@ public:
/// Must be a POD to allow inline initialisation without stepping
/// into the debugger.
struct PredicateContext {
typedef unsigned int Id;
using Id = unsigned int;
Id id_;
const char* file_;
unsigned int line_;
@@ -74,7 +74,7 @@ public:
/// 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;
@@ -102,7 +102,7 @@ private:
static Json::String indentText(const Json::String& text,
const Json::String& indent);
typedef std::deque<Failure> Failures;
using Failures = std::deque<Failure>;
Failures failures_;
Json::String name_;
PredicateContext rootPredicateNode_;
@@ -129,7 +129,7 @@ private:
};
/// Function pointer type for TestCase factory
typedef TestCase* (*TestCaseFactory)();
using TestCaseFactory = TestCase* (*)();
class Runner {
public:
@@ -168,7 +168,7 @@ private:
static void preventDialogOnCrash();
private:
typedef std::deque<TestCaseFactory> Factories;
using Factories = std::deque<TestCaseFactory>;
Factories tests_;
};
@@ -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
@@ -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) \

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{'//this is bad JSON.'}

View File

@@ -0,0 +1,4 @@
{
"a": "aaa",
"b": "bbb" // comments not allowed in strict mode
}

View File

@@ -0,0 +1,4 @@
{
"a": "aaa", // comments not allowed in strict mode
"b": "bbb"
}

View File

@@ -0,0 +1,3 @@
{
"array" : [1, 2, 3 /* comments not allowed in strict mode */]
}

View File

@@ -0,0 +1 @@
[1,,]

View File

@@ -0,0 +1 @@
{ "count" : 1234,, }

View File

@@ -0,0 +1 @@
{"one": 1 /* } */ { "two" : 2 }

View File

@@ -1,4 +1,4 @@
[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccccccc",
"dddddddddddddddddddddddddddddddddddddddddddddddddddd" ]

View File

@@ -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] }
}
}
}
}

View File

@@ -1,4 +1,4 @@
{
{
"count" : 1234,
"name" : "test",
"attribute" : "random"

View File

@@ -1,3 +1,3 @@
{
{
"" : 1234
}

View File

@@ -6,6 +6,6 @@
/* Comment before 'second'
*/
.second=2
/* A comment at
/* A comment at
the end of the file.
*/

View File

@@ -9,6 +9,6 @@
"second" : 2
}
/* A comment at
/* A comment at
the end of the file.
*/

View File

@@ -0,0 +1,3 @@
.=[]
.[0]=-inf
.[1]=inf

View File

@@ -0,0 +1 @@
[-1e+9999, 1e+9999]

View File

@@ -0,0 +1,2 @@
.=[]
.[0]=1

View File

@@ -0,0 +1 @@
[1,]

View File

@@ -0,0 +1,2 @@
.={}
.count=1234

View File

@@ -0,0 +1 @@
{ "count" : 1234, }

View File

@@ -15,7 +15,7 @@ import types
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_path = base_path + '.rewrite'
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)

View File

@@ -62,6 +62,10 @@ def safeReadFile(path):
except IOError as e:
return '<File "%s" is missing: %s>' % (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'):
@@ -69,57 +73,41 @@ 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:
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')
@@ -161,10 +149,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 +174,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)