Compare commits

...

347 Commits
v0.2 ... master

Author SHA1 Message Date
Tristan Penman
48424184f3
Merge pull request #220 from AdamKorcz/runtests
build tests in oss-fuzz build
2025-07-28 12:09:41 +10:00
Adam Korczynski
565c96b67b build tests in oss-fuzz build
Signed-off-by: Adam Korczynski <adam@adalogics.com>
2025-07-23 12:42:07 +01:00
Tristan Penman
5dc4596bd7 Fix grammatical errors 2025-07-06 12:59:15 +10:00
Tristan Penman
4d2f389531
Merge pull request #216 from MindaugasPaznekas/patch-1
Fix copy-paste error message
2025-07-06 12:57:25 +10:00
Mindaugas Paznekas
0369c22b5f
Fix copy-paste error message 2025-07-03 14:20:28 +03:00
Tristan Penman
2554d638ae
Merge pull request #215 from pri-patel/patelp/add-regex-to-bundle-script
Update bundle.sh to include regex.hpp
2025-06-15 14:28:37 +10:00
Pritesh Patel
1fab149d57 Update bundle.sh to include regex.hpp 2025-06-13 10:30:04 +01:00
Tristan Penman
6674bc91c7 Bump minimum CMake version for inspector 2025-06-10 17:40:26 +10:00
Tristan Penman
4edda75854
Merge pull request #213 from marzer/mg-boost-regex
Enable using boost::regex instead of std::regex
2025-05-07 09:56:45 +10:00
Mark Gillard
3ce2c4e0a6 Enable using boost::regex instead of std::regex 2025-05-06 17:35:06 +03:00
Tristan Penman
c5a34acc5e
Merge pull request #211 from jmarrec/RegexEngine-more
Eliminate an avoidable std::regex and replace with RegexEngine
2025-04-26 11:02:20 +10:00
Julien Marrec
88de63f752
Eliminate an avoidable std::regex and replace with RegexEngine 2025-04-22 21:00:34 +02:00
Tristan Penman
8b320f2567
Merge pull request #209 from tristanpenman/fix-cifuzz
Run cifuzz on push and pull requests
2025-04-06 08:27:34 +10:00
Tristan Penman
cd0e101642 Bump upload-sarif to v3 2025-04-06 08:09:58 +10:00
Tristan Penman
0ae101b4cf Run cifuzz in push and pull requests 2025-04-06 07:59:14 +10:00
Tristan Penman
bbb687d823
Merge pull request #208 from gema-mx/gema/bundle-add-schema-cache-header-file
bundle: Add `schema_cache.hpp' to bundle script
2025-04-06 07:53:22 +10:00
Tristan Penman
1aca39f679 Bump actions/upload-artifact 2025-04-06 07:52:24 +10:00
Guillermo E. Martinez
256c3b0511 bundle: Add `schema_cache.hpp' to bundle script
`bundle.sh' script generates a header file with missing `SchemaCache`
declaration.  So, this patch fix it.

valijsonQtjson.h:5746:46: error: ‘SchemaCache’ has not been declared
 5746 |     static const Subschema *querySchemaCache(SchemaCache &schemaCache,
      |                                              ^~~~~~~~~~~
valijsonQtjson.h:5769:35: error: ‘SchemaCache’ has not been declared
 5769 |     static void updateSchemaCache(SchemaCache &schemaCache,
      |                                   ^~~~~~~~~~~
valijsonQtjson.h:5822:9: error: ‘SchemaCache’ has not been declared
 5822 |         SchemaCache &schemaCache, std::vector<std::string> &newCacheKeys)

      * bundle.sh(common_headers): Add new `schema_cache.hpp' entry.

Signed-off-by: Guillermo E. Martinez <martinez.enrique@autozone.com>
2025-04-05 07:42:26 -06:00
Tristan Penman
2ba695cf93 Update README 2025-03-30 20:54:34 +11:00
Tristan Penman
2558acc022 Bump json11 2025-03-30 20:52:39 +11:00
Tristan Penman
be052856f1 Bump googletest 2025-03-30 20:51:46 +11:00
Tristan Penman
1cb60962a2 Add Foundation to Poco package list 2025-03-30 20:49:55 +11:00
Tristan Penman
6064db1c6c Changes to make property tree adapter compile with C++17 2025-03-27 17:09:11 +11:00
Tristan Penman
26938a1564 Enable C++17, use built-in CMake support for locating Poco 2025-03-27 17:07:29 +11:00
Tristan Penman
6c76ec65ba Bump minimum CMake version 2025-03-27 17:06:36 +11:00
Tristan Penman
7d59abf50c Fix uninitialised variable, update README 2025-02-08 18:21:40 +11:00
Tristan Penman
caa3ef055c Use statically allocated regexes for date/time pattern matching 2025-02-08 17:46:25 +11:00
Tristan Penman
203ca0de13 Add tests for date/time formats 2025-02-08 15:49:14 +11:00
Tristan Penman
4e2dfd1390 Allow permissive validation of date/time formats 2025-02-08 15:48:57 +11:00
Tristan Penman
db04461018 Add test case for circular references in schemas 2024-12-24 11:17:34 +11:00
Tristan Penman
0a15cf4fe9 Add simple example just for checking validity of schemas 2024-12-22 19:43:37 +11:00
Tristan Penman
b151d1e99a Detect certain JSON reference cycles while parsing schemas 2024-12-22 19:42:08 +11:00
Tristan Penman
ae0112b4be
Merge pull request #202 from jsoref/spelling
Spelling
2024-12-13 11:20:52 +11:00
Tristan Penman
a2611ada9a
Merge pull request #203 from tristanpenman/fix-build
Run apt update in build step
2024-12-13 11:19:12 +11:00
Tristan Penman
1c066ad778 Run apt update in build step 2024-12-13 11:06:13 +11:00
Josh Soref
3581168091 spelling: value
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 21:10:57 -10:00
Josh Soref
d81d0a0c1e spelling: unfortunately
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:46 -10:00
Josh Soref
2bc2b4982b spelling: transparent
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
b18ba8d777 spelling: the
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
e50c8d2b2b spelling: the name of
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
ad305fd8d3 spelling: than
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
769453eb93 spelling: satisfies
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
33de946dd0 spelling: satisfied
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
c34b49fbc9 spelling: present
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
95431d3d6e spelling: preexisting
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
20df7651f0 spelling: nonexistent
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
bcfd55ea2c spelling: macos
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
91eb9b1b07 spelling: javascript
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
39d88c7c3d spelling: invocations
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
43dd86e18c spelling: internal
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
a61c60a4d2 spelling: id
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
b231763704 spelling: higher
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
183919dd07 spelling: hierarchy
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
52b27287c3 spelling: for
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
a35817de30 spelling: contained
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
b54dcfe6e8 spelling: constraints
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
0ce6c378d9 spelling: constraint
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
3b742c234e spelling: command
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
b25260f98b spelling: case-sensitive
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
3553093929 spelling: backtracking
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 20:11:45 -10:00
Josh Soref
44b8eb5e62 spelling: anymore
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 17:04:44 -10:00
Josh Soref
cd34a32034 link: web-based demo is available
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 17:04:44 -10:00
Josh Soref
1353cc321b link: letmaik/valijson-wasm
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2024-12-11 17:04:44 -10:00
Tristan Penman
bd1f707f8c
Merge pull request #201 from tyler92/improve-fuzzing
Fuzzing improvements
2024-10-22 14:10:17 +11:00
Tristan Penman
cc6ca369d3
Merge pull request #197 from tyler92/fix-buffer-overflow
Fix buffer overflow in u8_strlen
2024-10-22 10:03:24 +11:00
Tristan Penman
ad1e184b1c
Merge pull request #199 from tyler92/stack-overflow-invalid-ref
Fix stack overflow for unresolved references
2024-10-21 20:42:00 +11:00
Tristan Penman
65d4d68373 Fix up include grouping 2024-10-21 09:45:24 +11:00
Tristan Penman
7fd212f68d
Merge pull request #198 from tyler92/division-by-zero
Prevent potential division by zero
2024-10-21 08:43:50 +11:00
Mikhail Khachayants
63c56dd730 Prevent potential division by zero 2024-10-21 00:16:06 +03:00
Mikhail Khachayants
48e4099ad2 Fuzzing improvements 2024-10-20 14:36:13 +03:00
Mikhail Khachayants
1c67b948b6 Fix stack overflow for unresolved references 2024-10-20 13:47:54 +03:00
Mikhail Khachayants
b7c051fbc1 Fix buffer overflow in u8_strlen 2024-10-19 00:02:36 +03:00
Tristan Penman
fc9ddf14db Fix bug in difference() for rapidjson 2024-08-28 13:02:35 +10:00
Tristan Penman
a0e05907ae Tidy up regex changes 2024-05-17 08:52:22 +10:00
Tristan Penman
31ce4a5948 Merge branch 'sandwoodK-master' 2024-05-17 08:35:18 +10:00
sandwoodK
2431bdeaa6 Ability to customize regular expression engine 2024-05-02 09:18:28 +02:00
Tristan Penman
c1dde4e270
Merge pull request #190 from BohdanBuinich/compatibility_with_new_boost_lib
Compatibility with boost-1.85.0
2024-04-24 15:47:41 +10:00
BohdanBuinich
c54607119d Compatibility with boost-1.85.0
Starting from boost version 1.85.0, json::error_code is now deprecated

Changes added here:
bacc644f93
2024-04-23 01:08:04 +03:00
Tristan Penman
27f7e75ca1
Merge pull request #187 from jackorobot/move_schema
Implemented functioning move constructors/operators
2024-01-07 11:41:11 +11:00
Tristan Penman
6599e8b33a
Merge pull request #188 from Rail-Connected/pullreq1
Various cosmetic fixes.
2024-01-07 11:27:46 +11:00
Maarten van der Schrieck
96f4740ab6 README.md: Fix un-escaped underscore characters and typo. 2024-01-06 22:37:00 +01:00
Maarten van der Schrieck
c70f22c506 updated examples/valijson_nlohmann_bundled.hpp 2024-01-06 22:33:22 +01:00
Maarten van der Schrieck
a40ec5ea96 Various fixes, reducing compiler warnings.
My compiler gave various warnings, which are easily fixed.
- redundant ";"
- missing NORETURN attributes
- inline @param documentation not in line with functions
- include guard prefix "_" is reserved
2024-01-06 22:30:26 +01:00
Jesse Hoogervorst
299fe1c78d Implemented Schema and Subschema move constructor and assignment operators.
Default implementations were not sufficient, since raw pointers are not actually moved correctly automatically, resulting in segmentation faults.
2024-01-04 15:05:37 +01:00
Tristan Penman
478f9a4671
Merge pull request #186 from jackorobot/move_schema
Added explicit default move constructors/operators
2023-12-17 15:42:40 +11:00
Jesse Hoogervorst
37dceaa5db Added explicit default move constructor/operator to Schema and Subschema to enable move semantics for these classes 2023-12-15 10:44:18 +01:00
Tristan Penman
0b4771e273 Merge branch 'domire8-fix/yaml-cpp-adapter' 2023-12-15 10:55:10 +11:00
Tristan Penman
afc92d5428 Change isString to IsString 2023-12-15 10:54:41 +11:00
Dominic Reber
5d7a6c5c4c Fix isString() method in yaml_cpp_adapter 2023-12-13 15:48:55 +01:00
Tristan Penman
9de00d75b4 Bump minimum cmake version to 3.5.1 2023-11-01 16:41:02 +11:00
Tristan Penman
d52d2dd053 Use string instead string_view 2023-08-26 09:03:02 +10:00
Tristan Penman
373576a3d2 Process each invalid example separately in picojson_format_test 2023-08-24 20:52:18 +10:00
Tristan Penman
0b7efb3763 Make subschema constraint validation clearer 2023-08-24 20:45:43 +10:00
Tristan Penman
0530af0709 Improve PicoJSON format test example 2023-08-24 20:40:00 +10:00
Tristan Penman
cd9258c241 Add picojson example 2023-08-24 09:38:06 +10:00
Tristan Penman
138c3785ef Tweak behaviour of format constraint validation 2023-08-24 09:37:44 +10:00
Tristan Penman
92b9514bde Revert "fail with the first unmet constraint to avoid running into type mismatches"
This reverts commit aee67d58f05972555bfd1e7ce5451da4333e6348.

I believe the original intention of this code was to fall through to
later constraints, even if earlier constraints were not satisfied. This
is not captured by any of the tests in the test suite, which is an
oversight on my part.
2023-08-24 09:18:24 +10:00
Marco Porsch
aee67d58f0 fail with the first unmet constraint to avoid running into type mismatches 2023-08-23 15:42:06 +02:00
Marco Porsch
f716227d0a check the type constraint first because others might rely on it 2023-08-23 15:41:15 +02:00
Tristan Penman
f1902801d6
Merge pull request #179 from DavidKorczynski/cifuzz-int 2023-07-15 15:55:28 +10:00
David Korczynski
3c63c49d60 Add CIFuzz Github Action
Signed-off-by: David Korczynski <david@adalogics.com>
2023-07-11 11:13:57 -07:00
Tristan Penman
4d857316f2 Revert "Bump nlohmann-json submodule"
This reverts commit 8065a5accc45f03b9dadc785341cae3a4583f501.
2023-06-10 12:11:50 +10:00
Tristan Penman
8065a5accc Bump nlohmann-json submodule 2023-06-10 09:00:53 +08:00
Tristan Penman
5dcec3ef49
Merge pull request #177 from taichi-dev/master 2023-06-10 10:55:19 +10:00
yekuang
94ca772cc7
[Build] Make it work on Linux (#1) 2023-06-07 22:52:25 +08:00
Cheng Cao
780bf06715 Rework adapter to build on VS 2022 with latest JSON for modern C++ 2023-06-05 14:50:43 -07:00
Tristan Penman
f7399c1a24
Merge pull request #175 from cbrumgard/master 2023-05-19 11:26:40 +10:00
Chris Brumgard
9e5b479b95 Fixed validation_visitor to work with adaptors that only support the
forward_iterator_tag for array value iterators.
2023-05-18 10:11:37 -04:00
Tristan Penman
2acde8ec54
Merge pull request #172 from silvergasp/ci
Adds Github Actions configuration for CI
2023-02-26 13:09:30 +11:00
Nathaniel Brough
e339c2c2ef Adds Github Actions configuration for CI 2023-02-25 11:25:30 -08:00
Tristan Penman
65ba76e493
Merge pull request #169 from AustinHaigh-Hach/fix-typos 2022-11-02 09:25:22 +11:00
Austin Haigh
f1ff351828 fix typos in preprocessor macros 2022-11-01 13:29:16 -06:00
Tristan Penman
78ac8a737d Correct token replacement issue 2022-10-26 21:01:58 +11:00
Tristan Penman
c4355eaa47 Simplify implementation of YamlCppObject::find() 2022-09-19 21:01:37 +10:00
Tristan Penman
375eaae06c Tidy up doc-comments 2022-09-15 11:06:04 +10:00
Tristan Penman
db8daacc32 Add std::nothrow when using operator new 2022-09-12 13:02:34 +10:00
Tristan Penman
e895d035dc Attempt to fix oss-fuzz build 2022-09-02 10:20:17 +12:00
Tristan Penman
d9c9d2eb0c Revert nlohmann-json module to 3.1.2 2022-08-30 18:05:01 +10:00
Tristan Penman
8d04b757d3 Fix whitespace in .gitmodules 2022-08-30 14:31:28 +12:00
Tristan Penman
2642dd4efc Bump rapidjson submodule to 06d58b9 2022-08-30 13:41:44 +12:00
Tristan Penman
74bd2a990f Switch to using submodule for JSON-Schema-Test-Suite 2022-08-30 13:28:52 +12:00
Tristan Penman
2fe3c829e1 Switch to using submodule for googletest 2022-08-30 13:26:37 +12:00
Tristan Penman
b63a08f379 Switch to using submodule for json11 2022-08-30 13:23:59 +12:00
Tristan Penman
444bc02def Switch to using submodule for jsoncpp 2022-08-30 13:21:15 +12:00
Tristan Penman
ac122d9ed3 Switch to using submodule for yaml-cpp 2022-08-30 13:20:56 +12:00
Tristan Penman
fb995cebd3 Switch to using submodule for nlohmann-json 2022-08-30 13:07:33 +12:00
Tristan Penman
582fd0fc13 Switch to using submodule for rapidjson 2022-08-30 11:54:37 +12:00
Tristan Penman
008c7ca4f9 Update readme 2022-08-30 11:44:38 +12:00
Tristan Penman
2cef1a6538 Switch to submodule for picojson 2022-08-30 11:41:15 +12:00
Tristan Penman
c0ce4cde7e Correct typo in license 2022-08-11 13:29:23 +10:00
Tristan Penman
d397ac6074 Include <limits> header in custom_allocator.hpp 2022-08-10 23:50:03 +10:00
Tristan Penman
94d3bfd39a Fix format regex escape sequences 2022-07-21 22:45:25 +10:00
Tristan Penman
25dcdb1c3a
Merge pull request #160 from jrave/time-format-fields 2022-07-19 10:36:08 +10:00
Johannes Rave
dee2fa64ff Support for time related format fields 2022-07-18 16:57:44 +03:00
Tristan Penman
5f49d77b1e Basic structure for format constraint 2022-07-17 07:30:55 +03:00
Tristan Penman
a6a4fbb580 Remove redundant call to baseline 2022-04-09 17:26:32 +10:00
Tristan Penman
0de61e0cca Tidy up readme 2022-04-09 13:52:45 +10:00
Tristan Penman
1ff3625482 Add script to bundle library into a single header 2022-04-09 13:46:54 +10:00
Tristan Penman
21322b2d82 Move Adapter and BasicAdapter classes to internal 2022-04-09 13:46:54 +10:00
Tristan Penman
23724b97e3
Merge pull request #159 from jackorobot/fix_poco_get_integer 2022-04-08 16:51:33 +10:00
Jesse Hoogervorst
72afeb1ff7 Fixed PocoJsonValue::getInteger being limited to 32-bit integers 2022-04-07 16:22:43 +02:00
Tristan Penman
4d603df433 Update Authors file 2022-02-22 11:46:06 +11:00
Tristan Penman
0e3f48c889 Remove vendored copy of urdl 2022-02-21 21:43:04 +11:00
Tristan Penman
9e7dbd8460 Remove outdated Xcode project files 2022-02-21 21:40:55 +11:00
Tristan Penman
2f6760f6a8
Merge pull request #154 from psigen/yaml-cpp-support 2022-02-21 21:35:44 +11:00
Pras Velagapudi
f4bbf4e0a7 Remove non-critical yaml-cpp files from PR. 2022-02-13 06:32:47 -05:00
Pras Velagapudi
b685584e42 Add optimization for find implementation. 2022-02-13 06:28:03 -05:00
Pras Velagapudi
c688aa3bcb Add a unit test for object member access. 2022-02-13 06:08:42 -05:00
Pras Velagapudi
76c9f40c42 Added simple loading utility. 2022-02-13 05:38:54 -05:00
Pras Velagapudi
66424a1116 Added a column limit to the file. 2022-02-13 05:38:23 -05:00
Pras Velagapudi
f03461bb01 Fixed issue with YAML::Node reference usage. 2022-02-13 05:25:31 -05:00
Pras Velagapudi
7f23f3694b Fix unit tests to match property tree. 2022-02-11 19:22:14 -05:00
Pras Velagapudi
698936aee1 Added missing dep for YAML-cpp. 2022-02-11 19:17:07 -05:00
Pras Velagapudi
328db2f644 Initial pass at yaml-cpp support. 2022-02-11 19:13:43 -05:00
Tristan Penman
34f75118f0 Add note about GCC versions to readme 2022-02-10 10:45:07 +11:00
Tristan Penman
5ca87a6199 Remove very obsolete valgrind suppressions file 2022-02-09 22:17:16 +11:00
Tristan Penman
27d30658d2 Update vendored jsoncpp to version 1.9.5 2022-02-09 22:01:49 +11:00
Tristan Penman
c2822576a2 Update CMakeLists to use add_compile_definitions 2022-02-08 09:21:21 +11:00
Tristan Penman
f97013928d Remove unnecessary indentation from code snippets in readme 2022-02-07 21:41:29 +11:00
Tristan Penman
7d4ea9088d Add boost::json example and delete problematic constructors 2022-02-07 20:50:23 +11:00
Tristan Penman
d34f78b435 Improve error messaging when parsing schemas and documents 2022-02-06 20:14:37 +11:00
Tristan Penman
dd32f66df8 Build tests for fuzzing 2022-02-04 11:00:17 +11:00
Tristan Penman
8b5f253c78 Tweak readme formatting 2022-02-03 10:36:12 +11:00
Tristan Penman
a2e3958617 Remove Travis CI config 2022-02-03 10:35:29 +11:00
Tristan Penman
3940b3615c Mention web-based demo in readme 2022-02-03 10:01:59 +11:00
Tristan Penman
f5f979b07d Mention boost compiler warnings in README 2022-01-31 20:29:45 +11:00
Tristan Penman
80afdef597
Merge pull request #150 from jonpetri/jonpetri/cmake-improvements 2022-01-31 19:54:45 +11:00
Jon Petrissans
4622b958e4 Set valijson_BUILD_TESTS OFF by default in cmake
Avoids extra unnecessary dependencies by default.
2022-01-31 08:40:44 +01:00
Jon Petrissans
50010fd959 Make VALIJSON_USE_EXCEPTIONS interface definition 2022-01-31 08:40:44 +01:00
Jon Petrissans
c5dac2bc0b Install cmake export file 2022-01-31 08:40:44 +01:00
Jon Petrissans
c7d5f2cbec Remove valijson_INSTALL_HEADERS from cmake build
As the install is done separately from the build, no need to make header
installation optional.
2022-01-30 18:11:30 +01:00
Tristan Penman
bfb5860cbd Fix fuzzer build 2022-01-10 07:35:04 +11:00
Tristan Penman
7b8654382a
Merge pull request #147 from keith-bennett-airmap/keith/shellcheck 2022-01-07 11:32:16 +11:00
Keith Bennett
1f25558c21 make shellcheck clean
`$ bash ./shellcheck.sh`
```
Checking: /home/kbennett/src/public/valijson/tests/fuzzing/oss-fuzz-build.sh
Checking: /home/kbennett/src/public/valijson/shellcheck.sh
All scripts found (listed above) passed shellcheck
```
2022-01-06 16:05:37 -06:00
Tristan Penman
3c185cb896
Merge pull request #145 from mporsch/smart-pointer-memory-management 2021-12-25 22:35:48 +11:00
Marco Porsch
828fc87623 use implicit conversion of unique_ptr<T, DeleterA> to unique_ptr<const T, DeleterB>
relies on DeleterB being constructible from DeleterA
also uses that T* can always be converted to void* (but not the other way around)
2021-12-20 10:37:47 +01:00
Marco Porsch
cf841e10e9 use unique_ptr for memory management in constraints and subschema 2021-12-09 15:33:25 +01:00
Tristan Penman
4a99dd79d0 Add missing include 2021-12-07 09:53:09 +11:00
Tristan Penman
75ada05cf8 Use strong types in external_schema example, and update README 2021-11-06 08:53:39 +11:00
Tristan Penman
26f3a8476f Less const-ness 2021-11-06 08:44:09 +11:00
Tristan Penman
3eaf1bb93e Add note about VALIJSON_USE_EXCEPTIONS to the README 2021-11-05 09:59:35 +11:00
Tristan Penman
4990e352a7 Update inspector to enable and handle exceptions 2021-11-05 08:57:42 +11:00
Tristan Penman
af071f0198 Update inspector build to work with Qt6 2021-11-05 08:33:43 +11:00
Tristan Penman
7b6d22f166 Update CMakeLists.txt to check for boost/json.hpp before building tests 2021-10-06 20:33:39 +11:00
Tristan Penman
5da8973097
Merge pull request #139 from YangJiao1996/master
Always apply callback function when validating schema
2021-10-06 10:57:22 +11:00
Yang Jiao
0f0cc2bc55 Always apply callback function when validating schema 2021-10-05 18:23:27 -04:00
Tristan Penman
9a2ebbdec2
Merge pull request #137 from veselypeta/readme-cmake
update README add with cmake
2021-09-17 09:24:26 +10:00
veselypeta
e5530febe7 update README add with cmake 2021-09-16 14:34:05 +01:00
Tristan Penman
2dfc7499a3 Update Authors file 2021-09-15 16:23:10 +10:00
Tristan Penman
6dab4978be Update README and tweak syntax in Boost.JSON adapter 2021-09-15 10:15:03 +10:00
Tristan Penman
2ecd211952
Merge pull request #136 from matty0ung/boostjson
Add support for Boost.JSON
2021-09-15 10:12:26 +10:00
Tristan Penman
b1119cccd6
Merge pull request #135 from matty0ung/uris
Support fetching sub-schemas from other files
2021-09-11 09:14:30 +10:00
Matt Young
f5cf601efa Add Boost.JSON support 2021-09-10 08:55:03 +02:00
Matt Young
14325788f8 Add Boost.JSON support 2021-09-10 08:54:00 +02:00
Matt Young
d3104ea8d8 Support fetching sub-schemas from other files 2021-09-09 19:27:13 +02:00
Tristan Penman
ad7dac75a5
Merge pull request #133 from rayvincent2/feature/add-urn-reference-support
Add support for urn document references
2021-08-26 10:12:09 +10:00
Ray Vincent
3442709aa7 Update urn regex expression to be std::regex safe 2021-08-25 16:57:33 -07:00
Ray Vincent
f787a8a7a7 Update urn regex to match widely accepted expression 2021-08-24 13:51:32 -07:00
Ray Vincent
653d515d32 Ensure that urn regex checks to end of string 2021-08-24 13:43:00 -07:00
Ray Vincent
eac0859cd8 Ensure that urn NID cannot include '.' 2021-08-24 13:39:05 -07:00
Ray Vincent
ef42dae296 Add support for urn document references 2021-08-23 15:45:49 -07:00
Tristan Penman
a4684c285d Fix path to rapidjson in fuzzing test code 2021-07-31 11:00:37 +10:00
Tristan Penman
11af652228 Merge remote-tracking branch 'clainio/build-fix' 2021-07-29 17:44:58 +10:00
Tristan Penman
c5487c39eb Update rapidjson to latest code from github 2021-07-29 07:31:00 +10:00
Tristan Penman
6a04040d4f Update adapters to avoid inheriting from std::iterator 2021-07-28 22:19:36 +10:00
Tristan Penman
385d2d8306 Improve handling of compiler flags when exceptions are disabled 2021-07-28 21:05:26 +10:00
Tristan Penman
82e093fe18 Upgrade gtest to v1.11.0 2021-07-28 19:27:28 +10:00
Tristan Penman
c63ac26f03 Disable C4702: unreachable code warnings for json_pointer.hpp 2021-07-28 17:09:45 +10:00
Tristan Penman
855365bce0 Disable C4702: unreachable code warnings within relevant headers 2021-07-28 16:58:15 +10:00
Konstantin Plotnikov
5c97e3ccd4
Fix gcc build error 2021-06-25 18:02:19 +03:00
Tristan Penman
4897d102bd Fix exclusiveMaximum and exclusiveMinimum error messages 2021-06-11 13:43:09 +10:00
Tristan Penman
6cc4cddc96 Suppress boost warnings that aren't relevant to the test suite 2021-05-24 10:00:16 +10:00
Tristan Penman
2cf8d3dd2e Add default tests for draft 7 2021-05-21 10:20:44 +10:00
Tristan Penman
e94179e191 Add definitions tests for draft 7 2021-05-21 10:11:45 +10:00
Tristan Penman
bb2c425104 Improve array_iteration_basics example 2021-05-20 22:14:22 +10:00
Tristan Penman
e6909b155c Add required test for draft 4 2021-05-20 22:03:35 +10:00
Tristan Penman
df89869e00 Add maxLength and minLength tests for draft 7 2021-05-20 21:36:20 +10:00
Tristan Penman
9183462118 Fix return type on getMinLength 2021-05-20 17:01:37 +10:00
Tristan Penman
3740dc5166 Explicitly initialise optionals in Subschema class 2021-05-20 16:07:07 +10:00
Tristan Penman
cb778b6bb6 Minor changes to address msvc warnings and make cmake work on Windows 2021-05-17 14:00:55 +10:00
Tristan Penman
70f12ed1d4
Merge pull request #123 from anishmonachan7/fix_unused_variable
fix unused variable error with gcc 8.3
2021-04-08 08:54:13 +10:00
anishmonachan7
03b8cccb27
Update include/valijson/constraints/concrete_constraints.hpp
Co-authored-by: Tristan Penman <tristan@tristanpenman.com>
2021-04-07 15:24:04 +02:00
Anish
dc6d2fe0e7 fix unused variable error with gcc 8.3 2021-04-07 12:39:39 +02:00
Tristan Penman
77bae9fb74 Fix xcode stuff 2021-04-04 13:33:13 +10:00
Tristan Penman
66262bafb8 Include nlohmann/json.hpp instead of json.hpp 2021-04-04 13:25:10 +10:00
Tristan Penman
b3b958c8c0
Merge pull request #121 from anishmonachan7/virtual_destructor
destructor to virtual destructor
2021-04-03 15:59:45 +11:00
Anish
84c9fbf52c destructor to virtual destructor 2021-04-02 11:09:55 +02:00
Tristan Penman
8a784f23bf Minor fix for example code in README 2021-01-25 09:54:24 +11:00
Tristan Penman
a19e1c00f0 Remove warning suppressions for clang 2021-01-24 15:47:57 +11:00
Tristan Penman
af2358b63f Use custom RAPIDJSON_ASSERT macro to catch parser errors 2021-01-24 14:06:15 +11:00
Tristan Penman
7ab96207c5 Ensure ref values are strings 2021-01-17 17:42:55 +11:00
Tristan Penman
635f36f095
Merge pull request #119 from BSipos-RKF/issue-118
Possible fix for #118
2021-01-17 16:56:00 +11:00
Tristan Penman
fba5a9e8a7 Reject JSON references that index into empty arrays 2021-01-17 13:34:52 +11:00
Brian Sipos
cbcde15c0b Possible fix for #118 2021-01-12 13:12:57 -05:00
Tristan Penman
3621f98d43 Update rapidjson_utils.hpp to use iterative parsing 2021-01-07 21:34:51 +11:00
Tristan Penman
f544cd020a
Merge pull request #116 from AdamKorcz/fuzz1
Add fuzzer with oss-fuzz build script
2020-12-17 09:39:17 +11:00
AdamKorcz
c13eed99d1 Minor refactoring 2020-12-16 12:32:37 +00:00
AdamKorcz
3a47f0cd0d Added fuzzer with oss-fuzz build file 2020-12-16 12:30:36 +00:00
Tristan Penman
cf64893031
Merge pull request #114 from baylesj/fix-memory-leak
Fix memory leak in concrete constraints
2020-12-03 10:44:56 +11:00
Jordan Bayles
1f964c1299 Fix memory leak in concrete constraints
This patch fixes a memory leak found from ASAN testing. There may be
more here, but this is the only one blocking our workflow.
2020-12-02 11:16:41 -08:00
Tristan Penman
7cb31947d8
Merge pull request #113 from hei-pa/master
move curlpp findPackage in EXAMPLES block
2020-12-02 21:40:06 +11:00
Pascal Heinrich
8cc83c8be9 move curlpp findPackage in EXAMPLES block 2020-12-02 10:01:36 +01:00
Tristan Penman
c1e75c700f
Merge pull request #110 from baylesj/remote_throws
Add VALIJSON_USE_EXCEPTIONS mode
2020-11-09 16:51:19 +11:00
Jordan Bayles
bc81adbd3f add version checks around BOOST_NORETURN 2020-11-08 21:40:01 -08:00
Jordan Bayles
7a560db2ed Fixup headers
This patch removes the include for boost's internal suffix.hpp header,
in favor of just including the throw_exception.hpp header.
2020-11-08 21:21:54 -08:00
Jordan Bayles
b8e9581057 Apply feedback, add boost version check 2020-11-08 19:54:53 -08:00
Jordan Bayles
8f6f9b6a80 Use deprecated declarations 2020-11-08 17:18:14 -08:00
Jordan Bayles
f100614249 Cleanup unnecessary returns 2020-11-08 17:04:52 -08:00
Jordan Bayles
a30ef97465 Add VALIJSON_USE_EXCEPTIONS mode
This patch adds support for a new Cmake option,
VALIJSON_USE_EXCEPTIONS. If specified and set to `0`, Valijson will
disable all exception throwing, add the `-fno-exceptions` compiler flag,
and print to std::err and abort where exceptions would have been thrown.

NOTE: to set the value of a CMake option, the easiest way is to modify
the appropriate source line in the <build folder>/CMakeCache.txt file.

Bug: #106
2020-11-08 16:58:32 -08:00
Tristan Penman
8a700811d5 Add JSON Inspector example app 2020-11-08 17:33:37 +11:00
Joshua Eckroth
bbfc3f5c97 Fixed build on certain GCC toolchains 2020-11-08 11:43:37 +11:00
Tristan Penman
84b67fa6fe
Merge pull request #107 from baylesj/readme
Minor tweaks to README.md file
2020-11-08 11:40:15 +11:00
Tristan Penman
90783ca4be Minor code style changes 2020-11-08 11:38:52 +11:00
Tristan Penman
3dd4482af2
Merge pull request #103 from wwriter/cond_schema_errormessage
Generate a detailed error message when if-then-else constraints are not met
2020-11-08 11:36:08 +11:00
Jordan Bayles
ee4f85bf5e Minor tweaks to README.md file
This patch cleans up the README.md file to use more language markup
instead of raw text.
2020-11-06 17:19:18 -08:00
Tristan Penman
a703886214 Update jsoncpp link in readme 2020-11-06 13:24:57 +11:00
Tristan Penman
abedaf0ecb
Merge pull request #105 from baylesj/update-jsoncpp
Update JsonCpp to 1.9.4
2020-11-06 13:23:26 +11:00
Jordan Bayles
825ee11008 Fix readme 2020-11-05 17:44:13 -08:00
Jordan Bayles
b6b6f167ad Delete jsoncpp fuzzing stuff 2020-11-05 17:42:26 -08:00
Jordan Bayles
2ee7474f96 Delete more unnecessary scripts 2020-11-05 17:39:46 -08:00
Jordan Bayles
1ff5308f22 fix submodule 2020-11-05 17:37:50 -08:00
Jordan Bayles
dbc4fcc8d4 Remove modules 2020-11-05 17:33:52 -08:00
Jordan Bayles
88d9d890b5 Update JsonCpp to 1.9.4
This patch updates the JsonCpp third party dependency to the latest
version.
2020-11-05 17:11:35 -08:00
Samuel
d5091b2dbb added feature : now users can get a detailed error message when if-then-else conditional constraints are not met 2020-10-07 20:16:30 +09:00
Tristan Penman
931f64d484
Merge pull request #102 from mathbunnyru/patch-2
Add conan package manager info
2020-10-03 07:24:01 +10:00
Ayaz Salikhov
c5e615431d
Add conan package manager info 2020-10-02 22:59:01 +03:00
Tristan Penman
6cda9227cc
Merge pull request #99 from mathbunnyru/patch-1
Fix README so the code actually throws, when json is invalid
2020-10-02 08:37:07 +10:00
Ayaz Salikhov
45b0f83b5a
Fix README so the code actually throws, when json is invalid 2020-10-01 17:31:04 +03:00
Tristan Penman
89e37cbf42 Fix typo 2020-09-04 20:53:29 +10:00
Tristan Penman
7f01c39116 Minor suggestions from clangtidy 2020-09-04 20:47:38 +10:00
Tristan Penman
a527564b10
Merge pull request #96 from joshuaeckroth/master
Switched from jsoncpp deprecated Reader to CharReader
2020-08-07 09:12:37 +10:00
Joshua Eckroth
ccad6b140f Switched from jsoncpp deprecated Reader to CharReader 2020-08-06 06:57:20 +00:00
Tristan Penman
45a333e60d Try to make builds faster 2020-07-17 17:23:32 +10:00
Tristan Penman
0ee3bada09 Fix broken build 2020-07-17 17:20:11 +10:00
Tristan Penman
bbe62ecd7d
Merge pull request #95 from wirenboard/feature/cache-regex
Regex objects cache for pattern constraints
2020-07-17 16:59:47 +10:00
Tristan Penman
f7f3acf20c
Merge pull request #94 from wirenboard/fix/pass-by-ref
Pass visitor to validationCallback by ref
2020-07-16 09:17:55 +10:00
pete
39f350692c Regex objects cache for pattern constraints 2020-07-15 17:09:18 +05:00
pete
2216c2b8b3 Pass visitor to validationCallback by ref 2020-07-15 16:43:46 +05:00
Tristan Penman
0db0d139b7
Merge pull request #93 from Delgan/fix-unused-args
Fix compilation errors due to unused parameters
2020-07-15 18:37:28 +10:00
Delgan
1c825cc638 Remove unused parameters instead of commenting them out 2020-07-15 10:06:16 +02:00
Delgan
ca031221fc Fix compilation errors due to unused parameters 2020-07-15 09:44:44 +02:00
Tristan Penman
105e345a73
Merge pull request #92 from arthurafarias/add-cmake-interface-library
Added interface target to CMakeLists.txt
2020-07-10 11:06:56 +10:00
Arthur Farias
f60a30899b Added interface target to CMakeLists.txt 2020-07-09 18:24:41 +02:00
Tristan Penman
d453ee2ed4 Revert breaking changes to jsoncpp_adapter.hpp 2020-07-06 19:55:07 +10:00
Tristan Penman
f3a0390e17 Revert changes to json11_adapter.hpp 2020-07-06 19:50:10 +10:00
Tristan Penman
49c20301ed Disable -Wshadow for included header in property_tree_utils.hpp 2020-07-06 19:46:31 +10:00
Tristan Penman
8875d80278 Add CLion paths to .gitignore 2020-07-06 19:31:44 +10:00
Tristan Penman
73a8e440c0 More aggressive compiler warnings 2020-07-06 19:30:55 +10:00
Tristan Penman
77d2ef8299 Cosmetic improvements for poco_json_adapter.hpp and property_tree_adapter.hpp 2020-07-06 12:48:55 +10:00
Tristan Penman
e5c1cbfe88 Ensure tests are run for Poco, Qt and property_tree adapters 2020-07-06 12:37:05 +10:00
Tristan Penman
8c0d16a068 Cosmetic improvements for std_string_adapter.hpp, test_json_pointer.cpp and test_poly_constraint.cpp 2020-07-06 11:47:58 +10:00
Tristan Penman
217b990b00 Cosmetic improvements for schema_parser.hpp and validation_results.hpp 2020-07-06 11:30:41 +10:00
Tristan Penman
71f4cdaa84 Cosmetic improvements for custom_allocator.hpp 2020-07-06 11:03:11 +10:00
Tristan Penman
e46af24588 Cosmetic improvements for concrete_constraints.hpp and basic_constraint.hpp 2020-07-06 09:16:40 +10:00
Tristan Penman
7917b2f75f Cosmetic improvements for schema.hpp, schema_parser.hpp and subschema.hpp 2020-07-05 22:38:47 +10:00
Tristan Penman
8150a52008 Cosmetic improvements for test_adapter_comparison.cpp 2020-07-05 22:19:54 +10:00
Tristan Penman
28cc9e8eeb Cosmetic improvements for qtjson_adapter.hpp 2020-07-05 22:11:01 +10:00
Tristan Penman
508bc019ec Cosmetic improvements for rapidjson_adapter.hpp 2020-07-05 22:02:55 +10:00
Tristan Penman
d7901d4858 Cosmetics improvements for picojson_adapter.hpp 2020-07-05 21:49:11 +10:00
Tristan Penman
3211a04dd1 Cosmetic improvements for nlohmann_json_adapter.hpp 2020-07-05 21:43:10 +10:00
Tristan Penman
0f57cb31bc Cosmetic improvements for jsoncpp_adapter.hpp 2020-07-05 21:37:03 +10:00
Tristan Penman
e11c17c3f0 Cosmetic improvements for json11_adapter.hpp 2020-07-05 21:10:26 +10:00
Tristan Penman
6f1f4acb82 Cosmetic improvements for basic_adapter.hpp 2020-07-05 20:31:47 +10:00
Tristan Penman
3ddbe585ba Cosmetic improvements for validation_visitor.hpp 2020-07-05 20:21:17 +10:00
Tristan Penman
09d21423cc Update xcode project files 2020-06-28 12:40:05 +10:00
Tristan Penman
0481a0bb69 Minor tidy up of const auto usage 2020-06-28 12:39:50 +10:00
Tristan Penman
94cef2fa8d Add example showing local file resolution 2020-06-26 20:05:26 +10:00
Tristan Penman
7a52fc88cd
Merge pull request #88 from silbo/master
Add QJsonArray include to use doc.array()
2020-06-10 14:35:48 +10:00
Silver Kuusik
622f9d6839
Add QJsonArray include to use doc.array()
* otherwise invalid use of incomplete type 'class QJsonArray'
2020-06-10 06:18:58 +02:00
Tristan Penman
83af012942
Merge pull request #87 from silbo/master
Add missing include for DerefProxy
2020-06-09 09:40:43 +10:00
Silver Kuusik
4e1b3be88e
Add missing include for DerefProxy 2020-06-08 23:00:21 +02:00
Tristan Penman
12a1d5e006 Switch back to using embedded copy of JSON-Schema-Test-Suite 2020-06-03 19:58:48 +10:00
Tristan Penman
aa0f766b03 Merge branch 'master' of github.com:tristanpenman/valijson 2020-06-03 19:56:37 +10:00
Tristan Penman
8febb456f4 Merge remote-tracking branch 'origin/master' into v6-and-v7-support 2020-06-03 19:54:48 +10:00
Tristan Penman
a4a1f98186 Update README to reflect current level of v7 support 2020-06-03 19:51:23 +10:00
Tristan Penman
92d369e916
Merge pull request #81 from myxo/master
Fix warning C4244 on x86 target
2020-02-06 11:45:07 +11:00
myxo
8866e6da24 Fix warning C4244 on x86 target
Warning message: "warning C4244: '=': conversion from 'uint64_t' to 'std::size_t'"
2020-02-04 16:08:50 +03:00
Tristan Penman
4cf83102af Minor whitespace fix 2020-01-08 14:39:22 +11:00
Tristan Penman
cdfaf7e434
Merge pull request #80 from beg0/master
Fix bad iterator comparaison when resolving json pointer
2020-01-08 14:34:17 +11:00
Cédric CARRÉE
4338affeb3 Fix bad iterator comparaison when resolving json pointer
When resolving a json pointer and use an empty string as a
referenceToken, the value is coerced as an empty object and a temporary empty
object is returned from 'asObject()'. Then we used to compare 2
iterators from 2 differents temporary empty objects.
2020-01-07 16:36:56 +01:00
Tristan Penman
42cdb3f5b3 Add file-level documentation to std_string_adapter.hpp 2019-10-10 13:32:16 +11:00
Tristan Penman
6287656e2b Implement propertyNames constraint 2019-10-10 13:23:42 +11:00
Tristan Penman
dcddea604d Add StdStringAdapter to support propertyNames constraint 2019-10-10 13:22:51 +11:00
Tristan Penman
bae7991fda Update some old-style for loops 2019-10-09 21:42:36 +11:00
Tristan Penman
05bd44744f Change default draft version 2019-10-09 21:22:36 +11:00
Tristan Penman
5f8c73fdf7 Update 'dependencies' constraint to pass v7 tests 2019-09-24 21:46:03 +10:00
Tristan Penman
5430e79754 Update 'required' constraint to match v7 tests 2019-09-24 21:22:15 +10:00
Tristan Penman
98d804a367 Add support for const constraint 2019-09-24 20:38:45 +10:00
Tristan Penman
caff3cdbd9 Fix up comments 2019-09-24 20:13:46 +10:00
Tristan Penman
c4f15c92cc Replace NULL with nullptr in schema_parser.hpp 2019-09-24 14:12:03 +10:00
Tristan Penman
f71355b90f Add support for 'contains' constraint 2019-09-24 14:08:45 +10:00
Tristan Penman
ba44a8d641 Replace NULLs with nullptr in validation_visitor.hpp 2019-09-03 21:38:08 +10:00
Tristan Penman
866f5761bf Improve support for boolean subschemas 2019-08-31 21:37:55 +10:00
Tristan Penman
c89d1d89cd Add passing test cases for draft 7 2019-08-30 11:00:21 +10:00
Tristan Penman
c210d07c61 Update AllOfConstraint and AnyOfConstraint to support draft 7 2019-08-30 10:33:56 +10:00
Tristan Penman
a285ed0fbe Add test cases for draft 7 exclusiveMaximum, exclusiveMinimum, maximum and minimum constraints 2019-08-29 22:21:30 +10:00
Tristan Penman
9b299c9517 Fix issues in parsing of if/then/else constraints 2019-08-29 22:18:04 +10:00
Tristan Penman
ef61c8e0de Support for draft 7 exclusiveMaximum and exclusiveMinimum constraints 2019-08-29 21:34:22 +10:00
Tristan Penman
925ff8ff68 Initial support for 'if', 'then' and 'else' subschemas 2019-08-29 10:31:37 +10:00
Tristan Penman
dac4cff42f Whitespace fixes 2019-08-28 21:27:45 +10:00
Tristan Penman
c8dfd94035 Merge remote-tracking branch 'origin/master' into v6-and-v7-support 2019-08-27 12:38:34 +10:00
Tristan Penman
d0f67e4afc Remove old header inclusion guards 2019-08-22 22:19:09 +10:00
Tristan Penman
162f246e63 Add placeholders for conditional constraint 2019-08-22 22:12:40 +10:00
Tristan Penman
0f9e8cacf8 Disable unnecessary C++11 checks in source code 2019-08-20 22:38:19 +10:00
Tristan Penman
b36de50d4a Update xcode project files 2019-08-20 22:21:53 +10:00
Tristan Penman
38d4b15ac8 Minor fixes for test suite build 2019-08-20 21:59:30 +10:00
Tristan Penman
9354601f11 Switch to using JSON-Schema-Test-Suite as a git submodule 2019-08-20 21:52:29 +10:00
507 changed files with 20434 additions and 207871 deletions

17
.clang-format Normal file
View File

@ -0,0 +1,17 @@
---
BasedOnStyle: LLVM
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBraces: Custom
IndentWidth: 4
AllowShortFunctionsOnASingleLine: Empty

41
.github/workflows/cifuzz.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: CIFuzz
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
Fuzzing:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'valijson'
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'valijson'
language: c++
fuzz-seconds: 300
output-sarif: true
- name: Upload Crash
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
- name: Upload Sarif
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v3
with:
# Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
category: CIFuzz

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

@ -0,0 +1,41 @@
name: CMake
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Install dependencies
run: |
sudo apt update --yes
sudo apt install --yes libboost-all-dev qtbase5-dev libcurlpp-dev libcurl4-openssl-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -Dvalijson_BUILD_TESTS=ON -Dvalijson_BUILD_EXAMPLES=ON
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j$(nproc)
- name: Test
working-directory: ${{github.workspace}}/build
run: ./test_suite

4
.gitignore vendored
View File

@ -4,3 +4,7 @@ xcode/valijson.xcodeproj/project.xcworkspace
xcode/valijson.xcodeproj/project.xcworkspace/xcuserdata
xcode/valijson.xcodeproj/xcuserdata
doc/html
.idea
cmake-build-*
CMakeFiles/
.vs

32
.gitmodules vendored Normal file
View File

@ -0,0 +1,32 @@
[submodule "thirdparty/picojson"]
path = thirdparty/picojson
url = https://github.com/tristanpenman/picojson.git
shallow = true
[submodule "thirdparty/rapidjson"]
path = thirdparty/rapidjson
url = https://github.com/Tencent/rapidjson.git
shallow = true
[submodule "thirdparty/nlohmann-json"]
path = thirdparty/nlohmann-json
url = https://github.com/nlohmann/json.git
shallow = true
[submodule "thirdparty/yaml-cpp"]
path = thirdparty/yaml-cpp
url = https://github.com/jbeder/yaml-cpp.git
shallow = true
[submodule "thirdparty/jsoncpp"]
path = thirdparty/jsoncpp
url = https://github.com/open-source-parsers/jsoncpp.git
shallow = true
[submodule "thirdparty/json11"]
path = thirdparty/json11
url = https://github.com/dropbox/json11.git
shallow = true
[submodule "thirdparty/googletest"]
path = thirdparty/googletest
url = https://github.com/google/googletest.git
shallow = true
[submodule "thirdparty/JSON-Schema-Test-Suite"]
path = thirdparty/JSON-Schema-Test-Suite
url = https://github.com/json-schema-org/JSON-Schema-Test-Suite.git
shallow = true

View File

@ -1,74 +0,0 @@
language: cpp
sudo: required
dist: trusty
matrix:
include:
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5', 'qtbase5-dev', 'libboost1.55-dev', 'libssl-dev', 'libcurl4-openssl-dev']
env:
- CXX_COMPILER=g++-5
- C_COMPILER=gcc-5
- os: linux
compiler: clang
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
packages: ['clang-3.6', 'qtbase5-dev', 'libboost1.55-dev', 'libssl-dev', 'libcurl4-openssl-dev']
env:
- CXX_COMPILER=clang++-3.6
- C_COMPILER=clang-3.6
- os: linux
compiler: clang
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7']
packages: ['clang-3.7', 'qtbase5-dev', 'libboost1.55-dev', 'libssl-dev', 'libcurl4-openssl-dev']
env:
- CXX_COMPILER=clang++-3.7
- C_COMPILER=clang-3.7
- os: linux
compiler: clang
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
packages: ['clang-3.8', 'libc++-dev', 'libc++abi-dev', 'qtbase5-dev', 'libboost1.55-dev', 'libssl-dev', 'libcurl4-openssl-dev']
env:
- CXX_COMPILER=clang++-3.8
- C_COMPILER=clang-3.8
- CMAKE_CXX_FLAGS="-stdlib=libc++"
- CMAKE_EXE_LINKER_FLAGS="-lc++"
before_install:
- pushd ~
- wget https://github.com/pocoproject/poco/archive/poco-1.7.8p2-release.tar.gz
- tar -xf poco-1.7.8p2-release.tar.gz
- cd poco-poco-1.7.8p2-release
- mkdir cmake_build
- cd cmake_build
- export POCO_OPTS="-DENABLE_CRYPTO=off -DENABLE_DATA=off -DENABLE_DATA_MYSQL=off -DENABLE_DATA_ODBC=off -DENABLE_DATA_SQLITE=off"
- export POCO_OPTS="$POCO_OPTS -DENABLE_MONGODB=off -DENABLE_NET=off -DENABLE_NETSSL=off -DENABLE_PAGECOMPILER=off"
- export POCO_OPTS="$POCO_OPTS -DENABLE_PAGECOMPILER_FILE2PAGE=off -DENABLE_PDF=off -DENABLE_UTIL=off -DENABLE_XML=off -DENABLE_ZIP=off"
- cmake -D CMAKE_CXX_COMPILER=`which ${CXX_COMPILER}` -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" -DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS" $POCO_OPTS ..
- sudo make install
- wget -O curlpp-0.8.1.tar.gz https://github.com/jpbarrette/curlpp/archive/v0.8.1.tar.gz
- tar -xf curlpp-0.8.1.tar.gz
- cd curlpp-0.8.1
- mkdir cmake_build
- cd cmake_build
- cmake -D CMAKE_CXX_COMPILER=`which ${CXX_COMPILER}` -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" -DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS" ..
- sudo make install
- popd
script:
- mkdir build && cd build
- cmake -D CMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" -D CMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS" -D CMAKE_CXX_COMPILER="$CXX_COMPILER" -D CMAKE_C_COMPILER="$C_COMPILER" ..
- VERBOSE=1 make
- ./test_suite

View File

@ -33,3 +33,12 @@ Pierre Lamot, pierre.lamot@yahoo.fr
drewxa (github username), bo.ro.da@mail.ru
Adapter for Poco JSON parser
Jordan Bayles (jophba), jophba@chromium.org
JsonCpp owner
Matt Young (matty0ung), <mfsy@yahoo.com>
Adapter for Boost.JSON parser library
Pras Velagapudi (psigen), <psigen@gmail.com>
Adapter for yaml-cpp parser library

View File

@ -1,63 +1,119 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.10.0)
project(valijson)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
option(valijson_INSTALL_HEADERS "Install valijson headers." FALSE)
option(valijson_BUILD_EXAMPLES "Build valijson examples." FALSE)
option(valijson_BUILD_TESTS "Build valijson test suite." TRUE)
option(valijson_BUILD_TESTS "Build valijson test suite." FALSE)
option(valijson_EXCLUDE_BOOST "Exclude Boost when building test suite." FALSE)
option(valijson_USE_EXCEPTIONS "Use exceptions in valijson and included libs." TRUE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
option(valijson_USE_BOOST_REGEX "Use boost::regex instead of std::regex internally." FALSE)
mark_as_advanced(valijson_USE_BOOST_REGEX)
if(valijson_INSTALL_HEADERS)
install(DIRECTORY include/ DESTINATION include)
if(MSVC)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
else()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17)
if(!COMPILER_SUPPORTS_CXX11)
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
if(!COMPILER_SUPPORTS_CXX17)
message(WARNING "The compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Some features (including PocoJSON support) may be unavailable.")
endif()
# Suppress boost warnings that aren't relevant to the test suite
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_BIND_GLOBAL_PLACEHOLDERS")
if(COMPILER_SUPPORTS_CXX17)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall")
elseif(COMPILER_SUPPORTS_CXX11)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
endif()
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
endif()
add_library(valijson INTERFACE)
# create alias, so that user could always write target_link_libraries(... ValiJSON::valijson)
# despite of valijson target is imported or not
add_library(ValiJSON::valijson ALIAS valijson)
include(GNUInstallDirs)
target_include_directories(valijson INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
if(valijson_USE_EXCEPTIONS)
target_compile_definitions(valijson INTERFACE -DVALIJSON_USE_EXCEPTIONS=1)
endif()
if (valijson_USE_BOOST_REGEX)
target_compile_definitions(valijson INTERFACE -DVALIJSON_USE_BOOST_REGEX=1)
endif()
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS valijson
EXPORT valijsonConfig
DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(EXPORT valijsonConfig
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/valijson"
)
if(NOT valijson_BUILD_TESTS AND NOT valijson_BUILD_EXAMPLES)
return()
endif()
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
if(valijson_USE_EXCEPTIONS)
add_compile_definitions(VALIJSON_USE_EXCEPTIONS=1)
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
add_compile_definitions(_HAS_EXCEPTIONS=0)
add_compile_definitions(BOOST_NO_EXCEPTIONS)
add_compile_definitions(JSON_USE_EXCEPTION=0)
add_compile_definitions(VALIJSON_USE_EXCEPTIONS=0)
endif()
find_package(curlpp)
find_package(Poco OPTIONAL_COMPONENTS JSON)
find_package(Poco COMPONENTS Foundation JSON)
find_package(Qt5Core)
# jsoncpp library
add_library(jsoncpp
thirdparty/jsoncpp-0.9.4/src/lib_json/json_reader.cpp
thirdparty/jsoncpp-0.9.4/src/lib_json/json_value.cpp
thirdparty/jsoncpp-0.9.4/src/lib_json/json_writer.cpp
thirdparty/jsoncpp/src/lib_json/json_reader.cpp
thirdparty/jsoncpp/src/lib_json/json_value.cpp
thirdparty/jsoncpp/src/lib_json/json_writer.cpp
)
target_include_directories(jsoncpp SYSTEM PRIVATE thirdparty/jsoncpp-0.9.4/include)
set_target_properties(jsoncpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/jsoncpp-0.9.4)
target_include_directories(jsoncpp SYSTEM PRIVATE thirdparty/jsoncpp/include)
set_target_properties(jsoncpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/jsoncpp)
add_library(json11
thirdparty/json11-ec4e452/json11.cpp
thirdparty/json11/json11.cpp
)
target_include_directories(json11 SYSTEM PRIVATE thirdparty/json11-ec4e452)
set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11-ec4e452)
target_include_directories(json11 SYSTEM PRIVATE thirdparty/json11)
set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11)
# yaml-cpp library
file(GLOB yamlcpp_SOURCES "thirdparty/yaml-cpp/src/*.cpp")
add_library(yamlcpp ${yamlcpp_SOURCES})
target_include_directories(yamlcpp SYSTEM PRIVATE thirdparty/yamlcpp/include)
set_target_properties(yamlcpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/yamlcpp)
# Not all of these are required for examples build it doesn't hurt to include them
include_directories(include SYSTEM
thirdparty/gtest-1.7.0/include
thirdparty/json11-ec4e452
thirdparty/jsoncpp-0.9.4/include
thirdparty/rapidjson-1.1.0/include
thirdparty/picojson-1.3.0
thirdparty/nlohmann-json-3.1.2
)
thirdparty/googletest/include
thirdparty/json11
thirdparty/jsoncpp/include
thirdparty/rapidjson/include
thirdparty/picojson
thirdparty/nlohmann-json/include
thirdparty/yaml-cpp/include
)
if(valijson_BUILD_TESTS)
if(NOT valijson_EXCLUDE_BOOST)
@ -66,11 +122,15 @@ if(valijson_BUILD_TESTS)
# Build local gtest
set(gtest_force_shared_crt ON)
add_subdirectory(thirdparty/gtest-1.7.0)
option(BUILD_GMOCK FALSE)
option(INSTALL_GTEST FALSE)
add_subdirectory(thirdparty/googletest)
set(TEST_SOURCES
tests/test_adapter_comparison.cpp
tests/test_fetch_document_callback.cpp
tests/test_date_time_format.cpp
tests/test_fetch_absolute_uri_document_callback.cpp
tests/test_fetch_urn_document_callback.cpp
tests/test_json_pointer.cpp
tests/test_json11_adapter.cpp
tests/test_jsoncpp_adapter.cpp
@ -80,37 +140,95 @@ if(valijson_BUILD_TESTS)
tests/test_poly_constraint.cpp
tests/test_validation_errors.cpp
tests/test_validator.cpp
tests/test_validator_with_custom_regular_expression_engine.cpp
tests/test_yaml_cpp_adapter.cpp
tests/test_utf8_utils.cpp
)
# Unit tests executable
add_executable(test_suite ${TEST_SOURCES})
# Definition for using picojson
set_target_properties(test_suite PROPERTIES COMPILE_DEFINITIONS "PICOJSON_USE_INT64")
set(TEST_LIBS gtest gtest_main jsoncpp json11)
set(TEST_LIBS gtest gtest_main jsoncpp json11 yamlcpp)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
# Property Trees have been in Boost since 1.41.0, so we just assume they're present
list(APPEND TEST_SOURCES tests/test_property_tree_adapter.cpp)
add_definitions(-DBOOST_ALL_DYN_LINK)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_PROPERTY_TREE_ADAPTER")
# Boost.JSON was introduced in Boost 1.75.0, so we should check for its presence before
# including the unit tests for boost_json_adapter
include(CheckIncludeFileCXX)
set (CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS})
check_include_file_cxx("boost/json.hpp" BOOST_JSON_HPP_FOUND)
if(${BOOST_JSON_HPP_FOUND})
list(APPEND TEST_SOURCES tests/test_boost_json_adapter.cpp)
else()
message(WARNING
"boost/json.hpp not found; tests for boost_json_adapter will not be built. "
"If you have recently upgraded Boost to 1.75.0 or later, you may need to clear "
"your CMake cache for the header to be found.")
endif()
endif()
if(Poco_FOUND)
include_directories(${Poco_INCLUDE_DIRS})
list(APPEND TEST_SOURCES tests/test_poco_json_adapter.cpp)
list(APPEND TEST_LIBS ${Poco_Foundation_LIBRARIES} ${Poco_JSON_LIBRARIES})
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_POCO_ADAPTER")
if(COMPILER_SUPPORTS_CXX17)
list(APPEND TEST_SOURCES tests/test_poco_json_adapter.cpp)
list(APPEND TEST_LIBS
Poco::Foundation
Poco::JSON)
else()
message(WARNING "Poco found, but the compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Poco will be disabled in this build.")
endif()
endif()
if(Qt5Core_FOUND)
include_directories(${Qt5Core_INCLUDE_DIRS})
list(APPEND TEST_SOURCES tests/test_qtjson_adapter.cpp)
list(APPEND TEST_LIBS Qt5::Core)
list(APPEND TEST_SOURCES tests/test_qtjson_adapter.cpp)
endif()
# Unit tests executable
add_executable(test_suite ${TEST_SOURCES})
if(NOT valijson_USE_EXCEPTIONS)
if(MSVC)
if(CMAKE_CXX_FLAGS MATCHES "/EHsc ")
string(REPLACE "/EHsc" "/EHs-c-" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
target_compile_options(test_suite PUBLIC /EHs-c-)
endif()
else()
target_compile_options(test_suite PUBLIC -fno-exceptions)
endif()
endif()
if(NOT MSVC)
set_target_properties(test_suite PROPERTIES
COMPILE_FLAGS " -pedantic -Werror -Wshadow -Wunused"
CXX_STANDARD 17
)
endif()
if (MSVC)
target_compile_options(test_suite PRIVATE "/bigobj")
endif()
# Definition for using picojson
set_target_properties(test_suite PROPERTIES COMPILE_DEFINITIONS "PICOJSON_USE_INT64")
if(Boost_FOUND)
add_compile_definitions(BOOST_ALL_DYN_LINK)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER")
if(${BOOST_JSON_HPP_FOUND})
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_BOOST_JSON_ADAPTER")
endif()
endif()
if(Poco_FOUND)
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_POCO_ADAPTER")
endif()
if(Qt5Core_FOUND)
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_QT_ADAPTER")
endif()
@ -118,6 +236,7 @@ if(valijson_BUILD_TESTS)
endif()
if(valijson_BUILD_EXAMPLES)
find_package(curlpp)
include_directories(SYSTEM)
add_executable(custom_schema
@ -136,6 +255,10 @@ if(valijson_BUILD_EXAMPLES)
examples/array_iteration_template_fn.cpp
)
add_executable(check_schema
examples/check_schema.cpp
)
add_executable(object_iteration
examples/object_iteration.cpp
)
@ -144,20 +267,33 @@ if(valijson_BUILD_EXAMPLES)
examples/json_pointers.cpp
)
add_executable(picojson_format_test
examples/picojson_format_test.cpp
)
add_executable(remote_resolution_local_file
examples/remote_resolution_local_file.cpp
)
add_executable(valijson_nlohmann_bundled_test
examples/valijson_nlohmann_bundled_test.cpp
)
if(curlpp_FOUND)
include_directories(${curlpp_INCLUDE_DIR})
add_executable(remote_resolution
examples/remote_resolution.cpp
add_executable(remote_resolution_url
examples/remote_resolution_url.cpp
)
target_link_libraries(remote_resolution curl ${curlpp_LIBRARIES})
target_link_libraries(remote_resolution_url curl ${curlpp_LIBRARIES})
endif()
target_link_libraries(custom_schema ${Boost_LIBRARIES})
target_link_libraries(external_schema ${Boost_LIBRARIES})
target_link_libraries(array_iteration_basics jsoncpp)
target_link_libraries(array_iteration_template_fn jsoncpp)
target_link_libraries(check_schema jsoncpp)
target_link_libraries(object_iteration jsoncpp)
target_link_libraries(json_pointers)
endif()

View File

@ -194,7 +194,7 @@ QT_AUTOBRIEF = NO
# tag to YES if you prefer the old behavior instead.
#
# Note that setting this tag to YES also means that rational rose comments are
# not recognized any more.
# not recognized anymore.
# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
@ -268,7 +268,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
@ -494,7 +494,7 @@ INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# in case and if your file system supports case-sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# The default value is: system dependent.
@ -659,7 +659,7 @@ SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command command input-file, where command is the value of the
# popen()) the command input-file, where command is the value of the
# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
# by doxygen. Whatever the program writes to standard output is used as the file
# version. For an example see the documentation.
@ -1405,7 +1405,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@ -1417,7 +1417,7 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# http://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@ -1487,7 +1487,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing

View File

@ -1,5 +1,5 @@
Copyright (c) 2016, Tristan Penman
Copyright (c) 2016, Akamai Technolgies, Inc.
Copyright (c) 2016, Akamai Technologies, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without

405
README.md
View File

@ -1,206 +1,369 @@
# Valijson [![Build Status](https://travis-ci.org/tristanpenman/valijson.svg?branch=master)](https://travis-ci.org/tristanpenman/valijson) #
# Valijson
## Overview ##
Valijson is a header-only [JSON Schema](http://json-schema.org/) Validation library for C++11.
Valijson is a header-only [JSON Schema](http://json-schema.org/) validation library for _Modern C++_.
Valijson provides a simple validation API that allows you to load JSON Schemas, and validate documents loaded by one of several supported parser libraries.
## Project Goals ##
## Project Goals
The goal of this project is to support validation of all constraints available in JSON Schema v4, while being competitive with the performance of a hand-written schema validator.
The goal of this project is to support validation of all constraints available in JSON Schema v7, while being competitive with the performance of a hand-written schema validator.
## Usage ##
## Usage
Clone the repo, including submodules:
git clone --recurse-submodules git@github.com:tristanpenman/valijson.git
The following code snippets show how you might implement a simple validator using RapidJson as the underlying JSON Parser.
Include the necessary headers:
#include <rapidjson/document.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
```cpp
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
```
These are the classes that we'll be using:
using valijson::Schema;
using valijson::SchemaParser;
using valijson::Validator;
using valijson::adapters::RapidJsonAdapter;
```cpp
using valijson::Schema;
using valijson::SchemaParser;
using valijson::Validator;
using valijson::adapters::RapidJsonAdapter;
```
We are going to use RapidJSON to load the schema and the target document:
```cpp
// Load JSON document using RapidJSON with Valijson helper function
rapidjson::Document mySchemaDoc;
if (!valijson::utils::loadDocument("mySchema.json", mySchemaDoc)) {
throw std::runtime_error("Failed to load schema document");
}
// Load JSON document using RapidJSON with Valijson helper function
rapidjson::Document mySchemaDoc;
if (!valijson::utils::loadDocument("mySchema.json", mySchemaDoc)) {
throw std::runtime_error("Failed to load schema document");
}
// Parse JSON schema content using valijson
Schema mySchema;
SchemaParser parser;
RapidJsonAdapter mySchemaAdapter(mySchemaDoc);
parser.populateSchema(mySchemaAdapter, mySchema);
// Parse JSON schema content using valijson
Schema mySchema;
SchemaParser parser;
RapidJsonAdapter mySchemaAdapter(mySchemaDoc);
parser.populateSchema(mySchemaAdapter, mySchema);
```
Load a document to validate:
rapidjson::Document myTargetDoc;
if (!valijson::utils::loadDocument("myTarget.json", myTargetDoc)) {
throw std::runtime_error("Failed to load target document");
}
```cpp
rapidjson::Document myTargetDoc;
if (!valijson::utils::loadDocument("myTarget.json", myTargetDoc)) {
throw std::runtime_error("Failed to load target document");
}
```
Validate a document:
Validator validator;
RapidJsonAdapter myTargetAdapter(myTargetDoc);
if (!validator.validate(mySchema, myTargetAdapter, NULL)) {
std::runtime_error("Validation failed.");
}
```cpp
Validator validator;
RapidJsonAdapter myTargetAdapter(myTargetDoc);
if (!validator.validate(mySchema, myTargetAdapter, NULL)) {
throw std::runtime_error("Validation failed.");
}
```
Note that Valijson's `SchemaParser` and `Validator` classes expect you to pass in a `RapidJsonAdapter` rather than a `rapidjson::Document`. This is due to the fact that `SchemaParser` and `Validator` are template classes that can be used with any of the JSON parsers supported by Valijson.
## Memory Management ##
### Exceptions
By default, Valijson classes will not throw exceptions (e.g. when failing to parse a schema). To enable exceptions for these cases, `VALIJSON_USE_EXCEPTIONS` must be defined.
However note that `VALIJSON_USE_EXCEPTIONS` is defined as interface compile definition of the cmake target, and the definition populates all the targets linking Valijson with cmake.
### Strong vs Weak Types
Valijson has a notion of strong and weak typing. By default, strong typing is used. For example, the following will create a validator that uses strong typing:
```cpp
Validator validator;
```
This is equivalent to:
```cpp
Validator validator(Validator::kStrongTypes);
```
This validator will not attempt to cast between types to satisfy a schema. So the string `"23"` will not be parsed as a number.
Alternatively, weak typing can be used:
```cpp
Validator validator(Validator::kWeakTypes);
```
This will create a validator that will attempt to cast values to satisfy a schema. The original motivation for this was to support the Boost Property Tree library, which can parse JSON, but stores values as strings.
### Strict vs Permissive Date/Time Formats
JSON Schema supports validation of certain types using the `format` keyword. Supported formats include `time`, `date`, and `date-time`. When `date-time` is used, the input is validated according to [RFC 3999](./doc/specifications/rfc3339-timestamps.txt). By default, RFC 3999 requires that all date/time strings are unambiguous - i.e. are defined in terms of a local time zone. This is controlled by the `Z` suffix (for UTC) or a `+01:00` style modifier.
Valijson can be configured to allow ambiguous date/time strings.
```cpp
Validator validator(Validator::kStrongTypes, Validator::kPermissiveDateTime);
```
The default is strict date/time validation, which is equivalent to:
```cpp
Validator validator(Validator::kStrongTypes, Validator::kStrictDateTime);
```
## Regular Expression Engine
When enforcing a 'pattern' property, a regular expression engine is used. By default, the default regular expression (`DefaultRegexEngine`) uses `std::regex`.
Unfortunately, `std::regex` has no protection against catastrophic backtracking and the implementation in gcc is so suboptimal that it can easily lead to segmentation faults.
This behaviour can be customised by implementing a wrapper for alternative regular expression engine.
To do this, you must implement the following interface:
```cpp
struct MyRegexpEngine
{
MyRegexpEngine(const std::string& pattern)
{
// implementation specific
}
static bool search(const std::string& s, const MyRegexpEngine& r)
{
// implementation specific
}
};
```
Then to use it, you must define a customer validator type:
```cpp
using MyValidator = ValidatorT<MyRegexpEngine>;
```
Once you've done this, `MyValidator` can be used in place of the default `valijson::Validator` type.
Alternatively the library can be instructed to use `boost::regex` by specifying either `valijson_USE_BOOST_REGEX=TRUE` in CMake or defining `VALIJSON_USE_BOOST_REGEX=1` as a `#define` before including any valijson headers. Note that the library does not source `boost::regex` for you when specifying this option- it is assumed you have it already.
## Memory Management
Valijson has been designed to safely manage, and eventually free, the memory that is allocated while parsing a schema or validating a document. When working with an externally loaded schema (i.e. one that is populated using the `SchemaParser` class) you can rely on RAII semantics.
Things get more interesting when you build a schema using custom code, as illustrated in the following snippet. This code demonstrates how you would create a schema to verify that the value of a 'description' property (if present) is always a string:
```cpp
{
// Root schema object that manages memory allocated for
// constraints or sub-schemas
Schema schema;
{
// Root schema object that manages memory allocated for
// constraints or sub-schemas
Schema schema;
// Allocating memory for a sub-schema returns a const pointer
// which allows inspection but not mutation. This memory will be
// freed only when the root schema goes out of scope
const Subschema *subschema = schema.createSubschema();
// Allocating memory for a sub-schema returns a const pointer
// which allows inspection but not mutation. This memory will be
// freed only when the root schema goes out of scope
const Subschema *subschema = schema.createSubschema();
{ // Limited scope, for example purposes
{ // Limited scope, for example purposes
// Construct a constraint on the stack
TypeConstraint typeConstraint;
typeConstraint.addNamedType(TypeConstraint::kString);
// Construct a constraint on the stack
TypeConstraint typeConstraint;
typeConstraint.addNamedType(TypeConstraint::kString);
// Constraints are added to a sub-schema via the root schema,
// which will make a copy of the constraint
schema.addConstraintToSubschema(typeConstraint, subschema);
// Constraints are added to a sub-schema via the root schema,
// which will make a copy of the constraint
schema.addConstraintToSubschema(typeConstraint, subschema);
// Constraint on the stack goes out of scope, but the copy
// held by the root schema continues to exist
}
// Include subschema in properties constraint
PropertiesConstraint propertiesConstraint;
propertiesConstraint.addPropertySubschema("description", subschema);
// Add the properties constraint
schema.addConstraint(propertiesConstraint);
// Root schema goes out of scope and all allocated memory is freed
// Constraint on the stack goes out of scope, but the copy
// held by the root schema continues to exist
}
## JSON References ##
// Include subschema in properties constraint
PropertiesConstraint propertiesConstraint;
propertiesConstraint.addPropertySubschema("description", subschema);
// Add the properties constraint
schema.addConstraint(propertiesConstraint);
// Root schema goes out of scope and all allocated memory is freed
}
```
## JSON References
The library includes support for local JSON References. Remote JSON References are supported only when the appropriate callback functions are provided.
Valijson's JSON Reference implementation requires that two callback functions are required. The first is expected to return a pointer to a newly fetched document. Valijson takes ownership of this pointer. The second callback function is used to release ownership of that pointer back to the application. Typically, this would immediately free the memory that was allocated for the document.
## Test Suite ##
## Test Suite
Valijson's' test suite currently contains several hand-crafted tests and uses the standard [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) to test support for parts of the JSON Schema feature set that have been implemented.
Valijson's test suite currently contains several hand-crafted tests and uses the standard [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) to test support for parts of the JSON Schema feature set that have been implemented.
### cmake ###
### cmake
The examples and test suite can be built using cmake:
```bash
# Build examples and test suite
mkdir build
cd build
cmake .. -Dvalijson_BUILD_TESTS=ON -Dvalijson_BUILD_EXAMPLES=ON
make
# Build examples and test suite
mkdir build
cd build
cmake ..
make
# Run test suite (from build directory)
./test_suite
```
## How to add this library to your cmake target
# Run test suite (from build directory)
./test_suite
Valijson can be integrated either as git submodule or with `find_package()`.
### Xcode ###
### Valijson as git submodule
An Xcode project has also been provided, in the 'xcode' directory. Note that in order to run the test suite, you may need to configure the working directory for the 'test\_suite' scheme. It is recommended that you use the 'xcode' directory as the working directory.
Download this repository into your project
The Xcode project has been configured so that /usr/local/include is in the include path, and /usr/local/lib is in the library path. These are the locations that homebrew installed Boost on my test system.
```bash
git clone --recurse-submodules https://github.com/tristanpenman/valijson <project-path>/third-party/valijson
```
## Examples ##
If your project is a git repository
```bash
cd <project-path>
git submodule add https://github.com/tristanpenman/valijson third-party/valijson
```
Before the target add the module subdirectory in your CMakeLists.txt
```cmake
set(valijson_BUILD_TESTS OFF CACHE BOOL "don't build valijson tests")
add_subdirectory(third-party/valijson)
add_executable(your-executable ...)
target_link_libraries(your-executable ValiJSON::valijson)
```
### Install Valijson and import it
It is possible to install headers by running cmake's install command from the build tree. Once Valijson is installed, use it from other CMake projects using `find_package(Valijson)` in your CMakeLists.txt.
```bash
# Install Valijson
git clone --recurse-submodules --depth=1 git@github.com:tristanpenman/valijson.git
cd valijson
mkdir build
cd build
cmake ..
cmake --install .
```
```cmake
# Import installed valijson and link it to your executable
find_package(valijson REQUIRED)
add_executable(executable main.cpp)
target_link_libraries(executable valijson)
```
## Bundled Headers
An alternative way to include Valijson in your project is to generate a bundled header file, containing support for just one parser/adapter.
You can generate a header file using the `bundle.sh` script:
./bundle.sh nlohmann_json > valijson_nlohmann_bundled.hpp
This can then be used in your project with a single `#include`:
#include "valijson_nlohmann_bundled.hpp"
An example can be found in [examples/valijson\_nlohmann\_bundled\_test.cpp](examples/valijson_nlohmann_bundled_test.cpp).
Note: the bundled version of Valijson always embeds a compatibility header in place of `std::optional`.
## Examples
Building the Valijson Test Suite, using the instructions above, will also compile two example applications: `custom_schema` and `external_schema`.
`custom_schema` shows how you can hard-code a schema definition into an application, while `external_schema` builds on the example code above to show you how to validate and document and report on any validation errors.
## JSON Schema Support ##
## JSON Schema Support
Valijson supports most of the constraints defined in [Draft 3](http://tools.ietf.org/search/draft-zyp-json-schema-03) and [Draft 4](http://tools.ietf.org/search/draft-zyp-json-schema-04) of the JSON Schema specification.
Valijson supports most of the constraints defined in [Draft 7](https://json-schema.org/draft-07/json-schema-release-notes.html)
The exceptions for Draft 3 are:
The main exceptions are
- default
- format
- disallow
- extends
- format (optional)
- readonly
Support for JSON References is in development. It is mostly working, however some of the test cases added to [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) for v6/v7 are still failing.
The exceptions for Draft 4 are:
## JSON Inspector
- format (optional)
An example application based on Qt is also included under [inspector](./inspector). It can be used to experiment with JSON Schemas and target documents. JSON Inspector is a self-contained CMake project, so it must be built separately:
Support for JSON References is in development.
```bash
cd inspector
mkdir build
cd build
cmake ..
make
```
## Documentation ##
Schemas and target documents can be loaded from file or entered manually. Content is parsed dynamically, so you get rapid feedback.
Here is a screenshot of JSON Inspector in action:
![JSON Inspector in action](./doc/screenshots/inspector.png)
## Live Demo
A [web-based demo is available](https://letmaik.github.io/valijson-wasm), courtesy of [Maik Riechert](https://github.com/letmaik).
This demo uses Emscripten to compile Valijson and Nlohmann JSON (JSON for Modern C++) to WebAssembly. The source code can be found in [letmaik/valijson-wasm](https://github.com/letmaik/valijson-wasm) and is available under the MIT license.
![WebAssembly Demo](doc/screenshots/wasm.png)
## Documentation
Doxygen documentation can be built by running 'doxygen' from the project root directory. Generated documentation will be placed in 'doc/html'. Other relevant documentation such as schemas and specifications have been included in the 'doc' directory.
## Dependencies ##
## Dependencies
Valijson requires a compiler with C++11 support.
Valijson requires a compiler with full C++14 support.
When building the test suite, Boost 1.54, Qt 5 and Poco are optional dependencies.
When building the test suite, Boost 1.54, Qt 5 and Poco are optional dependencies.
## Supported Parsers ##
## Supported Parsers
Valijson supports JSON documents loaded using various JSON parser libraries. It has been tested against the following versions of these libraries:
- [boost::property_tree 1.54](http://www.boost.org/doc/libs/1_54_0/doc/html/boost_propertytree/synopsis.html)
- [boost::property\_tree 1.54](http://www.boost.org/doc/libs/1_54_0/doc/html/boost_propertytree/synopsis.html)
- [Boost.JSON 1.75](https://www.boost.org/doc/libs/1_75_0/libs/json/doc/html/index.html)
- [json11 (commit afcc8d0)](https://github.com/dropbox/json11/tree/afcc8d0d82b1ce2df587a7a0637d05ba493bf5e6)
- [jsoncpp 0.9.4](https://github.com/open-source-parsers/jsoncpp/archive/0.9.4.tar.gz)
- [jsoncpp 1.9.4](https://github.com/open-source-parsers/jsoncpp/archive/1.9.4.tar.gz)
- [nlohmann/json 1.1.0](https://github.com/nlohmann/json/archive/v1.1.0.tar.gz)
- [rapidjson 1.1.0](https://github.com/miloyip/rapidjson/releases/tag/v1.1.0)
- [rapidjson (commit 48fbd8c)](https://github.com/Tencent/rapidjson/tree/48fbd8cd202ca54031fe799db2ad44ffa8e77c13)
- [PicoJSON 1.3.0](https://github.com/kazuho/picojson/archive/v1.3.0.tar.gz)
- [Poco JSON 1.7.8](https://pocoproject.org/docs/Poco.JSON.html)
- [Poco JSON 1.14.0](https://pocoproject.org/docs/Poco.JSON.html)
- [Qt 5.8](http://doc.qt.io/qt-5/json.html)
Other versions of these libraries may work, but have not been tested. In particular, versions of JsonCpp going back to 0.5.0 should also work correctly, but versions from 1.0 onwards have not yet been tested.
Other versions of these libraries may work, but have not been tested. In particular, versions of jsoncpp going back to 0.5.0 should also work correctly.
## Package Managers ##
When compiling with older versions of Boost (< 1.76.0) you may see compiler warnings from the `boost::property_tree` headers. This has been addressed in version 1.76.0 of Boost.
## Package Managers
If you are using [vcpkg](https://github.com/Microsoft/vcpkg) on your project for external dependencies, then you can use the [valijson](https://github.com/microsoft/vcpkg/tree/master/ports/valijson) package. Please see the vcpkg project for any issues regarding the packaging.
## Test Suite Requirements ##
You can also use [conan](https://conan.io/) as a package manager to handle [valijson](https://conan.io/center/valijson/0.3/) package. Please see the [conan recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/valijson) for any issues regarding the packaging via conan.
Supported versions of these libraries have been included in the 'thirdparty' directory so as to support Valijson's examples and test suite.
## Test Suite Requirements
Supported versions of these libraries have been included in the 'thirdparty' directory so as to support Valijson's examples and test suite.
The exceptions to this are boost, Poco and Qt5, which due to their size must be installed to a location that CMake can find.
## Known Issues ##
## Known Issues
When using PicoJSON, it may be necessary to include the `picojson.h` before other headers to ensure that the appropriate macros have been enabled.
When building Valijson using CMake on Mac OS X, with Qt 5 installed via Homebrew, you may need to set `CMAKE_PREFIX_PATH` so that CMake can find your Qt installation, e.g:
mkdir build
cd build
cmake .. -DCMAKE_PREFIX_PATH=$(brew --prefix qt5)
make
## License ##
When building Valijson using CMake on macOS, with Qt 5 installed via Homebrew, you may need to set `CMAKE_PREFIX_PATH` so that CMake can find your Qt installation, e.g:
```bash
mkdir build
cd build
cmake .. -DCMAKE_PREFIX_PATH=$(brew --prefix qt5)
make
```
## License
Valijson is licensed under the Simplified BSD License.

107
bundle.sh Executable file
View File

@ -0,0 +1,107 @@
#!/usr/bin/env bash
#
# Exit codes:
#
# 0 - success
# 64 - usage
# 65 - invalid adapter
#
set -euo pipefail
adapter_path=include/valijson/adapters
utils_path=include/valijson/utils
# find all available adapters
pushd "${adapter_path}" > /dev/null
adapters=($(ls *.hpp))
popd > /dev/null
# remove _adapter.hpp suffix
adapters=("${adapters[@]/_adapter.hpp/}")
usage() {
echo 'Generates a single header file for a particular Valijson adapter'
echo
echo 'This makes it easier to embed Valijson in smaller projects, where integrating a'
echo 'third-party dependency is inconvenient or undesirable.'
echo
echo 'Output is written to STDOUT.'
echo
echo 'Usage:'
echo
echo ' ./bundle.sh <adapter-prefix>'
echo
echo 'Example usage:'
echo
echo ' ./bundle.sh nlohmann_json > valijson_nlohmann_bundled.hpp'
echo
echo 'Available adapters:'
echo
for adapter in "${adapters[@]}"; do
echo " - ${adapter}"
done
echo
exit 64
}
if [ $# -ne 1 ]; then
usage
fi
adapter_header=
for adapter in "${adapters[@]}"; do
if [ "${adapter}" == "$1" ]; then
adapter_header="${adapter_path}/${adapter}_adapter.hpp"
break
fi
done
if [ -z "${adapter_header}" ]; then
echo "Error: Adapter name is not valid."
exit 65
fi
common_headers=(
include/valijson/exceptions.hpp
include/compat/optional.hpp
include/valijson/internal/optional_bundled.hpp
include/valijson/internal/adapter.hpp
include/valijson/internal/basic_adapter.hpp
include/valijson/internal/custom_allocator.hpp
include/valijson/internal/debug.hpp
include/valijson/internal/frozen_value.hpp
include/valijson/internal/json_pointer.hpp
include/valijson/internal/json_reference.hpp
include/valijson/internal/regex.hpp
include/valijson/internal/uri.hpp
include/valijson/utils/file_utils.hpp
include/valijson/utils/utf8_utils.hpp
include/valijson/constraints/constraint.hpp
include/valijson/subschema.hpp
include/valijson/schema_cache.hpp
include/valijson/schema.hpp
include/valijson/constraints/constraint_visitor.hpp
include/valijson/constraints/basic_constraint.hpp
include/valijson/constraints/concrete_constraints.hpp
include/valijson/constraint_builder.hpp
include/valijson/schema_parser.hpp
include/valijson/adapters/std_string_adapter.hpp
include/valijson/validation_results.hpp
include/valijson/validation_visitor.hpp
include/valijson/validator.hpp)
# remove internal #includes
grep --no-filename -v "include <valijson/" ${common_headers[@]}
# std_string_adapter is always included
if [ "${adapter}" != "std_string" ]; then
grep --no-filename -v "include <valijson/" "${adapter_header}"
fi
# include file utils if available
utils_header="${utils_path}/${adapter}_utils.hpp"
if [ -f "${utils_header}" ]; then
grep --no-filename -v "include <valijson/" "${utils_header}"
fi

View File

@ -1,111 +0,0 @@
# - Try to find the required Poco components (default: Zip Net NetSSL Crypto Util XML CppParser Foundation)
#
# Once done this will define
# Poco_FOUND - System has the all required components.
# Poco_INCLUDE_DIRS - Include directory necessary for using the required components headers.
# Poco_LIBRARY_DIRS - Library directories necessary for using the required components.
# Poco_LIBRARIES - Link these to use the required components.
# Poco_DEFINITIONS - Compiler switches required for using the required components.
#
# For each of the components it will additionally set.
# - Foundation
# - CppParser
# - CppUnit
# - Net
# - NetSSL
# - Crypto
# - Util
# - XML
# - Zip
# - Data
# - PageCompiler
#
# the following variables will be defined
# Poco_<component>_FOUND - System has <component>
# Poco_<component>_INCLUDE_DIRS - Include directories necessary for using the <component> headers
# Poco_<component>_LIBRARY_DIRS - Library directories necessary for using the <component>
# Poco_<component>_LIBRARIES - Link these to use <component>
# Poco_<component>_DEFINITIONS - Compiler switches required for using <component>
# Poco_<component>_VERSION - The components version
include(CMakeHelpers REQUIRED)
include(CMakeFindExtensions REQUIRED)
# The default components to find
if (NOT Poco_FIND_COMPONENTS)
set(Poco_FIND_COMPONENTS Zip Net NetSSL Crypto Util XML CppParser Foundation)
endif()
# Set required variables
set(Poco_ROOT_DIR "" CACHE STRING "Where is the Poco root directory located?")
set(Poco_INCLUDE_DIR "${Poco_ROOT_DIR}" CACHE STRING "Where are the Poco headers (.h) located?")
set(Poco_LIBRARY_DIR "${Poco_ROOT_DIR}/lib" CACHE STRING "Where are the Poco libraries (.dll/.so) located?")
set(Poco_LINK_SHARED_LIBS FALSE CACHE BOOL "Link with shared Poco libraries (.dll/.so) instead of static ones (.lib/.a)")
#message("Poco_ROOT_DIR=${Poco_ROOT_DIR}")
#message("Poco_INCLUDE_DIR=${Poco_INCLUDE_DIR}")
#message("Poco_LIBRARY_DIR=${Poco_LIBRARY_DIR}")
# Check for cached results. If there are then skip the costly part.
set_module_notfound(Poco)
if (NOT Poco_FOUND)
# Set the library suffix for our build type
set(Poco_LIB_SUFFIX "")
if(WIN32 AND MSVC)
set(Poco_MULTI_CONFIGURATION TRUE)
# add_definitions(-DPOCO_NO_AUTOMATIC_LIBS)
# add_definitions(-DPOCO_NO_UNWINDOWS)
if(Poco_LINK_SHARED_LIBS)
add_definitions(-DPOCO_DLL)
else()
add_definitions(-DPOCO_STATIC)
if(BUILD_WITH_STATIC_CRT)
set(Poco_LIB_SUFFIX "mt")
else()
set(Poco_LIB_SUFFIX "md")
endif()
endif()
endif()
# Set search path suffixes
set(Poco_INCLUDE_SUFFIXES
CppUnit/include
CppParser/include
Data/include
Data/ODBC/include
Foundation/include
Crypto/include
Net/include
NetSSL_OpenSSL/include
PageCompiler/include
Util/include
JSON/include
XML/include
Zip/include
)
set(Poco_LIBRARY_SUFFIXES
Linux/i686
Linux/x86_64
)
# Check for all available components
find_component(Poco CppParser CppParser PocoCppParser${Poco_LIB_SUFFIX} Poco/CppParser/CppParser.h)
find_component(Poco CppUnit CppUnit PocoCppUnit${Poco_LIB_SUFFIX} Poco/CppUnit/CppUnit.h)
find_component(Poco Net Net PocoNet${Poco_LIB_SUFFIX} Poco/Net/Net.h)
find_component(Poco NetSSL NetSSL PocoNetSSL${Poco_LIB_SUFFIX} Poco/Net/NetSSL.h)
find_component(Poco Crypto Crypto PocoCrypto${Poco_LIB_SUFFIX} Poco/Crypto/Crypto.h)
find_component(Poco Util Util PocoUtil${Poco_LIB_SUFFIX} Poco/Util/Util.h)
find_component(Poco JSON JSON PocoJSON${Poco_LIB_SUFFIX} Poco/JSON/JSON.h)
find_component(Poco XML XML PocoXML${Poco_LIB_SUFFIX} Poco/XML/XML.h)
find_component(Poco Zip Zip PocoZip${Poco_LIB_SUFFIX} Poco/Zip/Zip.h)
find_component(Poco Data Data PocoData${Poco_LIB_SUFFIX} Poco/Data/Data.h)
find_component(Poco ODBC ODBC PocoDataODBC${Poco_LIB_SUFFIX} Poco/Data/ODBC/Connector.h)
find_component(Poco PageCompiler PageCompiler PocoPageCompiler${Poco_LIB_SUFFIX} Poco/PageCompiler/PageCompiler.h)
find_component(Poco Foundation Foundation PocoFoundation${Poco_LIB_SUFFIX} Poco/Foundation.h)
# Set Poco as found or not
# print_module_variables(Poco)
set_module_found(Poco)
endif ()

151
doc/schema/draft-07.json Normal file
View File

@ -0,0 +1,151 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://json-schema.org/draft-07/schema#",
"title": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": {"$ref": "#"}
},
"nonNegativeInteger": {
"type": "integer",
"minimum": 0
},
"nonNegativeIntegerDefault0": {
"allOf": [{"$ref": "#/definitions/nonNegativeInteger"}, {"default": 0}]
},
"simpleTypes": {
"enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
},
"stringArray": {
"type": "array",
"items": {"type": "string"},
"uniqueItems": true,
"default": []
}
},
"type": ["object", "boolean"],
"properties": {
"$id": {
"type": "string",
"format": "uri-reference"
},
"$schema": {
"type": "string",
"format": "uri"
},
"$ref": {
"type": "string",
"format": "uri-reference"
},
"$comment": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": true,
"readOnly": {
"type": "boolean",
"default": false
},
"examples": {
"type": "array",
"items": true
},
"multipleOf": {
"type": "number",
"exclusiveMinimum": 0
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "number"
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "number"
},
"maxLength": {"$ref": "#/definitions/nonNegativeInteger"},
"minLength": {"$ref": "#/definitions/nonNegativeIntegerDefault0"},
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {"$ref": "#"},
"items": {
"anyOf": [{"$ref": "#"}, {"$ref": "#/definitions/schemaArray"}],
"default": true
},
"maxItems": {"$ref": "#/definitions/nonNegativeInteger"},
"minItems": {"$ref": "#/definitions/nonNegativeIntegerDefault0"},
"uniqueItems": {
"type": "boolean",
"default": false
},
"contains": {"$ref": "#"},
"maxProperties": {"$ref": "#/definitions/nonNegativeInteger"},
"minProperties": {"$ref": "#/definitions/nonNegativeIntegerDefault0"},
"required": {"$ref": "#/definitions/stringArray"},
"additionalProperties": {"$ref": "#"},
"definitions": {
"type": "object",
"additionalProperties": {"$ref": "#"},
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": {"$ref": "#"},
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": {"$ref": "#"},
"propertyNames": {"format": "regex"},
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [{"$ref": "#"}, {"$ref": "#/definitions/stringArray"}]
}
},
"propertyNames": {"$ref": "#"},
"const": true,
"enum": {
"type": "array",
"items": true,
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{"$ref": "#/definitions/simpleTypes"},
{
"type": "array",
"items": {"$ref": "#/definitions/simpleTypes"},
"minItems": 1,
"uniqueItems": true
}
]
},
"format": {"type": "string"},
"contentMediaType": {"type": "string"},
"contentEncoding": {"type": "string"},
"if": {"$ref": "#"},
"then": {"$ref": "#"},
"else": {"$ref": "#"},
"allOf": {"$ref": "#/definitions/schemaArray"},
"anyOf": {"$ref": "#/definitions/schemaArray"},
"oneOf": {"$ref": "#/definitions/schemaArray"},
"not": {"$ref": "#"}
},
"default": true
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
doc/screenshots/wasm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@ -579,14 +579,14 @@ Internet-Draft JSON Schema Media Type November 2010
This attribute indicates if the value of the instance (if the
instance is a number) can not equal the number defined by the
"minimum" attribute. This is false by default, meaning the instance
value can be greater then or equal to the minimum value.
value can be greater than or equal to the minimum value.
5.12. exclusiveMaximum
This attribute indicates if the value of the instance (if the
instance is a number) can not equal the number defined by the
"maximum" attribute. This is false by default, meaning the instance
value can be less then or equal to the maximum value.
value can be less than or equal to the maximum value.
5.13. minItems

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,16 @@
/**
* @file
*
* @brief Demonstrates iteration over an array and type check functions
*
* @brief Demonstrates iteration over an array, and how to use type check functions
*/
#include <exception>
#include <iostream>
// jsoncpp
#include <json/json.h>
#include <valijson/adapters/jsoncpp_adapter.hpp>
#include <valijson/utils/jsoncpp_utils.hpp>
// RapidJSON
#include <rapidjson/document.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
@ -26,12 +22,81 @@ using std::runtime_error;
// The first example uses RapidJson to load a JSON document. If the document
// contains an array, this function will print any array values that have a
// valid string representation.
void usingRapidJson(const char *filename);
void usingRapidJson(const char *filename)
{
using valijson::adapters::RapidJsonAdapter;
rapidjson::Document document;
if (!valijson::utils::loadDocument(filename, document)) {
return;
}
const RapidJsonAdapter adapter(document);
if (!adapter.isArray()) {
cout << "Not an array." << endl;
return;
}
cout << "Array values:" << endl;
int index = 0;
const RapidJsonAdapter::Array array = adapter.asArray();
for (auto &&item : array) {
cout << " " << index++ << ": ";
// maybeString is a loose type check
if (item.maybeString()) {
// If a value may be a string, we are allowed to get a string
// representation of the value using asString
cout << item.asString();
}
cout << endl;
}
}
// The second example uses JsonCpp to perform the same task, but unlike the
// RapidJson example, we see how to use strict type checks and exception
// handling.
void usingJsonCpp(const char *filename);
void usingJsonCpp(const char *filename)
{
using valijson::adapters::JsonCppAdapter;
Json::Value value;
if (!valijson::utils::loadDocument(filename, value)) {
return;
}
const JsonCppAdapter adapter(value);
if (!adapter.isArray()) {
cout << "Not an array." << endl;
return;
}
cout << "Array values:" << endl;
int index = 0;
// If a value is not an array, then calling getArray will cause a runtime
// exception to be raised.
const JsonCppAdapter::Array array = adapter.getArray();
for (auto &&item : array) {
cout << " " << index++ << ": ";
// isString is another strict type check. Valijson uses the convention
// that strict type check functions are prefixed with 'is'.
if (!item.isString()) {
cout << "Not a string. ";
}
try {
// Also by convention, functions prefixed with 'get' will raise a
// runtime exception if the item is not of the correct type.
cout << item.getString() << endl;
} catch (const runtime_error &e) {
cout << "Caught exception: " << e.what() << endl;
}
}
}
int main(int argc, char **argv)
{
@ -53,80 +118,3 @@ int main(int argc, char **argv)
return 0;
}
void usingRapidJson(const char *filename)
{
using valijson::adapters::RapidJsonAdapter;
rapidjson::Document document;
if (!valijson::utils::loadDocument(filename, document)) {
return;
}
RapidJsonAdapter adapter(document);
if (!adapter.isArray()) {
cout << "Not an array." << endl;
return;
}
cout << "Array values:" << endl;
int index = 0;
// We support the old way of doing things...
const RapidJsonAdapter::Array array = adapter.asArray();
for (RapidJsonAdapter::Array::const_iterator itr = array.begin();
itr != array.end(); ++itr) {
cout << " " << index++ << ": ";
// Each element of the array is just another RapidJsonAdapter
const RapidJsonAdapter &value = *itr;
// maybeString is a loose type check
if (value.maybeString()) {
// If a value may be a string, we are allowed to get a string
// representation of the value using asString
cout << value.asString();
}
cout << endl;
}
}
void usingJsonCpp(const char *filename)
{
Json::Value value;
if (!valijson::utils::loadDocument(filename, value)) {
return;
}
valijson::adapters::JsonCppAdapter adapter(value);
// isArray is a strict type check
if (!adapter.isArray()) {
cout << "Not an array." << endl;
return;
}
cout << "Array values:" << endl;
int index = 0;
// If a value is not an array, then calling getArray will cause a runtime
// exception to be raised.
for (auto value : adapter.getArray()) {
cout << " " << index++ << ": ";
// isString is another strict type check. Valijson uses the convention
// that strict type check functions are prefixed with 'is'.
if (!value.isString()) {
cout << "Not a string. ";
}
try {
// Also by convention, functions prefixed with 'get' will raise a
// runtime exception if the value is not of the correct type.
cout << value.getString() << endl;
} catch (runtime_error &e) {
cout << "Caught exception: " << e.what() << endl;
}
}
}

View File

@ -0,0 +1,107 @@
#include <boost/json/src.hpp>
#include <valijson/adapters/boost_json_adapter.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
#include <valijson/validation_results.hpp>
#include <iostream>
using namespace std::string_literals;
namespace json = boost::json;
const auto schemaJson = R"({
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a product",
"type": "integer"
},
"name": {
"description": "Name of the product",
"type": "string"
},
"price": {
"type": "number",
"minimum": 0
},
"tags": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
}
},
"required": ["id", "name", "price" ]
})"s;
const auto targetJson = R"({
"id": 123,
"name": "Test"
})"s;
int main()
{
boost::system::error_code ec;
auto schemaDoc = json::parse(schemaJson, ec);
if (ec) {
std::cerr << "Error parsing schema json: " << ec.message() << std::endl;
return 1;
}
auto obj = schemaDoc.as_object();
auto iter = obj.find("$schema");
if (iter == obj.cend()) {
std::cerr << "Error finding key $schema" << std::endl;
return 2;
}
iter = obj.find("$ref");
if (iter != obj.cend()) {
std::cerr << "Invalid iterator for nonexistent key $ref" << std::endl;
return 3;
}
valijson::Schema schema;
valijson::SchemaParser schemaParser;
// Won't compile because the necessary constructor has been deleted
// valijson::adapters::BoostJsonAdapter schemaAdapter(obj);
valijson::adapters::BoostJsonAdapter schemaAdapter(schemaDoc);
std::cerr << "Populating schema..." << std::endl;
schemaParser.populateSchema(schemaAdapter, schema);
auto targetDoc = json::parse(targetJson, ec);
if (ec) {
std::cerr << "Error parsing target json: " << ec.message() << std::endl;
return 1;
}
valijson::Validator validator;
valijson::ValidationResults results;
valijson::adapters::BoostJsonAdapter targetAdapter(targetDoc);
if (validator.validate(schema, targetAdapter, &results)) {
std::cerr << "Validation succeeded." << std::endl;
return 0;
}
std::cerr << "Validation failed." << std::endl;
valijson::ValidationResults::Error error;
unsigned int errorNum = 1;
while (results.popError(error)) {
std::cerr << "Error #" << errorNum << std::endl;
std::cerr << " ";
for (const std::string &contextElement : error.context) {
std::cerr << contextElement << " ";
}
std::cerr << std::endl;
std::cerr << " - " << error.description << std::endl;
++errorNum;
}
return 1;
}

48
examples/check_schema.cpp Normal file
View File

@ -0,0 +1,48 @@
/**
* @file
*
* @brief Loads a schema then exits. Exit code will be 0 if the schema is
* valid, and 1 otherwise. This example uses jsoncpp to parse the
* schema document.
*/
#include <iostream>
#include <valijson/adapters/jsoncpp_adapter.hpp>
#include <valijson/utils/jsoncpp_utils.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
using std::cerr;
using std::endl;
using valijson::Schema;
using valijson::SchemaParser;
using valijson::adapters::JsonCppAdapter;
int main(int argc, char *argv[])
{
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <schema document>" << endl;
return 1;
}
// Load the document containing the schema
Json::Value schemaDocument;
if (!valijson::utils::loadDocument(argv[1], schemaDocument)) {
cerr << "Failed to load schema document." << endl;
return 1;
}
Schema schema;
SchemaParser parser;
JsonCppAdapter adapter(schemaDocument);
try {
parser.populateSchema(adapter, schema);
} catch (std::exception &e) {
cerr << "Failed to parse schema: " << e.what() << endl;
return 1;
}
return 0;
}

View File

@ -59,8 +59,6 @@
#include <iostream>
#include <stdexcept>
#include <rapidjson/document.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/constraints/concrete_constraints.hpp>
#include <valijson/utils/rapidjson_utils.hpp>

View File

@ -5,12 +5,9 @@
*
*/
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <rapidjson/document.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#include <valijson/schema.hpp>
@ -60,7 +57,7 @@ int main(int argc, char *argv[])
}
// Perform validation
Validator validator(Validator::kWeakTypes);
Validator validator(Validator::kStrongTypes);
ValidationResults results;
RapidJsonAdapter targetDocumentAdapter(targetDocument);
if (!validator.validate(schema, targetDocumentAdapter, &results)) {
@ -68,13 +65,13 @@ int main(int argc, char *argv[])
ValidationResults::Error error;
unsigned int errorNum = 1;
while (results.popError(error)) {
std::string context;
std::vector<std::string>::iterator itr = error.context.begin();
for (; itr != error.context.end(); itr++) {
context += *itr;
}
cerr << "Error #" << errorNum << std::endl
<< " context: " << context << endl
<< " desc: " << error.description << endl;

View File

@ -7,8 +7,6 @@
#include <iostream>
#include <rapidjson/document.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/internal/json_pointer.hpp>
#include <valijson/internal/json_reference.hpp>

View File

@ -0,0 +1,112 @@
#include <iostream>
#include <string>
#define PICOJSON_USE_INT64
#include "picojson.h"
#include "valijson/adapters/picojson_adapter.hpp"
#include "valijson/validation_results.hpp"
#include "valijson/schema_parser.hpp"
#include "valijson/validator.hpp"
constexpr auto schemaStr = R"JSON({
"additionalItems": false,
"items": [
{
"format": "date-time",
"type": "string"
},
{
"format": "date-time",
"type": "string"
}
],
"maxItems": 2,
"minItems": 2,
"type": "array"
})JSON";
constexpr auto validStr = R"JSON([
"2023-07-18T14:46:22Z",
"2023-07-18T14:46:22Z"
])JSON";
constexpr auto invalidStrs = R"JSON([
["um 12", "um 12"],
["2023-07-18T14:46:22Z"],
["2023-07-18T14:46:22Z", "2023-07-18T14:46:22Z", "2023-07-18T14:46:22Z", "2023-07-18T14:46:22Z"]
])JSON";
picojson::value Parse(std::string serialized, picojson::value def)
{
picojson::value v;
auto first = serialized.data();
auto last = first + serialized.size();
auto err = picojson::parse(v, first, last);
if (!err.empty()) {
return def;
}
return v;
}
int main(int argc, char **argv)
{
auto validatorSchema = std::make_shared<valijson::Schema>();
{
auto schemaJson = Parse(schemaStr, picojson::value{});
auto schemaAdapter = valijson::adapters::PicoJsonAdapter(schemaJson);
valijson::SchemaParser parser;
parser.populateSchema(schemaAdapter, *validatorSchema);
std::cout << "Schema:" << std::endl << schemaStr << std::endl << std::endl;;
}
{
// valid
auto targetJson = Parse(validStr, picojson::value{});
auto targetAdapter = valijson::adapters::PicoJsonAdapter(targetJson);
std::cout << "Valid Target:" << std::endl << validStr << std::endl << std::endl;
valijson::ValidationResults results;
auto validator = valijson::Validator();
auto isValid = validator.validate(
*validatorSchema,
targetAdapter,
&results);
std::cout << "Is valid: " << (isValid ? "YES" : "NO") << std::endl << std::endl;;
}
{
// invalid
auto targetJsonArray = Parse(invalidStrs, picojson::value{});
std::cout << "Invalid Targets:" << std::endl << invalidStrs << std::endl << std::endl;
for (auto &&testCase : targetJsonArray.get<picojson::array>()) {
auto targetAdapter = valijson::adapters::PicoJsonAdapter(testCase);
valijson::ValidationResults results;
auto validator = valijson::Validator();
auto isValid = validator.validate(
*validatorSchema,
targetAdapter,
&results);
std::cout << "Is valid: " << (isValid ? "YES" : "NO") << std::endl << std::endl;
valijson::ValidationResults::Error error;
unsigned int errorNum = 1;
while (results.popError(error)) {
std::cerr << "Error #" << errorNum << std::endl;
std::cerr << " ";
for (const std::string &contextElement : error.context) {
std::cerr << contextElement << " ";
}
std::cerr << std::endl;
std::cerr << " - " << error.description << std::endl << std::endl;
++errorNum;
}
}
}
}

View File

@ -0,0 +1,102 @@
/**
* @file
*
* @brief Demonstrates resolution of remote JSON references using cURLpp
*
*/
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validation_results.hpp>
#include <valijson/validator.hpp>
using std::cerr;
using std::cout;
using std::endl;
using valijson::Schema;
using valijson::SchemaParser;
using valijson::Validator;
using valijson::ValidationResults;
using valijson::adapters::RapidJsonAdapter;
const rapidjson::Document * fetchDocument(const std::string &uri)
{
cout << "Fetching " << uri << "..." << endl;
rapidjson::Document *fetchedRoot = new rapidjson::Document();
if (!valijson::utils::loadDocument(uri.substr(0, 7) == "file://" ? uri.substr(7, uri.size()) : uri, *fetchedRoot)) {
return nullptr;
}
return fetchedRoot;
}
void freeDocument(const rapidjson::Document *adapter)
{
delete adapter;
}
int main(int argc, char *argv[])
{
if (argc != 3) {
cerr << "Usage: " << argv[0] << " <schema document> <test/target document>" << endl;
return 1;
}
// Load the document containing the schema
rapidjson::Document schemaDocument;
if (!valijson::utils::loadDocument(argv[1], schemaDocument)) {
cerr << "Failed to load schema document." << endl;
return 1;
}
// Load the document that is to be validated
rapidjson::Document targetDocument;
if (!valijson::utils::loadDocument(argv[2], targetDocument)) {
cerr << "Failed to load target document." << endl;
return 1;
}
// Parse the json schema into an internal schema format
Schema schema;
SchemaParser parser;
RapidJsonAdapter schemaDocumentAdapter(schemaDocument);
try {
parser.populateSchema(schemaDocumentAdapter, schema, fetchDocument, freeDocument);
} catch (std::exception &e) {
cerr << "Failed to parse schema: " << e.what() << endl;
return 1;
}
// Perform validation
Validator validator(Validator::kWeakTypes);
ValidationResults results;
RapidJsonAdapter targetDocumentAdapter(targetDocument);
if (!validator.validate(schema, targetDocumentAdapter, &results)) {
std::cerr << "Validation failed." << endl;
ValidationResults::Error error;
unsigned int errorNum = 1;
while (results.popError(error)) {
std::string context;
std::vector<std::string>::iterator itr = error.context.begin();
for (; itr != error.context.end(); itr++) {
context += *itr;
}
cerr << "Error #" << errorNum << std::endl
<< " context: " << context << endl
<< " desc: " << error.description << endl;
++errorNum;
}
return 1;
}
return 0;
}

View File

@ -12,8 +12,6 @@
#include <curlpp/cURLpp.hpp>
#include <curlpp/Options.hpp>
#include <rapidjson/document.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#include <valijson/schema.hpp>
@ -88,13 +86,13 @@ int main(int argc, char *argv[])
ValidationResults::Error error;
unsigned int errorNum = 1;
while (results.popError(error)) {
std::string context;
std::vector<std::string>::iterator itr = error.context.begin();
for (; itr != error.context.end(); itr++) {
context += *itr;
}
cerr << "Error #" << errorNum << std::endl
<< " context: " << context << endl
<< " desc: " << error.description << endl;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
#include <nlohmann/json.hpp>
#include "valijson_nlohmann_bundled.hpp"
using namespace std;
using namespace valijson;
using namespace valijson::adapters;
int main(int argc, char *argv[])
{
if (argc != 3) {
cerr << "Usage: " << argv[0] << " <schema document> <test/target document>" << endl;
return 1;
}
// Load the document containing the schema
nlohmann::json schemaDocument;
if (!valijson::utils::loadDocument(argv[1], schemaDocument)) {
cerr << "Failed to load schema document." << endl;
return 1;
}
// Load the document that is to be validated
nlohmann::json targetDocument;
if (!valijson::utils::loadDocument(argv[2], targetDocument)) {
cerr << "Failed to load target document." << endl;
return 1;
}
// Parse the json schema into an internal schema format
Schema schema;
SchemaParser parser;
NlohmannJsonAdapter schemaDocumentAdapter(schemaDocument);
try {
parser.populateSchema(schemaDocumentAdapter, schema);
} catch (std::exception &e) {
cerr << "Failed to parse schema: " << e.what() << endl;
return 1;
}
// Perform validation
Validator validator(Validator::kStrongTypes);
ValidationResults results;
NlohmannJsonAdapter targetDocumentAdapter(targetDocument);
if (!validator.validate(schema, targetDocumentAdapter, &results)) {
std::cerr << "Validation failed." << endl;
ValidationResults::Error error;
unsigned int errorNum = 1;
while (results.popError(error)) {
std::string context;
std::vector<std::string>::iterator itr = error.context.begin();
for (; itr != error.context.end(); itr++) {
context += *itr;
}
cerr << "Error #" << errorNum << std::endl
<< " context: " << context << endl
<< " desc: " << error.description << endl;
++errorNum;
}
return 1;
}
return 0;
}

View File

@ -7,8 +7,8 @@
// The idea and interface is based on Boost.Optional library
// authored by Fernando Luis Cacciola Carballal
# ifndef ___OPTIONAL_HPP___
# define ___OPTIONAL_HPP___
# ifndef OPTIONAL_HPP
# define OPTIONAL_HPP
# include <utility>
# include <type_traits>
@ -17,6 +17,7 @@
# include <functional>
# include <string>
# include <stdexcept>
# include <valijson/exceptions.hpp>
# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false
@ -44,11 +45,11 @@
#
# if defined __clang_major__
# if (__clang_major__ == 3 && __clang_minor__ >= 5)
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_
# elif (__clang_major__ > 3)
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_
# endif
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_
# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2)
# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_
@ -84,7 +85,7 @@
# define OPTIONAL_CONSTEXPR_INIT_LIST
# endif
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L)
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_ && (defined __cplusplus) && (__cplusplus != 201103L)
# define OPTIONAL_HAS_MOVE_ACCESSORS 1
# else
# define OPTIONAL_HAS_MOVE_ACCESSORS 0
@ -269,7 +270,7 @@ namespace std{
unsigned char dummy_;
T value_;
constexpr storage_t( trivial_init_t ) noexcept : dummy_() {};
constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}
template <class... Args>
constexpr storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
@ -284,7 +285,7 @@ namespace std{
unsigned char dummy_;
T value_;
constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {};
constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}
template <class... Args>
constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward<Args>(args)...) {}
@ -299,7 +300,7 @@ namespace std{
bool init_;
storage_t<T> storage_;
constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {};
constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}
explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {}
@ -322,7 +323,7 @@ namespace std{
bool init_;
constexpr_storage_t<T> storage_;
constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {};
constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}
explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {}
@ -397,8 +398,8 @@ namespace std{
typedef T value_type;
// 20.5.5.1, constructors
constexpr optional() noexcept : OptionalBase<T>() {};
constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {};
constexpr optional() noexcept : OptionalBase<T>() {}
constexpr optional(nullopt_t) noexcept : OptionalBase<T>() {}
optional(const optional& rhs)
: OptionalBase<T>()
@ -523,15 +524,15 @@ namespace std{
}
constexpr T const& value() const& {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
}
OPTIONAL_MUTABLE_CONSTEXPR T& value() & {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
}
OPTIONAL_MUTABLE_CONSTEXPR T&& value() && {
if (!initialized()) throw bad_optional_access("bad optional access");
if (!initialized()) valijson::throwRuntimeError("bad optional access");
return std::move(contained_val());
}
@ -552,11 +553,11 @@ namespace std{
}
constexpr T const& value() const {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
}
T& value() {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
}
# endif
@ -685,7 +686,7 @@ namespace std{
}
constexpr T& value() const {
return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref);
return ref ? *ref : (valijson::throwRuntimeError("bad optional access"), *ref);
}
explicit constexpr operator bool() const noexcept {
@ -1039,4 +1040,4 @@ namespace std
# undef TR2_OPTIONAL_REQUIRES
# undef TR2_OPTIONAL_ASSERTED_EXPRESSION
# endif //___OPTIONAL_HPP___
# endif //OPTIONAL_HPP

View File

@ -0,0 +1,724 @@
/**
* @file
*
* @brief Adapter implementation for the Boost.JSON library.
*
* Include this file in your program to enable support for boost Boost.JSONs.
*
* This file defines the following classes (not in this order):
* - BoostJsonAdapter
* - BoostJsonArray
* - BoostJsonArrayValueIterator
* - BoostJsonFrozenValue
* - BoostJsonObject
* - BoostJsonObjectMember
* - BoostJsonObjectMemberIterator
* - BoostJsonValue
*
* Due to the dependencies that exist between these classes, the ordering of
* class declarations and definitions may be a bit confusing. The best place to
* start is BoostJsonAdapter. This class definition is actually very small,
* since most of the functionality is inherited from the BasicAdapter class.
* Most of the classes in this file are provided as template arguments to the
* inherited BasicAdapter class.
*/
#pragma once
#include <string>
#include <boost/json.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
namespace valijson {
namespace adapters {
class BoostJsonAdapter;
class BoostJsonArrayValueIterator;
class BoostJsonObjectMemberIterator;
typedef std::pair<std::string, BoostJsonAdapter> BoostJsonObjectMember;
/**
* @brief Light weight wrapper for a Boost.JSON that contains
* array-like data.
*
* This class is light weight wrapper for a Boost.JSON array. It provides a
* minimum set of container functions and typedefs that allow it to be used as
* an iterable container.
*
* An instance of this class contains a single reference to the underlying
* Boost.JSON value, assumed to be an array, so there is very little overhead
* associated with copy construction and passing by value.
*/
class BoostJsonArray
{
public:
typedef BoostJsonArrayValueIterator const_iterator;
typedef BoostJsonArrayValueIterator iterator;
/// Construct a BoostJsonArray referencing an empty array.
BoostJsonArray()
: m_value(emptyArray()) { }
/**
* @brief Construct BoostJsonArray referencing a specific Boost.JSON
* value.
*
* @param value reference to a Boost.JSON value
*
* Note that this constructor will throw an exception if the value is not
* an array.
*/
explicit BoostJsonArray(const boost::json::value &value)
: m_value(value.as_array())
{
// boost::json::value::as_array() will already have thrown an exception
// if the underlying value is not an array
}
/**
* @brief Return an iterator for the first element of the array.
*
* The iterator return by this function is effectively the iterator
* returned by the underlying Boost.JSON implementation.
*/
BoostJsonArrayValueIterator begin() const;
/**
* @brief Return an iterator for one-past the last element of the array.
*
* The iterator return by this function is effectively the iterator
* returned by the underlying Boost.JSON implementation.
*/
BoostJsonArrayValueIterator end() const;
/// Return the number of elements in the array
size_t size() const
{
return m_value.size();
}
private:
/**
* @brief Return a reference to a Boost.JSON value that is an empty array.
*
* Note that the value returned by this function is a singleton.
*/
static const boost::json::array & emptyArray()
{
static const boost::json::array array;
return array;
}
/// Reference to the contained value
const boost::json::array &m_value;
};
/**
* @brief Light weight wrapper for a Boost.JSON object.
*
* This class is light weight wrapper for a Boost.JSON. It provides a
* minimum set of container functions and typedefs that allow it to be used as
* an iterable container.
*
* An instance of this class contains a single reference to the underlying
* Boost.JSON value, assumed to be an object, so there is very little overhead
* associated with copy construction and passing by value.
*/
class BoostJsonObject
{
public:
typedef BoostJsonObjectMemberIterator const_iterator;
typedef BoostJsonObjectMemberIterator iterator;
/// Construct a BoostJsonObject referencing an empty object singleton.
BoostJsonObject()
: m_value(emptyObject()) { }
/**
* @brief Construct a BoostJsonObject referencing a specific Boost.JSON
* value.
*
* @param value reference to a Boost.JSON value
*
* Note that this constructor will throw an exception if the value is not
* an object.
*/
BoostJsonObject(const boost::json::value &value)
: m_value(value.as_object())
{
// boost::json::value::as_object() will already have thrown an exception
// if the underlying value is not an array
}
/**
* @brief Return an iterator for this first object member
*
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying Boost.JSON
* implementation.
*/
BoostJsonObjectMemberIterator begin() const;
/**
* @brief Return an iterator for an invalid object member that indicates
* the end of the collection.
*
* The iterator return by this function is effectively a wrapper around
* the pointer value returned by the underlying Boost.JSON
* implementation.
*/
BoostJsonObjectMemberIterator end() const;
/**
* @brief Return an iterator for the object member with the specified
* property name.
*
* If an object member with the specified name does not exist, the iterator
* returned will be the same as the iterator returned by the end() function.
*
* @param property property name to search for
*/
BoostJsonObjectMemberIterator find(const std::string &property) const;
/// Returns the number of members belonging to this object.
size_t size() const
{
return m_value.size();
}
private:
/**
* @brief Return a reference to an empty Boost.JSON.
*
* Note that the value returned by this function is a singleton.
*/
static const boost::json::object & emptyObject()
{
static const boost::json::object object;
return object;
}
/// Reference to the contained object
const boost::json::object &m_value;
};
/**
* @brief Stores an independent copy of a Boost.JSON value.
*
* This class allows a Boost.JSON value to be stored independent of its
* original 'document'. Boost.JSON makes this easy to do, as it does
* not require you to use custom memory management.
*
* @see FrozenValue
*/
class BoostJsonFrozenValue: public FrozenValue
{
public:
/**
* @brief Make a copy of a Boost.JSON value
*
* @param source the Boost.JSON value to be copied
*/
explicit BoostJsonFrozenValue(const boost::json::value &source)
: m_value(source) { }
FrozenValue * clone() const override
{
return new BoostJsonFrozenValue(m_value);
}
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored Boost.JSON value
boost::json::value m_value;
};
/**
* @brief Light weight wrapper for a Boost.JSON value.
*
* This class is passed as an argument to the BasicAdapter template class,
* and is used to provide access to a Boost.JSON value. This class is
* responsible for the mechanics of actually reading a Boost.JSON value, whereas
* BasicAdapter class is responsible for the semantics of type comparisons
* and conversions.
*
* The functions that need to be provided by this class are defined implicitly
* by the implementation of the BasicAdapter template class.
*
* @see BasicAdapter
*/
class BoostJsonValue
{
public:
/// Construct a wrapper for the empty object singleton
BoostJsonValue()
: m_value(emptyObject()) { }
/**
* @brief Construct a BoostJsonValue for a specific Boost.JSON value
*/
BoostJsonValue(const boost::json::value &value)
: m_value(value) { }
/**
* @brief Create a new BoostJsonFrozenValue instance that contains the
* value referenced by this BoostJsonValue instance.
*
* @returns pointer to a new BoostJsonFrozenValue instance, belonging to
* the caller.
*/
FrozenValue* freeze() const
{
return new BoostJsonFrozenValue(m_value);
}
/**
* @brief Return an instance of BoostJsonArrayAdapter.
*
* If the referenced Boost.JSON value is an array, this function will
* return a std::optional containing a BoostJsonArray instance
* referencing the array.
*
* Otherwise it will return an empty optional.
*/
opt::optional<BoostJsonArray> getArrayOptional() const
{
if (m_value.is_array()) {
return opt::make_optional(BoostJsonArray(m_value));
}
return {};
}
/**
* @brief Retrieve the number of elements in the array
*
* If the referenced Boost.JSON value is an array, this function will
* retrieve the number of elements in the array and store it in the output
* variable provided.
*
* @param result reference to size_t to set with result
*
* @returns true if the number of elements was retrieved, false otherwise.
*/
bool getArraySize(size_t &result) const
{
if (m_value.is_array()) {
result = m_value.get_array().size();
return true;
}
return false;
}
bool getBool(bool &result) const
{
if (m_value.is_bool()) {
result = m_value.get_bool();
return true;
}
return false;
}
bool getDouble(double &result) const
{
if (m_value.is_double()) {
result = m_value.get_double();
return true;
}
return false;
}
bool getInteger(int64_t &result) const
{
if(m_value.is_int64()) {
result = m_value.get_int64();
return true;
}
return false;
}
/**
* @brief Optionally return a BoostJsonObject instance.
*
* If the referenced Boost.JSON is an object, this function will return a
* std::optional containing a BoostJsonObject instance referencing the
* object.
*
* Otherwise it will return an empty optional.
*/
opt::optional<BoostJsonObject> getObjectOptional() const
{
if (m_value.is_object()) {
return opt::make_optional(BoostJsonObject(m_value));
}
#if __cplusplus >= 201703
// std::nullopt is available since C++17
return std::nullopt;
#else
// This is the older way to achieve the same result, but potentially at the cost of a compiler warning
return {};
#endif
}
/**
* @brief Retrieve the number of members in the object
*
* If the referenced Boost.JSON value is an object, this function will
* retrieve the number of members in the object and store it in the output
* variable provided.
*
* @param result reference to size_t to set with result
*
* @returns true if the number of members was retrieved, false otherwise.
*/
bool getObjectSize(size_t &result) const
{
if (m_value.is_object()) {
result = m_value.get_object().size();
return true;
}
return false;
}
bool getString(std::string &result) const
{
if (m_value.is_string()) {
result = m_value.get_string().c_str();
return true;
}
return false;
}
static bool hasStrictTypes()
{
return true;
}
bool isArray() const
{
return m_value.is_array();
}
bool isBool() const
{
return m_value.is_bool();
}
bool isDouble() const
{
return m_value.is_double();
}
bool isInteger() const
{
return m_value.is_int64();
}
bool isNull() const
{
return m_value.is_null();
}
bool isNumber() const
{
return m_value.is_number();
}
bool isObject() const
{
return m_value.is_object();
}
bool isString() const
{
return m_value.is_string();
}
private:
/// Return a reference to an empty object singleton
static const boost::json::value & emptyObject()
{
static const boost::json::value object;
return object;
}
/// Reference to the contained Boost.JSON value.
const boost::json::value &m_value;
};
/**
* @brief An implementation of the Adapter interface supporting the Boost.JSON
* library.
*
* This class is defined in terms of the BasicAdapter template class, which
* helps to ensure that all of the Adapter implementations behave consistently.
*
* @see Adapter
* @see BasicAdapter
*/
class BoostJsonAdapter:
public BasicAdapter<BoostJsonAdapter,
BoostJsonArray,
BoostJsonObjectMember,
BoostJsonObject,
BoostJsonValue>
{
public:
// deleted to avoid holding references to temporaries
BoostJsonAdapter(boost::json::array &) = delete;
BoostJsonAdapter(boost::json::object &) = delete;
/// Construct a BoostJsonAdapter that contains an empty object
BoostJsonAdapter()
: BasicAdapter() { }
/// Construct a BoostJsonAdapter using a specific Boost.JSON value
explicit BoostJsonAdapter(const boost::json::value &value)
: BasicAdapter(value) { }
};
/**
* @brief Class for iterating over values held in a JSON array.
*
* This class provides a JSON array iterator that dereferences as an instance of
* BoostJsonAdapter representing a value stored in the array.
*
* @see BoostJsonArray
*/
class BoostJsonArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = BoostJsonAdapter;
using difference_type = BoostJsonAdapter;
using pointer = BoostJsonAdapter*;
using reference = BoostJsonAdapter&;
/**
* @brief Construct a new BoostJsonArrayValueIterator using an existing
* Boost.JSON iterator.
*
* @param itr Boost.JSON iterator to store
*/
BoostJsonArrayValueIterator(
const boost::json::array::const_iterator itr)
: m_itr(itr) { }
/// Returns a BoostJsonAdapter that contains the value of the current
/// element.
BoostJsonAdapter operator*() const
{
return BoostJsonAdapter(*m_itr);
}
DerefProxy<BoostJsonAdapter> operator->() const
{
return DerefProxy<BoostJsonAdapter>(**this);
}
/**
* @brief Compare this iterator against another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other iterator to compare against
*
* @returns true if the iterators are equal, false otherwise.
*/
bool operator==(const BoostJsonArrayValueIterator &other) const
{
return m_itr == other.m_itr;
}
bool operator!=(const BoostJsonArrayValueIterator &other) const
{
return !(m_itr == other.m_itr);
}
const BoostJsonArrayValueIterator& operator++()
{
m_itr++;
return *this;
}
BoostJsonArrayValueIterator operator++(int)
{
BoostJsonArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const BoostJsonArrayValueIterator& operator--()
{
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
m_itr += n;
}
private:
boost::json::array::const_iterator m_itr;
};
/**
* @brief Class for iterating over the members belonging to a JSON object.
*
* This class provides a JSON object iterator that dereferences as an instance
* of BoostJsonObjectMember representing one of the members of the object.
*
* @see BoostJsonObject
* @see BoostJsonObjectMember
*/
class BoostJsonObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = BoostJsonObjectMember;
using difference_type = BoostJsonObjectMember;
using pointer = BoostJsonObjectMember*;
using reference = BoostJsonObjectMember&;
/**
* @brief Construct an iterator from a BoostJson iterator.
*
* @param itr BoostJson iterator to store
*/
BoostJsonObjectMemberIterator(boost::json::object::const_iterator itr)
: m_itr(itr) { }
/**
* @brief Returns a BoostJsonObjectMember that contains the key and
* value belonging to the object member identified by the iterator.
*/
BoostJsonObjectMember operator*() const
{
return BoostJsonObjectMember(m_itr->key(), m_itr->value());
}
DerefProxy<BoostJsonObjectMember> operator->() const
{
return DerefProxy<BoostJsonObjectMember>(**this);
}
/**
* @brief Compare this iterator with another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other Iterator to compare with
*
* @returns true if the underlying iterators are equal, false otherwise
*/
bool operator==(const BoostJsonObjectMemberIterator &other) const
{
return m_itr == other.m_itr;
}
bool operator!=(const BoostJsonObjectMemberIterator &other) const
{
return !(m_itr == other.m_itr);
}
const BoostJsonObjectMemberIterator& operator++()
{
m_itr++;
return *this;
}
BoostJsonObjectMemberIterator operator++(int)
{
BoostJsonObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const BoostJsonObjectMemberIterator& operator--()
{
m_itr--;
return *this;
}
private:
/// Internal copy of the original Boost.JSON iterator
boost::json::object::const_iterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for BoostJsonAdapter.
template<>
struct AdapterTraits<valijson::adapters::BoostJsonAdapter>
{
typedef boost::json::value DocumentType;
static std::string adapterName()
{
return "BoostJsonAdapter";
}
};
inline bool BoostJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return BoostJsonAdapter(m_value).equalTo(other, strict);
}
inline BoostJsonArrayValueIterator BoostJsonArray::begin() const
{
return m_value.cbegin();
}
inline BoostJsonArrayValueIterator BoostJsonArray::end() const
{
return m_value.cend();
}
inline BoostJsonObjectMemberIterator BoostJsonObject::begin() const
{
return m_value.cbegin();
}
inline BoostJsonObjectMemberIterator BoostJsonObject::end() const
{
return m_value.cend();
}
inline BoostJsonObjectMemberIterator BoostJsonObject::find(
const std::string &propertyName) const
{
return m_value.find(propertyName);
}
} // namespace adapters
} // namespace valijson

View File

@ -28,9 +28,10 @@
#include <string>
#include <json11.hpp>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -61,7 +62,7 @@ public:
/// Construct a Json11Array referencing an empty array.
Json11Array()
: value(emptyArray()) { }
: m_value(emptyArray()) { }
/**
* @brief Construct a Json11Array referencing a specific Json11
@ -73,10 +74,10 @@ public:
* an array.
*/
Json11Array(const json11::Json &value)
: value(value)
: m_value(value)
{
if (!value.is_array()) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -99,7 +100,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
return value.array_items().size();
return m_value.array_items().size();
}
private:
@ -116,7 +117,7 @@ private:
}
/// Reference to the contained value
const json11::Json &value;
const json11::Json &m_value;
};
/**
@ -139,7 +140,7 @@ public:
/// Construct a Json11Object referencing an empty object singleton.
Json11Object()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/**
* @brief Construct a Json11Object referencing a specific Json11
@ -151,10 +152,10 @@ public:
* an object.
*/
Json11Object(const json11::Json &value)
: value(value)
: m_value(value)
{
if (!value.is_object()) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -189,7 +190,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
return value.object_items().size();
return m_value.object_items().size();
}
private:
@ -206,7 +207,7 @@ private:
}
/// Reference to the contained object
const json11::Json &value;
const json11::Json &m_value;
};
/**
@ -227,20 +228,20 @@ public:
*
* @param source the Json11 value to be copied
*/
explicit Json11FrozenValue(const json11::Json &source)
: value(source) { }
explicit Json11FrozenValue(json11::Json source)
: m_value(std::move(source)) { }
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new Json11FrozenValue(value);
return new Json11FrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored Json11 value
json11::Json value;
json11::Json m_value;
};
/**
@ -263,11 +264,11 @@ public:
/// Construct a wrapper for the empty object singleton
Json11Value()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/// Construct a wrapper for a specific Json11 value
Json11Value(const json11::Json &value)
: value(value) { }
: m_value(value) { }
/**
* @brief Create a new Json11FrozenValue instance that contains the
@ -278,7 +279,7 @@ public:
*/
FrozenValue * freeze() const
{
return new Json11FrozenValue(value);
return new Json11FrozenValue(m_value);
}
/**
@ -292,11 +293,11 @@ public:
*/
opt::optional<Json11Array> getArrayOptional() const
{
if (value.is_array()) {
return opt::make_optional(Json11Array(value));
if (m_value.is_array()) {
return opt::make_optional(Json11Array(m_value));
}
return opt::optional<Json11Array>();
return {};
}
/**
@ -312,8 +313,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.is_array()) {
result = value.array_items().size();
if (m_value.is_array()) {
result = m_value.array_items().size();
return true;
}
@ -322,8 +323,8 @@ public:
bool getBool(bool &result) const
{
if (value.is_bool()) {
result = value.bool_value();
if (m_value.is_bool()) {
result = m_value.bool_value();
return true;
}
@ -332,8 +333,8 @@ public:
bool getDouble(double &result) const
{
if (value.is_number()) {
result = value.number_value();
if (m_value.is_number()) {
result = m_value.number_value();
return true;
}
@ -342,8 +343,8 @@ public:
bool getInteger(int64_t &result) const
{
if(isInteger()) {
result = value.int_value();
if (isInteger()) {
result = m_value.int_value();
return true;
}
return false;
@ -360,11 +361,11 @@ public:
*/
opt::optional<Json11Object> getObjectOptional() const
{
if (value.is_object()) {
return opt::make_optional(Json11Object(value));
if (m_value.is_object()) {
return opt::make_optional(Json11Object(m_value));
}
return opt::optional<Json11Object>();
return {};
}
/**
@ -380,8 +381,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.is_object()) {
result = value.object_items().size();
if (m_value.is_object()) {
result = m_value.object_items().size();
return true;
}
@ -390,8 +391,8 @@ public:
bool getString(std::string &result) const
{
if (value.is_string()) {
result = value.string_value();
if (m_value.is_string()) {
result = m_value.string_value();
return true;
}
@ -405,43 +406,42 @@ public:
bool isArray() const
{
return value.is_array();
return m_value.is_array();
}
bool isBool() const
{
return value.is_bool();
return m_value.is_bool();
}
bool isDouble() const
{
return value.is_number();
return m_value.is_number();
}
bool isInteger() const
{
return value.is_number()
&& value.int_value() == value.number_value();
return m_value.is_number() && m_value.int_value() == m_value.number_value();
}
bool isNull() const
{
return value.is_null();
return m_value.is_null();
}
bool isNumber() const
{
return value.is_number();
return m_value.is_number();
}
bool isObject() const
{
return value.is_object();
return m_value.is_object();
}
bool isString() const
{
return value.is_string();
return m_value.is_string();
}
private:
@ -454,7 +454,7 @@ private:
}
/// Reference to the contained Json11 value.
const json11::Json &value;
const json11::Json &m_value;
};
/**
@ -493,12 +493,14 @@ public:
*
* @see Json11Array
*/
class Json11ArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
Json11Adapter> // value type
class Json11ArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = Json11Adapter;
using difference_type = Json11Adapter;
using pointer = Json11Adapter*;
using reference = Json11Adapter&;
/**
* @brief Construct a new Json11ArrayValueIterator using an existing
@ -506,15 +508,14 @@ public:
*
* @param itr Json11 iterator to store
*/
Json11ArrayValueIterator(
const json11::Json::array::const_iterator &itr)
: itr(itr) { }
Json11ArrayValueIterator(const json11::Json::array::const_iterator &itr)
: m_itr(itr) { }
/// Returns a Json11Adapter that contains the value of the current
/// element.
Json11Adapter operator*() const
{
return Json11Adapter(*itr);
return Json11Adapter(*m_itr);
}
DerefProxy<Json11Adapter> operator->() const
@ -535,43 +536,43 @@ public:
*/
bool operator==(const Json11ArrayValueIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const Json11ArrayValueIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const Json11ArrayValueIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
Json11ArrayValueIterator operator++(int)
{
Json11ArrayValueIterator iterator_pre(itr);
Json11ArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const Json11ArrayValueIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
itr += n;
m_itr += n;
}
private:
json11::Json::array::const_iterator itr;
json11::Json::array::const_iterator m_itr;
};
/**
@ -584,21 +585,22 @@ private:
* @see Json11Object
* @see Json11ObjectMember
*/
class Json11ObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
Json11ObjectMember> // value type
class Json11ObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = Json11ObjectMember;
using difference_type = Json11ObjectMember;
using pointer = Json11ObjectMember*;
using reference = Json11ObjectMember&;
/**
* @brief Construct an iterator from a Json11 iterator.
*
* @param itr Json11 iterator to store
*/
Json11ObjectMemberIterator(
const json11::Json::object::const_iterator &itr)
: itr(itr) { }
Json11ObjectMemberIterator(const json11::Json::object::const_iterator &itr)
: m_itr(itr) { }
/**
* @brief Returns a Json11ObjectMember that contains the key and value
@ -606,7 +608,7 @@ public:
*/
Json11ObjectMember operator*() const
{
return Json11ObjectMember(itr->first, itr->second);
return Json11ObjectMember(m_itr->first, m_itr->second);
}
DerefProxy<Json11ObjectMember> operator->() const
@ -627,39 +629,39 @@ public:
*/
bool operator==(const Json11ObjectMemberIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const Json11ObjectMemberIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const Json11ObjectMemberIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
Json11ObjectMemberIterator operator++(int)
{
Json11ObjectMemberIterator iterator_pre(itr);
Json11ObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const Json11ObjectMemberIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
private:
/// Iternal copy of the original Json11 iterator
json11::Json::object::const_iterator itr;
/// Internal copy of the original Json11 iterator
json11::Json::object::const_iterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for Json11Adapter.
@ -676,33 +678,33 @@ struct AdapterTraits<valijson::adapters::Json11Adapter>
inline bool Json11FrozenValue::equalTo(const Adapter &other, bool strict) const
{
return Json11Adapter(value).equalTo(other, strict);
return Json11Adapter(m_value).equalTo(other, strict);
}
inline Json11ArrayValueIterator Json11Array::begin() const
{
return value.array_items().begin();
return m_value.array_items().begin();
}
inline Json11ArrayValueIterator Json11Array::end() const
{
return value.array_items().end();
return m_value.array_items().end();
}
inline Json11ObjectMemberIterator Json11Object::begin() const
{
return value.object_items().begin();
return m_value.object_items().begin();
}
inline Json11ObjectMemberIterator Json11Object::end() const
{
return value.object_items().end();
return m_value.object_items().end();
}
inline Json11ObjectMemberIterator Json11Object::find(
const std::string &propertyName) const
{
return value.object_items().find(propertyName);
return m_value.object_items().find(propertyName);
}
} // namespace adapters

View File

@ -31,9 +31,10 @@
#include <json/json.h>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -64,7 +65,7 @@ public:
/// Construct a JsonCppArray referencing an empty array.
JsonCppArray()
: value(emptyArray()) { }
: m_value(emptyArray()) { }
/**
* @brief Construct a JsonCppArray referencing a specific JsonCpp value.
@ -75,10 +76,10 @@ public:
* an array.
*/
JsonCppArray(const Json::Value &value)
: value(value)
: m_value(value)
{
if (!value.isArray()) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -101,7 +102,7 @@ public:
/// Return the number of elements in the array.
size_t size() const
{
return value.size();
return m_value.size();
}
private:
@ -118,7 +119,7 @@ private:
}
/// Reference to the contained array
const Json::Value &value;
const Json::Value &m_value;
};
@ -142,7 +143,7 @@ public:
/// Construct a JsonCppObject referencing an empty object singleton.
JsonCppObject()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/**
* @brief Construct a JsonCppObject referencing a specific JsonCpp value.
@ -153,10 +154,10 @@ public:
* an object.
*/
JsonCppObject(const Json::Value &value)
: value(value)
: m_value(value)
{
if (!value.isObject()) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -189,7 +190,7 @@ public:
/// Return the number of members in the object
size_t size() const
{
return value.size();
return m_value.size();
}
private:
@ -202,7 +203,7 @@ private:
}
/// Reference to the contained object
const Json::Value &value;
const Json::Value &m_value;
};
/**
@ -224,19 +225,19 @@ public:
* @param source the JsonCpp value to be copied
*/
explicit JsonCppFrozenValue(const Json::Value &source)
: value(source) { }
: m_value(source) { }
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new JsonCppFrozenValue(value);
return new JsonCppFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored JsonCpp value
Json::Value value;
Json::Value m_value;
};
/**
@ -259,11 +260,11 @@ public:
/// Construct a wrapper for the empty object singleton
JsonCppValue()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/// Construct a wrapper for a specific JsonCpp value
JsonCppValue(const Json::Value &value)
: value(value) { }
: m_value(value) { }
/**
* @brief Create a new JsonCppFrozenValue instance that contains the
@ -274,7 +275,7 @@ public:
*/
FrozenValue * freeze() const
{
return new JsonCppFrozenValue(value);
return new JsonCppFrozenValue(m_value);
}
/**
@ -288,11 +289,11 @@ public:
*/
opt::optional<JsonCppArray> getArrayOptional() const
{
if (value.isArray()) {
return opt::make_optional(JsonCppArray(value));
if (m_value.isArray()) {
return opt::make_optional(JsonCppArray(m_value));
}
return opt::optional<JsonCppArray>();
return {};
}
/**
@ -308,8 +309,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.isArray()) {
result = value.size();
if (m_value.isArray()) {
result = m_value.size();
return true;
}
@ -318,8 +319,8 @@ public:
bool getBool(bool &result) const
{
if (value.isBool()) {
result = value.asBool();
if (m_value.isBool()) {
result = m_value.asBool();
return true;
}
@ -328,8 +329,8 @@ public:
bool getDouble(double &result) const
{
if (value.isDouble()) {
result = value.asDouble();
if (m_value.isDouble()) {
result = m_value.asDouble();
return true;
}
@ -338,8 +339,8 @@ public:
bool getInteger(int64_t &result) const
{
if (value.isIntegral()) {
result = static_cast<int64_t>(value.asInt());
if (m_value.isIntegral()) {
result = static_cast<int64_t>(m_value.asInt());
return true;
}
@ -357,11 +358,11 @@ public:
*/
opt::optional<JsonCppObject> getObjectOptional() const
{
if (value.isObject()) {
return opt::make_optional(JsonCppObject(value));
if (m_value.isObject()) {
return opt::make_optional(JsonCppObject(m_value));
}
return opt::optional<JsonCppObject>();
return {};
}
/**
@ -377,8 +378,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.isObject()) {
result = value.size();
if (m_value.isObject()) {
result = m_value.size();
return true;
}
@ -387,8 +388,8 @@ public:
bool getString(std::string &result) const
{
if (value.isString()) {
result = value.asString();
if (m_value.isString()) {
result = m_value.asString();
return true;
}
@ -402,42 +403,42 @@ public:
bool isArray() const
{
return value.isArray() && !value.isNull();
return m_value.isArray() && !m_value.isNull();
}
bool isBool() const
{
return value.isBool();
return m_value.isBool();
}
bool isDouble() const
{
return value.isDouble();
return m_value.isDouble();
}
bool isInteger() const
{
return value.isIntegral() && !value.isBool();
return m_value.isIntegral() && !m_value.isBool();
}
bool isNull() const
{
return value.isNull();
return m_value.isNull();
}
bool isNumber() const
{
return value.isNumeric() && !value.isBool();
return m_value.isNumeric() && !m_value.isBool();
}
bool isObject() const
{
return value.isObject() && !value.isNull();
return m_value.isObject() && !m_value.isNull();
}
bool isString() const
{
return value.isString();
return m_value.isString();
}
private:
@ -450,7 +451,7 @@ private:
}
/// Reference to the contained JsonCpp value
const Json::Value &value;
const Json::Value &m_value;
};
/**
@ -489,13 +490,14 @@ public:
*
* @see JsonCppArray
*/
class JsonCppArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
JsonCppAdapter> // value type
class JsonCppArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = JsonCppAdapter;
using difference_type = JsonCppAdapter;
using pointer = JsonCppAdapter*;
using reference = JsonCppAdapter&;
/**
* @brief Construct a new JsonCppArrayValueIterator using an existing
@ -504,12 +506,12 @@ public:
* @param itr JsonCpp iterator to store
*/
JsonCppArrayValueIterator(const Json::Value::const_iterator &itr)
: itr(itr) { }
: m_itr(itr) { }
/// Returns a JsonCppAdapter that contains the value of the current element.
JsonCppAdapter operator*() const
{
return JsonCppAdapter(*itr);
return JsonCppAdapter(*m_itr);
}
DerefProxy<JsonCppAdapter> operator->() const
@ -530,31 +532,31 @@ public:
*/
bool operator==(const JsonCppArrayValueIterator &rhs) const
{
return itr == rhs.itr;
return m_itr == rhs.m_itr;
}
bool operator!=(const JsonCppArrayValueIterator &rhs) const
{
return !(itr == rhs.itr);
return !(m_itr == rhs.m_itr);
}
JsonCppArrayValueIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
JsonCppArrayValueIterator operator++(int)
{
JsonCppArrayValueIterator iterator_pre(itr);
JsonCppArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
JsonCppArrayValueIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
@ -563,18 +565,18 @@ public:
{
if (n > 0) {
while (n-- > 0) {
itr++;
m_itr++;
}
} else {
while (n++ < 0) {
itr--;
m_itr--;
}
}
}
private:
Json::Value::const_iterator itr;
Json::Value::const_iterator m_itr;
};
/**
@ -587,12 +589,14 @@ private:
* @see JsonCppObject
* @see JsonCppObjectMember
*/
class JsonCppObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
JsonCppObjectMember> // value type
class JsonCppObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = JsonCppObjectMember;
using difference_type = JsonCppObjectMember;
using pointer = JsonCppObjectMember*;
using reference = JsonCppObjectMember&;
/**
* @brief Construct an iterator from a JsonCpp iterator.
@ -600,7 +604,7 @@ public:
* @param itr JsonCpp iterator to store
*/
JsonCppObjectMemberIterator(const Json::ValueConstIterator &itr)
: itr(itr) { }
: m_itr(itr) { }
/**
* @brief Returns a JsonCppObjectMember that contains the key and value
@ -608,7 +612,7 @@ public:
*/
JsonCppObjectMember operator*() const
{
return JsonCppObjectMember(itr.key().asString(), *itr);
return JsonCppObjectMember(m_itr.key().asString(), *m_itr);
}
DerefProxy<JsonCppObjectMember> operator->() const
@ -629,39 +633,39 @@ public:
*/
bool operator==(const JsonCppObjectMemberIterator &rhs) const
{
return itr == rhs.itr;
return m_itr == rhs.m_itr;
}
bool operator!=(const JsonCppObjectMemberIterator &rhs) const
{
return !(itr == rhs.itr);
return !(m_itr == rhs.m_itr);
}
const JsonCppObjectMemberIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
JsonCppObjectMemberIterator operator++(int)
{
JsonCppObjectMemberIterator iterator_pre(itr);
JsonCppObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
JsonCppObjectMemberIterator operator--()
{
itr--;
m_itr--;
return *this;
}
private:
/// Iternal copy of the original JsonCpp iterator
Json::ValueConstIterator itr;
/// Internal copy of the original JsonCpp iterator
Json::ValueConstIterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for JsonCppAdapter.
@ -678,42 +682,42 @@ struct AdapterTraits<valijson::adapters::JsonCppAdapter>
inline bool JsonCppFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return JsonCppAdapter(value).equalTo(other, strict);
return JsonCppAdapter(m_value).equalTo(other, strict);
}
inline JsonCppArrayValueIterator JsonCppArray::begin() const
{
return value.begin();
return m_value.begin();
}
inline JsonCppArrayValueIterator JsonCppArray::end() const
{
return value.end();
return m_value.end();
}
inline JsonCppObjectMemberIterator JsonCppObject::begin() const
{
return value.begin();
return m_value.begin();
}
inline JsonCppObjectMemberIterator JsonCppObject::end() const
{
return value.end();
return m_value.end();
}
inline JsonCppObjectMemberIterator JsonCppObject::find(
const std::string &propertyName) const
{
if (value.isMember(propertyName)) {
if (m_value.isMember(propertyName)) {
Json::ValueConstIterator itr;
for ( itr = value.begin(); itr != value.end(); ++itr) {
for (itr = m_value.begin(); itr != m_value.end(); ++itr) {
if (itr.key() == propertyName) {
return itr;
}
}
}
return value.end();
return m_value.end();
}
} // namespace adapters

View File

@ -26,21 +26,206 @@
#pragma once
#include <string>
#include <json.hpp>
#include <nlohmann/json.hpp>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
#include <utility>
namespace valijson {
namespace adapters {
class NlohmannJsonAdapter;
class NlohmannJsonArrayValueIterator;
class NlohmannJsonObjectMemberIterator;
typedef std::pair<std::string, NlohmannJsonAdapter> NlohmannJsonObjectMember;
/**
* @brief Class for iterating over values held in a JSON array.
*
* This class provides a JSON array iterator that dereferences as an instance of
* NlohmannJsonAdapter representing a value stored in the array. It has been
* implemented using the boost iterator_facade template.
*
* @see NlohmannJsonArray
*/
template <class ValueType>
class NlohmannJsonArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = ValueType;
using difference_type = ValueType;
using pointer = ValueType *;
using reference = ValueType &;
/**
* @brief Construct a new NlohmannJsonArrayValueIterator using an existing
* NlohmannJson iterator.
*
* @param itr NlohmannJson iterator to store
*/
NlohmannJsonArrayValueIterator(const nlohmann::json::const_iterator &itr)
: m_itr(itr)
{
}
/// Returns a NlohmannJsonAdapter that contains the value of the current
/// element.
ValueType operator*() const
{
return ValueType(*m_itr);
}
DerefProxy<ValueType> operator->() const
{
return DerefProxy<ValueType>(**this);
}
/**
* @brief Compare this iterator against another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other iterator to compare against
*
* @returns true if the iterators are equal, false otherwise.
*/
bool operator==(const NlohmannJsonArrayValueIterator &other) const
{
return m_itr == other.m_itr;
}
bool operator!=(const NlohmannJsonArrayValueIterator &other) const
{
return !(m_itr == other.m_itr);
}
const NlohmannJsonArrayValueIterator &operator++()
{
m_itr++;
return *this;
}
NlohmannJsonArrayValueIterator operator++(int)
{
NlohmannJsonArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const NlohmannJsonArrayValueIterator &operator--()
{
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
m_itr += n;
}
private:
nlohmann::json::const_iterator m_itr;
};
/**
* @brief Class for iterating over the members belonging to a JSON object.
*
* This class provides a JSON object iterator that dereferences as an instance
* of NlohmannJsonObjectMember representing one of the members of the object. It
* has been implemented using the boost iterator_facade template.
*
* @see NlohmannJsonObject
* @see NlohmannJsonObjectMember
*/
template <class ValueType> class NlohmannJsonObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = ValueType;
using difference_type = ValueType;
using pointer = ValueType *;
using reference = ValueType &;
/**
* @brief Construct an iterator from a NlohmannJson iterator.
*
* @param itr NlohmannJson iterator to store
*/
NlohmannJsonObjectMemberIterator(const nlohmann::json::const_iterator &itr)
: m_itr(itr)
{
}
/**
* @brief Returns a NlohmannJsonObjectMember that contains the key and
* value belonging to the object member identified by the iterator.
*/
ValueType operator*() const
{
return ValueType(m_itr.key(), m_itr.value());
}
DerefProxy<ValueType> operator->() const
{
return DerefProxy<ValueType>(**this);
}
/**
* @brief Compare this iterator with another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other Iterator to compare with
*
* @returns true if the underlying iterators are equal, false otherwise
*/
bool operator==(const NlohmannJsonObjectMemberIterator &other) const
{
return m_itr == other.m_itr;
}
bool operator!=(const NlohmannJsonObjectMemberIterator &other) const
{
return !(m_itr == other.m_itr);
}
const NlohmannJsonObjectMemberIterator &operator++()
{
m_itr++;
return *this;
}
NlohmannJsonObjectMemberIterator operator++(int)
{
NlohmannJsonObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const NlohmannJsonObjectMemberIterator &operator--()
{
m_itr--;
return *this;
}
private:
/// Internal copy of the original NlohmannJson iterator
nlohmann::json::const_iterator m_itr;
};
/**
* @brief Light weight wrapper for a NlohmannJson array value.
*
@ -52,16 +237,17 @@ typedef std::pair<std::string, NlohmannJsonAdapter> NlohmannJsonObjectMember;
* NlohmannJson value, assumed to be an array, so there is very little overhead
* associated with copy construction and passing by value.
*/
template <class ValueType>
class NlohmannJsonArray
{
public:
typedef NlohmannJsonArrayValueIterator const_iterator;
typedef NlohmannJsonArrayValueIterator iterator;
typedef NlohmannJsonArrayValueIterator<ValueType> const_iterator;
typedef NlohmannJsonArrayValueIterator<ValueType> iterator;
/// Construct a NlohmannJsonArray referencing an empty array.
NlohmannJsonArray()
: value(emptyArray()) { }
: m_value(emptyArray()) { }
/**
* @brief Construct a NlohmannJsonArray referencing a specific NlohmannJson
@ -73,10 +259,10 @@ public:
* an array.
*/
NlohmannJsonArray(const nlohmann::json &value)
: value(value)
: m_value(value)
{
if (!value.is_array()) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -86,7 +272,10 @@ public:
* The iterator return by this function is effectively the iterator
* returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonArrayValueIterator begin() const;
NlohmannJsonArrayValueIterator<ValueType> begin() const {
return m_value.begin();
}
/**
* @brief Return an iterator for one-past the last element of the array.
@ -94,12 +283,14 @@ public:
* The iterator return by this function is effectively the iterator
* returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonArrayValueIterator end() const;
NlohmannJsonArrayValueIterator<ValueType> end() const {
return m_value.end();
}
/// Return the number of elements in the array
size_t size() const
{
return value.size();
return m_value.size();
}
private:
@ -116,7 +307,7 @@ private:
}
/// Reference to the contained value
const nlohmann::json &value;
const nlohmann::json &m_value;
};
/**
@ -134,12 +325,12 @@ class NlohmannJsonObject
{
public:
typedef NlohmannJsonObjectMemberIterator const_iterator;
typedef NlohmannJsonObjectMemberIterator iterator;
typedef NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> const_iterator;
typedef NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> iterator;
/// Construct a NlohmannJsonObject referencing an empty object singleton.
NlohmannJsonObject()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/**
* @brief Construct a NlohmannJsonObject referencing a specific NlohmannJson
@ -151,10 +342,10 @@ public:
* an object.
*/
NlohmannJsonObject(const nlohmann::json &value)
: value(value)
: m_value(value)
{
if (!value.is_object()) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -164,7 +355,7 @@ public:
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonObjectMemberIterator begin() const;
NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> begin() const;
/**
* @brief Return an iterator for an invalid object member that indicates
@ -173,7 +364,7 @@ public:
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonObjectMemberIterator end() const;
NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> end() const;
/**
* @brief Return an iterator for the object member with the specified
@ -184,12 +375,13 @@ public:
*
* @param propertyName property name to search for
*/
NlohmannJsonObjectMemberIterator find(const std::string &propertyName) const;
NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
find(const std::string &propertyName) const;
/// Returns the number of members belonging to this object.
size_t size() const
{
return value.size();
return m_value.size();
}
private:
@ -206,7 +398,7 @@ private:
}
/// Reference to the contained object
const nlohmann::json &value;
const nlohmann::json &m_value;
};
@ -228,20 +420,20 @@ public:
*
* @param source the NlohmannJson value to be copied
*/
explicit NlohmannJsonFrozenValue(const nlohmann::json &source)
: value(source) { }
explicit NlohmannJsonFrozenValue(nlohmann::json source)
: m_value(std::move(source)) { }
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new NlohmannJsonFrozenValue(value);
return new NlohmannJsonFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored NlohmannJson value
nlohmann::json value;
nlohmann::json m_value;
};
@ -259,17 +451,18 @@ private:
*
* @see BasicAdapter
*/
template<class ValueType>
class NlohmannJsonValue
{
public:
/// Construct a wrapper for the empty object singleton
NlohmannJsonValue()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/// Construct a wrapper for a specific NlohmannJson value
NlohmannJsonValue(const nlohmann::json &value)
: value(value) { }
: m_value(value) { }
/**
* @brief Create a new NlohmannJsonFrozenValue instance that contains the
@ -280,7 +473,7 @@ public:
*/
FrozenValue * freeze() const
{
return new NlohmannJsonFrozenValue(value);
return new NlohmannJsonFrozenValue(m_value);
}
/**
@ -292,13 +485,13 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<NlohmannJsonArray> getArrayOptional() const
opt::optional<NlohmannJsonArray<ValueType>> getArrayOptional() const
{
if (value.is_array()) {
return opt::make_optional(NlohmannJsonArray(value));
if (m_value.is_array()) {
return opt::make_optional(NlohmannJsonArray<ValueType>(m_value));
}
return opt::optional<NlohmannJsonArray>();
return {};
}
/**
@ -314,8 +507,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.is_array()) {
result = value.size();
if (m_value.is_array()) {
result = m_value.size();
return true;
}
@ -324,8 +517,8 @@ public:
bool getBool(bool &result) const
{
if (value.is_boolean()) {
result = value.get<bool>();
if (m_value.is_boolean()) {
result = m_value.get<bool>();
return true;
}
@ -334,8 +527,8 @@ public:
bool getDouble(double &result) const
{
if (value.is_number_float()) {
result = value.get<double>();
if (m_value.is_number_float()) {
result = m_value.get<double>();
return true;
}
@ -344,8 +537,8 @@ public:
bool getInteger(int64_t &result) const
{
if(value.is_number_integer()) {
result = value.get<int64_t>();
if(m_value.is_number_integer()) {
result = m_value.get<int64_t>();
return true;
}
return false;
@ -360,14 +553,7 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<NlohmannJsonObject> getObjectOptional() const
{
if (value.is_object()) {
return opt::make_optional(NlohmannJsonObject(value));
}
return opt::optional<NlohmannJsonObject>();
}
opt::optional<NlohmannJsonObject> getObjectOptional() const;
/**
* @brief Retrieve the number of members in the object
@ -382,8 +568,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.is_object()) {
result = value.size();
if (m_value.is_object()) {
result = m_value.size();
return true;
}
@ -392,8 +578,8 @@ public:
bool getString(std::string &result) const
{
if (value.is_string()) {
result = value.get<std::string>();
if (m_value.is_string()) {
result = m_value.get<std::string>();
return true;
}
@ -407,42 +593,42 @@ public:
bool isArray() const
{
return value.is_array();
return m_value.is_array();
}
bool isBool() const
{
return value.is_boolean();
return m_value.is_boolean();
}
bool isDouble() const
{
return value.is_number_float();
return m_value.is_number_float();
}
bool isInteger() const
{
return value.is_number_integer();
return m_value.is_number_integer();
}
bool isNull() const
{
return value.is_null();
return m_value.is_null();
}
bool isNumber() const
{
return value.is_number();
return m_value.is_number();
}
bool isObject() const
{
return value.is_object();
return m_value.is_object();
}
bool isString() const
{
return value.is_string();
return m_value.is_string();
}
private:
@ -455,7 +641,7 @@ private:
}
/// Reference to the contained NlohmannJson value.
const nlohmann::json &value;
const nlohmann::json &m_value;
};
/**
@ -467,198 +653,35 @@ private:
* @see Adapter
* @see BasicAdapter
*/
class NlohmannJsonAdapter:
public BasicAdapter<NlohmannJsonAdapter,
NlohmannJsonArray,
NlohmannJsonObjectMember,
NlohmannJsonObject,
NlohmannJsonValue>
class NlohmannJsonAdapter
: public BasicAdapter<NlohmannJsonAdapter,
NlohmannJsonArray<NlohmannJsonAdapter>,
NlohmannJsonObjectMember, NlohmannJsonObject,
NlohmannJsonValue<NlohmannJsonAdapter>>
{
public:
/// Construct a NlohmannJsonAdapter that contains an empty object
NlohmannJsonAdapter()
: BasicAdapter() { }
/// Construct a NlohmannJsonAdapter containing a specific Nlohmann Json object
/// Construct a NlohmannJsonAdapter containing a specific Nlohmann Json
/// object
NlohmannJsonAdapter(const nlohmann::json &value)
: BasicAdapter(NlohmannJsonValue{value}) { }
: BasicAdapter(NlohmannJsonValue<NlohmannJsonAdapter>{value})
{
}
};
/**
* @brief Class for iterating over values held in a JSON array.
*
* This class provides a JSON array iterator that dereferences as an instance of
* NlohmannJsonAdapter representing a value stored in the array. It has been
* implemented using the boost iterator_facade template.
*
* @see NlohmannJsonArray
*/
class NlohmannJsonArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
NlohmannJsonAdapter> // value type
template <class ValueType>
opt::optional<NlohmannJsonObject>
NlohmannJsonValue<ValueType>::getObjectOptional() const
{
public:
/**
* @brief Construct a new NlohmannJsonArrayValueIterator using an existing
* NlohmannJson iterator.
*
* @param itr NlohmannJson iterator to store
*/
NlohmannJsonArrayValueIterator(const nlohmann::json::const_iterator &itr)
: itr(itr) { }
/// Returns a NlohmannJsonAdapter that contains the value of the current
/// element.
NlohmannJsonAdapter operator*() const
{
return NlohmannJsonAdapter(*itr);
if (m_value.is_object()) {
return opt::make_optional(NlohmannJsonObject(m_value));
}
DerefProxy<NlohmannJsonAdapter> operator->() const
{
return DerefProxy<NlohmannJsonAdapter>(**this);
}
/**
* @brief Compare this iterator against another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other iterator to compare against
*
* @returns true if the iterators are equal, false otherwise.
*/
bool operator==(const NlohmannJsonArrayValueIterator &other) const
{
return itr == other.itr;
}
bool operator!=(const NlohmannJsonArrayValueIterator &other) const
{
return !(itr == other.itr);
}
const NlohmannJsonArrayValueIterator& operator++()
{
itr++;
return *this;
}
NlohmannJsonArrayValueIterator operator++(int)
{
NlohmannJsonArrayValueIterator iterator_pre(itr);
++(*this);
return iterator_pre;
}
const NlohmannJsonArrayValueIterator& operator--()
{
itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
itr += n;
}
private:
nlohmann::json::const_iterator itr;
};
/**
* @brief Class for iterating over the members belonging to a JSON object.
*
* This class provides a JSON object iterator that dereferences as an instance
* of NlohmannJsonObjectMember representing one of the members of the object. It
* has been implemented using the boost iterator_facade template.
*
* @see NlohmannJsonObject
* @see NlohmannJsonObjectMember
*/
class NlohmannJsonObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
NlohmannJsonObjectMember> // value type
{
public:
/**
* @brief Construct an iterator from a NlohmannJson iterator.
*
* @param itr NlohmannJson iterator to store
*/
NlohmannJsonObjectMemberIterator(const nlohmann::json::const_iterator &itr)
: itr(itr) { }
/**
* @brief Returns a NlohmannJsonObjectMember that contains the key and value
* belonging to the object member identified by the iterator.
*/
NlohmannJsonObjectMember operator*() const
{
return NlohmannJsonObjectMember(itr.key(), itr.value());
}
DerefProxy<NlohmannJsonObjectMember> operator->() const
{
return DerefProxy<NlohmannJsonObjectMember>(**this);
}
/**
* @brief Compare this iterator with another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other Iterator to compare with
*
* @returns true if the underlying iterators are equal, false otherwise
*/
bool operator==(const NlohmannJsonObjectMemberIterator &other) const
{
return itr == other.itr;
}
bool operator!=(const NlohmannJsonObjectMemberIterator &other) const
{
return !(itr == other.itr);
}
const NlohmannJsonObjectMemberIterator& operator++()
{
itr++;
return *this;
}
NlohmannJsonObjectMemberIterator operator++(int)
{
NlohmannJsonObjectMemberIterator iterator_pre(itr);
++(*this);
return iterator_pre;
}
const NlohmannJsonObjectMemberIterator& operator--()
{
itr--;
return *this;
}
private:
/// Iternal copy of the original NlohmannJson iterator
nlohmann::json::const_iterator itr;
};
return {};
}
/// Specialisation of the AdapterTraits template struct for NlohmannJsonAdapter.
template<>
@ -674,33 +697,27 @@ struct AdapterTraits<valijson::adapters::NlohmannJsonAdapter>
inline bool NlohmannJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return NlohmannJsonAdapter(value).equalTo(other, strict);
return NlohmannJsonAdapter(m_value).equalTo(other, strict);
}
inline NlohmannJsonArrayValueIterator NlohmannJsonArray::begin() const
inline NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
NlohmannJsonObject::begin() const
{
return value.begin();
return m_value.begin();
}
inline NlohmannJsonArrayValueIterator NlohmannJsonArray::end() const
inline NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
NlohmannJsonObject::end() const
{
return value.end();
return m_value.end();
}
inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::begin() const
{
return value.begin();
}
inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::end() const
{
return value.end();
}
inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::find(
inline NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
NlohmannJsonObject::find(
const std::string &propertyName) const
{
return value.find(propertyName);
return m_value.find(propertyName);
}
} // namespace adapters

View File

@ -27,11 +27,18 @@
#include <string>
#ifdef _MSC_VER
#pragma warning(disable: 4706)
#include <picojson.h>
#pragma warning(default: 4706)
#else
#include <picojson.h>
#endif
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -62,7 +69,7 @@ public:
/// Construct a PicoJsonArray referencing an empty array.
PicoJsonArray()
: value(emptyArray()) { }
: m_value(emptyArray()) { }
/**
* @brief Construct a PicoJsonArray referencing a specific PicoJson
@ -74,10 +81,10 @@ public:
* an array.
*/
explicit PicoJsonArray(const picojson::value &value)
: value(value)
: m_value(value)
{
if (!value.is<picojson::array>()) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -100,7 +107,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
const picojson::array &array = value.get<picojson::array>();
const picojson::array &array = m_value.get<picojson::array>();
return array.size();
}
@ -118,7 +125,7 @@ private:
}
/// Reference to the contained value
const picojson::value &value;
const picojson::value &m_value;
};
/**
@ -141,7 +148,7 @@ public:
/// Construct a PicoJsonObject referencing an empty object singleton.
PicoJsonObject()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/**
* @brief Construct a PicoJsonObject referencing a specific PicoJson
@ -153,10 +160,10 @@ public:
* an object.
*/
PicoJsonObject(const picojson::value &value)
: value(value)
: m_value(value)
{
if (!value.is<picojson::object>()) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -191,7 +198,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
const picojson::object &object = value.get<picojson::object>();
const picojson::object &object = m_value.get<picojson::object>();
return object.size();
}
@ -209,7 +216,7 @@ private:
}
/// Reference to the contained object
const picojson::value &value;
const picojson::value &m_value;
};
/**
@ -231,19 +238,19 @@ public:
* @param source the PicoJson value to be copied
*/
explicit PicoJsonFrozenValue(const picojson::value &source)
: value(source) { }
: m_value(source) { }
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new PicoJsonFrozenValue(value);
return new PicoJsonFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored PicoJson value
picojson::value value;
picojson::value m_value;
};
/**
@ -266,11 +273,11 @@ public:
/// Construct a wrapper for the empty object singleton
PicoJsonValue()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/// Construct a wrapper for a specific PicoJson value
PicoJsonValue(const picojson::value &value)
: value(value) { }
: m_value(value) { }
/**
* @brief Create a new PicoJsonFrozenValue instance that contains the
@ -281,7 +288,7 @@ public:
*/
FrozenValue * freeze() const
{
return new PicoJsonFrozenValue(value);
return new PicoJsonFrozenValue(m_value);
}
/**
@ -295,11 +302,11 @@ public:
*/
opt::optional<PicoJsonArray> getArrayOptional() const
{
if (value.is<picojson::array>()) {
return opt::make_optional(PicoJsonArray(value));
if (m_value.is<picojson::array>()) {
return opt::make_optional(PicoJsonArray(m_value));
}
return opt::optional<PicoJsonArray>();
return {};
}
/**
@ -315,8 +322,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.is<picojson::array>()) {
const picojson::array& array = value.get<picojson::array>();
if (m_value.is<picojson::array>()) {
const picojson::array& array = m_value.get<picojson::array>();
result = array.size();
return true;
}
@ -326,8 +333,8 @@ public:
bool getBool(bool &result) const
{
if (value.is<bool>()) {
result = value.get<bool>();
if (m_value.is<bool>()) {
result = m_value.get<bool>();
return true;
}
@ -336,8 +343,8 @@ public:
bool getDouble(double &result) const
{
if (value.is<double>()) {
result = value.get<double>();
if (m_value.is<double>()) {
result = m_value.get<double>();
return true;
}
@ -346,8 +353,8 @@ public:
bool getInteger(int64_t &result) const
{
if (value.is<int64_t>()) {
result = value.get<int64_t>();
if (m_value.is<int64_t>()) {
result = m_value.get<int64_t>();
return true;
}
@ -365,11 +372,11 @@ public:
*/
opt::optional<PicoJsonObject> getObjectOptional() const
{
if (value.is<picojson::object>()) {
return opt::make_optional(PicoJsonObject(value));
if (m_value.is<picojson::object>()) {
return opt::make_optional(PicoJsonObject(m_value));
}
return opt::optional<PicoJsonObject>();
return {};
}
/**
@ -385,8 +392,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.is<picojson::object>()) {
const picojson::object &object = value.get<picojson::object>();
if (m_value.is<picojson::object>()) {
const picojson::object &object = m_value.get<picojson::object>();
result = object.size();
return true;
}
@ -396,8 +403,8 @@ public:
bool getString(std::string &result) const
{
if (value.is<std::string>()) {
result = value.get<std::string>();
if (m_value.is<std::string>()) {
result = m_value.get<std::string>();
return true;
}
@ -411,46 +418,46 @@ public:
bool isArray() const
{
return value.is<picojson::array>();
return m_value.is<picojson::array>();
}
bool isBool() const
{
return value.is<bool>();
return m_value.is<bool>();
}
bool isDouble() const
{
if (value.is<int64_t>()) {
if (m_value.is<int64_t>()) {
return false;
}
return value.is<double>();
return m_value.is<double>();
}
bool isInteger() const
{
return value.is<int64_t>();
return m_value.is<int64_t>();
}
bool isNull() const
{
return value.is<picojson::null>();
return m_value.is<picojson::null>();
}
bool isNumber() const
{
return value.is<double>();
return m_value.is<double>();
}
bool isObject() const
{
return value.is<picojson::object>();
return m_value.is<picojson::object>();
}
bool isString() const
{
return value.is<std::string>();
return m_value.is<std::string>();
}
private:
@ -463,7 +470,7 @@ private:
}
/// Reference to the contained PicoJson value.
const picojson::value &value;
const picojson::value &m_value;
};
/**
@ -502,12 +509,14 @@ public:
*
* @see PicoJsonArray
*/
class PicoJsonArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
PicoJsonAdapter> // value type
class PicoJsonArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = PicoJsonAdapter;
using difference_type = PicoJsonAdapter;
using pointer = PicoJsonAdapter*;
using reference = PicoJsonAdapter&;
/**
* @brief Construct a new PicoJsonArrayValueIterator using an existing
@ -515,15 +524,14 @@ public:
*
* @param itr PicoJson iterator to store
*/
PicoJsonArrayValueIterator(
const picojson::array::const_iterator &itr)
: itr(itr) { }
PicoJsonArrayValueIterator(const picojson::array::const_iterator &itr)
: m_itr(itr) { }
/// Returns a PicoJsonAdapter that contains the value of the current
/// element.
PicoJsonAdapter operator*() const
{
return PicoJsonAdapter(*itr);
return PicoJsonAdapter(*m_itr);
}
DerefProxy<PicoJsonAdapter> operator->() const
@ -544,43 +552,43 @@ public:
*/
bool operator==(const PicoJsonArrayValueIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const PicoJsonArrayValueIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const PicoJsonArrayValueIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
PicoJsonArrayValueIterator operator++(int)
{
PicoJsonArrayValueIterator iterator_pre(itr);
PicoJsonArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const PicoJsonArrayValueIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
itr += n;
m_itr += n;
}
private:
picojson::array::const_iterator itr;
picojson::array::const_iterator m_itr;
};
/**
@ -593,21 +601,22 @@ private:
* @see PicoJsonObject
* @see PicoJsonObjectMember
*/
class PicoJsonObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
PicoJsonObjectMember> // value type
class PicoJsonObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = PicoJsonObjectMember;
using difference_type = PicoJsonObjectMember;
using pointer = PicoJsonObjectMember*;
using reference = PicoJsonObjectMember&;
/**
* @brief Construct an iterator from a PicoJson iterator.
*
* @param itr PicoJson iterator to store
*/
PicoJsonObjectMemberIterator(
const picojson::object::const_iterator &itr)
: itr(itr) { }
PicoJsonObjectMemberIterator(const picojson::object::const_iterator &itr)
: m_itr(itr) { }
/**
* @brief Returns a PicoJsonObjectMember that contains the key and value
@ -615,7 +624,7 @@ public:
*/
PicoJsonObjectMember operator*() const
{
return PicoJsonObjectMember(itr->first, itr->second);
return PicoJsonObjectMember(m_itr->first, m_itr->second);
}
DerefProxy<PicoJsonObjectMember> operator->() const
@ -636,39 +645,39 @@ public:
*/
bool operator==(const PicoJsonObjectMemberIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const PicoJsonObjectMemberIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const PicoJsonObjectMemberIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
PicoJsonObjectMemberIterator operator++(int)
{
PicoJsonObjectMemberIterator iterator_pre(itr);
PicoJsonObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const PicoJsonObjectMemberIterator& operator--(int)
{
itr--;
m_itr--;
return *this;
}
private:
/// Iternal copy of the original PicoJson iterator
picojson::object::const_iterator itr;
/// Internal copy of the original PicoJson iterator
picojson::object::const_iterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for PicoJsonAdapter.
@ -685,37 +694,37 @@ struct AdapterTraits<valijson::adapters::PicoJsonAdapter>
inline bool PicoJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return PicoJsonAdapter(value).equalTo(other, strict);
return PicoJsonAdapter(m_value).equalTo(other, strict);
}
inline PicoJsonArrayValueIterator PicoJsonArray::begin() const
{
const picojson::array &array = value.get<picojson::array>();
const picojson::array &array = m_value.get<picojson::array>();
return array.begin();
}
inline PicoJsonArrayValueIterator PicoJsonArray::end() const
{
const picojson::array &array = value.get<picojson::array>();
const picojson::array &array = m_value.get<picojson::array>();
return array.end();
}
inline PicoJsonObjectMemberIterator PicoJsonObject::begin() const
{
const picojson::object &object = value.get<picojson::object>();
const picojson::object &object = m_value.get<picojson::object>();
return object.begin();
}
inline PicoJsonObjectMemberIterator PicoJsonObject::end() const
{
const picojson::object &object = value.get<picojson::object>();
const picojson::object &object = m_value.get<picojson::object>();
return object.end();
}
inline PicoJsonObjectMemberIterator PicoJsonObject::find(
const std::string &propertyName) const
{
const picojson::object &object = value.get<picojson::object>();
const picojson::object &object = m_value.get<picojson::object>();
return object.find(propertyName);
}

View File

@ -28,9 +28,10 @@
#include <string>
#include <Poco/JSON/Object.h>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -61,7 +62,7 @@ public:
/// Construct a PocoJsonArray referencing an empty array.
PocoJsonArray()
: value(emptyArray())
: m_value(emptyArray())
{ }
/**
@ -74,10 +75,10 @@ public:
* an array.
*/
PocoJsonArray(const Poco::Dynamic::Var &value)
: value(value)
: m_value(value)
{
if (value.type() != typeid(Poco::JSON::Array::Ptr)) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -100,7 +101,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
return value.extract<Poco::JSON::Array::Ptr>()->size();
return m_value.extract<Poco::JSON::Array::Ptr>()->size();
}
private:
@ -115,7 +116,7 @@ private:
}
/// Contained value
Poco::Dynamic::Var value;
Poco::Dynamic::Var m_value;
};
/**
@ -138,7 +139,7 @@ public:
/// Construct a PocoJsonObject an empty object.
PocoJsonObject()
: value(emptyObject())
: m_value(emptyObject())
{ }
/**
@ -151,10 +152,10 @@ public:
* an object.
*/
PocoJsonObject(const Poco::Dynamic::Var &value)
: value(value)
: m_value(value)
{
if (value.type() != typeid(Poco::JSON::Object::Ptr)) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -189,7 +190,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
return value.extract<Poco::JSON::Object::Ptr>()->size();
return m_value.extract<Poco::JSON::Object::Ptr>()->size();
}
private:
@ -204,7 +205,7 @@ private:
}
/// Contained value
Poco::Dynamic::Var value;
Poco::Dynamic::Var m_value;
};
/**
@ -226,12 +227,12 @@ public:
* @param source the PocoJson value to be copied
*/
explicit PocoJsonFrozenValue(const Poco::Dynamic::Var &source)
: value(source)
: m_value(source)
{ }
virtual FrozenValue * clone() const
{
return new PocoJsonFrozenValue(value);
return new PocoJsonFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
@ -239,7 +240,7 @@ public:
private:
/// Stored PocoJson value
Poco::Dynamic::Var value;
Poco::Dynamic::Var m_value;
};
@ -263,12 +264,12 @@ public:
/// Construct a wrapper for the empty object
PocoJsonValue()
: value(emptyObject())
: m_value(emptyObject())
{ }
/// Construct a wrapper for a specific PocoJson value
PocoJsonValue(const Poco::Dynamic::Var& value)
: value(value)
: m_value(value)
{ }
/**
@ -280,7 +281,7 @@ public:
*/
FrozenValue * freeze() const
{
return new PocoJsonFrozenValue(value);
return new PocoJsonFrozenValue(m_value);
}
/**
@ -294,8 +295,8 @@ public:
*/
opt::optional<PocoJsonArray> getArrayOptional() const
{
if (value.type() == typeid(Poco::JSON::Array::Ptr)) {
return opt::make_optional(PocoJsonArray(value));
if (m_value.type() == typeid(Poco::JSON::Array::Ptr)) {
return opt::make_optional(PocoJsonArray(m_value));
}
return opt::optional<PocoJsonArray>();
@ -314,8 +315,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.type() == typeid(Poco::JSON::Array::Ptr)) {
result = value.extract<Poco::JSON::Array::Ptr>()->size();
if (m_value.type() == typeid(Poco::JSON::Array::Ptr)) {
result = m_value.extract<Poco::JSON::Array::Ptr>()->size();
return true;
}
@ -324,8 +325,8 @@ public:
bool getBool(bool &result) const
{
if (value.isBoolean()) {
result = value.convert<bool>();
if (m_value.isBoolean()) {
result = m_value.convert<bool>();
return true;
}
@ -334,8 +335,8 @@ public:
bool getDouble(double &result) const
{
if (value.isNumeric() && !value.isInteger()) {
result = value.convert<double>();
if (m_value.isNumeric() && !m_value.isInteger()) {
result = m_value.convert<double>();
return true;
}
@ -344,8 +345,8 @@ public:
bool getInteger(int64_t &result) const
{
if (value.isInteger()) {
result = value.convert<int>();
if (m_value.isInteger()) {
result = m_value.convert<int64_t>();
return true;
}
return false;
@ -362,8 +363,8 @@ public:
*/
opt::optional<PocoJsonObject> getObjectOptional() const
{
if (value.type() == typeid(Poco::JSON::Object::Ptr)) {
return opt::make_optional(PocoJsonObject(value));
if (m_value.type() == typeid(Poco::JSON::Object::Ptr)) {
return opt::make_optional(PocoJsonObject(m_value));
}
return opt::optional<PocoJsonObject>();
@ -382,8 +383,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.type() == typeid(Poco::JSON::Object::Ptr)) {
result = value.extract<Poco::JSON::Object::Ptr>()->size();
if (m_value.type() == typeid(Poco::JSON::Object::Ptr)) {
result = m_value.extract<Poco::JSON::Object::Ptr>()->size();
return true;
}
@ -392,8 +393,8 @@ public:
bool getString(std::string &result) const
{
if (value.isString()) {
result = value.convert<std::string>();
if (m_value.isString()) {
result = m_value.convert<std::string>();
return true;
}
@ -407,42 +408,42 @@ public:
bool isArray() const
{
return value.type() == typeid(Poco::JSON::Array::Ptr);
return m_value.type() == typeid(Poco::JSON::Array::Ptr);
}
bool isBool() const
{
return value.isBoolean();
return m_value.isBoolean();
}
bool isDouble() const
{
return value.isNumeric() && !value.isInteger();
return m_value.isNumeric() && !m_value.isInteger();
}
bool isInteger() const
{
return !isBool() && value.isInteger();
return !isBool() && m_value.isInteger();
}
bool isNull() const
{
return value.isEmpty();
return m_value.isEmpty();
}
bool isNumber() const
{
return value.isNumeric();
return m_value.isNumeric();
}
bool isObject() const
{
return value.type() == typeid(Poco::JSON::Object::Ptr);
return m_value.type() == typeid(Poco::JSON::Object::Ptr);
}
bool isString() const
{
return value.isString();
return m_value.isString();
}
private:
@ -455,7 +456,7 @@ private:
}
/// Contained value
Poco::Dynamic::Var value;
Poco::Dynamic::Var m_value;
};
/**
@ -495,12 +496,14 @@ public:
*
* @see PocoJsonArray
*/
class PocoJsonArrayValueIterator :
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
PocoJsonAdapter> // value type
class PocoJsonArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = PocoJsonAdapter;
using difference_type = PocoJsonAdapter;
using pointer = PocoJsonAdapter*;
using reference = PocoJsonAdapter&;
/**
* @brief Construct a new PocoJsonArrayValueIterator using an existing
@ -509,14 +512,14 @@ public:
* @param itr PocoJson iterator to store
*/
PocoJsonArrayValueIterator(const Poco::JSON::Array::ConstIterator &itr)
: itr(itr)
: m_itr(itr)
{ }
/// Returns a PocoJsonAdapter that contains the value of the current
/// element.
PocoJsonAdapter operator*() const
{
return PocoJsonAdapter(*itr);
return PocoJsonAdapter(*m_itr);
}
DerefProxy<PocoJsonAdapter> operator->() const
@ -537,42 +540,42 @@ public:
*/
bool operator==(const PocoJsonArrayValueIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const PocoJsonArrayValueIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const PocoJsonArrayValueIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
PocoJsonArrayValueIterator operator++(int)
{
PocoJsonArrayValueIterator iterator_pre(itr);
PocoJsonArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const PocoJsonArrayValueIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
itr += n;
m_itr += n;
}
private:
Poco::JSON::Array::ConstIterator itr;
Poco::JSON::Array::ConstIterator m_itr;
};
@ -586,12 +589,14 @@ private:
* @see PocoJsonObject
* @see PocoJsonObjectMember
*/
class PocoJsonObjectMemberIterator :
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
PocoJsonObjectMember> // value type
class PocoJsonObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = PocoJsonObjectMember;
using difference_type = PocoJsonObjectMember;
using pointer = PocoJsonObjectMember*;
using reference = PocoJsonObjectMember&;
/**
* @brief Construct an iterator from a PocoJson iterator.
@ -599,7 +604,7 @@ public:
* @param itr PocoJson iterator to store
*/
PocoJsonObjectMemberIterator(const Poco::JSON::Object::ConstIterator &itr)
: itr(itr)
: m_itr(itr)
{ }
/**
@ -608,7 +613,7 @@ public:
*/
PocoJsonObjectMember operator*() const
{
return PocoJsonObjectMember(itr->first, itr->second);
return PocoJsonObjectMember(m_itr->first, m_itr->second);
}
DerefProxy<PocoJsonObjectMember> operator->() const
@ -629,39 +634,39 @@ public:
*/
bool operator==(const PocoJsonObjectMemberIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const PocoJsonObjectMemberIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const PocoJsonObjectMemberIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
PocoJsonObjectMemberIterator operator++(int)
{
PocoJsonObjectMemberIterator iterator_pre(itr);
PocoJsonObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const PocoJsonObjectMemberIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
private:
/// Iternal copy of the original PocoJson iterator
Poco::JSON::Object::ConstIterator itr;
/// Internal copy of the original PocoJson iterator
Poco::JSON::Object::ConstIterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for PocoJsonAdapter.
@ -678,32 +683,29 @@ struct AdapterTraits<valijson::adapters::PocoJsonAdapter>
inline PocoJsonArrayValueIterator PocoJsonArray::begin() const
{
return value.extract<Poco::JSON::Array::Ptr>()->begin();
return m_value.extract<Poco::JSON::Array::Ptr>()->begin();
}
inline PocoJsonArrayValueIterator PocoJsonArray::end() const
{
return value.extract<Poco::JSON::Array::Ptr>()->end();
return m_value.extract<Poco::JSON::Array::Ptr>()->end();
}
inline PocoJsonObjectMemberIterator PocoJsonObject::begin() const
{
return value.extract<Poco::JSON::Object::Ptr>()->begin();
return m_value.extract<Poco::JSON::Object::Ptr>()->begin();
}
inline PocoJsonObjectMemberIterator PocoJsonObject::end() const
{
return value.extract<Poco::JSON::Object::Ptr>()->end();
return m_value.extract<Poco::JSON::Object::Ptr>()->end();
}
inline PocoJsonObjectMemberIterator PocoJsonObject::find(
const std::string &propertyName) const
inline PocoJsonObjectMemberIterator PocoJsonObject::find(const std::string &propertyName) const
{
auto& ptr = value.extract<Poco::JSON::Object::Ptr>();
auto& ptr = m_value.extract<Poco::JSON::Object::Ptr>();
auto it = std::find_if(ptr->begin(), ptr->end(),
[&propertyName](const Poco::JSON::Object::ValueType& p)
{
auto it = std::find_if(ptr->begin(), ptr->end(), [&propertyName](const Poco::JSON::Object::ValueType& p) {
return p.first == propertyName;
});
return it;
@ -711,7 +713,7 @@ inline PocoJsonObjectMemberIterator PocoJsonObject::find(
inline bool PocoJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return PocoJsonAdapter(value).equalTo(other, strict);
return PocoJsonAdapter(m_value).equalTo(other, strict);
}
} // namespace adapters

View File

@ -29,9 +29,9 @@
#include <boost/property_tree/ptree.hpp>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
namespace valijson {
namespace adapters {
@ -61,10 +61,10 @@ public:
typedef PropertyTreeArrayValueIterator const_iterator;
typedef PropertyTreeArrayValueIterator iterator;
/// Construct a PropertyTreeArra7 referencing an empty property tree
/// Construct a PropertyTreeArray referencing an empty property tree
/// singleton.
PropertyTreeArray()
: array(emptyTree()) { }
: m_array(emptyTree()) { }
/**
* @brief Construct PropertyTreeArray referencing a specific Boost
@ -76,7 +76,7 @@ public:
* checked due to runtime cost.
*/
explicit PropertyTreeArray(const boost::property_tree::ptree &array)
: array(array) { }
: m_array(array) { }
/// Return an iterator for the first element in the array.
PropertyTreeArrayValueIterator begin() const;
@ -87,7 +87,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
return array.size();
return m_array.size();
}
private:
@ -105,7 +105,7 @@ private:
}
/// Reference to the contained value
const boost::property_tree::ptree &array;
const boost::property_tree::ptree &m_array;
};
/**
@ -129,7 +129,7 @@ public:
/// Construct a PropertyTreeObject referencing an empty property tree.
PropertyTreeObject()
: object(emptyTree()) { }
: m_object(emptyTree()) { }
/**
* @brief Construct a PropertyTreeObject referencing a specific property
@ -141,7 +141,7 @@ public:
* runtime cost of doing so.
*/
PropertyTreeObject(const boost::property_tree::ptree &object)
: object(object) { }
: m_object(object) { }
/**
* @brief Return an iterator for this first object member
@ -176,7 +176,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
return object.size();
return m_object.size();
}
private:
@ -193,7 +193,7 @@ private:
}
/// Reference to the contained object
const boost::property_tree::ptree &object;
const boost::property_tree::ptree &m_object;
};
@ -213,32 +213,30 @@ public:
/**
* @brief Make a copy of a Boost property tree POD value
*
* @param source string containing the POD vlaue
* @param source string containing the POD value
*/
explicit PropertyTreeFrozenValue(
const boost::property_tree::ptree::data_type &source)
: value(source) { }
explicit PropertyTreeFrozenValue(const boost::property_tree::ptree::data_type &source)
: m_value(source) { }
/**
* @brief Make a copy of a Boost property tree object or array value
*
* @param source the property tree to be copied
*/
explicit PropertyTreeFrozenValue(
const boost::property_tree::ptree &source)
: value(source) { }
explicit PropertyTreeFrozenValue(const boost::property_tree::ptree &source)
: m_value(source) { }
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new PropertyTreeFrozenValue(value);
return new PropertyTreeFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored value
boost::property_tree::ptree value;
boost::property_tree::ptree m_value;
};
/**
@ -261,7 +259,8 @@ public:
/// Construct a wrapper for an empty property tree
PropertyTreeValue()
: object(emptyTree()) { }
: m_array(nullptr)
, m_object(&emptyTree()) { }
/**
* @brief Construct a PropertyTreeValue from a tree object
@ -277,28 +276,29 @@ public:
* @param tree Tree object to be wrapped
*/
PropertyTreeValue(const boost::property_tree::ptree &tree)
: m_array(nullptr)
, m_object(nullptr)
{
if (tree.data().empty()) { // No string content
if (tree.size() == 0) { // No children
array.emplace(tree); // Treat as empty array
if (tree.data().empty()) { // No string content
if (tree.empty()) { // No children
m_array = &tree; // Treat as empty array
} else {
bool isArray = true;
boost::property_tree::ptree::const_iterator itr;
for (itr = tree.begin(); itr != tree.end(); itr++) {
if (!itr->first.empty()) {
for (const auto &node : tree) {
if (!node.first.empty()) {
isArray = false;
break;
}
}
if (isArray) {
array.emplace(tree);
m_array = &tree;
} else {
object.emplace(tree);
m_object = &tree;
}
}
} else {
value = tree.data();
m_value = tree.data();
}
}
@ -311,12 +311,12 @@ public:
*/
FrozenValue* freeze() const
{
if (array) {
return new PropertyTreeFrozenValue(*array);
} else if (object) {
return new PropertyTreeFrozenValue(*object);
if (m_array) {
return new PropertyTreeFrozenValue(*m_array);
} else if (m_object) {
return new PropertyTreeFrozenValue(*m_object);
} else {
return new PropertyTreeFrozenValue(*value);
return new PropertyTreeFrozenValue(*m_value);
}
}
@ -331,11 +331,11 @@ public:
*/
opt::optional<PropertyTreeArray> getArrayOptional() const
{
if (array) {
return opt::make_optional(PropertyTreeArray(*array));
if (m_array) {
return opt::make_optional(PropertyTreeArray(*m_array));
}
return opt::optional<PropertyTreeArray>();
return {};
}
/**
@ -351,25 +351,25 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (array) {
result = array->size();
if (m_array) {
result = m_array->size();
return true;
}
return false;
}
bool getBool(bool &) const
static bool getBool(bool &)
{
return false;
}
bool getDouble(double &) const
static bool getDouble(double &)
{
return false;
}
bool getInteger(int64_t &) const
static bool getInteger(int64_t &)
{
return false;
}
@ -385,11 +385,11 @@ public:
*/
opt::optional<PropertyTreeObject> getObjectOptional() const
{
if (object) {
return opt::make_optional(PropertyTreeObject(*object));
if (m_object) {
return opt::make_optional(PropertyTreeObject(*m_object));
}
return opt::optional<PropertyTreeObject>();
return {};
}
/**
@ -405,8 +405,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (object) {
result = object->size();
if (m_object) {
result = m_object->size();
return true;
}
@ -415,8 +415,8 @@ public:
bool getString(std::string &result) const
{
if (value) {
result = *value;
if (m_value) {
result = *m_value;
return true;
}
@ -430,42 +430,42 @@ public:
bool isArray() const
{
return static_cast<bool>(array);
return static_cast<bool>(m_array);
}
bool isBool() const
static bool isBool()
{
return false;
}
bool isDouble() const
static bool isDouble()
{
return false;
}
bool isInteger() const
static bool isInteger()
{
return false;
}
bool isNull() const
static bool isNull()
{
return false;
}
bool isNumber() const
static bool isNumber()
{
return false;
}
bool isObject() const
{
return static_cast<bool>(object);
return static_cast<bool>(m_object);
}
bool isString() const
{
return static_cast<bool>(value);
return static_cast<bool>(m_value);
}
private:
@ -477,13 +477,15 @@ private:
}
/// Reference used if the value is known to be an array
opt::optional<const boost::property_tree::ptree &> array;
// opt::optional<const boost::property_tree::ptree &> m_array;
const boost::property_tree::ptree *m_array;
/// Reference used if the value is known to be an object
opt::optional<const boost::property_tree::ptree &> object;
// opt::optional<const boost::property_tree::ptree &> m_object;
const boost::property_tree::ptree *m_object;
/// Reference used if the value is known to be a POD type
opt::optional<std::string> value;
opt::optional<std::string> m_value;
};
/**
@ -523,12 +525,14 @@ public:
*
* @see PropertyTreeArray
*/
class PropertyTreeArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
PropertyTreeAdapter> // value type
class PropertyTreeArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = PropertyTreeAdapter;
using difference_type = PropertyTreeAdapter;
using pointer = PropertyTreeAdapter*;
using reference = PropertyTreeAdapter&;
/**
* @brief Construct a new PropertyTreeArrayValueIterator using an existing
@ -538,13 +542,13 @@ public:
*/
PropertyTreeArrayValueIterator(
const boost::property_tree::ptree::const_iterator &itr)
: itr(itr) { }
: m_itr(itr) { }
/// Returns a PropertyTreeAdapter that contains the value of the current
/// element.
PropertyTreeAdapter operator*() const
{
return PropertyTreeAdapter(itr->second);
return PropertyTreeAdapter(m_itr->second);
}
DerefProxy<PropertyTreeAdapter> operator->() const
@ -565,31 +569,31 @@ public:
*/
bool operator==(const PropertyTreeArrayValueIterator &rhs) const
{
return itr == rhs.itr;
return m_itr == rhs.m_itr;
}
bool operator!=(const PropertyTreeArrayValueIterator &rhs) const
{
return !(itr == rhs.itr);
return !(m_itr == rhs.m_itr);
}
const PropertyTreeArrayValueIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
PropertyTreeArrayValueIterator operator++(int)
{
PropertyTreeArrayValueIterator iterator_pre(itr);
PropertyTreeArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const PropertyTreeArrayValueIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
@ -598,18 +602,18 @@ public:
{
if (n > 0) {
while (n-- > 0) {
itr++;
m_itr++;
}
} else {
while (n++ < 0) {
itr--;
m_itr--;
}
}
}
private:
boost::property_tree::ptree::const_iterator itr;
boost::property_tree::ptree::const_iterator m_itr;
};
/**
@ -622,12 +626,14 @@ private:
* @see PropertyTreeObject
* @see PropertyTreeObjectMember
*/
class PropertyTreeObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
PropertyTreeObjectMember> // value type
class PropertyTreeObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = PropertyTreeObjectMember;
using difference_type = PropertyTreeObjectMember;
using pointer = PropertyTreeObjectMember*;
using reference = PropertyTreeObjectMember&;
/**
* @brief Construct an iterator from a PropertyTree iterator.
@ -636,7 +642,7 @@ public:
*/
PropertyTreeObjectMemberIterator(
boost::property_tree::ptree::const_assoc_iterator itr)
: itr(itr) { }
: m_itr(itr) { }
/**
* @brief Returns a PropertyTreeObjectMember that contains the key and
@ -644,7 +650,7 @@ public:
*/
PropertyTreeObjectMember operator*() const
{
return PropertyTreeObjectMember(itr->first, itr->second);
return PropertyTreeObjectMember(m_itr->first, m_itr->second);
}
DerefProxy<PropertyTreeObjectMember> operator->() const
@ -665,38 +671,38 @@ public:
*/
bool operator==(const PropertyTreeObjectMemberIterator &rhs) const
{
return itr == rhs.itr;
return m_itr == rhs.m_itr;
}
bool operator!=(const PropertyTreeObjectMemberIterator &rhs) const
{
return !(itr == rhs.itr);
return !(m_itr == rhs.m_itr);
}
const PropertyTreeObjectMemberIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
PropertyTreeObjectMemberIterator operator++(int)
{
PropertyTreeObjectMemberIterator iterator_pre(itr);
PropertyTreeObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const PropertyTreeObjectMemberIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
private:
boost::property_tree::ptree::const_assoc_iterator itr;
boost::property_tree::ptree::const_assoc_iterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for PropertyTreeAdapter.
@ -713,40 +719,39 @@ struct AdapterTraits<valijson::adapters::PropertyTreeAdapter>
inline bool PropertyTreeFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return PropertyTreeAdapter(value).equalTo(other, strict);
return PropertyTreeAdapter(m_value).equalTo(other, strict);
}
inline PropertyTreeArrayValueIterator PropertyTreeArray::begin() const
{
return array.begin();
return m_array.begin();
}
inline PropertyTreeArrayValueIterator PropertyTreeArray::end() const
{
return array.end();
return m_array.end();
}
inline PropertyTreeObjectMemberIterator PropertyTreeObject::begin() const
{
return object.ordered_begin();
return m_object.ordered_begin();
}
inline PropertyTreeObjectMemberIterator PropertyTreeObject::end() const
{
return object.not_found();
return m_object.not_found();
}
inline PropertyTreeObjectMemberIterator PropertyTreeObject::find(
const std::string &propertyName) const
{
const boost::property_tree::ptree::const_assoc_iterator
itr = object.find(propertyName);
const boost::property_tree::ptree::const_assoc_iterator itr = m_object.find(propertyName);
if (itr != object.not_found()) {
if (itr != m_object.not_found()) {
return itr;
}
return object.not_found();
return m_object.not_found();
}
} // namespace adapters

View File

@ -26,14 +26,16 @@
#pragma once
#include <string>
#include <utility>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -64,7 +66,7 @@ public:
/// Construct a QtJsonArray referencing an empty array.
QtJsonArray()
: value(emptyArray())
: m_value(emptyArray())
{
}
@ -78,10 +80,10 @@ public:
* an array.
*/
explicit QtJsonArray(const QJsonValue &value)
: value(value.toArray())
: m_value(value.toArray())
{
if (!value.isArray()) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -104,7 +106,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
return value.size();
return m_value.size();
}
private:
@ -114,14 +116,14 @@ private:
*
* Note that the value returned by this function is a singleton.
*/
static const QJsonArray emptyArray()
static QJsonArray emptyArray()
{
static const QJsonArray array;
return array;
}
/// Reference to the contained value
const QJsonArray value;
const QJsonArray m_value;
};
/**
@ -144,7 +146,7 @@ public:
/// Construct a QtJsonObject referencing an empty object singleton.
QtJsonObject()
: value(emptyObject())
: m_value(emptyObject())
{
}
@ -158,10 +160,10 @@ public:
* an object.
*/
QtJsonObject(const QJsonValue &value)
: value(value.toObject())
: m_value(value.toObject())
{
if (!value.isObject()) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -196,7 +198,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
return value.size();
return m_value.size();
}
private:
@ -213,7 +215,7 @@ private:
}
/// Reference to the contained object
const QJsonObject value;
const QJsonObject m_value;
};
/**
@ -234,20 +236,20 @@ public:
*
* @param source the QtJson value to be copied
*/
explicit QtJsonFrozenValue(const QJsonValue &source)
: value(source) { }
explicit QtJsonFrozenValue(QJsonValue source)
: m_value(std::move(source)) { }
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new QtJsonFrozenValue(value);
return new QtJsonFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored QtJson value
QJsonValue value;
QJsonValue m_value;
};
/**
@ -270,11 +272,11 @@ public:
/// Construct a wrapper for the empty object singleton
QtJsonValue()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/// Construct a wrapper for a specific QtJson value
QtJsonValue(const QJsonValue &value)
: value(value) { }
QtJsonValue(QJsonValue value)
: m_value(std::move(value)) { }
/**
* @brief Create a new QtJsonFrozenValue instance that contains the
@ -285,7 +287,7 @@ public:
*/
FrozenValue * freeze() const
{
return new QtJsonFrozenValue(value);
return new QtJsonFrozenValue(m_value);
}
/**
@ -299,8 +301,8 @@ public:
*/
opt::optional<QtJsonArray> getArrayOptional() const
{
if (value.isArray()) {
return opt::make_optional(QtJsonArray(value));
if (m_value.isArray()) {
return opt::make_optional(QtJsonArray(m_value));
}
return opt::optional<QtJsonArray>();
@ -319,8 +321,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.isArray()) {
const QJsonArray array = value.toArray();
if (m_value.isArray()) {
const QJsonArray array = m_value.toArray();
result = array.size();
return true;
}
@ -330,8 +332,8 @@ public:
bool getBool(bool &result) const
{
if (value.isBool()) {
result = value.toBool();
if (m_value.isBool()) {
result = m_value.toBool();
return true;
}
@ -340,8 +342,8 @@ public:
bool getDouble(double &result) const
{
if (value.isDouble()) {
result = value.toDouble();
if (m_value.isDouble()) {
result = m_value.toDouble();
return true;
}
@ -350,8 +352,8 @@ public:
bool getInteger(int64_t &result) const
{
if (value.isDouble()) {
result = value.toInt();
if (m_value.isDouble()) {
result = m_value.toInt();
return true;
}
@ -369,8 +371,8 @@ public:
*/
opt::optional<QtJsonObject> getObjectOptional() const
{
if (value.isObject()) {
return opt::make_optional(QtJsonObject(value));
if (m_value.isObject()) {
return opt::make_optional(QtJsonObject(m_value));
}
return opt::optional<QtJsonObject>();
@ -389,8 +391,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.isObject()) {
const QJsonObject &object = value.toObject();
if (m_value.isObject()) {
const QJsonObject &object = m_value.toObject();
result = object.size();
return true;
}
@ -400,8 +402,8 @@ public:
bool getString(std::string &result) const
{
if (value.isString()) {
result = value.toString().toStdString();
if (m_value.isString()) {
result = m_value.toString().toStdString();
return true;
}
@ -415,56 +417,56 @@ public:
bool isArray() const
{
return value.isArray();
return m_value.isArray();
}
bool isBool() const
{
return value.isBool();
return m_value.isBool();
}
bool isDouble() const
{
return value.isDouble();
return m_value.isDouble();
}
bool isInteger() const
{
//toInt returns the default value (0, 1) if the value is not a whole number
return value.isDouble() && (value.toInt(0) == value.toInt(1));
return m_value.isDouble() && (m_value.toInt(0) == m_value.toInt(1));
}
bool isNull() const
{
return value.isNull();
return m_value.isNull();
}
bool isNumber() const
{
return value.isDouble();
return m_value.isDouble();
}
bool isObject() const
{
return value.isObject();
return m_value.isObject();
}
bool isString() const
{
return value.isString();
return m_value.isString();
}
private:
/// Return a reference to an empty object singleton
static const QJsonValue emptyObject()
static QJsonValue emptyObject()
{
static const QJsonValue object;
return object;
}
/// Reference to the contained QtJson value.
const QJsonValue value;
const QJsonValue m_value;
};
/**
@ -498,17 +500,18 @@ public:
* @brief Class for iterating over values held in a JSON array.
*
* This class provides a JSON array iterator that dereferences as an instance of
* QtJsonAdapter representing a value stored in the array. It has been
* implemented using the std::iterator template.
* QtJsonAdapter representing a value stored in the array.
*
* @see QtJsonArray
*/
class QtJsonArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
QtJsonAdapter> // value type
class QtJsonArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = QtJsonAdapter;
using difference_type = QtJsonAdapter;
using pointer = QtJsonAdapter*;
using reference = QtJsonAdapter&;
/**
* @brief Construct a new QtJsonArrayValueIterator using an existing
@ -516,15 +519,14 @@ public:
*
* @param itr QtJson iterator to store
*/
QtJsonArrayValueIterator(
const QJsonArray::const_iterator &itr)
: itr(itr) { }
QtJsonArrayValueIterator(const QJsonArray::const_iterator &itr)
: m_itr(itr) { }
/// Returns a QtJsonAdapter that contains the value of the current
/// element.
QtJsonAdapter operator*() const
{
return QtJsonAdapter(*itr);
return QtJsonAdapter(*m_itr);
}
DerefProxy<QtJsonAdapter> operator->() const
@ -545,43 +547,43 @@ public:
*/
bool operator==(const QtJsonArrayValueIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const QtJsonArrayValueIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const QtJsonArrayValueIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
QtJsonArrayValueIterator operator++(int)
{
QtJsonArrayValueIterator iterator_pre(itr);
QtJsonArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const QtJsonArrayValueIterator& operator--()
{
itr--;
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
itr += n;
m_itr += n;
}
private:
QJsonArray::const_iterator itr;
QJsonArray::const_iterator m_itr;
};
/**
@ -594,21 +596,22 @@ private:
* @see QtJsonObject
* @see QtJsonObjectMember
*/
class QtJsonObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
QtJsonObjectMember> // value type
class QtJsonObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = QtJsonObjectMember;
using difference_type = QtJsonObjectMember;
using pointer = QtJsonObjectMember*;
using reference = QtJsonObjectMember&;
/**
* @brief Construct an iterator from a QtJson iterator.
*
* @param itr QtJson iterator to store
*/
QtJsonObjectMemberIterator(
const QJsonObject::const_iterator &itr)
: itr(itr) { }
QtJsonObjectMemberIterator(const QJsonObject::const_iterator &itr)
: m_itr(itr) { }
/**
* @brief Returns a QtJsonObjectMember that contains the key and value
@ -616,8 +619,8 @@ public:
*/
QtJsonObjectMember operator*() const
{
std::string key = itr.key().toStdString();
return QtJsonObjectMember(key, itr.value());
std::string key = m_itr.key().toStdString();
return QtJsonObjectMember(key, m_itr.value());
}
DerefProxy<QtJsonObjectMember> operator->() const
@ -638,39 +641,38 @@ public:
*/
bool operator==(const QtJsonObjectMemberIterator &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const QtJsonObjectMemberIterator &other) const
{
return !(itr == other.itr);
return !(m_itr == other.m_itr);
}
const QtJsonObjectMemberIterator& operator++()
{
itr++;
m_itr++;
return *this;
}
QtJsonObjectMemberIterator operator++(int)
{
QtJsonObjectMemberIterator iterator_pre(itr);
QtJsonObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
const QtJsonObjectMemberIterator& operator--(int)
{
itr--;
m_itr--;
return *this;
}
private:
/// Iternal copy of the original QtJson iterator
QJsonObject::const_iterator itr;
/// Internal copy of the original QtJson iterator
QJsonObject::const_iterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for QtJsonAdapter.
@ -687,33 +689,33 @@ struct AdapterTraits<valijson::adapters::QtJsonAdapter>
inline bool QtJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return QtJsonAdapter(value).equalTo(other, strict);
return QtJsonAdapter(m_value).equalTo(other, strict);
}
inline QtJsonArrayValueIterator QtJsonArray::begin() const
{
return value.begin();
return m_value.begin();
}
inline QtJsonArrayValueIterator QtJsonArray::end() const
{
return value.end();
return m_value.end();
}
inline QtJsonObjectMemberIterator QtJsonObject::begin() const
{
return value.begin();
return m_value.begin();
}
inline QtJsonObjectMemberIterator QtJsonObject::end() const
{
return value.end();
return m_value.end();
}
inline QtJsonObjectMemberIterator QtJsonObject::find(
const std::string &propertyName) const
{
return value.find(QString::fromStdString(propertyName));
return m_value.find(QString::fromStdString(propertyName));
}
} // namespace adapters

View File

@ -43,11 +43,30 @@
#include <string>
#include <iterator>
#ifdef VALIJSON_USE_EXCEPTIONS
#ifdef RAPIDJSON_ASSERT
#warning "RAPIDJSON_ASSERT already defined."
#warning "Please include valijson/adapters/rapidjson_adapter.hpp before any RapidJSON headers."
#else
template<typename T>
T rapidjson_assert(T t, const std::string& file, const int line) {
if (t) {
return t;
}
throw std::runtime_error("assertion failed; file: " + file + "; line: " + std::to_string(line));
}
#define RAPIDJSON_ASSERT(x) rapidjson_assert(x, __FILE__, __LINE__)
#endif
#endif
#include <rapidjson/document.h>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -64,10 +83,10 @@ class GenericRapidJsonObjectMemberIterator;
/// Container for a property name and an associated RapidJson value
template<class ValueType = rapidjson::Value>
class GenericRapidJsonObjectMember :
public std::pair<std::string, GenericRapidJsonAdapter<ValueType> >
public std::pair<std::string, GenericRapidJsonAdapter<ValueType>>
{
private:
typedef std::pair<std::string, GenericRapidJsonAdapter<ValueType> > Super;
typedef std::pair<std::string, GenericRapidJsonAdapter<ValueType>> Super;
public:
GenericRapidJsonObjectMember(
@ -97,7 +116,7 @@ public:
/// Construct a RapidJsonArray referencing an empty array singleton.
GenericRapidJsonArray()
: value(emptyArray()) { }
: m_value(emptyArray()) { }
/**
* @brief Construct a RapidJsonArray referencing a specific RapidJson
@ -109,10 +128,10 @@ public:
* an array.
*/
GenericRapidJsonArray(const ValueType &value)
: value(value)
: m_value(value)
{
if (!value.IsArray()) {
throw std::runtime_error("Value is not an array.");
throwRuntimeError("Value is not an array.");
}
}
@ -125,7 +144,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
return value.Size();
return m_value.Size();
}
private:
@ -142,7 +161,7 @@ private:
}
/// Reference to the contained value
const ValueType &value;
const ValueType &m_value;
};
/**
@ -166,7 +185,7 @@ public:
/// Construct a GenericRapidJsonObject referencing an empty object singleton.
GenericRapidJsonObject()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/**
* @brief Construct a GenericRapidJsonObject referencing a specific
@ -178,10 +197,10 @@ public:
* an object.
*/
GenericRapidJsonObject(const ValueType &value)
: value(value)
: m_value(value)
{
if (!value.IsObject()) {
throw std::runtime_error("Value is not an object.");
throwRuntimeError("Value is not an object.");
}
}
@ -216,7 +235,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
return value.MemberEnd() - value.MemberBegin();
return m_value.MemberEnd() - m_value.MemberBegin();
}
private:
@ -233,7 +252,7 @@ private:
}
/// Reference to the contained object
const ValueType &value;
const ValueType &m_value;
};
/**
@ -254,12 +273,12 @@ public:
explicit GenericRapidJsonFrozenValue(const char *str)
{
value.SetString(str, allocator);
m_value.SetString(str, m_allocator);
}
explicit GenericRapidJsonFrozenValue(const std::string &str)
{
value.SetString(str.c_str(), (unsigned int)str.length(), allocator);
m_value.SetString(str.c_str(), (unsigned int)str.length(), m_allocator);
}
/**
@ -269,17 +288,17 @@ public:
*/
explicit GenericRapidJsonFrozenValue(const ValueType &source)
{
if (!copy(source, value, allocator)) {
throw std::runtime_error("Failed to copy ValueType");
if (!copy(source, m_value, m_allocator)) {
throwRuntimeError("Failed to copy ValueType");
}
}
virtual FrozenValue * clone() const
FrozenValue * clone() const override
{
return new GenericRapidJsonFrozenValue(value);
return new GenericRapidJsonFrozenValue(m_value);
}
virtual bool equalTo(const Adapter &other, bool strict) const;
bool equalTo(const Adapter &other, bool strict) const override;
private:
@ -311,8 +330,7 @@ private:
return true;
case rapidjson::kObjectType:
dest.SetObject();
for (typename ValueType::ConstMemberIterator itr = source.MemberBegin();
itr != source.MemberEnd(); ++itr) {
for (typename ValueType::ConstMemberIterator itr = source.MemberBegin(); itr != source.MemberEnd(); ++itr) {
ValueType name(itr->name.GetString(), itr->name.GetStringLength(), allocator);
ValueType value;
copy(itr->value, value, allocator);
@ -351,10 +369,10 @@ private:
}
/// Local memory allocator for RapidJson value
typename ValueType::AllocatorType allocator;
typename ValueType::AllocatorType m_allocator;
/// Local RapidJson value
ValueType value;
ValueType m_value;
};
/**
@ -377,11 +395,11 @@ class GenericRapidJsonValue
public:
/// Construct a wrapper for the empty object singleton
GenericRapidJsonValue()
: value(emptyObject()) { }
: m_value(emptyObject()) { }
/// Construct a wrapper for a specific RapidJson value
GenericRapidJsonValue(const ValueType &value)
: value(value) { }
: m_value(value) { }
/**
* @brief Create a new GenericRapidJsonFrozenValue instance that contains
@ -392,7 +410,7 @@ public:
*/
FrozenValue * freeze() const
{
return new GenericRapidJsonFrozenValue<ValueType>(value);
return new GenericRapidJsonFrozenValue<ValueType>(m_value);
}
/**
@ -404,13 +422,13 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<GenericRapidJsonArray<ValueType> > getArrayOptional() const
opt::optional<GenericRapidJsonArray<ValueType>> getArrayOptional() const
{
if (value.IsArray()) {
return opt::make_optional(GenericRapidJsonArray<ValueType>(value));
if (m_value.IsArray()) {
return opt::make_optional(GenericRapidJsonArray<ValueType>(m_value));
}
return opt::optional<GenericRapidJsonArray<ValueType> >();
return {};
}
/**
@ -426,8 +444,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (value.IsArray()) {
result = value.Size();
if (m_value.IsArray()) {
result = m_value.Size();
return true;
}
@ -436,8 +454,8 @@ public:
bool getBool(bool &result) const
{
if (value.IsBool()) {
result = value.GetBool();
if (m_value.IsBool()) {
result = m_value.GetBool();
return true;
}
@ -446,8 +464,8 @@ public:
bool getDouble(double &result) const
{
if (value.IsDouble()) {
result = value.GetDouble();
if (m_value.IsDouble()) {
result = m_value.GetDouble();
return true;
}
@ -456,17 +474,17 @@ public:
bool getInteger(int64_t &result) const
{
if (value.IsInt()) {
result = value.GetInt();
if (m_value.IsInt()) {
result = m_value.GetInt();
return true;
} else if (value.IsInt64()) {
result = value.GetInt64();
} else if (m_value.IsInt64()) {
result = m_value.GetInt64();
return true;
} else if (value.IsUint()) {
result = static_cast<int64_t>(value.GetUint());
} else if (m_value.IsUint()) {
result = static_cast<int64_t>(m_value.GetUint());
return true;
} else if (value.IsUint64()) {
result = static_cast<int64_t>(value.GetUint64());
} else if (m_value.IsUint64()) {
result = static_cast<int64_t>(m_value.GetUint64());
return true;
}
@ -482,13 +500,13 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<GenericRapidJsonObject<ValueType> > getObjectOptional() const
opt::optional<GenericRapidJsonObject<ValueType>> getObjectOptional() const
{
if (value.IsObject()) {
return opt::make_optional(GenericRapidJsonObject<ValueType>(value));
if (m_value.IsObject()) {
return opt::make_optional(GenericRapidJsonObject<ValueType>(m_value));
}
return opt::optional<GenericRapidJsonObject<ValueType> >();
return {};
}
/**
@ -504,8 +522,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (value.IsObject()) {
result = value.MemberEnd() - value.MemberBegin();
if (m_value.IsObject()) {
result = m_value.MemberEnd() - m_value.MemberBegin();
return true;
}
@ -514,8 +532,8 @@ public:
bool getString(std::string &result) const
{
if (value.IsString()) {
result.assign(value.GetString(), value.GetStringLength());
if (m_value.IsString()) {
result.assign(m_value.GetString(), m_value.GetStringLength());
return true;
}
@ -529,43 +547,42 @@ public:
bool isArray() const
{
return value.IsArray();
return m_value.IsArray();
}
bool isBool() const
{
return value.IsBool();
return m_value.IsBool();
}
bool isDouble() const
{
return value.IsDouble();
return m_value.IsDouble();
}
bool isInteger() const
{
return value.IsInt() || value.IsInt64() || value.IsUint() ||
value.IsUint64();
return m_value.IsInt() || m_value.IsInt64() || m_value.IsUint() || m_value.IsUint64();
}
bool isNull() const
{
return value.IsNull();
return m_value.IsNull();
}
bool isNumber() const
{
return value.IsNumber();
return m_value.IsNumber();
}
bool isObject() const
{
return value.IsObject();
return m_value.IsObject();
}
bool isString() const
{
return value.IsString();
return m_value.IsString();
}
private:
@ -578,7 +595,7 @@ private:
}
/// Reference to the contained RapidJson value.
const ValueType &value;
const ValueType &m_value;
};
/**
@ -596,7 +613,7 @@ class GenericRapidJsonAdapter:
GenericRapidJsonArray<ValueType>,
GenericRapidJsonObjectMember<ValueType>,
GenericRapidJsonObject<ValueType>,
GenericRapidJsonValue<ValueType> >
GenericRapidJsonValue<ValueType>>
{
public:
@ -606,7 +623,7 @@ public:
GenericRapidJsonArray<ValueType>,
GenericRapidJsonObjectMember<ValueType>,
GenericRapidJsonObject<ValueType>,
GenericRapidJsonValue<ValueType> >() { }
GenericRapidJsonValue<ValueType>>() { }
/// Construct a RapidJsonAdapter containing a specific RapidJson value
GenericRapidJsonAdapter(const ValueType &value)
@ -614,25 +631,26 @@ public:
GenericRapidJsonArray<ValueType>,
GenericRapidJsonObjectMember<ValueType>,
GenericRapidJsonObject<ValueType>,
GenericRapidJsonValue<ValueType> >(value) { }
GenericRapidJsonValue<ValueType>>(value) { }
};
/**
* @brief Class for iterating over values held in a JSON array.
*
* This class provides a JSON array iterator that dereferences as an instance of
* RapidJsonAdapter representing a value stored in the array. It has been
* implemented using the std::iterator template.
* RapidJsonAdapter representing a value stored in the array.
*
* @see RapidJsonArray
*/
template<class ValueType>
class GenericRapidJsonArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
GenericRapidJsonAdapter<ValueType> > // value type
class GenericRapidJsonArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = GenericRapidJsonAdapter<ValueType>;
using difference_type = GenericRapidJsonAdapter<ValueType>;
using pointer = GenericRapidJsonAdapter<ValueType>*;
using reference = GenericRapidJsonAdapter<ValueType>&;
/**
* @brief Construct a new GenericRapidJsonArrayValueIterator using an
@ -642,19 +660,19 @@ public:
*/
GenericRapidJsonArrayValueIterator(
const typename ValueType::ConstValueIterator &itr)
: itr(itr) { }
: m_itr(itr) { }
/// Returns a GenericRapidJsonAdapter that contains the value of the current
/// element.
GenericRapidJsonAdapter<ValueType> operator*() const
{
return GenericRapidJsonAdapter<ValueType>(*itr);
return GenericRapidJsonAdapter<ValueType>(*m_itr);
}
/// Returns a proxy for the value of the current element
DerefProxy<GenericRapidJsonAdapter<ValueType> > operator->() const
DerefProxy<GenericRapidJsonAdapter<ValueType>> operator->() const
{
return DerefProxy<GenericRapidJsonAdapter<ValueType> >(**this);
return DerefProxy<GenericRapidJsonAdapter<ValueType>>(**this);
}
/**
@ -670,47 +688,47 @@ public:
*/
bool operator==(const GenericRapidJsonArrayValueIterator<ValueType> &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const GenericRapidJsonArrayValueIterator<ValueType>& other) const
{
return !(itr == other.itr);
return m_itr != other.m_itr;
}
GenericRapidJsonArrayValueIterator<ValueType>& operator++()
{
itr++;
m_itr++;
return *this;
}
GenericRapidJsonArrayValueIterator<ValueType> operator++(int) {
GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(itr);
GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
GenericRapidJsonArrayValueIterator<ValueType>& operator--()
{
itr--;
m_itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
itr += n;
m_itr += n;
}
std::ptrdiff_t difference(const GenericRapidJsonArrayValueIterator<ValueType> &other)
{
return std::distance(itr, other.itr);
return std::distance(m_itr, other.m_itr);
}
private:
typename ValueType::ConstValueIterator itr;
typename ValueType::ConstValueIterator m_itr;
};
/**
@ -718,18 +736,20 @@ private:
*
* This class provides a JSON object iterator that dereferences as an instance
* of GenericRapidJsonObjectMember representing one of the members of the
* object. It has been implemented using the std::iterator template.
* object.
*
* @see GenericRapidJsonObject
* @see GenericRapidJsonObjectMember
*/
template<class ValueType>
class GenericRapidJsonObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
GenericRapidJsonObjectMember<ValueType> > // value type
class GenericRapidJsonObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = GenericRapidJsonObjectMember<ValueType>;
using difference_type = GenericRapidJsonObjectMember<ValueType>;
using pointer = GenericRapidJsonObjectMember<ValueType>*;
using reference = GenericRapidJsonObjectMember<ValueType>&;
/**
* @brief Construct an iterator from a RapidJson iterator.
@ -738,7 +758,7 @@ public:
*/
GenericRapidJsonObjectMemberIterator(
const typename ValueType::ConstMemberIterator &itr)
: itr(itr) { }
: m_itr(itr) { }
/**
@ -748,14 +768,14 @@ public:
GenericRapidJsonObjectMember<ValueType> operator*() const
{
return GenericRapidJsonObjectMember<ValueType>(
std::string(itr->name.GetString(), itr->name.GetStringLength()),
itr->value);
std::string(m_itr->name.GetString(), m_itr->name.GetStringLength()),
m_itr->value);
}
/// Returns a proxy for the value of the current element
DerefProxy<GenericRapidJsonObjectMember<ValueType> > operator->() const
DerefProxy<GenericRapidJsonObjectMember<ValueType>> operator->() const
{
return DerefProxy<GenericRapidJsonObjectMember<ValueType> >(**this);
return DerefProxy<GenericRapidJsonObjectMember<ValueType>>(**this);
}
/**
@ -771,85 +791,77 @@ public:
*/
bool operator==(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
{
return itr == other.itr;
return m_itr == other.m_itr;
}
bool operator!=(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
{
return !(itr == other.itr);
return m_itr != other.m_itr;
}
GenericRapidJsonObjectMemberIterator<ValueType>& operator++()
{
itr++;
m_itr++;
return *this;
}
GenericRapidJsonObjectMemberIterator<ValueType> operator++(int)
{
GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(itr);
GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
GenericRapidJsonObjectMemberIterator<ValueType>& operator--()
{
itr--;
m_itr--;
return *this;
}
std::ptrdiff_t difference(const GenericRapidJsonObjectMemberIterator &other)
{
return std::distance(itr, other.itr);
return std::distance(m_itr, other.m_itr);
}
private:
/// Iternal copy of the original RapidJson iterator
typename ValueType::ConstMemberIterator itr;
/// Internal copy of the original RapidJson iterator
typename ValueType::ConstMemberIterator m_itr;
};
template<class ValueType>
inline bool GenericRapidJsonFrozenValue<ValueType>::equalTo(
const Adapter &other, bool strict) const
inline bool GenericRapidJsonFrozenValue<ValueType>::equalTo(const Adapter &other, bool strict) const
{
return GenericRapidJsonAdapter<ValueType>(value).equalTo(other, strict);
return GenericRapidJsonAdapter<ValueType>(m_value).equalTo(other, strict);
}
template<class ValueType>
inline typename GenericRapidJsonArray<ValueType>::iterator
GenericRapidJsonArray<ValueType>::begin() const
inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::begin() const
{
return value.Begin();
return m_value.Begin();
}
template<class ValueType>
inline typename GenericRapidJsonArray<ValueType>::iterator
GenericRapidJsonArray<ValueType>::end() const
inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::end() const
{
return value.End();
return m_value.End();
}
template<class ValueType>
inline typename GenericRapidJsonObject<ValueType>::iterator GenericRapidJsonObject<ValueType>::begin() const
{
return m_value.MemberBegin();
}
template<class ValueType>
inline typename GenericRapidJsonObject<ValueType>::iterator GenericRapidJsonObject<ValueType>::end() const
{
return m_value.MemberEnd();
}
template<class ValueType>
inline typename GenericRapidJsonObject<ValueType>::iterator
GenericRapidJsonObject<ValueType>::begin() const
{
return value.MemberBegin();
}
template<class ValueType>
inline typename GenericRapidJsonObject<ValueType>::iterator
GenericRapidJsonObject<ValueType>::end() const
{
return value.MemberEnd();
}
template<class ValueType>
inline typename GenericRapidJsonObject<ValueType>::iterator
GenericRapidJsonObject<ValueType>::find(
const std::string &propertyName) const
GenericRapidJsonObject<ValueType>::find(const std::string &propertyName) const
{
// Hack to support older versions of rapidjson where pointers are used as
// the built in iterator type. In those versions, the FindMember function
@ -866,20 +878,18 @@ inline typename GenericRapidJsonObject<ValueType>::iterator
// properties being compared. We get around this by implementing our
// own linear scan.
const size_t propertyNameLength = propertyName.length();
for (typename ValueType::ConstMemberIterator itr = value.MemberBegin();
itr != value.MemberEnd(); ++itr) {
for (typename ValueType::ConstMemberIterator itr = m_value.MemberBegin(); itr != m_value.MemberEnd(); ++itr) {
const size_t memberNameLength = itr->name.GetStringLength();
if (memberNameLength == propertyNameLength &&
strncmp(itr->name.GetString(), propertyName.c_str(),
itr->name.GetStringLength()) == 0) {
strncmp(itr->name.GetString(), propertyName.c_str(), itr->name.GetStringLength()) == 0) {
return itr;
}
}
return value.MemberEnd();
return m_value.MemberEnd();
}
return value.FindMember(propertyName.c_str()); // Times are good.
return m_value.FindMember(propertyName.c_str()); // Times are good.
}
typedef GenericRapidJsonAdapter<> RapidJsonAdapter;
@ -906,18 +916,16 @@ struct AdapterTraits<valijson::adapters::RapidJsonAdapter>
}
};
typedef rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>
RapidJsonCrt;
typedef rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator> RapidJsonCrt;
/**
* @brief Specialisation of the AdapterTraits template struct for a
* RapidJsonAdapter that uses the default CRT allocator
*/
template<>
struct AdapterTraits<valijson::adapters::GenericRapidJsonAdapter<RapidJsonCrt> >
struct AdapterTraits<valijson::adapters::GenericRapidJsonAdapter<RapidJsonCrt>>
{
typedef rapidjson::GenericDocument<rapidjson::UTF8<>,
rapidjson::CrtAllocator> DocumentType;
typedef rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> DocumentType;
static std::string adapterName()
{

View File

@ -0,0 +1,491 @@
/**
* @file
*
* @brief Adapter implementation that wraps a single std::string value
*
* This allows property names to be validated against a schema as though they are a generic JSON
* value, while allowing the rest of Valijson's API to expose property names as plain std::string
* values.
*
* This was added while implementing draft 7 support. This included support for a constraint
* called propertyNames, which can be used to ensure that the property names in an object
* validate against a subschema.
*/
#pragma once
#include <string>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
class StdStringAdapter;
class StdStringArrayValueIterator;
class StdStringObjectMemberIterator;
typedef std::pair<std::string, StdStringAdapter> StdStringObjectMember;
class StdStringArray
{
public:
typedef StdStringArrayValueIterator const_iterator;
typedef StdStringArrayValueIterator iterator;
StdStringArray() = default;
StdStringArrayValueIterator begin() const;
StdStringArrayValueIterator end() const;
static size_t size()
{
return 0;
}
};
class StdStringObject
{
public:
typedef StdStringObjectMemberIterator const_iterator;
typedef StdStringObjectMemberIterator iterator;
StdStringObject() = default;
StdStringObjectMemberIterator begin() const;
StdStringObjectMemberIterator end() const;
StdStringObjectMemberIterator find(const std::string &propertyName) const;
static size_t size()
{
return 0;
}
};
class StdStringFrozenValue: public FrozenValue
{
public:
explicit StdStringFrozenValue(std::string source)
: value(std::move(source)) { }
FrozenValue * clone() const override
{
return new StdStringFrozenValue(value);
}
bool equalTo(const Adapter &other, bool strict) const override;
private:
std::string value;
};
class StdStringAdapter: public Adapter
{
public:
typedef StdStringArray Array;
typedef StdStringObject Object;
typedef StdStringObjectMember ObjectMember;
explicit StdStringAdapter(const std::string &value)
: m_value(value) { }
bool applyToArray(ArrayValueCallback) const override
{
return maybeArray();
}
bool applyToObject(ObjectMemberCallback) const override
{
return maybeObject();
}
StdStringArray asArray() const
{
if (maybeArray()) {
return {};
}
throwRuntimeError("String value cannot be cast to array");
}
bool asBool() const override
{
return true;
}
bool asBool(bool &result) const override
{
result = true;
return true;
}
double asDouble() const override
{
return 0;
}
bool asDouble(double &result) const override
{
result = 0;
return true;
}
int64_t asInteger() const override
{
return 0;
}
bool asInteger(int64_t &result) const override
{
result = 0;
return true;
}
StdStringObject asObject() const
{
if (maybeObject()) {
return {};
}
throwRuntimeError("String value cannot be cast to object");
}
std::string asString() const override
{
return m_value;
}
bool asString(std::string &result) const override
{
result = m_value;
return true;
}
bool equalTo(const Adapter &other, bool strict) const override
{
if (strict && !other.isString()) {
return false;
}
return m_value == other.asString();
}
FrozenValue* freeze() const override
{
return new StdStringFrozenValue(m_value);
}
VALIJSON_NORETURN static StdStringArray getArray()
{
throwNotSupported();
}
VALIJSON_NORETURN size_t getArraySize() const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getArraySize(size_t &) const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getBool() const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getBool(bool &) const override
{
throwNotSupported();
}
VALIJSON_NORETURN double getDouble() const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getDouble(double &) const override
{
throwNotSupported();
}
VALIJSON_NORETURN int64_t getInteger() const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getInteger(int64_t &) const override
{
throwNotSupported();
}
VALIJSON_NORETURN double getNumber() const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getNumber(double &) const override
{
throwNotSupported();
}
VALIJSON_NORETURN size_t getObjectSize() const override
{
throwNotSupported();
}
VALIJSON_NORETURN bool getObjectSize(size_t &) const override
{
throwNotSupported();
}
std::string getString() const override
{
return m_value;
}
bool getString(std::string &result) const override
{
result = m_value;
return true;
}
bool hasStrictTypes() const override
{
return true;
}
bool isArray() const override
{
return false;
}
bool isBool() const override
{
return false;
}
bool isDouble() const override
{
return false;
}
bool isInteger() const override
{
return false;
}
bool isNull() const override
{
return false;
}
bool isNumber() const override
{
return false;
}
bool isObject() const override
{
return false;
}
bool isString() const override
{
return true;
}
bool maybeArray() const override
{
return false;
}
bool maybeBool() const override
{
return m_value == "true" || m_value == "false";
}
bool maybeDouble() const override
{
const char *b = m_value.c_str();
char *e = nullptr;
strtod(b, &e);
return e != b && e == b + m_value.length();
}
bool maybeInteger() const override
{
std::istringstream i(m_value);
int64_t x;
char c;
if (!(i >> x) || i.get(c)) {
return false;
}
return true;
}
bool maybeNull() const override
{
return m_value.empty();
}
bool maybeObject() const override
{
return m_value.empty();
}
bool maybeString() const override
{
return true;
}
private:
const std::string &m_value;
};
class StdStringArrayValueIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = StdStringAdapter;
using difference_type = StdStringAdapter;
using pointer = StdStringAdapter*;
using reference = StdStringAdapter&;
VALIJSON_NORETURN StdStringAdapter operator*() const
{
throwNotSupported();
}
VALIJSON_NORETURN DerefProxy<StdStringAdapter> operator->() const
{
throwNotSupported();
}
bool operator==(const StdStringArrayValueIterator &) const
{
return true;
}
bool operator!=(const StdStringArrayValueIterator &) const
{
return false;
}
VALIJSON_NORETURN const StdStringArrayValueIterator& operator++()
{
throwNotSupported();
}
VALIJSON_NORETURN StdStringArrayValueIterator operator++(int)
{
throwNotSupported();
}
VALIJSON_NORETURN const StdStringArrayValueIterator& operator--()
{
throwNotSupported();
}
VALIJSON_NORETURN void advance(std::ptrdiff_t)
{
throwNotSupported();
}
};
inline StdStringArrayValueIterator StdStringArray::begin() const
{
return {};
}
inline StdStringArrayValueIterator StdStringArray::end() const
{
return {};
}
class StdStringObjectMemberIterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = StdStringObjectMember;
using difference_type = StdStringObjectMember;
using pointer = StdStringObjectMember*;
using reference = StdStringObjectMember&;
VALIJSON_NORETURN StdStringObjectMember operator*() const
{
throwNotSupported();
}
VALIJSON_NORETURN DerefProxy<StdStringObjectMember> operator->() const
{
throwNotSupported();
}
bool operator==(const StdStringObjectMemberIterator &) const
{
return true;
}
bool operator!=(const StdStringObjectMemberIterator &) const
{
return false;
}
VALIJSON_NORETURN const StdStringObjectMemberIterator& operator++()
{
throwNotSupported();
}
VALIJSON_NORETURN StdStringObjectMemberIterator operator++(int)
{
throwNotSupported();
}
VALIJSON_NORETURN const StdStringObjectMemberIterator& operator--()
{
throwNotSupported();
}
};
inline StdStringObjectMemberIterator StdStringObject::begin() const
{
return {};
}
inline StdStringObjectMemberIterator StdStringObject::end() const
{
return {};
}
inline StdStringObjectMemberIterator StdStringObject::find(const std::string &) const
{
return {};
}
template<>
struct AdapterTraits<valijson::adapters::StdStringAdapter>
{
typedef std::string DocumentType;
static std::string adapterName()
{
return "StdStringAdapter";
}
};
inline bool StdStringFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return StdStringAdapter(value).equalTo(other, strict);
}
} // namespace adapters
} // namespace valijson

View File

@ -0,0 +1,694 @@
/**
* @file
*
* @brief Adapter implementation for the yaml-cpp parser library.
*
* Include this file in your program to enable support for yaml-cpp.
*
* This file defines the following classes (not in this order):
* - YamlCppAdapter
* - YamlCppArray
* - YamlCppArrayValueIterator
* - YamlCppFrozenValue
* - YamlCppObject
* - YamlCppObjectMember
* - YamlCppObjectMemberIterator
* - YamlCppValue
*
* Due to the dependencies that exist between these classes, the ordering of
* class declarations and definitions may be a bit confusing. The best place to
* start is YamlCppAdapter. This class definition is actually very small,
* since most of the functionality is inherited from the BasicAdapter class.
* Most of the classes in this file are provided as template arguments to the
* inherited BasicAdapter class.
*/
#pragma once
#include <string>
#include <yaml-cpp/yaml.h>
#include <utility>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
class YamlCppAdapter;
class YamlCppArrayValueIterator;
class YamlCppObjectMemberIterator;
typedef std::pair<std::string, YamlCppAdapter> YamlCppObjectMember;
/**
* @brief Light weight wrapper for a YamlCpp array value.
*
* This class is light weight wrapper for a YamlCpp array. It provides a
* minimum set of container functions and typedefs that allow it to be used as
* an iterable container.
*
* An instance of this class contains a single reference to the underlying
* YamlCpp value, assumed to be an array, so there is very little overhead
* associated with copy construction and passing by value.
*/
class YamlCppArray
{
public:
typedef YamlCppArrayValueIterator const_iterator;
typedef YamlCppArrayValueIterator iterator;
/// Construct a YamlCppArray referencing an empty array.
YamlCppArray() : m_value(emptyArray()) {}
/**
* @brief Construct a YamlCppArray referencing a specific
* YamlCpp value.
*
* @param value reference to a YamlCpp value
*
* Note that this constructor will throw an exception if the value is not
* an array.
*/
YamlCppArray(const YAML::Node &value) : m_value(value)
{
if (!value.IsSequence()) {
throwRuntimeError("Value is not an array.");
}
}
/**
* @brief Return an iterator for the first element of the array.
*
* The iterator return by this function is effectively the iterator
* returned by the underlying YamlCpp implementation.
*/
YamlCppArrayValueIterator begin() const;
/**
* @brief Return an iterator for one-past the last element of the array.
*
* The iterator return by this function is effectively the iterator
* returned by the underlying YamlCpp implementation.
*/
YamlCppArrayValueIterator end() const;
/// Return the number of elements in the array
size_t size() const
{
return m_value.size();
}
private:
/**
* @brief Return a reference to a YamlCpp value that is an empty
* array.
*
* Note that the value returned by this function is a singleton.
*/
static const YAML::Node &emptyArray()
{
static const YAML::Node array = YAML::Node(YAML::NodeType::Sequence);
return array;
}
/// Reference to the contained value
const YAML::Node m_value;
};
/**
* @brief Light weight wrapper for a YamlCpp object.
*
* This class is light weight wrapper for a YamlCpp object. It provides a
* minimum set of container functions and typedefs that allow it to be used as
* an iterable container.
*
* An instance of this class contains a single reference to the underlying
* YamlCpp value, assumed to be an object, so there is very little overhead
* associated with copy construction and passing by value.
*/
class YamlCppObject
{
public:
typedef YamlCppObjectMemberIterator const_iterator;
typedef YamlCppObjectMemberIterator iterator;
/// Construct a YamlCppObject referencing an empty object singleton.
YamlCppObject() : m_value(emptyObject()) {}
/**
* @brief Construct a YamlCppObject referencing a specific
* YamlCpp value.
*
* @param value reference to a YamlCpp value
*
* Note that this constructor will throw an exception if the value is not
* an object.
*/
YamlCppObject(const YAML::Node &value) : m_value(value)
{
if (!value.IsMap()) {
throwRuntimeError("Value is not an object.");
}
}
/**
* @brief Return an iterator for this first object member
*
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying YamlCpp
* implementation.
*/
YamlCppObjectMemberIterator begin() const;
/**
* @brief Return an iterator for an invalid object member that indicates
* the end of the collection.
*
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying YamlCpp
* implementation.
*/
YamlCppObjectMemberIterator end() const;
/**
* @brief Return an iterator for the object member with the specified
* property name.
*
* If an object member with the specified name does not exist, the iterator
* returned will be the same as the iterator returned by the end() function.
*
* @param propertyName property name to search for
*/
YamlCppObjectMemberIterator find(const std::string &propertyName) const;
/// Returns the number of members belonging to this object.
size_t size() const
{
return m_value.size();
}
private:
/**
* @brief Return a reference to a YamlCpp value that is empty object.
*
* Note that the value returned by this function is a singleton.
*/
static const YAML::Node &emptyObject()
{
static const YAML::Node object = YAML::Node(YAML::NodeType::Map);
return object;
}
/// Reference to the contained object
const YAML::Node m_value;
};
/**
* @brief Stores an independent copy of a YamlCpp value.
*
* This class allows a YamlCpp value to be stored independent of its
* original document.
*
* @see FrozenValue
*/
class YamlCppFrozenValue : public FrozenValue
{
public:
/**
* @brief Make a copy of a YamlCpp value
*
* @param source the YamlCpp value to be copied
*/
explicit YamlCppFrozenValue(YAML::Node source)
: m_value(YAML::Clone(source))
{
}
FrozenValue *clone() const override
{
return new YamlCppFrozenValue(m_value);
}
bool equalTo(const Adapter &other, bool strict) const override;
private:
/// Stored YamlCpp value
YAML::Node m_value;
};
/**
* @brief Light weight wrapper for a YamlCpp value.
*
* This class is passed as an argument to the BasicAdapter template class,
* and is used to provide access to a YamlCpp value. This class is
* responsible for the mechanics of actually reading a YamlCpp value,
* whereas the BasicAdapter class is responsible for the semantics of type
* comparisons and conversions.
*
* The functions that need to be provided by this class are defined implicitly
* by the implementation of the BasicAdapter template class.
*
* @see BasicAdapter
*/
class YamlCppValue
{
public:
/// Construct a wrapper for the empty object singleton
YamlCppValue() : m_value(emptyObject()) {}
/// Construct a wrapper for a specific YamlCpp value
YamlCppValue(const YAML::Node &value) : m_value(value) {}
/**
* @brief Create a new YamlCppFrozenValue instance that contains the
* value referenced by this YamlCppValue instance.
*
* @returns pointer to a new YamlCppFrozenValue instance, belonging to
* the caller.
*/
FrozenValue *freeze() const
{
return new YamlCppFrozenValue(m_value);
}
/**
* @brief Optionally return a YamlCppArray instance.
*
* If the referenced YamlCpp value is an array, this function will
* return a std::optional containing a YamlCppArray instance
* referencing the array.
*
* Otherwise it will return an empty optional.
*/
opt::optional<YamlCppArray> getArrayOptional() const
{
if (m_value.IsSequence()) {
return opt::make_optional(YamlCppArray(m_value));
}
return {};
}
/**
* @brief Retrieve the number of elements in the array
*
* If the referenced YamlCpp value is an array, this function will
* retrieve the number of elements in the array and store it in the output
* variable provided.
*
* @param result reference to size_t to set with result
*
* @returns true if the number of elements was retrieved, false otherwise.
*/
bool getArraySize(size_t &result) const
{
if (m_value.IsSequence()) {
result = m_value.size();
return true;
}
return false;
}
bool getBool(bool &result) const
{
if (m_value.IsScalar()) {
result = m_value.as<bool>();
return true;
}
return false;
}
bool getDouble(double &result) const
{
if (m_value.IsScalar()) {
result = m_value.as<double>();
return true;
}
return false;
}
bool getInteger(int64_t &result) const
{
if (m_value.IsScalar()) {
result = m_value.as<int64_t>();
return true;
}
return false;
}
/**
* @brief Optionally return a YamlCppObject instance.
*
* If the referenced YamlCpp value is an object, this function will
* return a std::optional containing a YamlCppObject instance
* referencing the object.
*
* Otherwise it will return an empty optional.
*/
opt::optional<YamlCppObject> getObjectOptional() const
{
if (m_value.IsMap()) {
return opt::make_optional(YamlCppObject(m_value));
}
return {};
}
/**
* @brief Retrieve the number of members in the object
*
* If the referenced YamlCpp value is an object, this function will
* retrieve the number of members in the object and store it in the output
* variable provided.
*
* @param result reference to size_t to set with result
*
* @returns true if the number of members was retrieved, false otherwise.
*/
bool getObjectSize(size_t &result) const
{
if (m_value.IsMap()) {
result = m_value.size();
return true;
}
return false;
}
bool getString(std::string &result) const
{
if (m_value.IsScalar()) {
result = m_value.as<std::string>();
return true;
}
return false;
}
static bool hasStrictTypes()
{
return false;
}
bool isArray() const
{
return m_value.IsSequence();
}
bool isBool() const
{
return false;
}
bool isDouble() const
{
return false;
}
bool isInteger() const
{
return false;
}
bool isNull() const
{
return m_value.IsNull();
}
bool isNumber() const
{
return false;
}
bool isObject() const
{
return m_value.IsMap();
}
bool isString() const
{
return m_value.IsScalar();
}
private:
/// Return a reference to an empty object singleton
static const YAML::Node &emptyObject()
{
static const YAML::Node object = YAML::Node(YAML::NodeType::Map);
return object;
}
/// Reference to the contained YamlCpp value.
const YAML::Node m_value;
};
/**
* @brief An implementation of the Adapter interface supporting YamlCpp.
*
* This class is defined in terms of the BasicAdapter template class, which
* helps to ensure that all of the Adapter implementations behave consistently.
*
* @see Adapter
* @see BasicAdapter
*/
class YamlCppAdapter
: public BasicAdapter<YamlCppAdapter, YamlCppArray, YamlCppObjectMember,
YamlCppObject, YamlCppValue>
{
public:
/// Construct a YamlCppAdapter that contains an empty object
YamlCppAdapter() : BasicAdapter() {}
/// Construct a YamlCppAdapter containing a specific Nlohmann Json
/// object
YamlCppAdapter(const YAML::Node &value) : BasicAdapter(YamlCppValue{value})
{
}
};
/**
* @brief Class for iterating over values held in a JSON array.
*
* This class provides a JSON array iterator that dereferences as an instance of
* YamlCppAdapter representing a value stored in the array. It has been
* implemented using the boost iterator_facade template.
*
* @see YamlCppArray
*/
class YamlCppArrayValueIterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = YamlCppAdapter;
using difference_type = YamlCppAdapter;
using pointer = YamlCppAdapter *;
using reference = YamlCppAdapter &;
/**
* @brief Construct a new YamlCppArrayValueIterator using an existing
* YamlCpp iterator.
*
* @param itr YamlCpp iterator to store
*/
YamlCppArrayValueIterator(const YAML::Node::const_iterator &itr)
: m_itr(itr)
{
}
/// Returns a YamlCppAdapter that contains the value of the current
/// element.
YamlCppAdapter operator*() const
{
return YamlCppAdapter(*m_itr);
}
DerefProxy<YamlCppAdapter> operator->() const
{
return DerefProxy<YamlCppAdapter>(**this);
}
/**
* @brief Compare this iterator against another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other iterator to compare against
*
* @returns true if the iterators are equal, false otherwise.
*/
bool operator==(const YamlCppArrayValueIterator &other) const
{
return m_itr == other.m_itr;
}
bool operator!=(const YamlCppArrayValueIterator &other) const
{
return !(m_itr == other.m_itr);
}
const YamlCppArrayValueIterator &operator++()
{
m_itr++;
return *this;
}
YamlCppArrayValueIterator operator++(int)
{
YamlCppArrayValueIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
void advance(std::ptrdiff_t n)
{
for (auto i = 0; i < n; ++i)
m_itr++;
}
private:
YAML::Node::const_iterator m_itr;
};
/**
* @brief Class for iterating over the members belonging to a JSON object.
*
* This class provides a JSON object iterator that dereferences as an instance
* of YamlCppObjectMember representing one of the members of the object. It
* has been implemented using the boost iterator_facade template.
*
* @see YamlCppObject
* @see YamlCppObjectMember
*/
class YamlCppObjectMemberIterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = YamlCppObjectMember;
using difference_type = YamlCppObjectMember;
using pointer = YamlCppObjectMember *;
using reference = YamlCppObjectMember &;
/**
* @brief Construct an iterator from a YamlCpp iterator.
*
* @param itr YamlCpp iterator to store
*/
YamlCppObjectMemberIterator(const YAML::Node::const_iterator &itr)
: m_itr(itr)
{
}
/**
* @brief Returns a YamlCppObjectMember that contains the key and
* value belonging to the object member identified by the iterator.
*/
YamlCppObjectMember operator*() const
{
return YamlCppObjectMember(m_itr->first.as<std::string>(),
m_itr->second);
}
DerefProxy<YamlCppObjectMember> operator->() const
{
return DerefProxy<YamlCppObjectMember>(**this);
}
/**
* @brief Compare this iterator with another iterator.
*
* Note that this directly compares the iterators, not the underlying
* values, and assumes that two identical iterators will point to the same
* underlying object.
*
* @param other Iterator to compare with
*
* @returns true if the underlying iterators are equal, false otherwise
*/
bool operator==(const YamlCppObjectMemberIterator &other) const
{
return m_itr == other.m_itr;
}
bool operator!=(const YamlCppObjectMemberIterator &other) const
{
return !(m_itr == other.m_itr);
}
const YamlCppObjectMemberIterator &operator++()
{
m_itr++;
return *this;
}
YamlCppObjectMemberIterator operator++(int)
{
YamlCppObjectMemberIterator iterator_pre(m_itr);
++(*this);
return iterator_pre;
}
private:
/// Internal copy of the original YamlCpp iterator
YAML::Node::const_iterator m_itr;
};
/// Specialisation of the AdapterTraits template struct for YamlCppAdapter.
template <> struct AdapterTraits<valijson::adapters::YamlCppAdapter>
{
typedef YAML::Node DocumentType;
static std::string adapterName()
{
return "YamlCppAdapter";
}
};
inline bool YamlCppFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return YamlCppAdapter(m_value).equalTo(other, strict);
}
inline YamlCppArrayValueIterator YamlCppArray::begin() const
{
return m_value.begin();
}
inline YamlCppArrayValueIterator YamlCppArray::end() const
{
return m_value.end();
}
inline YamlCppObjectMemberIterator YamlCppObject::begin() const
{
return m_value.begin();
}
inline YamlCppObjectMemberIterator YamlCppObject::end() const
{
return m_value.end();
}
inline YamlCppObjectMemberIterator
YamlCppObject::find(const std::string &propertyName) const
{
for (auto itr = begin(); itr != end(); ++itr) {
if (itr->first == propertyName) {
return itr;
}
}
return end();
}
} // namespace adapters
} // namespace valijson

View File

@ -13,7 +13,7 @@ namespace constraints {
class ConstraintBuilder
{
public:
virtual ~ConstraintBuilder() {}
virtual ~ConstraintBuilder() = default;
virtual constraints::Constraint * make(const adapters::Adapter &) const = 0;
};

View File

@ -2,63 +2,59 @@
#include <valijson/constraints/constraint.hpp>
#include <valijson/constraints/constraint_visitor.hpp>
#include <valijson/internal/custom_allocator.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace constraints {
/**
* @brief Template class that implements the accept() and clone() functions of
* the Constraint interface.
* @brief Template class that implements the accept() and clone() functions of the Constraint interface.
*
* @tparam ConstraintType name of the concrete constraint type, which must
* provide a copy constructor.
* @tparam ConstraintType name of the concrete constraint type, which must provide a copy constructor.
*/
template<typename ConstraintType>
struct BasicConstraint: Constraint
{
typedef internal::CustomAllocator<void *> Allocator;
typedef std::basic_string<char, std::char_traits<char>,
internal::CustomAllocator<char> > String;
typedef std::basic_string<char, std::char_traits<char>, internal::CustomAllocator<char>> String;
BasicConstraint()
: allocator() { }
: m_allocator() { }
BasicConstraint(Allocator::CustomAlloc allocFn, Allocator::CustomFree freeFn)
: allocator(allocFn, freeFn) { }
: m_allocator(allocFn, freeFn) { }
BasicConstraint(const BasicConstraint &other)
: allocator(other.allocator) { }
: m_allocator(other.m_allocator) { }
virtual ~BasicConstraint<ConstraintType>() { }
~BasicConstraint() override = default;
virtual bool accept(ConstraintVisitor &visitor) const
bool accept(ConstraintVisitor &visitor) const override
{
return visitor.visit(*static_cast<const ConstraintType*>(this));
}
virtual Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const
OwningPointer clone(CustomAlloc allocFn, CustomFree freeFn) const override
{
void *ptr = allocFn(sizeof(ConstraintType));
// smart pointer to automatically free raw memory on exception
typedef std::unique_ptr<Constraint, CustomFree> RawOwningPointer;
auto ptr = RawOwningPointer(static_cast<Constraint*>(allocFn(sizeof(ConstraintType))), freeFn);
if (!ptr) {
throw std::runtime_error(
"Failed to allocate memory for cloned constraint");
throwRuntimeError("Failed to allocate memory for cloned constraint");
}
try {
return new (ptr) ConstraintType(
*static_cast<const ConstraintType*>(this));
} catch (...) {
freeFn(ptr);
throw;
}
// constructor might throw but the memory will be taken care of anyways
(void)new (ptr.get()) ConstraintType(*static_cast<const ConstraintType*>(this));
// implicitly convert to smart pointer that will also destroy object instance
return ptr;
}
protected:
Allocator allocator;
Allocator m_allocator;
};
} // namespace constraints

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,8 @@
#pragma once
#include <memory>
#include <type_traits>
namespace valijson {
namespace constraints {
@ -18,10 +21,32 @@ struct Constraint
/// Typedef for custom free-like function
typedef void (*CustomFree)(void *);
/// Deleter type to be used with std::unique_ptr / std::shared_ptr
/// @tparam T Const or non-const type (same as the one used in unique_ptr/shared_ptr)
template<typename T>
struct CustomDeleter
{
CustomDeleter(CustomFree freeFn)
: m_freeFn(freeFn) { }
void operator()(T *ptr) const
{
auto *nonconst = const_cast<typename std::remove_const<T>::type *>(ptr);
nonconst->~T();
m_freeFn(nonconst);
}
private:
CustomFree m_freeFn;
};
/// Exclusive-ownership pointer to automatically handle deallocation
typedef std::unique_ptr<const Constraint, CustomDeleter<const Constraint>> OwningPointer;
/**
* @brief Virtual destructor.
*/
virtual ~Constraint() { }
virtual ~Constraint() = default;
/**
* @brief Perform an action on the constraint using the visitor pattern.
@ -42,7 +67,7 @@ struct Constraint
*
* @returns an owning-pointer to the new constraint.
*/
virtual Constraint * clone(CustomAlloc, CustomFree) const = 0;
virtual OwningPointer clone(CustomAlloc, CustomFree) const = 0;
};

View File

@ -5,8 +5,12 @@ namespace constraints {
class AllOfConstraint;
class AnyOfConstraint;
class ConditionalConstraint;
class ConstConstraint;
class ContainsConstraint;
class DependenciesConstraint;
class EnumConstraint;
class FormatConstraint;
class LinearItemsConstraint;
class MaxItemsConstraint;
class MaximumConstraint;
@ -23,6 +27,7 @@ class OneOfConstraint;
class PatternConstraint;
class PolyConstraint;
class PropertiesConstraint;
class PropertyNamesConstraint;
class RequiredConstraint;
class SingularItemsConstraint;
class TypeConstraint;
@ -32,13 +37,17 @@ class UniqueItemsConstraint;
class ConstraintVisitor
{
protected:
virtual ~ConstraintVisitor() {}
virtual ~ConstraintVisitor() = default;
// Shorten type names for derived classes outside of this namespace
typedef constraints::AllOfConstraint AllOfConstraint;
typedef constraints::AnyOfConstraint AnyOfConstraint;
typedef constraints::ConditionalConstraint ConditionalConstraint;
typedef constraints::ConstConstraint ConstConstraint;
typedef constraints::ContainsConstraint ContainsConstraint;
typedef constraints::DependenciesConstraint DependenciesConstraint;
typedef constraints::EnumConstraint EnumConstraint;
typedef constraints::FormatConstraint FormatConstraint;
typedef constraints::LinearItemsConstraint LinearItemsConstraint;
typedef constraints::MaximumConstraint MaximumConstraint;
typedef constraints::MaxItemsConstraint MaxItemsConstraint;
@ -55,6 +64,7 @@ protected:
typedef constraints::PatternConstraint PatternConstraint;
typedef constraints::PolyConstraint PolyConstraint;
typedef constraints::PropertiesConstraint PropertiesConstraint;
typedef constraints::PropertyNamesConstraint PropertyNamesConstraint;
typedef constraints::RequiredConstraint RequiredConstraint;
typedef constraints::SingularItemsConstraint SingularItemsConstraint;
typedef constraints::TypeConstraint TypeConstraint;
@ -64,8 +74,12 @@ public:
virtual bool visit(const AllOfConstraint &) = 0;
virtual bool visit(const AnyOfConstraint &) = 0;
virtual bool visit(const ConditionalConstraint &) = 0;
virtual bool visit(const ConstConstraint &) = 0;
virtual bool visit(const ContainsConstraint &) = 0;
virtual bool visit(const DependenciesConstraint &) = 0;
virtual bool visit(const EnumConstraint &) = 0;
virtual bool visit(const FormatConstraint &) = 0;
virtual bool visit(const LinearItemsConstraint &) = 0;
virtual bool visit(const MaximumConstraint &) = 0;
virtual bool visit(const MaxItemsConstraint &) = 0;
@ -82,6 +96,7 @@ public:
virtual bool visit(const PatternConstraint &) = 0;
virtual bool visit(const PolyConstraint &) = 0;
virtual bool visit(const PropertiesConstraint &) = 0;
virtual bool visit(const PropertyNamesConstraint &) = 0;
virtual bool visit(const RequiredConstraint &) = 0;
virtual bool visit(const SingularItemsConstraint &) = 0;
virtual bool visit(const TypeConstraint &) = 0;

View File

@ -0,0 +1,39 @@
#pragma once
#include <iostream>
#include <exception>
namespace valijson {
#if defined(_MSC_VER) && _MSC_VER == 1800
#define VALIJSON_NORETURN __declspec(noreturn)
#else
#define VALIJSON_NORETURN [[noreturn]]
#endif
#if VALIJSON_USE_EXCEPTIONS
#include <stdexcept>
VALIJSON_NORETURN inline void throwRuntimeError(const std::string& msg) {
throw std::runtime_error(msg);
}
VALIJSON_NORETURN inline void throwLogicError(const std::string& msg) {
throw std::logic_error(msg);
}
#else
VALIJSON_NORETURN inline void throwRuntimeError(const std::string& msg) {
std::cerr << msg << std::endl;
abort();
}
VALIJSON_NORETURN inline void throwLogicError(const std::string& msg) {
std::cerr << msg << std::endl;
abort();
}
#endif
VALIJSON_NORETURN inline void throwNotSupported() {
throwRuntimeError("Not supported");
}
} // namespace valijson

View File

@ -35,7 +35,7 @@ public:
* @brief Virtual destructor defined to ensure deletion via base-class
* pointers is safe.
*/
virtual ~Adapter() { };
virtual ~Adapter() = default;
/**
* @brief Apply a callback function to each value in an array.
@ -68,7 +68,7 @@ public:
*
* This function shall return a boolean value if the Adapter contains either
* an actual boolean value, or one of the strings 'true' or 'false'.
* The string comparison is case sensitive.
* The string comparison is case-sensitive.
*
* An exception shall be thrown if the value cannot be cast to a boolean.
*
@ -81,7 +81,7 @@ public:
*
* This function shall retrieve a boolean value if the Adapter contains
* either an actual boolean value, or one of the strings 'true' or 'false'.
* The string comparison is case sensitive.
* The string comparison is case-sensitive.
*
* The retrieved value is returned via reference.
*

View File

@ -1,10 +1,11 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <sstream>
#include <valijson/adapters/adapter.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace adapters {
@ -28,7 +29,7 @@ struct DerefProxy
return std::addressof(m_ref);
}
operator Value*()
explicit operator Value*()
{
return std::addressof(m_ref);
}
@ -109,9 +110,9 @@ protected:
* @param strict Flag to use strict type comparison
*/
ArrayComparisonFunctor(const ArrayType &array, bool strict)
: itr(array.begin()),
end(array.end()),
strict(strict) { }
: m_itr(array.begin()),
m_end(array.end()),
m_strict(strict) { }
/**
* @brief Compare a value against the current element in the array.
@ -122,23 +123,23 @@ protected:
*/
bool operator()(const Adapter &adapter)
{
if (itr == end) {
if (m_itr == m_end) {
return false;
}
return AdapterType(*itr++).equalTo(adapter, strict);
return AdapterType(*m_itr++).equalTo(adapter, m_strict);
}
private:
/// Iterator for current element in the array
typename ArrayType::const_iterator itr;
typename ArrayType::const_iterator m_itr;
/// Iterator for one-past the last element of the array
typename ArrayType::const_iterator end;
typename ArrayType::const_iterator m_end;
/// Flag to use strict type comparison
const bool strict;
const bool m_strict;
};
/**
@ -166,10 +167,9 @@ protected:
* @param object object to use as comparison baseline
* @param strict flag to use strict type-checking
*/
ObjectComparisonFunctor(
const ObjectType &object, bool strict)
: object(object),
strict(strict) { }
ObjectComparisonFunctor(const ObjectType &object, bool strict)
: m_object(object),
m_strict(strict) { }
/**
* @brief Find a key in the object and compare its value.
@ -181,21 +181,21 @@ protected:
*/
bool operator()(const std::string &key, const Adapter &value)
{
const typename ObjectType::const_iterator itr = object.find(key);
if (itr == object.end()) {
const typename ObjectType::const_iterator itr = m_object.find(key);
if (itr == m_object.end()) {
return false;
}
return (*itr).second.equalTo(value, strict);
return (*itr).second.equalTo(value, m_strict);
}
private:
/// Object to be used as a comparison baseline
const ObjectType &object;
const ObjectType &m_object;
/// Flag to use strict type-checking
bool strict;
bool m_strict;
};
@ -216,7 +216,7 @@ public:
* This constructor relies on the default constructor of the ValueType
* class provided as a template argument.
*/
BasicAdapter() { }
BasicAdapter() = default;
/**
* @brief Construct an Adapter using a specified ValueType object.
@ -224,10 +224,10 @@ public:
* This constructor relies on the copy constructor of the ValueType
* class provided as template argument.
*/
BasicAdapter(const ValueType &value)
: value(value) { }
explicit BasicAdapter(const ValueType &value)
: m_value(value) { }
virtual bool applyToArray(ArrayValueCallback fn) const
bool applyToArray(ArrayValueCallback fn) const override
{
if (!maybeArray()) {
return false;
@ -237,8 +237,8 @@ public:
// if it is an empty string or empty object, we only need to go to
// effort of constructing an ArrayType instance if the value is
// definitely an array.
if (value.isArray()) {
const opt::optional<Array> array = value.getArrayOptional();
if (m_value.isArray()) {
const opt::optional<Array> array = m_value.getArrayOptional();
for (const AdapterType element : *array) {
if (!fn(element)) {
return false;
@ -249,14 +249,14 @@ public:
return true;
}
virtual bool applyToObject(ObjectMemberCallback fn) const
bool applyToObject(ObjectMemberCallback fn) const override
{
if (!maybeObject()) {
return false;
}
if (value.isObject()) {
const opt::optional<Object> object = value.getObjectOptional();
if (m_value.isObject()) {
const opt::optional<Object> object = m_value.getObjectOptional();
for (const ObjectMemberType member : *object) {
if (!fn(member.first, AdapterType(member.second))) {
return false;
@ -284,44 +284,44 @@ public:
*/
ArrayType asArray() const
{
if (value.isArray()) {
return *value.getArrayOptional();
} else if (value.isObject()) {
if (m_value.isArray()) {
return *m_value.getArrayOptional();
} else if (m_value.isObject()) {
size_t objectSize;
if (value.getObjectSize(objectSize) && objectSize == 0) {
if (m_value.getObjectSize(objectSize) && objectSize == 0) {
return ArrayType();
}
} else if (value.isString()) {
} else if (m_value.isString()) {
std::string stringValue;
if (value.getString(stringValue) && stringValue.empty()) {
if (m_value.getString(stringValue) && stringValue.empty()) {
return ArrayType();
}
}
throw std::runtime_error("JSON value cannot be cast to an array.");
throwRuntimeError("JSON value cannot be cast to an array.");
}
virtual bool asBool() const
bool asBool() const override
{
bool result;
if (asBool(result)) {
return result;
}
throw std::runtime_error("JSON value cannot be cast to a boolean.");
throwRuntimeError("JSON value cannot be cast to a boolean.");
}
virtual bool asBool(bool &result) const
bool asBool(bool &result) const override
{
if (value.isBool()) {
return value.getBool(result);
} else if (value.isString()) {
if (m_value.isBool()) {
return m_value.getBool(result);
} else if (m_value.isString()) {
std::string s;
if (value.getString(s)) {
if (s.compare("true") == 0) {
if (m_value.getString(s)) {
if (s == "true") {
result = true;
return true;
} else if (s.compare("false") == 0) {
} else if (s == "false") {
result = false;
return true;
}
@ -331,31 +331,31 @@ public:
return false;
}
virtual double asDouble() const
double asDouble() const override
{
double result;
if (asDouble(result)) {
return result;
}
throw std::runtime_error("JSON value cannot be cast to a double.");
throwRuntimeError("JSON value cannot be cast to a double.");
}
virtual bool asDouble(double &result) const
bool asDouble(double &result) const override
{
if (value.isDouble()) {
return value.getDouble(result);
} else if (value.isInteger()) {
if (m_value.isDouble()) {
return m_value.getDouble(result);
} else if (m_value.isInteger()) {
int64_t i;
if (value.getInteger(i)) {
if (m_value.getInteger(i)) {
result = double(i);
return true;
}
} else if (value.isString()) {
} else if (m_value.isString()) {
std::string s;
if (value.getString(s)) {
if (m_value.getString(s)) {
const char *b = s.c_str();
char *e = NULL;
char *e = nullptr;
double x = strtod(b, &e);
if (e == b || e != b + s.length()) {
return false;
@ -368,23 +368,23 @@ public:
return false;
}
virtual int64_t asInteger() const
int64_t asInteger() const override
{
int64_t result;
if (asInteger(result)) {
return result;
}
throw std::runtime_error("JSON value cannot be cast as an integer.");
throwRuntimeError("JSON value cannot be cast as an integer.");
}
virtual bool asInteger(int64_t &result) const
bool asInteger(int64_t &result) const override
{
if (value.isInteger()) {
return value.getInteger(result);
} else if (value.isString()) {
if (m_value.isInteger()) {
return m_value.getInteger(result);
} else if (m_value.isString()) {
std::string s;
if (value.getString(s)) {
if (m_value.getString(s)) {
std::istringstream i(s);
int64_t x;
char c;
@ -412,67 +412,67 @@ public:
*/
ObjectType asObject() const
{
if (value.isObject()) {
return *value.getObjectOptional();
} else if (value.isArray()) {
if (m_value.isObject()) {
return *m_value.getObjectOptional();
} else if (m_value.isArray()) {
size_t arraySize;
if (value.getArraySize(arraySize) && arraySize == 0) {
if (m_value.getArraySize(arraySize) && arraySize == 0) {
return ObjectType();
}
} else if (value.isString()) {
} else if (m_value.isString()) {
std::string stringValue;
if (value.getString(stringValue) && stringValue.empty()) {
if (m_value.getString(stringValue) && stringValue.empty()) {
return ObjectType();
}
}
throw std::runtime_error("JSON value cannot be cast to an object.");
throwRuntimeError("JSON value cannot be cast to an object.");
}
virtual std::string asString() const
std::string asString() const override
{
std::string result;
if (asString(result)) {
return result;
}
throw std::runtime_error("JSON value cannot be cast to a string.");
throwRuntimeError("JSON value cannot be cast to a string.");
}
virtual bool asString(std::string &result) const
bool asString(std::string &result) const override
{
if (value.isString()) {
return value.getString(result);
} else if (value.isNull()) {
if (m_value.isString()) {
return m_value.getString(result);
} else if (m_value.isNull()) {
result.clear();
return true;
} else if (value.isArray()) {
} else if (m_value.isArray()) {
size_t arraySize;
if (value.getArraySize(arraySize) && arraySize == 0) {
if (m_value.getArraySize(arraySize) && arraySize == 0) {
result.clear();
return true;
}
} else if (value.isObject()) {
} else if (m_value.isObject()) {
size_t objectSize;
if (value.getObjectSize(objectSize) && objectSize == 0) {
if (m_value.getObjectSize(objectSize) && objectSize == 0) {
result.clear();
return true;
}
} else if (value.isBool()) {
} else if (m_value.isBool()) {
bool boolValue;
if (value.getBool(boolValue)) {
if (m_value.getBool(boolValue)) {
result = boolValue ? "true" : "false";
return true;
}
} else if (value.isInteger()) {
} else if (m_value.isInteger()) {
int64_t integerValue;
if (value.getInteger(integerValue)) {
if (m_value.getInteger(integerValue)) {
result = std::to_string(integerValue);
return true;
}
} else if (value.isDouble()) {
} else if (m_value.isDouble()) {
double doubleValue;
if (value.getDouble(doubleValue)) {
if (m_value.getDouble(doubleValue)) {
result = std::to_string(doubleValue);
return true;
}
@ -481,27 +481,24 @@ public:
return false;
}
virtual bool equalTo(const Adapter &other, bool strict) const
bool equalTo(const Adapter &other, bool strict) const override
{
if (isNull() || (!strict && maybeNull())) {
return other.isNull() || (!strict && other.maybeNull());
} else if (isBool() || (!strict && maybeBool())) {
return (other.isBool() || (!strict && other.maybeBool())) &&
other.asBool() == asBool();
return (other.isBool() || (!strict && other.maybeBool())) && other.asBool() == asBool();
} else if (isNumber() && strict) {
return other.isNumber() && other.getNumber() == getNumber();
} else if (!strict && maybeDouble()) {
return (other.maybeDouble() &&
other.asDouble() == asDouble());
return (other.maybeDouble() && other.asDouble() == asDouble());
} else if (!strict && maybeInteger()) {
return (other.maybeInteger() &&
other.asInteger() == asInteger());
return (other.maybeInteger() && other.asInteger() == asInteger());
} else if (isString() || (!strict && maybeString())) {
return (other.isString() || (!strict && other.maybeString())) &&
other.asString() == asString();
} else if (isArray()) {
if (other.isArray() && getArraySize() == other.getArraySize()) {
const opt::optional<ArrayType> array = value.getArrayOptional();
const opt::optional<ArrayType> array = m_value.getArrayOptional();
if (array) {
ArrayComparisonFunctor fn(*array, strict);
return other.applyToArray(fn);
@ -511,7 +508,7 @@ public:
}
} else if (isObject()) {
if (other.isObject() && other.getObjectSize() == getObjectSize()) {
const opt::optional<ObjectType> object = value.getObjectOptional();
const opt::optional<ObjectType> object = m_value.getObjectOptional();
if (object) {
ObjectComparisonFunctor fn(*object, strict);
return other.applyToObject(fn);
@ -540,85 +537,85 @@ public:
*/
ArrayType getArray() const
{
opt::optional<ArrayType> arrayValue = value.getArrayOptional();
opt::optional<ArrayType> arrayValue = m_value.getArrayOptional();
if (arrayValue) {
return *arrayValue;
}
throw std::runtime_error("JSON value is not an array.");
throwRuntimeError("JSON value is not an array.");
}
virtual size_t getArraySize() const
size_t getArraySize() const override
{
size_t result;
if (value.getArraySize(result)) {
if (m_value.getArraySize(result)) {
return result;
}
throw std::runtime_error("JSON value is not an array.");
throwRuntimeError("JSON value is not an array.");
}
virtual bool getArraySize(size_t &result) const
bool getArraySize(size_t &result) const override
{
return value.getArraySize(result);
return m_value.getArraySize(result);
}
virtual bool getBool() const
bool getBool() const override
{
bool result;
if (getBool(result)) {
return result;
}
throw std::runtime_error("JSON value is not a boolean.");
throwRuntimeError("JSON value is not a boolean.");
}
virtual bool getBool(bool &result) const
bool getBool(bool &result) const override
{
return value.getBool(result);
return m_value.getBool(result);
}
virtual double getDouble() const
double getDouble() const override
{
double result;
if (getDouble(result)) {
return result;
}
throw std::runtime_error("JSON value is not a double.");
throwRuntimeError("JSON value is not a double.");
}
virtual bool getDouble(double &result) const
bool getDouble(double &result) const override
{
return value.getDouble(result);
return m_value.getDouble(result);
}
virtual int64_t getInteger() const
int64_t getInteger() const override
{
int64_t result;
if (getInteger(result)) {
return result;
}
throw std::runtime_error("JSON value is not an integer.");
throwRuntimeError("JSON value is not an integer.");
}
virtual bool getInteger(int64_t &result) const
bool getInteger(int64_t &result) const override
{
return value.getInteger(result);
return m_value.getInteger(result);
}
virtual double getNumber() const
double getNumber() const override
{
double result;
if (getNumber(result)) {
return result;
}
throw std::runtime_error("JSON value is not a number.");
throwRuntimeError("JSON value is not a number.");
}
virtual bool getNumber(double &result) const
bool getNumber(double &result) const override
{
if (isDouble()) {
return getDouble(result);
@ -649,101 +646,101 @@ public:
*/
ObjectType getObject() const
{
opt::optional<ObjectType> objectValue = value.getObjectOptional();
opt::optional<ObjectType> objectValue = m_value.getObjectOptional();
if (objectValue) {
return *objectValue;
}
throw std::runtime_error("JSON value is not an object.");
throwRuntimeError("JSON value is not an object.");
}
virtual size_t getObjectSize() const
size_t getObjectSize() const override
{
size_t result;
if (getObjectSize(result)) {
return result;
}
throw std::runtime_error("JSON value is not an object.");
throwRuntimeError("JSON value is not an object.");
}
virtual bool getObjectSize(size_t &result) const
bool getObjectSize(size_t &result) const override
{
return value.getObjectSize(result);
return m_value.getObjectSize(result);
}
virtual std::string getString() const
std::string getString() const override
{
std::string result;
if (getString(result)) {
return result;
}
throw std::runtime_error("JSON value is not a string.");
throwRuntimeError("JSON value is not a string.");
}
virtual bool getString(std::string &result) const
bool getString(std::string &result) const override
{
return value.getString(result);
return m_value.getString(result);
}
virtual FrozenValue * freeze() const
FrozenValue * freeze() const override
{
return value.freeze();
return m_value.freeze();
}
virtual bool hasStrictTypes() const
bool hasStrictTypes() const override
{
return ValueType::hasStrictTypes();
}
virtual bool isArray() const
bool isArray() const override
{
return value.isArray();
return m_value.isArray();
}
virtual bool isBool() const
bool isBool() const override
{
return value.isBool();
return m_value.isBool();
}
virtual bool isDouble() const
bool isDouble() const override
{
return value.isDouble();
return m_value.isDouble();
}
virtual bool isInteger() const
bool isInteger() const override
{
return value.isInteger();
return m_value.isInteger();
}
virtual bool isNull() const
bool isNull() const override
{
return value.isNull();
return m_value.isNull();
}
virtual bool isNumber() const
bool isNumber() const override
{
return value.isInteger() || value.isDouble();
return m_value.isInteger() || m_value.isDouble();
}
virtual bool isObject() const
bool isObject() const override
{
return value.isObject();
return m_value.isObject();
}
virtual bool isString() const
bool isString() const override
{
return value.isString();
return m_value.isString();
}
virtual bool maybeArray() const
bool maybeArray() const override
{
if (value.isArray()) {
if (m_value.isArray()) {
return true;
} else if (value.isObject()) {
} else if (m_value.isObject()) {
size_t objectSize;
if (value.getObjectSize(objectSize) && objectSize == 0) {
if (m_value.getObjectSize(objectSize) && objectSize == 0) {
return true;
}
}
@ -751,14 +748,14 @@ public:
return false;
}
virtual bool maybeBool() const
bool maybeBool() const override
{
if (value.isBool()) {
if (m_value.isBool()) {
return true;
} else if (maybeString()) {
std::string stringValue;
if (value.getString(stringValue)) {
if (stringValue.compare("true") == 0 || stringValue.compare("false") == 0) {
if (m_value.getString(stringValue)) {
if (stringValue == "true" || stringValue == "false") {
return true;
}
}
@ -767,15 +764,15 @@ public:
return false;
}
virtual bool maybeDouble() const
bool maybeDouble() const override
{
if (value.isNumber()) {
if (m_value.isNumber()) {
return true;
} else if (maybeString()) {
std::string s;
if (value.getString(s)) {
if (m_value.getString(s)) {
const char *b = s.c_str();
char *e = NULL;
char *e = nullptr;
strtod(b, &e);
return e != b && e == b + s.length();
}
@ -784,13 +781,13 @@ public:
return false;
}
virtual bool maybeInteger() const
bool maybeInteger() const override
{
if (value.isInteger()) {
if (m_value.isInteger()) {
return true;
} else if (maybeString()) {
std::string s;
if (value.getString(s)) {
if (m_value.getString(s)) {
std::istringstream i(s);
int64_t x;
char c;
@ -804,13 +801,13 @@ public:
return false;
}
virtual bool maybeNull() const
bool maybeNull() const override
{
if (value.isNull()) {
if (m_value.isNull()) {
return true;
} else if (maybeString()) {
std::string stringValue;
if (value.getString(stringValue)) {
if (m_value.getString(stringValue)) {
if (stringValue.empty()) {
return true;
}
@ -820,13 +817,13 @@ public:
return false;
}
virtual bool maybeObject() const
bool maybeObject() const override
{
if (value.isObject()) {
if (m_value.isObject()) {
return true;
} else if (maybeArray()) {
size_t arraySize;
if (value.getArraySize(arraySize) && arraySize == 0) {
if (m_value.getArraySize(arraySize) && arraySize == 0) {
return true;
}
}
@ -834,19 +831,18 @@ public:
return false;
}
virtual bool maybeString() const
bool maybeString() const override
{
if (value.isString() || value.isBool() || value.isInteger() ||
value.isDouble()) {
if (m_value.isString() || m_value.isBool() || m_value.isInteger() || m_value.isDouble()) {
return true;
} else if (value.isObject()) {
} else if (m_value.isObject()) {
size_t objectSize;
if (value.getObjectSize(objectSize) && objectSize == 0) {
if (m_value.getObjectSize(objectSize) && objectSize == 0) {
return true;
}
} else if (value.isArray()) {
} else if (m_value.isArray()) {
size_t arraySize;
if (value.getArraySize(arraySize) && arraySize == 0) {
if (m_value.getArraySize(arraySize) && arraySize == 0) {
return true;
}
}
@ -856,8 +852,7 @@ public:
private:
const ValueType value;
const ValueType m_value;
};
} // namespace adapters

View File

@ -1,5 +1,7 @@
#pragma once
#include <limits>
namespace valijson {
namespace internal {
@ -29,26 +31,26 @@ public:
};
CustomAllocator()
: allocFn(::operator new),
freeFn(::operator delete) { }
: m_allocFn([](size_t size) { return ::operator new(size, std::nothrow); }),
m_freeFn(::operator delete) { }
CustomAllocator(CustomAlloc allocFn, CustomFree freeFn)
: allocFn(allocFn),
freeFn(freeFn) { }
: m_allocFn(allocFn),
m_freeFn(freeFn) { }
CustomAllocator(const CustomAllocator &other)
: allocFn(other.allocFn),
freeFn(other.freeFn) { }
: m_allocFn(other.m_allocFn),
m_freeFn(other.m_freeFn) { }
template<typename U>
CustomAllocator(CustomAllocator<U> const &other)
: allocFn(other.allocFn),
freeFn(other.freeFn) { }
: m_allocFn(other.m_allocFn),
m_freeFn(other.m_freeFn) { }
CustomAllocator & operator=(const CustomAllocator &other)
{
allocFn = other.allocFn;
freeFn = other.freeFn;
m_allocFn = other.m_allocFn;
m_freeFn = other.m_freeFn;
return *this;
}
@ -63,14 +65,14 @@ public:
return &r;
}
pointer allocate(size_type cnt, const void * = 0)
pointer allocate(size_type cnt, const void * = nullptr)
{
return reinterpret_cast<pointer>(allocFn(cnt * sizeof(T)));
return reinterpret_cast<pointer>(m_allocFn(cnt * sizeof(T)));
}
void deallocate(pointer p, size_type)
{
freeFn(p);
m_freeFn(p);
}
size_type max_size() const
@ -90,7 +92,7 @@ public:
bool operator==(const CustomAllocator &other) const
{
return other.allocFn == allocFn && other.freeFn == freeFn;
return other.m_allocFn == m_allocFn && other.m_freeFn == m_freeFn;
}
bool operator!=(const CustomAllocator &other) const
@ -98,9 +100,9 @@ public:
return !operator==(other);
}
CustomAlloc allocFn;
CustomAlloc m_allocFn;
CustomFree freeFn;
CustomFree m_freeFn;
};
} // end namespace internal

View File

@ -1,6 +1,6 @@
#pragma once
#include <valijson/adapters/adapter.hpp>
#include <valijson/internal/adapter.hpp>
namespace valijson {
namespace adapters {

View File

@ -7,8 +7,14 @@
#include <stdexcept>
#include <string>
#include <valijson/adapters/adapter.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4702 )
#endif
namespace valijson {
namespace internal {
@ -43,17 +49,17 @@ inline void replaceAllInPlace(std::string& subject, const char* search,
inline char decodePercentEncodedChar(const std::string &digits)
{
if (digits.length() != 2) {
throw std::runtime_error("Failed to decode %-encoded character '" +
throwRuntimeError("Failed to decode %-encoded character '" +
digits + "' due to unexpected number of characters; "
"expected two characters");
}
errno = 0;
const char *begin = digits.c_str();
char *end = NULL;
char *end = nullptr;
const unsigned long value = strtoul(begin, &end, 16);
if (end != begin && *end != '\0') {
throw std::runtime_error("Failed to decode %-encoded character '" +
throwRuntimeError("Failed to decode %-encoded character '" +
digits + "'");
}
@ -101,14 +107,17 @@ inline std::string extractReferenceToken(std::string::const_iterator begin,
for (size_t n = token.find('%'); n != std::string::npos;
n = token.find('%', n + 1)) {
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
const char c = decodePercentEncodedChar(token.substr(n + 1, 2));
token.replace(n, 3, &c, 1);
token.replace(n, 3, 1, c);
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::runtime_error &e) {
throw std::runtime_error(
throwRuntimeError(
std::string(e.what()) + "; in token: " + token);
}
#endif
}
return token;
@ -124,7 +133,7 @@ inline std::string extractReferenceToken(std::string::const_iterator begin,
* at least one character in length to be considered valid.
*
* Once the next reference token has been identified, it will be used either as
* an array index or as an the name an object member. The validity of a
* an array index or as the name of an object member. The validity of a
* reference token depends on the type of the node currently being traversed,
* and the applicability of the token to that node. For example, an array can
* only be dereferenced by a non-negative integral index.
@ -159,7 +168,7 @@ inline AdapterType resolveJsonPointer(
// Reference tokens must begin with a leading slash
if (*jsonPointerItr != '/') {
throw std::runtime_error("Expected reference token to begin with "
throwRuntimeError("Expected reference token to begin with "
"leading slash; remaining tokens: " +
std::string(jsonPointerItr, jsonPointerEnd));
}
@ -178,25 +187,29 @@ inline AdapterType resolveJsonPointer(
return resolveJsonPointer(node, jsonPointer, jsonPointerNext);
} else if (node.isArray()) {
if (referenceToken.compare("-") == 0) {
throw std::runtime_error("Hyphens cannot be used as array indices "
if (referenceToken == "-") {
throwRuntimeError("Hyphens cannot be used as array indices "
"since the requested array element does not yet exist");
}
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
// Fragment must be non-negative integer
const uint64_t index = std::stoul(referenceToken);
typedef typename AdapterType::Array Array;
typename Array::const_iterator itr = node.asArray().begin();
const Array arr = node.asArray();
typename Array::const_iterator itr = arr.begin();
const uint64_t arrSize = arr.size();
if (index > node.asArray().size() - 1) {
throw std::runtime_error("Expected reference token to identify "
if (arrSize == 0 || index > arrSize - 1) {
throwRuntimeError("Expected reference token to identify "
"an element in the current array, but array index is "
"out of bounds; actual token: " + referenceToken);
}
if (index > static_cast<uint64_t>(std::numeric_limits<std::ptrdiff_t>::max())) {
throw std::runtime_error("Array index out of bounds; hard "
throwRuntimeError("Array index out of bounds; hard "
"limit is " + std::to_string(
std::numeric_limits<std::ptrdiff_t>::max()));
}
@ -206,30 +219,35 @@ inline AdapterType resolveJsonPointer(
// Recursively process the remaining tokens
return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext);
#if VALIJSON_USE_EXCEPTIONS
} catch (std::invalid_argument &) {
throw std::runtime_error("Expected reference token to contain a "
throwRuntimeError("Expected reference token to contain a "
"non-negative integer to identify an element in the "
"current array; actual token: " + referenceToken);
}
#endif
} else if (node.maybeObject()) {
// Fragment must identify a member of the candidate object
typedef typename AdapterType::Object Object;
typename Object::const_iterator itr = node.asObject().find(
const Object object = node.asObject();
typename Object::const_iterator itr = object.find(
referenceToken);
if (itr == node.asObject().end()) {
throw std::runtime_error("Expected reference token to identify an "
if (itr == object.end()) {
throwRuntimeError("Expected reference token to identify an "
"element in the current object; "
"actual token: " + referenceToken);
abort();
}
// Recursively process the remaining tokens
return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext);
}
throw std::runtime_error("Expected end of JSON Pointer, but at least "
throwRuntimeError("Expected end of JSON Pointer, but at least "
"one reference token has not been processed; remaining tokens: " +
std::string(jsonPointerNext, jsonPointerEnd));
abort();
}
/**
@ -251,3 +269,7 @@ inline AdapterType resolveJsonPointer(
} // namespace json_pointer
} // namespace internal
} // namespace valijson
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@ -13,14 +13,13 @@ namespace json_reference {
* @brief Extract URI from JSON Reference relative to the current schema
*
* @param jsonRef JSON Reference to extract from
* @param schema Schema that JSON Reference URI is relative to
*
* @return Optional string containing URI
*/
inline opt::optional<std::string> getJsonReferenceUri(
const std::string &jsonRef)
{
const size_t ptrPos = jsonRef.find("#");
const size_t ptrPos = jsonRef.find('#');
if (ptrPos == 0) {
// The JSON Reference does not contain a URI, but might contain a
// JSON Pointer that refers to the current document
@ -47,7 +46,7 @@ inline opt::optional<std::string> getJsonReferencePointer(
// Attempt to extract JSON Pointer if '#' character is present. Note
// that a valid pointer would contain at least a leading forward
// slash character.
const size_t ptrPos = jsonRef.find("#");
const size_t ptrPos = jsonRef.find('#');
if (ptrPos != std::string::npos) {
return jsonRef.substr(ptrPos + 1);
}

View File

@ -0,0 +1,3 @@
#pragma once
namespace opt = std::experimental;

View File

@ -0,0 +1,27 @@
#if defined(VALIJSON_USE_BOOST_REGEX) && VALIJSON_USE_BOOST_REGEX
#include <boost/regex.hpp>
namespace valijson {
namespace internal {
using boost::regex;
using boost::regex_match;
using boost::regex_search;
using boost::smatch;
} // namespace internal
} // namespace valijson
#else
#include <regex>
namespace valijson {
namespace internal {
using std::regex;
using std::regex_match;
using std::regex_search;
using std::smatch;
} // namespace internal
} // namespace valijson
#endif

View File

@ -2,6 +2,8 @@
#include <string>
#include <valijson/internal/regex.hpp>
namespace valijson {
namespace internal {
namespace uri {
@ -19,8 +21,20 @@ inline bool isUriAbsolute(const std::string &documentUri)
}
/**
* Placeholder function to resolve a relative URI within a given scope
*/
* @brief Placeholder function to check whether a URI is a URN
*
* This function validates that the URI matches the RFC 8141 spec
*/
inline bool isUrn(const std::string &documentUri) {
static const internal::regex pattern(
"^((urn)|(URN)):(?!urn:)([a-zA-Z0-9][a-zA-Z0-9-]{1,31})(:[-a-zA-Z0-9\\\\._~%!$&'()\\/*+,;=]+)+(\\?[-a-zA-Z0-9\\\\._~%!$&'()\\/*+,;:=]+){0,1}(#[-a-zA-Z0-9\\\\._~%!$&'()\\/*+,;:=]+){0,1}$");
return internal::regex_match(documentUri, pattern);
}
/**
* Placeholder function to resolve a relative URI within a given scope
*/
inline std::string resolveRelativeUri(
const std::string &resolutionScope,
const std::string &relativeUri)

View File

@ -4,6 +4,7 @@
#include <set>
#include <valijson/subschema.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
@ -35,29 +36,72 @@ public:
: Subschema(allocFn, freeFn),
sharedEmptySubschema(newSubschema()) { }
// Disable copy construction
Schema(const Schema &) = delete;
// Disable copy assignment
Schema & operator=(const Schema &) = delete;
/**
* @brief Move construct a new Schema
*
* @param other Schema that is moved into the new Schema
*/
Schema(Schema &&other)
: Subschema(std::move(other)),
subschemaSet(std::move(other.subschemaSet)),
sharedEmptySubschema(other.sharedEmptySubschema)
{
// Makes other invalid by setting sharedEmptySubschema to nullptr
other.sharedEmptySubschema = nullptr;
}
/**
* @brief Move assign a Schema
*
* @param other Schema that is move assigned to this Schema
* @return Schema&
*/
Schema & operator=(Schema &&other)
{
// Calls the base class move assignment operator
Subschema::operator=(std::move(other));
// Swaps all Schema members
std::swap(subschemaSet, other.subschemaSet);
std::swap(sharedEmptySubschema, other.sharedEmptySubschema);
return *this;
}
/**
* @brief Clean up and free all memory managed by the Schema
*
* Note that any Subschema pointers created and returned by this Schema
* should be considered invalid.
*/
virtual ~Schema()
~Schema() override
{
sharedEmptySubschema->~Subschema();
freeFn(const_cast<Subschema *>(sharedEmptySubschema));
sharedEmptySubschema = NULL;
if(sharedEmptySubschema != nullptr)
{
sharedEmptySubschema->~Subschema();
m_freeFn(const_cast<Subschema *>(sharedEmptySubschema));
sharedEmptySubschema = nullptr;
}
#if VALIJSON_USE_EXCEPTIONS
try {
for (std::set<Subschema *>::iterator itr = subschemaSet.begin();
itr != subschemaSet.end(); ++itr) {
Subschema *subschema = *itr;
#endif
for (auto subschema : subschemaSet) {
subschema->~Subschema();
freeFn(subschema);
m_freeFn(subschema);
}
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::exception &e) {
fprintf(stderr, "Caught an exception while destroying Schema: %s",
e.what());
}
#endif
}
/**
@ -74,7 +118,7 @@ public:
void addConstraintToSubschema(const Constraint &constraint,
const Subschema *subschema)
{
// TODO: Check heirarchy for subschemas that do not belong...
// TODO: Check hierarchy for subschemas that do not belong...
mutableSubschema(subschema)->addConstraint(constraint);
}
@ -88,17 +132,20 @@ public:
{
Subschema *subschema = newSubschema();
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
if (!subschemaSet.insert(subschema).second) {
throw std::runtime_error(
throwRuntimeError(
"Failed to store pointer for new sub-schema");
}
#if VALIJSON_USE_EXCEPTIONS
} catch (...) {
subschema->~Subschema();
freeFn(subschema);
m_freeFn(subschema);
throw;
}
#endif
return subschema;
}
@ -118,6 +165,11 @@ public:
return this;
}
void setAlwaysInvalid(const Subschema *subschema, bool value)
{
mutableSubschema(subschema)->setAlwaysInvalid(value);
}
/**
* @brief Update the description for one of the sub-schemas owned by this
* Schema instance
@ -157,26 +209,24 @@ public:
private:
// Disable copy construction
Schema(const Schema &);
// Disable copy assignment
Schema & operator=(const Schema &);
Subschema *newSubschema()
{
void *ptr = allocFn(sizeof(Subschema));
void *ptr = m_allocFn(sizeof(Subschema));
if (!ptr) {
throw std::runtime_error(
throwRuntimeError(
"Failed to allocate memory for shared empty sub-schema");
}
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
return new (ptr) Subschema();
#if VALIJSON_USE_EXCEPTIONS
} catch (...) {
freeFn(ptr);
m_freeFn(ptr);
throw;
}
#endif
}
Subschema * mutableSubschema(const Subschema *subschema)
@ -186,13 +236,13 @@ private:
}
if (subschema == sharedEmptySubschema) {
throw std::runtime_error(
throwRuntimeError(
"Cannot modify the shared empty sub-schema");
}
Subschema *noConst = const_cast<Subschema*>(subschema);
auto *noConst = const_cast<Subschema*>(subschema);
if (subschemaSet.find(noConst) == subschemaSet.end()) {
throw std::runtime_error(
throwRuntimeError(
"Subschema pointer is not owned by this Schema instance");
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <map>
#include <string>
#include <valijson/subschema.hpp>
namespace valijson {
typedef std::map<std::string, const Subschema *> SchemaCache;
} // namespace valijson

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,12 @@
#pragma once
#include <vector>
#include <functional>
#include <memory>
#include <vector>
#include <valijson/constraints/constraint.hpp>
#include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
@ -22,6 +23,7 @@ namespace valijson {
class Subschema
{
public:
/// Typedef for custom new-/malloc-like function
typedef void * (*CustomAlloc)(size_t size);
@ -35,12 +37,53 @@ public:
/// instances owned by a Schema.
typedef std::function<bool (const Constraint &)> ApplyFunction;
// Disable copy construction
Subschema(const Subschema &) = delete;
// Disable copy assignment
Subschema & operator=(const Subschema &) = delete;
/**
* @brief Move construct a new Subschema
*
* @param other Subschema that is moved into the new Subschema
*/
Subschema(Subschema &&other)
: m_allocFn(other.m_allocFn),
m_freeFn(other.m_freeFn),
m_alwaysInvalid(std::move(other.m_alwaysInvalid)),
m_constraints(std::move(other.m_constraints)),
m_description(std::move(other.m_description)),
m_id(std::move(other.m_id)),
m_title(std::move(other.m_title)) { }
/**
* @brief Move assign a Subschema
*
* @param other Subschema that is move assigned to this Subschema
* @return Subschema&
*/
Subschema & operator=(Subschema &&other)
{
// Swaps all members
std::swap(m_allocFn, other.m_allocFn);
std::swap(m_freeFn, other.m_freeFn);
std::swap(m_alwaysInvalid, other.m_alwaysInvalid);
std::swap(m_constraints, other.m_constraints);
std::swap(m_description, other.m_description);
std::swap(m_id, other.m_id);
std::swap(m_title, other.m_title);
return *this;
}
/**
* @brief Construct a new Subschema object
*/
Subschema()
: allocFn(::operator new)
, freeFn(::operator delete) { }
: m_allocFn([](size_t size) { return ::operator new(size, std::nothrow); })
, m_freeFn(::operator delete)
, m_alwaysInvalid(false) { }
/**
* @brief Construct a new Subschema using custom memory management
@ -52,26 +95,31 @@ public:
* the `customAlloc` function
*/
Subschema(CustomAlloc allocFn, CustomFree freeFn)
: allocFn(allocFn)
, freeFn(freeFn) { }
: m_allocFn(allocFn)
, m_freeFn(freeFn)
, m_alwaysInvalid(false)
{
// explicitly initialise optionals. See: https://github.com/tristanpenman/valijson/issues/124
m_description = opt::nullopt;
m_id = opt::nullopt;
m_title = opt::nullopt;
}
/**
* @brief Clean up and free all memory managed by the Subschema
*/
virtual ~Subschema()
{
#if VALIJSON_USE_EXCEPTIONS
try {
for (std::vector<const Constraint *>::iterator itr =
constraints.begin(); itr != constraints.end(); ++itr) {
Constraint *constraint = const_cast<Constraint *>(*itr);
constraint->~Constraint();
freeFn(constraint);
}
constraints.clear();
#endif
m_constraints.clear();
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::exception &e) {
fprintf(stderr, "Caught an exception in Subschema destructor: %s",
e.what());
}
#endif
}
/**
@ -87,32 +135,31 @@ public:
*/
void addConstraint(const Constraint &constraint)
{
Constraint *newConstraint = constraint.clone(allocFn, freeFn);
try {
constraints.push_back(newConstraint);
} catch (...) {
newConstraint->~Constraint();
freeFn(newConstraint);
throw;
}
// the vector allocation might throw but the constraint memory will be taken care of anyways
m_constraints.push_back(constraint.clone(m_allocFn, m_freeFn));
}
/**
* @brief Invoke a function on each child Constraint
*
* This function will apply the callback function to each constraint in
* the Subschema, even if one of the invokations returns \c false. However,
* if one or more invokations of the callback function return \c false,
* the Subschema, even if one of the invocations returns \c false. However,
* if one or more invocations of the callback function return \c false,
* this function will also return \c false.
*
* @returns \c true if all invokations of the callback function are
* @returns \c true if all invocations of the callback function are
* successful, \c false otherwise
*/
bool apply(ApplyFunction &applyFunction) const
{
bool allTrue = true;
for (const Constraint *constraint : constraints) {
allTrue = allTrue && applyFunction(*constraint);
for (auto &&constraint : m_constraints) {
// Even if an application fails, we want to continue checking the
// schema. In that case we set allTrue to false, and then fall
// through to the next constraint
if (!applyFunction(*constraint)) {
allTrue = false;
}
}
return allTrue;
@ -122,15 +169,15 @@ public:
* @brief Invoke a function on each child Constraint
*
* This is a stricter version of the apply() function that will return
* immediately if any of the invokations of the callback function return
* immediately if any of the invocations of the callback function return
* \c false.
*
* @returns \c true if all invokations of the callback function are
* @returns \c true if all invocations of the callback function are
* successful, \c false otherwise
*/
bool applyStrict(ApplyFunction &applyFunction) const
{
for (const Constraint *constraint : constraints) {
for (auto &&constraint : m_constraints) {
if (!applyFunction(*constraint)) {
return false;
}
@ -139,6 +186,11 @@ public:
return true;
}
bool getAlwaysInvalid() const
{
return m_alwaysInvalid;
}
/**
* @brief Get the description associated with this sub-schema
*
@ -148,11 +200,11 @@ public:
*/
std::string getDescription() const
{
if (description) {
return *description;
if (m_description) {
return *m_description;
}
throw std::runtime_error("Schema does not have a description");
throwRuntimeError("Schema does not have a description");
}
/**
@ -164,11 +216,11 @@ public:
*/
std::string getId() const
{
if (id) {
return *id;
if (m_id) {
return *m_id;
}
throw std::runtime_error("Schema does not have an ID");
throwRuntimeError("Schema does not have an ID");
}
/**
@ -180,11 +232,11 @@ public:
*/
std::string getTitle() const
{
if (title) {
return *title;
if (m_title) {
return *m_title;
}
throw std::runtime_error("Schema does not have a title");
throwRuntimeError("Schema does not have a title");
}
/**
@ -194,7 +246,7 @@ public:
*/
bool hasDescription() const
{
return static_cast<bool>(description);
return static_cast<bool>(m_description);
}
/**
@ -204,7 +256,7 @@ public:
*/
bool hasId() const
{
return static_cast<bool>(id);
return static_cast<bool>(m_id);
}
/**
@ -214,7 +266,12 @@ public:
*/
bool hasTitle() const
{
return static_cast<bool>(title);
return static_cast<bool>(m_title);
}
void setAlwaysInvalid(bool value)
{
m_alwaysInvalid = value;
}
/**
@ -229,12 +286,12 @@ public:
*/
void setDescription(const std::string &description)
{
this->description = description;
m_description = description;
}
void setId(const std::string &id)
{
this->id = id;
m_id = id;
}
/**
@ -249,34 +306,30 @@ public:
*/
void setTitle(const std::string &title)
{
this->title = title;
m_title = title;
}
protected:
CustomAlloc allocFn;
CustomAlloc m_allocFn;
CustomFree freeFn;
CustomFree m_freeFn;
private:
// Disable copy construction
Subschema(const Subschema &);
// Disable copy assignment
Subschema & operator=(const Subschema &);
bool m_alwaysInvalid;
/// List of pointers to constraints that apply to this schema.
std::vector<const Constraint *> constraints;
std::vector<Constraint::OwningPointer> m_constraints;
/// Schema description (optional)
opt::optional<std::string> description;
opt::optional<std::string> m_description;
/// Id to apply when resolving the schema URI
opt::optional<std::string> id;
/// ID to apply when resolving the schema URI
opt::optional<std::string> m_id;
/// Title string associated with the schema (optional)
opt::optional<std::string> title;
opt::optional<std::string> m_title;
};
} // namespace valijson

View File

@ -0,0 +1,44 @@
#pragma once
#include <iostream>
#include <boost/json.hpp>
#include <valijson/utils/file_utils.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace utils {
inline bool loadDocument(const std::string &path, boost::json::value &document)
{
// Load schema JSON from file
std::string file;
if (!loadFile(path, file)) {
std::cerr << "Failed to load json from file '" << path << "'."
<< std::endl;
return false;
}
// Parse schema
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
boost::system::error_code errorCode;
boost::json::string_view stringView{file};
document = boost::json::parse(stringView, errorCode);
if (errorCode) {
std::cerr << "Boost.JSON parsing error: " << errorCode.message();
return false;
}
#if VALIJSON_USE_EXCEPTIONS
} catch (std::exception const & exception) {
std::cerr << "Boost.JSON parsing exception: " << exception.what();
return false;
}
#endif
return true;
}
} // namespace utils
} // namespace valijson

View File

@ -1,6 +1,8 @@
#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <json/json.h>
@ -18,14 +20,14 @@ inline bool loadDocument(const std::string &path, Json::Value &document)
return false;
}
Json::Reader reader;
bool parsingSuccessful = reader.parse(file, document);
if (!parsingSuccessful) {
std::cerr << "Jsoncpp parser failed to parse the document:" << std::endl
<< reader.getFormattedErrorMessages();
const auto fileLength = static_cast<int>(file.length());
Json::CharReaderBuilder builder;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
std::string err;
if (!reader->parse(file.c_str(), file.c_str() + fileLength, &document, &err)) {
std::cerr << "Jsoncpp parser failed to parse the document:" << std::endl << err;
return false;
}
return true;
}

View File

@ -2,8 +2,9 @@
#include <iostream>
#include <json.hpp>
#include <nlohmann/json.hpp>
#include <valijson/utils/file_utils.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace utils {
@ -19,6 +20,7 @@ inline bool loadDocument(const std::string &path, nlohmann::json &document)
}
// Parse schema
#if VALIJSON_USE_EXCEPTIONS
try {
document = nlohmann::json::parse(file);
} catch (std::invalid_argument const& exception) {
@ -26,6 +28,13 @@ inline bool loadDocument(const std::string &path, nlohmann::json &document)
<< "Parse error:" << exception.what() << "\n";
return false;
}
#else
document = nlohmann::json::parse(file, nullptr, false);
if (document.is_discarded()) {
std::cerr << "nlohmann::json failed to parse the document.";
return false;
}
#endif
return true;
}

View File

@ -2,7 +2,13 @@
#include <iostream>
#ifdef _MSC_VER
#pragma warning(disable: 4706)
#include <picojson.h>
#pragma warning(default: 4706)
#else
#include <picojson.h>
#endif
#include <valijson/utils/file_utils.hpp>

View File

@ -4,30 +4,68 @@
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/throw_exception.hpp>
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
# pragma clang diagnostic ignored "-Wshadow"
# include <boost/property_tree/json_parser.hpp>
# pragma clang diagnostic pop
#else
# include <boost/property_tree/json_parser.hpp>
#endif
// Source locations were added in boost 1.73.
#include <boost/version.hpp>
#if (BOOST_VERSION > 107300)
#include <boost/assert/source_location.hpp>
#endif
#include <valijson/utils/file_utils.hpp>
#include <valijson/exceptions.hpp>
#if !VALIJSON_USE_EXCEPTIONS
namespace boost {
// Boost requires used-defined exception throwers when exceptions are
// disabled.
// NOTE: BOOST_NORETURN attribute was added in 1.71.
#if (BOOST_VERSION >= 107100)
BOOST_NORETURN
#endif
void throw_exception(std::exception const & e ) {
valijson::throwRuntimeError(e.what());
}
// Source location override was added in 1.73.
#if (BOOST_VERSION >= 107300)
BOOST_NORETURN
void throw_exception(std::exception const & e, boost::source_location const & loc ) {
valijson::throwRuntimeError(e.what());
}
#endif
} // namespace boost
#endif
namespace valijson {
namespace utils {
inline bool loadDocument(const std::string &path, boost::property_tree::ptree &document)
{
#if !defined(BOOST_NO_EXCEPTIONS)
try {
#endif
boost::property_tree::read_json(path, document);
#if !defined(BOOST_NO_EXCEPTIONS)
} catch (std::exception &e) {
std::cerr << "Boost Property Tree JSON parser failed to parse the document:" << std::endl;
std::cerr << e.what() << std::endl;
return false;
}
#endif
return true;
}

View File

@ -4,7 +4,7 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <valijson/utils/file_utils.hpp>

View File

@ -1,6 +1,7 @@
#pragma once
#include <iostream>
#include <stdexcept>
#include <rapidjson/document.h>
@ -20,13 +21,23 @@ inline bool loadDocument(const std::string &path, rapidjson::GenericDocument<Enc
}
// Parse schema
document.template Parse<0>(file.c_str());
if (document.HasParseError()) {
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
document.template Parse<rapidjson::kParseIterativeFlag>(file.c_str());
if (document.HasParseError()) {
std::cerr << "RapidJson failed to parse the document:" << std::endl;
std::cerr << "Parse error: " << document.GetParseError() << std::endl;
std::cerr << "Near: " << file.substr((std::max)(size_t(0), document.GetErrorOffset() - 20), 40) << std::endl;
return false;
}
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::runtime_error &e) {
std::cerr << "RapidJson failed to parse the document:" << std::endl;
std::cerr << "Parse error: " << document.GetParseError() << std::endl;
std::cerr << "Near: " << file.substr((std::max)(size_t(0), document.GetErrorOffset() - 20), 40) << std::endl;
std::cerr << "Runtime error: " << e.what() << std::endl;
return false;
}
#endif
return true;
}

View File

@ -1,6 +1,10 @@
#pragma once
#include <assert.h>
#include <stdexcept>
#include <string>
#include <valijson/exceptions.hpp>
/*
Basic UTF-8 manipulation routines, adapted from code that was released into
@ -10,51 +14,39 @@
namespace valijson {
namespace utils {
static const uint32_t offsetsFromUTF8[6] = {
0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL
};
/* is c the start of a utf8 sequence? */
inline bool isutf(char c) {
return ((c & 0xC0) != 0x80);
}
/* reads the next utf-8 sequence out of a string, updating an index */
inline uint32_t u8_nextchar(const char *s, int *i)
inline bool isutf(char c)
{
uint32_t ch = 0;
int sz = 0;
do {
ch <<= 6;
ch += (unsigned char)s[(*i)++];
sz++;
} while (s[*i] && !isutf(s[*i]));
ch -= offsetsFromUTF8[sz-1];
return ch;
return ((c & 0xC0) != 0x80);
}
/* number of characters */
inline uint64_t u8_strlen(const char *s)
{
static const int maxLength = std::numeric_limits<int>::max();
uint64_t count = 0;
int i = 0;
while (s[i] != 0 && u8_nextchar(s, &i) != 0) {
if (i == maxLength) {
throw std::runtime_error(
"String exceeded maximum size of " +
std::to_string(maxLength) + " bytes.");
while (*s) {
unsigned char p = static_cast<unsigned char>(*s);
size_t seqLen = p < 0x80 ? 1 // 0xxxxxxx: 1-byte (ASCII)
: p < 0xE0 ? 2 // 110xxxxx: 2-byte sequence
: p < 0xF0 ? 3 // 1110xxxx: 3-byte sequence
: p < 0xF8 ? 4 // 11110xxx: 4-byte sequence
: 1; // treat as a single character
for (size_t i = 1; i < seqLen; ++i) {
if (s[i] == 0 || isutf(s[i])) {
seqLen = i;
break;
}
}
s += seqLen;
count++;
}
return count;
}
} // namespace utils
} // namespace valijson
} // namespace utils
} // namespace valijson

View File

@ -0,0 +1,29 @@
#pragma once
#include <iostream>
#include <memory>
#include <string>
#include <yaml-cpp/yaml.h>
#include <valijson/utils/file_utils.hpp>
namespace valijson {
namespace utils {
inline bool loadDocument(const std::string &path, YAML::Node &document)
{
try {
document = YAML::LoadFile(path);
return true;
} catch (const YAML::BadFile &ex) {
std::cerr << "Failed to load YAML from file '" << path << "'." << std::endl;
return false;
} catch (const YAML::ParserException &ex) {
std::cout << "yaml-cpp failed to parse the document '" << ex.what() << std::endl;
return false;
}
}
} // namespace utils
} // namespace valijson

View File

@ -2,6 +2,7 @@
#include <deque>
#include <string>
#include <utility>
#include <vector>
namespace valijson {
@ -25,21 +26,6 @@ public:
*/
struct Error
{
/**
* @brief Construct an Error object with no context or description.
*/
Error() { }
/**
* @brief Construct an Error object using a context and description.
*
* @param context Context string to use
* @param description Description string to use
*/
Error(const std::vector<std::string> &context, const std::string &description)
: context(context),
description(description) { }
/// Path to the node that failed validation.
std::vector<std::string> context;
@ -52,7 +38,7 @@ public:
*/
std::deque<Error>::const_iterator begin() const
{
return errors.begin();
return m_errors.begin();
}
/**
@ -60,7 +46,7 @@ public:
*/
std::deque<Error>::const_iterator end() const
{
return errors.end();
return m_errors.end();
}
/**
@ -68,7 +54,7 @@ public:
*/
size_t numErrors() const
{
return errors.size();
return m_errors.size();
}
/**
@ -78,7 +64,7 @@ public:
*/
void pushError(const Error &error)
{
errors.push_back(error);
m_errors.push_back(error);
}
/**
@ -90,7 +76,7 @@ public:
void
pushError(const std::vector<std::string> &context, const std::string &description)
{
errors.push_back(Error(context, description));
m_errors.push_back({context, description});
}
/**
@ -103,20 +89,19 @@ public:
bool
popError(Error &error)
{
if (errors.empty()) {
if (m_errors.empty()) {
return false;
}
error = errors.front();
errors.pop_front();
error = m_errors.front();
m_errors.pop_front();
return true;
}
private:
/// FIFO queue of validation errors that have been reported
std::deque<Error> errors;
std::deque<Error> m_errors;
};
} // namespace valijson

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,15 @@ namespace valijson {
class Schema;
class ValidationResults;
/**
* @brief Class that provides validation functionality.
* @brief Class that provides validation functionality.
*
* @tparam RegexEngine regular expression engine used for pattern constraint validation.
*/
class Validator
template <typename RegexEngine>
class ValidatorT
{
public:
enum TypeCheckingMode
@ -20,19 +25,29 @@ public:
kWeakTypes
};
enum DateTimeMode
{
kStrictDateTime,
kPermissiveDateTime
};
/**
* @brief Construct a Validator that uses strong type checking by default
*/
Validator()
: strictTypes(true) { }
ValidatorT()
: strictTypes(true)
, strictDateTime(true)
{ }
/**
* @brief Construct a Validator using a specific type checking mode
*
* @param typeCheckingMode choice of strong or weak type checking
*/
Validator(TypeCheckingMode typeCheckingMode)
: strictTypes(typeCheckingMode == kStrongTypes) { }
ValidatorT(TypeCheckingMode typeCheckingMode, DateTimeMode dateTimeMode = kStrictDateTime)
: strictTypes(typeCheckingMode == kStrongTypes)
, strictDateTime(dateTimeMode == kStrictDateTime)
{ }
/**
* @brief Validate a JSON document and optionally return the results.
@ -58,8 +73,13 @@ public:
ValidationResults *results)
{
// Construct a ValidationVisitor to perform validation at the root level
ValidationVisitor<AdapterType> v(target,
std::vector<std::string>(1, "<root>"), strictTypes, results);
ValidationVisitor<AdapterType, RegexEngine> v(
target,
std::vector<std::string>(1, "<root>"),
strictTypes,
strictDateTime,
results,
regexesCache);
return v.validateSchema(schema);
}
@ -67,8 +87,32 @@ public:
private:
/// Flag indicating that strict type comparisons should be used
const bool strictTypes;
bool strictTypes;
/// Parse date/time values strictly, according to RFC-3999
bool strictDateTime;
/// Cached regex objects for pattern constraint. Key - pattern.
std::unordered_map<std::string, RegexEngine> regexesCache;
};
/**
* @brief Struct that provides a default Regular Expression Engine using std::regex
*/
struct DefaultRegexEngine
{
DefaultRegexEngine(const std::string& pattern)
: regex(pattern) { }
static bool search(const std::string& s, const DefaultRegexEngine& r)
{
return internal::regex_search(s, r.regex);
}
private:
internal::regex regex;
};
using Validator = ValidatorT<DefaultRegexEngine>;
} // namespace valijson

3
inspector/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
build/
cmake-build-*/
CMakeFiles/

43
inspector/CMakeLists.txt Normal file
View File

@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.10.0)
# Add folder where are supportive functions
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Include Qt basic functions
include(QtCommon)
# Basic information about project
project(inspector VERSION 1.0)
# Set PROJECT_VERSION_PATCH and PROJECT_VERSION_TWEAK to 0 if not present, needed by add_project_meta
fix_project_version()
# Set additional project information
set(COPYRIGHT "Copyright (c) 2021 Tristan Penman. All rights reserved.")
set(IDENTIFIER "com.tristanpenman.valijson.inspector")
set(SOURCE_FILES
src/highlighter.cpp
src/main.cpp
src/window.cpp
)
include_directories(SYSTEM ../include)
add_project_meta(META_FILES_TO_INCLUDE)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets REQUIRED)
add_definitions(-DVALIJSON_USE_EXCEPTIONS=1)
add_executable(${PROJECT_NAME} ${OS_BUNDLE} # Expands to WIN32 or MACOS_BUNDLE depending on OS
${SOURCE_FILES} ${META_FILES_TO_INCLUDE} ${RESOURCE_FILES}
)
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Widgets
)

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>JSON Inspector</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -0,0 +1,82 @@
macro(fix_project_version)
if (NOT PROJECT_VERSION_PATCH)
set(PROJECT_VERSION_PATCH 0)
endif()
if (NOT PROJECT_VERSION_TWEAK)
set(PROJECT_VERSION_TWEAK 0)
endif()
endmacro()
macro(add_project_meta FILES_TO_INCLUDE)
if (NOT RESOURCE_FOLDER)
set(RESOURCE_FOLDER res)
endif()
if (NOT ICON_NAME)
set(ICON_NAME AppIcon)
endif()
if (APPLE)
set(ICON_FILE ${RESOURCE_FOLDER}/${ICON_NAME}.icns)
elseif (WIN32)
set(ICON_FILE ${RESOURCE_FOLDER}/${ICON_NAME}.ico)
endif()
if (WIN32)
configure_file("${PROJECT_SOURCE_DIR}/cmake/windows_metafile.rc.in"
"windows_metafile.rc"
)
set(RES_FILES "windows_metafile.rc")
set(CMAKE_RC_COMPILER_INIT windres)
ENABLE_LANGUAGE(RC)
SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
endif()
if (APPLE)
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# Identify macOS bundle
set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION})
set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION})
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
set(MACOSX_BUNDLE_COPYRIGHT ${COPYRIGHT})
set(MACOSX_BUNDLE_GUI_IDENTIFIER ${IDENTIFIER})
set(MACOSX_BUNDLE_ICON_FILE ${ICON_NAME})
endif()
if (APPLE)
set(${FILES_TO_INCLUDE} ${ICON_FILE})
elseif (WIN32)
set(${FILES_TO_INCLUDE} ${RES_FILES})
endif()
endmacro()
macro(init_os_bundle)
if (APPLE)
set(OS_BUNDLE MACOSX_BUNDLE)
elseif (WIN32)
set(OS_BUNDLE WIN32)
endif()
endmacro()
macro(fix_win_compiler)
if (MSVC)
set_target_properties(${PROJECT_NAME} PROPERTIES
WIN32_EXECUTABLE YES
LINK_FLAGS "/ENTRY:mainCRTStartup"
)
endif()
endmacro()
macro(init_qt)
# Let's do the CMake job for us
set(CMAKE_AUTOMOC ON) # For meta object compiler
set(CMAKE_AUTORCC ON) # Resource files
set(CMAKE_AUTOUIC ON) # UI files
endmacro()
init_os_bundle()
init_qt()
fix_win_compiler()

View File

@ -0,0 +1,28 @@
#include "winver.h"
IDI_ICON1 ICON DISCARDABLE "@ICON_FILE@"
VS_VERSION_INFO VERSIONINFO
FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_TWEAK@
PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_TWEAK@
FILEFLAGS 0x0L
FILEFLAGSMASK 0x3fL
FILEOS 0x00040004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004b0"
BEGIN
VALUE "CompanyName", "@COMPANY@"
VALUE "FileDescription", "@PROJECT_NAME@"
VALUE "FileVersion", "@PROJECT_VERSION@"
VALUE "LegalCopyright", "@COPYRIGHT@"
VALUE "InternalName", "@PROJECT_NAME@"
VALUE "OriginalFilename", "@PROJECT_NAME@.exe"
VALUE "ProductName", "@PROJECT_NAME@"
VALUE "ProductVersion", "@PROJECT_VERSION@"
END
END
END

4
inspector/inspector.qrc Normal file
View File

@ -0,0 +1,4 @@
<RCC version="1.0">
<qresource prefix="/">
</qresource>
</RCC>

BIN
inspector/res/AppIcon.icns Normal file

Binary file not shown.

BIN
inspector/res/AppIcon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

View File

@ -0,0 +1,12 @@
#include "highlighter.h"
Highlighter::Highlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
// TODO
}
void Highlighter::highlightBlock(const QString &text)
{
// TODO
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <QSyntaxHighlighter>
class Highlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
Highlighter(QTextDocument * parent = 0);
protected:
void highlightBlock(const QString & text) override;
};

14
inspector/src/main.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <QApplication>
#include "window.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < 0x060000
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}

223
inspector/src/window.cpp Normal file
View File

@ -0,0 +1,223 @@
#include <sstream>
#include <stdexcept>
#include <QFile>
#include <QFileDialog>
#include <QMenu>
#include <QSplitter>
#include <QStatusBar>
#include <QString>
#include <QTabWidget>
#include <QTextEdit>
#include <QToolBar>
#include <QToolButton>
#include <valijson/adapters/qtjson_adapter.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validation_results.hpp>
#include <valijson/validator.hpp>
#include "highlighter.h"
#include "window.h"
Window::Window(QWidget * parent)
: QMainWindow(parent)
, m_schema(nullptr)
{
setWindowTitle("JSON Inspector");
m_documentEditor = createEditor(false);
m_schemaEditor = createEditor(false);
m_errors = createEditor(true);
auto documentTabWidget = createTabWidget(m_documentEditor, "Document");
auto schemaTabWidget = createTabWidget(m_schemaEditor, "Schema");
auto horizontalSplitter = createSplitter(schemaTabWidget, documentTabWidget, true);
auto errorsTabWidget = createTabWidget(m_errors, "Errors");
auto verticalSplitter = createSplitter(horizontalSplitter, errorsTabWidget, false);
verticalSplitter->setStretchFactor(0, 2);
verticalSplitter->setStretchFactor(1, 1);
auto toolBar = createToolBar();
auto statusBar = createStatusBar();
addToolBar(toolBar);
setCentralWidget(verticalSplitter);
setStatusBar(statusBar);
connect(m_documentEditor, SIGNAL(textChanged()), this, SLOT(refreshJson()));
connect(m_schemaEditor, SIGNAL(textChanged()), this, SLOT(refreshJson()));
refreshJson();
}
QTextEdit * Window::createEditor(bool readOnly)
{
QFont font;
font.setFamily("Courier");
font.setFixedPitch(true);
font.setPointSize(12);
auto editor = new QTextEdit();
editor->setFont(font);
editor->setReadOnly(readOnly);
auto highlighter = new Highlighter(editor->document());
return editor;
}
QSplitter * Window::createSplitter(QWidget * left, QWidget * right, bool horizontal)
{
auto splitter = new QSplitter(horizontal ? Qt::Horizontal : Qt::Vertical);
splitter->setChildrenCollapsible(false);
splitter->insertWidget(0, left);
splitter->insertWidget(1, right);
return splitter;
}
QStatusBar * Window::createStatusBar()
{
return new QStatusBar();
}
QTabWidget * Window::createTabWidget(QWidget * child, const QString & name)
{
auto tabWidget = new QTabWidget();
tabWidget->addTab(child, name);
tabWidget->setDocumentMode(true);
return tabWidget;
}
QToolBar * Window::createToolBar()
{
auto toolbar = new QToolBar();
toolbar->setMovable(false);
auto openMenu = new QMenu("Open");
auto openSchemaAction = openMenu->addAction("Open Schema...");
auto openDocumentAction = openMenu->addAction("Open Document...");
auto openButton = new QToolButton();
openButton->setMenu(openMenu);
openButton->setPopupMode(QToolButton::MenuButtonPopup);
openButton->setText("Open");
openButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
toolbar->addWidget(openButton);
connect(openButton, &QToolButton::clicked, openButton, &QToolButton::showMenu);
connect(openDocumentAction, SIGNAL(triggered()), this, SLOT(showOpenDocumentDialog()));
connect(openSchemaAction, SIGNAL(triggered()), this, SLOT(showOpenSchemaDialog()));
return toolbar;
}
void Window::refreshJson()
{
QString errors;
m_errors->setText("");
const auto schema = m_schemaEditor->toPlainText().toUtf8();
const auto doc = m_documentEditor->toPlainText().toUtf8();
if (schema.isEmpty()) {
if (doc.isEmpty()) {
m_errors->setText(
"Please provide a schema and a document to be validated.\n\n"
"Note that this example uses QtJson, which does not consider non-array and "
"non-object values to be valid JSON documents.");
return;
} else {
errors += "Schema error: must not be empty\n\n";
}
} else {
QJsonParseError error;
m_schemaJson = QJsonDocument::fromJson(schema, &error);
if (m_schemaJson.isNull()) {
errors += QString("Schema error: ") + error.errorString() + "\n\n";
}
}
if (doc.isEmpty()) {
if (!schema.isEmpty()) {
errors += "Document error: must not be empty\n\n";
}
} else {
QJsonParseError error;
m_documentJson = QJsonDocument::fromJson(doc, &error);
if (m_documentJson.isNull()) {
errors += QString("Document error: ") + error.errorString() + "\n\n";
}
}
if (!errors.isEmpty()) {
m_errors->setText(errors);
return;
}
try {
valijson::adapters::QtJsonAdapter adapter(m_schemaJson.object());
valijson::SchemaParser parser;
delete m_schema;
m_schema = new valijson::Schema();
parser.populateSchema(adapter, *m_schema);
validate();
} catch (std::runtime_error & error) {
delete m_schema;
m_schema = nullptr;
m_errors->setText(QString("Schema error: ") + error.what());
}
}
void Window::showOpenDocumentDialog()
{
const QString fileName = QFileDialog::getOpenFileName(this, "Open Document", QString(), QString("*.json"));
if (!fileName.isEmpty()) {
QFile file(fileName);
file.open(QFile::ReadOnly | QFile::Text);
m_documentEditor->setText(file.readAll());
}
}
void Window::showOpenSchemaDialog()
{
const QString fileName = QFileDialog::getOpenFileName(this, "Open Schema", QString(), QString("*.json"));
if (!fileName.isEmpty()) {
QFile file(fileName);
file.open(QFile::ReadOnly | QFile::Text);
m_schemaEditor->setText(file.readAll());
}
}
void Window::validate()
{
valijson::ValidationResults results;
valijson::Validator validator;
valijson::adapters::QtJsonAdapter adapter(m_documentJson.object());
if (validator.validate(*m_schema, adapter, &results)) {
m_errors->setText("Document is valid.");
return;
}
valijson::ValidationResults::Error error;
unsigned int errorNum = 1;
std::stringstream ss;
while (results.popError(error)) {
std::string context;
for (auto & itr : error.context) {
context += itr;
}
ss << "Validation error #" << errorNum << std::endl
<< " context: " << context << std::endl
<< " desc: " << error.description << std::endl;
++errorNum;
}
m_errors->setText(QString::fromStdString(ss.str()));
}

48
inspector/src/window.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <QJsonDocument>
#include <QMainWindow>
class QJsonDocument;
class QSplitter;
class QStatusBar;
class QTabWidget;
class QTextEdit;
class QToolBar;
namespace valijson {
class Schema;
}
class Window : public QMainWindow
{
Q_OBJECT
public:
explicit Window(QWidget * parent = 0);
public slots:
void refreshJson();
void showOpenDocumentDialog();
void showOpenSchemaDialog();
private:
QTextEdit * createEditor(bool readOnly);
QSplitter * createSplitter(QWidget * left, QWidget * right, bool horizontal);
QStatusBar * createStatusBar();
QTabWidget * createTabWidget(QWidget * child, const QString & name);
QToolBar * createToolBar();
void validate();
QTextEdit * m_documentEditor;
QTextEdit * m_schemaEditor;
QTextEdit * m_errors;
QJsonDocument m_documentJson;
QJsonDocument m_schemaJson;
valijson::Schema * m_schema;
};

62
shellcheck.sh Normal file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env bash
#
# Shellcheck is a static analyzer for shell scripts: https://shellcheck.net/
# It is available in several operating systems and also as a docker image.
#
# If it finds any issues, it will output a small blurb describing the affected
# line(s) and will have a generic issue ID. The issue ID can be opened on its
# website to learn more about what the underlying problem is, why it's a
# problem, and (usually) suggests a way to fix.
# Specific shellcheck issues can be disabled (aka silenced). Doing so is
# usually pretty loud during code review.
# https://github.com/koalaman/shellcheck/wiki/Directive
# https://stackoverflow.com/a/2871034/1111557
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
SHELLCHECK="${SHELLCHECK:-"/usr/bin/shellcheck"}"
SEARCH_DIR="${SEARCH_DIR:-"$HERE"}"
cd "${SEARCH_DIR}" #so that we can call git
#
# This block will:
# 1) `find` files under `SEARCH_DIR`
# 2) skip anything under `/thirdparty/`, `/.git/`
# 3) in a loop reading each path:
# 3a) ignore files that git also ignores
# 3b) use `file` to filter only script files
# 3c) run shellcheck against that script
# 4) if any paths are found to have an error, their paths are collated.
FAILED_PATHS=()
while read -r file_path
do
if git rev-parse --git-dir > /dev/null 2>&1;
then
git check-ignore --quiet "${file_path}" && continue
fi
file "${file_path}" | grep -q 'shell script' || continue
SCRIPT_PATH="${file_path}"
echo "Checking: ${SCRIPT_PATH}"
"${SHELLCHECK}" \
"${SCRIPT_PATH}" \
|| FAILED_PATHS+=( "${SCRIPT_PATH}" )
done < <(
find "${SEARCH_DIR}" -type f \
| grep -v '/\.git/\|/thirdparty/'
)
#
# If there are any failed paths, summarize them here.
# Then report a failing status to our caller.
if [[ 0 -lt "${#FAILED_PATHS[@]}" ]]; then
>&2 echo "These scripts aren't shellcheck-clean:"
for path in "${FAILED_PATHS[@]}"; do
>&2 echo "${path}"
done
exit 1
fi
# If we get here, then none of the scripts had any warnings.
echo "All scripts found (listed above) passed shellcheck"

View File

@ -0,0 +1,22 @@
[
{
"timestamp": "AAA",
"validity": "invalid"
},
{
"timestamp": "2000",
"validity": "invalid"
},
{
"timestamp": "2000-01-01T00:00:00",
"validity": "permissive"
},
{
"timestamp": "2000-01-01T00:00:00Z",
"validity": "strict"
},
{
"timestamp": "2000-01-01T00:00:00+02:00",
"validity": "strict"
}
]

View File

@ -1 +1 @@
{}
{}

View File

@ -0,0 +1,8 @@
{
"description": "Circular reference when parsing properties keyword",
"properties": {
"foo": {"$ref": "#/properties/bar"},
"bar": {"$ref": "#/properties/baz"},
"baz": {"$ref": "#/properties/foo"}
}
}

View File

@ -0,0 +1,7 @@
{
"properties": {
"timestamp": {
"format": "date-time"
}
}
}

78
tests/fuzzing/fuzzer.cpp Normal file
View File

@ -0,0 +1,78 @@
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
using valijson::Schema;
using valijson::SchemaParser;
using valijson::ValidationResults;
using valijson::Validator;
using valijson::adapters::AdapterTraits;
using valijson::adapters::RapidJsonAdapter;
using AdapterType = RapidJsonAdapter;
void runOneTest(const AdapterType &test, const Schema &schema,
Validator::TypeCheckingMode mode)
{
try {
if (!test.isObject()) {
return;
}
const AdapterType::Object testObject = test.getObject();
const auto dataItr = testObject.find("data");
if (dataItr == testObject.end()) {
return;
}
Validator validator(mode);
ValidationResults results;
validator.validate(schema, dataItr->second, &results);
} catch (const std::exception &) {
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
AdapterTraits<AdapterType>::DocumentType document;
document.template Parse<rapidjson::kParseIterativeFlag>(reinterpret_cast<const char *>(data), size);
if (document.HasParseError() || !document.IsArray()) {
return 0;
}
for (const auto &testCase : AdapterType(document).getArray()) {
if (!testCase.isObject()) {
continue;
}
const AdapterType::Object object = testCase.getObject();
const auto schemaItr = object.find("schema");
const auto testsItr = object.find("tests");
if (schemaItr == object.end() || testsItr == object.end() ||
!testsItr->second.isArray()) {
continue;
}
Schema schema;
SchemaParser parser(size % 2 ? SchemaParser::kDraft4
: SchemaParser::kDraft7);
try {
parser.populateSchema(schemaItr->second, schema);
} catch (const std::exception &) {
continue;
}
const auto mode = testsItr->second.hasStrictTypes()
? Validator::kStrongTypes
: Validator::kWeakTypes;
for (const AdapterType test : testsItr->second.getArray()) {
runOneTest(test, schema, mode);
}
}
return 0;
}

32
tests/fuzzing/oss-fuzz-build.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash -eu
git submodule update --init --depth 1 thirdparty
mkdir build
cd build
cmake \
-Dvalijson_BUILD_TESTS=TRUE \
-Dvalijson_BUILD_EXAMPLES=FALSE \
-Dvalijson_EXCLUDE_BOOST=TRUE \
..
make -j"$(nproc)"
cd ../tests/fuzzing
# CXXFLAGS may contain spaces
# shellcheck disable=SC2086
"$CXX" $CXXFLAGS "$LIB_FUZZING_ENGINE" \
-DVALIJSON_USE_EXCEPTIONS=1 \
-I/src/valijson/thirdparty/rapidjson/include \
-I/src/valijson/include \
fuzzer.cpp -o "${OUT}/fuzzer"
mkdir seed_corpus
find "${SRC}/valijson/thirdparty/JSON-Schema-Test-Suite/tests" -name "*.json" | while read file; do
sha1=$(sha1sum "$file" | awk '{print $1}')
cp "$file" seed_corpus/"${sha1}"
done
zip -j -r "${OUT}/fuzzer_seed_corpus.zip" seed_corpus

View File

@ -1,4 +1,10 @@
#ifdef _MSC_VER
#pragma warning(disable: 4706)
#include <picojson.h>
#pragma warning(default: 4706)
#else
#include <picojson.h>
#endif
#include <gtest/gtest.h>
@ -14,7 +20,12 @@
#include <valijson/utils/picojson_utils.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
#include <valijson/adapters/boost_json_adapter.hpp>
#include <valijson/utils/boost_json_utils.hpp>
#endif
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#include <valijson/adapters/property_tree_adapter.hpp>
#include <valijson/utils/property_tree_utils.hpp>
#endif
@ -22,6 +33,7 @@
#ifdef VALIJSON_BUILD_QT_ADAPTER
#include <valijson/adapters/qtjson_adapter.hpp>
#include <valijson/utils/qtjson_utils.hpp>
#include <utility>
#endif
#ifdef VALIJSON_BUILD_POCO_ADAPTER
@ -39,19 +51,18 @@ protected:
struct JsonFile
{
JsonFile(const std::string &path, int strictGroup, int looseGroup)
: path(path),
strictGroup(strictGroup),
looseGroup(looseGroup) { }
JsonFile(std::string path, int strictGroup, int looseGroup)
: m_path(std::move(path)),
m_strictGroup(strictGroup),
m_looseGroup(looseGroup) { }
std::string path;
int strictGroup;
int looseGroup;
std::string m_path;
int m_strictGroup;
int m_looseGroup;
};
static void SetUpTestCase() {
static void SetUpTestCase()
{
const std::string testDataDir(TEST_DATA_DIR);
//
@ -66,17 +77,17 @@ protected:
// strict types. However, only the first two files in the same strict
// group, which means that only they should be equal.
//
jsonFiles.push_back(JsonFile(testDataDir + "array_doubles_1_2_3.json", 1, 1));
jsonFiles.push_back(JsonFile(testDataDir + "array_integers_1_2_3.json", 1, 1));
jsonFiles.push_back(JsonFile(testDataDir + "array_strings_1_2_3.json", 2, 1));
jsonFiles.emplace_back(testDataDir + "array_doubles_1_2_3.json", 1, 1);
jsonFiles.emplace_back(testDataDir + "array_integers_1_2_3.json", 1, 1);
jsonFiles.emplace_back(testDataDir + "array_strings_1_2_3.json", 2, 1);
jsonFiles.push_back(JsonFile(testDataDir + "array_doubles_1_2_3_4.json", 3, 2));
jsonFiles.push_back(JsonFile(testDataDir + "array_integers_1_2_3_4.json", 3, 2));
jsonFiles.push_back(JsonFile(testDataDir + "array_strings_1_2_3_4.json", 4, 2));
jsonFiles.emplace_back(testDataDir + "array_doubles_1_2_3_4.json", 3, 2);
jsonFiles.emplace_back(testDataDir + "array_integers_1_2_3_4.json", 3, 2);
jsonFiles.emplace_back(testDataDir + "array_strings_1_2_3_4.json", 4, 2);
jsonFiles.push_back(JsonFile(testDataDir + "array_doubles_10_20_30_40.json", 5, 3));
jsonFiles.push_back(JsonFile(testDataDir + "array_integers_10_20_30_40.json", 5, 3));
jsonFiles.push_back(JsonFile(testDataDir + "array_strings_10_20_30_40.json", 6, 3));
jsonFiles.emplace_back(testDataDir + "array_doubles_10_20_30_40.json", 5, 3);
jsonFiles.emplace_back(testDataDir + "array_integers_10_20_30_40.json", 5, 3);
jsonFiles.emplace_back(testDataDir + "array_strings_10_20_30_40.json", 6, 3);
}
template<typename Adapter1, typename Adapter2>
@ -87,16 +98,16 @@ protected:
for(outerItr = jsonFiles.begin(); outerItr != jsonFiles.end() - 1; ++outerItr) {
for(innerItr = outerItr; innerItr != jsonFiles.end(); ++innerItr) {
const bool expectedStrict = (outerItr->strictGroup == innerItr->strictGroup);
const bool expectedLoose = (outerItr->looseGroup == innerItr->looseGroup);
const bool expectedStrict = (outerItr->m_strictGroup == innerItr->m_strictGroup);
const bool expectedLoose = (outerItr->m_looseGroup == innerItr->m_looseGroup);
typename AdapterTraits<Adapter1>::DocumentType document1;
ASSERT_TRUE( valijson::utils::loadDocument(outerItr->path, document1) );
ASSERT_TRUE( valijson::utils::loadDocument(outerItr->m_path, document1) );
const Adapter1 adapter1(document1);
const std::string adapter1Name = AdapterTraits<Adapter1>::adapterName();
typename AdapterTraits<Adapter2>::DocumentType document2;
ASSERT_TRUE( valijson::utils::loadDocument(innerItr->path, document2) );
ASSERT_TRUE( valijson::utils::loadDocument(innerItr->m_path, document2) );
const Adapter2 adapter2(document2);
const std::string adapter2Name = AdapterTraits<Adapter2>::adapterName();
@ -107,22 +118,22 @@ protected:
// of equality makes sense.
if (adapter1.hasStrictTypes() && adapter2.hasStrictTypes() && adapter1Name == adapter2Name) {
EXPECT_EQ(expectedStrict, adapter1.equalTo(adapter2, true))
<< "Comparing '" << outerItr->path << "' to '"
<< innerItr->path << "' "
<< "Comparing '" << outerItr->m_path << "' to '"
<< innerItr->m_path << "' "
<< "with strict comparison enabled";
EXPECT_EQ(expectedStrict, adapter2.equalTo(adapter1, true))
<< "Comparing '" << innerItr->path << "' to '"
<< outerItr->path << "' "
<< "Comparing '" << innerItr->m_path << "' to '"
<< outerItr->m_path << "' "
<< "with strict comparison enabled";
}
EXPECT_EQ(expectedLoose, adapter1.equalTo(adapter2, false))
<< "Comparing '" << outerItr->path << "' to '"
<< innerItr->path << "' "
<< "Comparing '" << outerItr->m_path << "' to '"
<< innerItr->m_path << "' "
<< "with strict comparison disabled";
EXPECT_EQ(expectedLoose, adapter2.equalTo(adapter1, false))
<< "Comparing '" << innerItr->path << "' to '"
<< outerItr->path << "' "
<< "Comparing '" << innerItr->m_path << "' to '"
<< outerItr->m_path << "' "
<< "with strict comparison disabled";
}
}
@ -151,7 +162,18 @@ TEST_F(TestAdapterComparison, JsonCppVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
TEST_F(TestAdapterComparison, JsonCppVsBoostJson)
{
testComparison<
valijson::adapters::JsonCppAdapter,
valijson::adapters::BoostJsonAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_JSON_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, JsonCppVsPropertyTree)
{
@ -160,7 +182,7 @@ TEST_F(TestAdapterComparison, JsonCppVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, JsonCppVsRapidJson)
{
@ -178,12 +200,49 @@ TEST_F(TestAdapterComparison, JsonCppVsRapidJsonCrtAlloc)
rapidjson::CrtAllocator> > >();
}
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
//
// BoostJsonAdapter vs X
// ------------------------------------------------------------------------------------------------
TEST_F(TestAdapterComparison, BoostJsonVsPicoJson)
{
testComparison<
valijson::adapters::BoostJsonAdapter,
valijson::adapters::PicoJsonAdapter>();
}
TEST_F(TestAdapterComparison, BoostJsonVsBoostJson)
{
testComparison<
valijson::adapters::BoostJsonAdapter,
valijson::adapters::BoostJsonAdapter>();
}
TEST_F(TestAdapterComparison, BoostJsonVsRapidJson)
{
testComparison<
valijson::adapters::BoostJsonAdapter,
valijson::adapters::RapidJsonAdapter>();
}
TEST_F(TestAdapterComparison, BoostJsonVsRapidJsonCrtAlloc)
{
testComparison<
valijson::adapters::BoostJsonAdapter,
valijson::adapters::GenericRapidJsonAdapter<
rapidjson::GenericValue<rapidjson::UTF8<>,
rapidjson::CrtAllocator> > >();
}
#endif // VALIJSON_BUILD_BOOST_JSON_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
//
// PropertyTreeAdapter vs X
// ------------------------------------------------------------------------------------------------
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, PropertyTreeVsPicoJson)
{
testComparison<
@ -214,7 +273,7 @@ TEST_F(TestAdapterComparison, PropertyTreeVsRapidJsonCrtAlloc)
rapidjson::CrtAllocator> > >();
}
#endif
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
//
// RapidJson vs X
@ -316,7 +375,18 @@ TEST_F(TestAdapterComparison, Json11VsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
TEST_F(TestAdapterComparison, Json11VsBoostJson)
{
testComparison<
valijson::adapters::Json11Adapter,
valijson::adapters::BoostJsonAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_JSON_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, Json11VsPropertyTree)
{
@ -325,7 +395,7 @@ TEST_F(TestAdapterComparison, Json11VsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
//
// NlohmannJsonAdapter vs X
@ -375,7 +445,18 @@ TEST_F(TestAdapterComparison, NlohmannJsonVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
TEST_F(TestAdapterComparison, NlohmannJsonVsBoostJson)
{
testComparison<
valijson::adapters::NlohmannJsonAdapter,
valijson::adapters::BoostJsonAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_JSON_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, NlohmannJsonVsPropertyTree)
{
@ -384,7 +465,7 @@ TEST_F(TestAdapterComparison, NlohmannJsonVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
//
// QtJsonAdapter vs X
@ -428,7 +509,18 @@ TEST_F(TestAdapterComparison, QtJsonVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
TEST_F(TestAdapterComparison, QtJsonVsBoostJson)
{
testComparison<
valijson::adapters::QtJsonAdapter,
valijson::adapters::BoostJsonAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_JSON_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, QtJsonVsPropertyTree)
{
@ -437,7 +529,7 @@ TEST_F(TestAdapterComparison, QtJsonVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, QtJsonVsJson11)
{
@ -498,7 +590,18 @@ TEST_F(TestAdapterComparison, PocoJsonVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_JSON_ADAPTER
TEST_F(TestAdapterComparison, PocoJsonVsBoostJson)
{
testComparison<
valijson::adapters::PocoJsonAdapter,
valijson::adapters::BoostJsonAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_JSON_ADAPTER
#ifdef VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, PocoJsonVsPropertyTree)
{
@ -507,7 +610,7 @@ TEST_F(TestAdapterComparison, PocoJsonVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, PocoJsonVsJson11)
{

View File

@ -0,0 +1,89 @@
#include <gtest/gtest.h>
#include <boost/json/src.hpp> // Needs to be included exactly once in the code to use header-only version of Boost.JSON
#include <valijson/adapters/boost_json_adapter.hpp>
class TestBoostJsonAdapter : public testing::Test
{
};
TEST_F(TestBoostJsonAdapter, BasicArrayIteration)
{
const unsigned int numElements = 10;
// Create a Json document that consists of an array of numbers
boost::json::array array;
for (unsigned int i = 0; i < numElements; i++) {
// Boost.JSON differs from some other libraries in offering emplace_back()
// as well as push_back(). Using the former here saves us having to create
// a temporary.
array.emplace_back(static_cast<double>(i));
}
boost::json::value document(array);
// Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types
valijson::adapters::BoostJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() );
// Ensure that the elements are returned in the order they were inserted
unsigned int expectedValue = 0;
for (const valijson::adapters::BoostJsonAdapter value : adapter.getArray()) {
ASSERT_TRUE( value.isNumber() );
EXPECT_EQ( double(expectedValue), value.getDouble() );
expectedValue++;
}
// Ensure that the correct number of elements were iterated over
EXPECT_EQ(numElements, expectedValue);
}
TEST_F(TestBoostJsonAdapter, BasicObjectIteration)
{
const unsigned int numElements = 10;
// Create a DropBoxJson document that consists of an object that maps numeric
// strings their corresponding numeric values
boost::json::object object;
for (uint32_t i = 0; i < numElements; i++) {
object[std::to_string(i)] = static_cast<double>(i);
}
boost::json::value document(object);
// Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types
valijson::adapters::BoostJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() );
// Ensure that the members are returned in the order they were inserted
unsigned int expectedValue = 0;
for (const valijson::adapters::BoostJsonAdapter::ObjectMember member : adapter.getObject()) {
ASSERT_TRUE( member.second.isNumber() );
EXPECT_EQ( std::to_string(expectedValue), member.first );
EXPECT_EQ( double(expectedValue), member.second.getDouble() );
expectedValue++;
}
// Ensure that the correct number of elements were iterated over
EXPECT_EQ( numElements, expectedValue );
}

View File

@ -0,0 +1,69 @@
#include <iostream>
#include <gtest/gtest.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validation_results.hpp>
#include <valijson/validator.hpp>
#define TEST_DATA_DIR "../tests/data"
using std::string;
using valijson::adapters::AdapterTraits;
using valijson::adapters::RapidJsonAdapter;
using valijson::utils::loadDocument;
using valijson::Schema;
using valijson::SchemaParser;
using valijson::Validator;
using valijson::ValidationResults;
class TestDateTimeFormat : public ::testing::Test
{
};
TEST_F(TestDateTimeFormat, StrictAndPermissiveDateTimes)
{
// Load schema document
rapidjson::Document schemaDocument;
ASSERT_TRUE( loadDocument(TEST_DATA_DIR "/schemas/date_time_format.schema.json", schemaDocument) );
RapidJsonAdapter schemaAdapter(schemaDocument);
// Parse schema document
Schema schema;
SchemaParser schemaParser;
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW(schemaParser.populateSchema(schemaAdapter, schema));
#else
schemaParser.populateSchema(schemaAdapter, schema);
#endif
// Load test document
rapidjson::Document testDocument;
ASSERT_TRUE( loadDocument(TEST_DATA_DIR "/documents/date_time_format.json", testDocument) );
RapidJsonAdapter testAdapter(testDocument);
// Setup validators
Validator strictValidator(Validator::kStrongTypes, Validator::kStrictDateTime);
Validator permissiveValidator(Validator::kStrongTypes, Validator::kPermissiveDateTime);
const RapidJsonAdapter::Array examples = testAdapter.asArray();
for (auto &&example : examples) {
auto validity = example.asObject().find("validity")->second.asString();
if (validity == "strict") {
EXPECT_TRUE( strictValidator.validate(schema, example, NULL) );
EXPECT_TRUE( permissiveValidator.validate(schema, example, NULL) );
} else if (validity == "permissive") {
EXPECT_FALSE( strictValidator.validate(schema, example, NULL) );
EXPECT_TRUE( permissiveValidator.validate(schema, example, NULL) );
} else {
EXPECT_FALSE( strictValidator.validate(schema, example, NULL) );
EXPECT_FALSE( permissiveValidator.validate(schema, example, NULL) );
}
}
}

View File

@ -12,12 +12,12 @@ using valijson::SchemaParser;
using valijson::adapters::RapidJsonAdapter;
using valijson::Validator;
class TestFetchDocumentCallback : public ::testing::Test
class TestFetchAbsoluteUriDocumentCallback : public ::testing::Test
{
};
const rapidjson::Document * fetchDocument(const std::string &uri)
const rapidjson::Document * fetchAbsoluteUriDocument(const std::string &uri)
{
EXPECT_STREQ("http://localhost:1234/", uri.c_str());
@ -43,12 +43,12 @@ const rapidjson::Document * fetchDocument(const std::string &uri)
return fetchedRoot;
}
void freeDocument(const rapidjson::Document *adapter)
void freeAbsoluteUriDocument(const rapidjson::Document *adapter)
{
delete adapter;
}
TEST_F(TestFetchDocumentCallback, Basics)
TEST_F(TestFetchAbsoluteUriDocumentCallback, Basics)
{
// Define schema
rapidjson::Document schemaDocument;
@ -60,8 +60,8 @@ TEST_F(TestFetchDocumentCallback, Basics)
// Parse schema document
Schema schema;
SchemaParser schemaParser;
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchDocument,
freeDocument);
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchAbsoluteUriDocument,
freeAbsoluteUriDocument);
// Test resulting schema with a valid document
rapidjson::Document validDocument;

View File

@ -0,0 +1,80 @@
#include <gtest/gtest.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
using valijson::Schema;
using valijson::SchemaParser;
using valijson::adapters::RapidJsonAdapter;
using valijson::Validator;
class TestFetchUrnDocumentCallback : public ::testing::Test
{
};
const rapidjson::Document * fetchUrnDocument(const std::string &uri)
{
EXPECT_STREQ("urn:mvn:example.schema.common:status:1.1.0", uri.c_str());
rapidjson::Document *fetchedRoot = new rapidjson::Document();
fetchedRoot->SetObject();
rapidjson::Value valueOfTypeAttribute;
valueOfTypeAttribute.SetString("string", fetchedRoot->GetAllocator());
rapidjson::Value schemaOfTestProperty;
schemaOfTestProperty.SetObject();
schemaOfTestProperty.AddMember("type", valueOfTypeAttribute,
fetchedRoot->GetAllocator());
rapidjson::Value propertiesConstraint;
propertiesConstraint.SetObject();
propertiesConstraint.AddMember("test", schemaOfTestProperty,
fetchedRoot->GetAllocator());
fetchedRoot->AddMember("properties", propertiesConstraint,
fetchedRoot->GetAllocator());
return fetchedRoot;
}
void freeUrnDocument(const rapidjson::Document *adapter)
{
delete adapter;
}
TEST_F(TestFetchUrnDocumentCallback, Basics)
{
// Define schema
rapidjson::Document schemaDocument;
RapidJsonAdapter schemaDocumentAdapter(schemaDocument);
schemaDocument.SetObject();
schemaDocument.AddMember("$ref", "urn:mvn:example.schema.common:status:1.1.0",
schemaDocument.GetAllocator());
// Parse schema document
Schema schema;
SchemaParser schemaParser;
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchUrnDocument,
freeUrnDocument);
// Test resulting schema with a valid document
rapidjson::Document validDocument;
validDocument.SetObject();
validDocument.AddMember("test", "valid", schemaDocument.GetAllocator());
Validator validator;
EXPECT_TRUE(validator.validate(schema, RapidJsonAdapter(validDocument),
NULL));
// Test resulting schema with an invalid document
rapidjson::Document invalidDocument;
invalidDocument.SetObject();
invalidDocument.AddMember("test", 123, schemaDocument.GetAllocator());
EXPECT_FALSE(validator.validate(schema, RapidJsonAdapter(invalidDocument),
NULL));
}

View File

@ -22,12 +22,13 @@ TEST_F(TestJson11Adapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types
valijson::adapters::Json11Adapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() );
@ -59,12 +60,13 @@ TEST_F(TestJson11Adapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types
valijson::adapters::Json11Adapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -3,14 +3,20 @@
#include <gtest/gtest.h>
#include <valijson/internal/json_pointer.hpp>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#define TEST_DATA_DIR "../tests/data"
using valijson::adapters::RapidJsonAdapter;
using valijson::internal::json_pointer::resolveJsonPointer;
using valijson::utils::loadDocument;
using valijson::Schema;
using valijson::SchemaParser;
typedef rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>
RapidJsonCrtAllocator;
typedef rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> RapidJsonCrtAllocator;
class TestJsonPointer : public testing::Test
{
@ -19,9 +25,6 @@ class TestJsonPointer : public testing::Test
struct JsonPointerTestCase
{
JsonPointerTestCase(const std::string &description)
: description(description) { }
/// Description of test case
std::string description;
@ -43,66 +46,93 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
std::vector<TestCase> testCases;
TestCase testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '#' should cause an exception to be thrown");
TestCase testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '#' should cause an exception to be thrown";
testCase->value.SetNull();
testCase->jsonPointer = "#";
testCase->expectedValue = NULL;
testCase->expectedValue = nullptr;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving an empty string should return the root node");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving an empty string should return the root node";
testCase->value.SetNull();
testCase->jsonPointer = "";
testCase->expectedValue = &testCase->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/' should return the root node");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/' should return the root node";
testCase->value.SetNull();
testCase->jsonPointer = "/";
testCase->expectedValue = &testCase->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '//' should return the root node");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '//' should return the root node";
testCase->value.SetNull();
testCase->jsonPointer = "//";
testCase->expectedValue = &testCase->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/test' in object containing one member named 'test'");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test' in object containing one member named 'test'";
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/test";
testCase->expectedValue = &testCase->value.FindMember("test")->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/test/' in object containing one member named 'test'");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/' in object containing one member named 'test'";
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/test/";
testCase->expectedValue = &testCase->value.FindMember("test")->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '//test//' in object containing one member named 'test'");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '//test//' in object containing one member named 'test'";
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "//test//";
testCase->expectedValue = &testCase->value.FindMember("test")->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/missing' in object containing one member name 'test'");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/missing' in object containing one member name 'test'";
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/missing";
testCase->expectedValue = NULL;
testCase->expectedValue = nullptr;
testCases.push_back(testCase);
{
rapidjson::Value nonemptyString;
nonemptyString.SetString("hello, world");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/value/foo' fails because 'value' is not an object (but a non empty string)";
testCase->value.SetObject();
testCase->value.AddMember("value", nonemptyString, allocator);
testCase->jsonPointer = "/value/bar";
testCase->expectedValue = &testCase->value;
testCase->expectedValue = nullptr;
testCases.push_back(testCase);
}
{
rapidjson::Value emptyString;
emptyString.SetString("");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/empty/after_empty' fails because 'empty' is an empty string";
testCase->value.SetObject();
testCase->value.AddMember("empty", emptyString, allocator);
testCase->jsonPointer = "/empty/after_empty";
testCase->expectedValue = nullptr;
testCases.push_back(testCase);
}
{
rapidjson::Value testArray;
testArray.SetArray();
@ -110,9 +140,8 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/test/0' in object containing one member containing "
"an array with 3 elements");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/0' in object containing one member containing an array with 3 elements";
testCase->value.SetObject();
testCase->value.AddMember("test", testArray, allocator);
testCase->jsonPointer = "/test/0";
@ -127,9 +156,8 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/test/1' in object containing one member containing "
"an array with 3 elements");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/1' in object containing one member containing an array with 3 elements";
testCase->value.SetObject();
testCase->value.AddMember("test", testArray, allocator);
testCase->jsonPointer = "/test/1";
@ -144,9 +172,8 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/test/2' in object containing one member containing "
"an array with 3 elements");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/2' in object containing one member containing an array with 3 elements";
testCase->value.SetObject();
testCase->value.AddMember("test", testArray, allocator);
testCase->jsonPointer = "/test/2";
@ -161,13 +188,13 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/test/3' in object containing one member containing "
"an array with 3 elements should throw an exception");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/test/3' in object containing one member containing "
"an array with 3 elements should throw an exception";
testCase->value.SetObject();
testCase->value.AddMember("test", testArray, allocator);
testCase->jsonPointer = "/test/3";
testCase->expectedValue = NULL;
testCase->expectedValue = nullptr;
testCases.push_back(testCase);
}
@ -192,12 +219,12 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/test/-' in object containing one member containing "
"an array with 3 elements should throw an exception");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/test/-' in object containing one member containing "
"an array with 3 elements should throw an exception";
testCase->value.SetNull();
testCase->jsonPointer = "/test/-";
testCase->expectedValue = NULL;
testCase->expectedValue = nullptr;
testCases.push_back(testCase);
}
@ -220,9 +247,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
rapidjson::Value value;
value.SetDouble(10.);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/hello~1world' in object containing one member named "
"'hello/world' should return the associated value");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/hello~1world' in object containing one member named "
"'hello/world' should return the associated value";
testCase->value.SetObject();
testCase->value.AddMember("hello/world", value, allocator);
testCase->jsonPointer = "/hello~1world";
@ -234,9 +261,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
rapidjson::Value value;
value.SetDouble(10.);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/hello~0world' in object containing one member named "
"'hello~world' should return the associated value");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/hello~0world' in object containing one member named "
"'hello~world' should return the associated value";
testCase->value.SetObject();
testCase->value.AddMember("hello~world", value, allocator);
testCase->jsonPointer = "/hello~0world";
@ -248,9 +275,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
rapidjson::Value value;
value.SetDouble(10.);
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/hello~01world' in object containing one member named "
"'hello~1world' should return the associated value");
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/hello~01world' in object containing one member named "
"'hello~1world' should return the associated value";
testCase->value.SetObject();
testCase->value.AddMember("hello~1world", value, allocator);
testCase->jsonPointer = "/hello~01world";
@ -270,21 +297,33 @@ TEST_F(TestJsonPointer, JsonPointerTestCases)
TestCases testCases = testCasesForSingleLevelObjectPointers(allocator);
for (TestCases::const_iterator itr = testCases.begin();
itr != testCases.end(); ++itr) {
const std::string &jsonPointer = (*itr)->jsonPointer;
const RapidJsonAdapter valueAdapter((*itr)->value);
if ((*itr)->expectedValue) {
const RapidJsonAdapter expectedAdapter(*((*itr)->expectedValue));
const RapidJsonAdapter actualAdapter =
resolveJsonPointer(valueAdapter, jsonPointer);
EXPECT_TRUE(actualAdapter.equalTo(expectedAdapter, true)) <<
(*itr)->description;
for (const auto & testCase : testCases) {
const std::string &jsonPointer = testCase->jsonPointer;
const RapidJsonAdapter valueAdapter(testCase->value);
if (testCase->expectedValue) {
const RapidJsonAdapter expectedAdapter(*(testCase->expectedValue));
const RapidJsonAdapter actualAdapter = resolveJsonPointer(valueAdapter, jsonPointer);
EXPECT_TRUE(actualAdapter.equalTo(expectedAdapter, true)) << testCase->description;
} else {
EXPECT_THROW(
resolveJsonPointer(valueAdapter, jsonPointer),
std::runtime_error) <<
(*itr)->description;
// Since the tests with throwing disabled will abort, we can't
// do anything here.
#if VALIJSON_USE_EXCEPTIONS
EXPECT_THROW(resolveJsonPointer(valueAdapter, jsonPointer), std::runtime_error) << testCase->description;
#endif
}
}
}
TEST_F(TestJsonPointer, CircularReferences)
{
// Load schema document
rapidjson::Document schemaDocument;
ASSERT_TRUE( loadDocument(TEST_DATA_DIR "/schemas/circular_reference.schema.json", schemaDocument) );
RapidJsonAdapter schemaAdapter(schemaDocument);
// Attempt to parse schema
Schema schema;
SchemaParser parser;
EXPECT_THROW(parser.populateSchema(schemaAdapter, schema), std::runtime_error);
}

View File

@ -21,12 +21,13 @@ TEST_F(TestJsonCppAdapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types
valijson::adapters::JsonCppAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() );
@ -57,11 +58,13 @@ TEST_F(TestJsonCppAdapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types
valijson::adapters::JsonCppAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() );

Some files were not shown because too many files have changed in this diff Show More