Compare commits

..

No commits in common. "master" and "v0.2" have entirely different histories.
master ... v0.2

507 changed files with 207869 additions and 20432 deletions

View File

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

View File

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

View File

@ -1,41 +0,0 @@
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,7 +4,3 @@ 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
View File

@ -1,32 +0,0 @@
[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

74
.travis.yml Normal file
View File

@ -0,0 +1,74 @@
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,12 +33,3 @@ 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,119 +1,63 @@
cmake_minimum_required(VERSION 3.10.0)
cmake_minimum_required(VERSION 3.1)
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." FALSE)
option(valijson_BUILD_TESTS "Build valijson test suite." TRUE)
option(valijson_EXCLUDE_BOOST "Exclude Boost when building test suite." FALSE)
option(valijson_USE_EXCEPTIONS "Use exceptions in valijson and included libs." TRUE)
option(valijson_USE_BOOST_REGEX "Use boost::regex instead of std::regex internally." FALSE)
mark_as_advanced(valijson_USE_BOOST_REGEX)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
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")
if(valijson_INSTALL_HEADERS)
install(DIRECTORY include/ DESTINATION include)
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()
if(valijson_USE_EXCEPTIONS)
add_compile_definitions(VALIJSON_USE_EXCEPTIONS=1)
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")
else()
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)
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
find_package(Poco COMPONENTS Foundation JSON)
find_package(curlpp)
find_package(Poco OPTIONAL_COMPONENTS JSON)
find_package(Qt5Core)
# jsoncpp library
add_library(jsoncpp
thirdparty/jsoncpp/src/lib_json/json_reader.cpp
thirdparty/jsoncpp/src/lib_json/json_value.cpp
thirdparty/jsoncpp/src/lib_json/json_writer.cpp
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
)
target_include_directories(jsoncpp SYSTEM PRIVATE thirdparty/jsoncpp/include)
set_target_properties(jsoncpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/jsoncpp)
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)
add_library(json11
thirdparty/json11/json11.cpp
thirdparty/json11-ec4e452/json11.cpp
)
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)
target_include_directories(json11 SYSTEM PRIVATE thirdparty/json11-ec4e452)
set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11-ec4e452)
# Not all of these are required for examples build it doesn't hurt to include them
include_directories(include SYSTEM
thirdparty/googletest/include
thirdparty/json11
thirdparty/jsoncpp/include
thirdparty/rapidjson/include
thirdparty/picojson
thirdparty/nlohmann-json/include
thirdparty/yaml-cpp/include
)
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
)
if(valijson_BUILD_TESTS)
if(NOT valijson_EXCLUDE_BOOST)
@ -122,15 +66,11 @@ if(valijson_BUILD_TESTS)
# Build local gtest
set(gtest_force_shared_crt ON)
option(BUILD_GMOCK FALSE)
option(INSTALL_GTEST FALSE)
add_subdirectory(thirdparty/googletest)
add_subdirectory(thirdparty/gtest-1.7.0)
set(TEST_SOURCES
tests/test_adapter_comparison.cpp
tests/test_date_time_format.cpp
tests/test_fetch_absolute_uri_document_callback.cpp
tests/test_fetch_urn_document_callback.cpp
tests/test_fetch_document_callback.cpp
tests/test_json_pointer.cpp
tests/test_json11_adapter.cpp
tests/test_jsoncpp_adapter.cpp
@ -140,95 +80,37 @@ 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
)
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)
# 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)
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_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")
set(TEST_LIBS gtest gtest_main jsoncpp json11)
if(Boost_FOUND)
add_compile_definitions(BOOST_ALL_DYN_LINK)
include_directories(${Boost_INCLUDE_DIRS})
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_BOOST_PROPERTY_TREE_ADAPTER")
if(${BOOST_JSON_HPP_FOUND})
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_BOOST_JSON_ADAPTER")
endif()
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_PROPERTY_TREE_ADAPTER")
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")
endif()
if(Qt5Core_FOUND)
include_directories(${Qt5Core_INCLUDE_DIRS})
list(APPEND TEST_SOURCES tests/test_qtjson_adapter.cpp)
list(APPEND TEST_LIBS Qt5::Core)
target_compile_definitions(test_suite PRIVATE "VALIJSON_BUILD_QT_ADAPTER")
endif()
@ -236,7 +118,6 @@ if(valijson_BUILD_TESTS)
endif()
if(valijson_BUILD_EXAMPLES)
find_package(curlpp)
include_directories(SYSTEM)
add_executable(custom_schema
@ -255,10 +136,6 @@ 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
)
@ -267,33 +144,20 @@ 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_url
examples/remote_resolution_url.cpp
add_executable(remote_resolution
examples/remote_resolution.cpp
)
target_link_libraries(remote_resolution_url curl ${curlpp_LIBRARIES})
target_link_libraries(remote_resolution 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 anymore.
# not recognized any more.
# 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 input-file, where command is the value of the
# popen()) the command 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_TRANSPARENT tag to determine whether or not the images
# Use the FORMULA_TRANPARENT 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 Technologies, Inc.
Copyright (c) 2016, Akamai Technolgies, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without

405
README.md
View File

@ -1,369 +1,206 @@
# Valijson
# Valijson [![Build Status](https://travis-ci.org/tristanpenman/valijson.svg?branch=master)](https://travis-ci.org/tristanpenman/valijson) #
Valijson is a header-only [JSON Schema](http://json-schema.org/) validation library for _Modern C++_.
## Overview ##
Valijson is a header-only [JSON Schema](http://json-schema.org/) Validation library for C++11.
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 v7, 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 v4, while being competitive with the performance of a hand-written schema validator.
## Usage
Clone the repo, including submodules:
git clone --recurse-submodules git@github.com:tristanpenman/valijson.git
## Usage ##
The following code snippets show how you might implement a simple validator using RapidJson as the underlying JSON Parser.
Include the necessary headers:
```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:
```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");
}
// Parse JSON schema content using valijson
Schema mySchema;
SchemaParser parser;
RapidJsonAdapter mySchemaAdapter(mySchemaDoc);
parser.populateSchema(mySchemaAdapter, mySchema);
```
#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>
These are the classes that we'll be using:
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:
// 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);
Load a document to validate:
```cpp
rapidjson::Document myTargetDoc;
if (!valijson::utils::loadDocument("myTarget.json", myTargetDoc)) {
throw std::runtime_error("Failed to load target document");
}
```
rapidjson::Document myTargetDoc;
if (!valijson::utils::loadDocument("myTarget.json", myTargetDoc)) {
throw std::runtime_error("Failed to load target document");
}
Validate a document:
```cpp
Validator validator;
RapidJsonAdapter myTargetAdapter(myTargetDoc);
if (!validator.validate(mySchema, myTargetAdapter, NULL)) {
throw std::runtime_error("Validation failed.");
}
```
Validator validator;
RapidJsonAdapter myTargetAdapter(myTargetDoc);
if (!validator.validate(mySchema, myTargetAdapter, NULL)) {
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.
### 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
## 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;
// 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();
{
// Root schema object that manages memory allocated for
// constraints or sub-schemas
Schema schema;
{ // Limited scope, for example purposes
// 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();
// Construct a constraint on the stack
TypeConstraint typeConstraint;
typeConstraint.addNamedType(TypeConstraint::kString);
{ // Limited scope, for example purposes
// Constraints are added to a sub-schema via the root schema,
// which will make a copy of the constraint
schema.addConstraintToSubschema(typeConstraint, subschema);
// Construct a constraint on the stack
TypeConstraint typeConstraint;
typeConstraint.addNamedType(TypeConstraint::kString);
// Constraint on the stack goes out of scope, but the copy
// held by the root schema continues to exist
// 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
}
// 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
## 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
# Run test suite (from build directory)
./test_suite
```
## How to add this library to your cmake target
# Build examples and test suite
mkdir build
cd build
cmake ..
make
Valijson can be integrated either as git submodule or with `find_package()`.
# Run test suite (from build directory)
./test_suite
### Valijson as git submodule
### Xcode ###
Download this repository into your project
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.
```bash
git clone --recurse-submodules https://github.com/tristanpenman/valijson <project-path>/third-party/valijson
```
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.
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
## 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 7](https://json-schema.org/draft-07/json-schema-release-notes.html)
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.
The main exceptions are
- default
- format
The exceptions for Draft 3 are:
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.
- disallow
- extends
- format (optional)
- readonly
## JSON Inspector
The exceptions for Draft 4 are:
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:
- format (optional)
```bash
cd inspector
mkdir build
cd build
cmake ..
make
```
Support for JSON References is in development.
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
## 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 full C++14 support.
Valijson requires a compiler with C++11 support.
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.JSON 1.75](https://www.boost.org/doc/libs/1_75_0/libs/json/doc/html/index.html)
- [boost::property_tree 1.54](http://www.boost.org/doc/libs/1_54_0/doc/html/boost_propertytree/synopsis.html)
- [json11 (commit afcc8d0)](https://github.com/dropbox/json11/tree/afcc8d0d82b1ce2df587a7a0637d05ba493bf5e6)
- [jsoncpp 1.9.4](https://github.com/open-source-parsers/jsoncpp/archive/1.9.4.tar.gz)
- [jsoncpp 0.9.4](https://github.com/open-source-parsers/jsoncpp/archive/0.9.4.tar.gz)
- [nlohmann/json 1.1.0](https://github.com/nlohmann/json/archive/v1.1.0.tar.gz)
- [rapidjson (commit 48fbd8c)](https://github.com/Tencent/rapidjson/tree/48fbd8cd202ca54031fe799db2ad44ffa8e77c13)
- [rapidjson 1.1.0](https://github.com/miloyip/rapidjson/releases/tag/v1.1.0)
- [PicoJSON 1.3.0](https://github.com/kazuho/picojson/archive/v1.3.0.tar.gz)
- [Poco JSON 1.14.0](https://pocoproject.org/docs/Poco.JSON.html)
- [Poco JSON 1.7.8](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.
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.
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
## 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.
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.
## Test Suite Requirements
## 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 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
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 ##
Valijson is licensed under the Simplified BSD License.

107
bundle.sh
View File

@ -1,107 +0,0 @@
#!/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

111
cmake/FindPoco.cmake Normal file
View File

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

View File

@ -1,151 +0,0 @@
{
"$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.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

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 than or equal to the minimum value.
value can be greater then 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 than or equal to the maximum value.
value can be less then or equal to the maximum value.
5.13. minItems

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,20 @@
/**
* @file
*
* @brief Demonstrates iteration over an array, and how to use type check functions
* @brief Demonstrates iteration over an array and 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>
@ -22,81 +26,12 @@ 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)
{
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;
}
}
void usingRapidJson(const char *filename);
// 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)
{
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;
}
}
}
void usingJsonCpp(const char *filename);
int main(int argc, char **argv)
{
@ -118,3 +53,80 @@ 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

@ -1,107 +0,0 @@
#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;
}

View File

@ -1,48 +0,0 @@
/**
* @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,6 +59,8 @@
#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,9 +5,12 @@
*
*/
#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>
@ -57,7 +60,7 @@ int main(int argc, char *argv[])
}
// Perform validation
Validator validator(Validator::kStrongTypes);
Validator validator(Validator::kWeakTypes);
ValidationResults results;
RapidJsonAdapter targetDocumentAdapter(targetDocument);
if (!validator.validate(schema, targetDocumentAdapter, &results)) {

View File

@ -7,6 +7,8 @@
#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

@ -1,112 +0,0 @@
#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

@ -12,6 +12,8 @@
#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>

View File

@ -1,102 +0,0 @@
/**
* @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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
#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,7 +17,6 @@
# include <functional>
# include <string>
# include <stdexcept>
# include <valijson/exceptions.hpp>
# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false
@ -45,11 +44,11 @@
#
# if defined __clang_major__
# if (__clang_major__ == 3 && __clang_minor__ >= 5)
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
# elif (__clang_major__ > 3)
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_
# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
# endif
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_
# 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_
@ -85,7 +84,7 @@
# define OPTIONAL_CONSTEXPR_INIT_LIST
# endif
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHER_ && (defined __cplusplus) && (__cplusplus != 201103L)
# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L)
# define OPTIONAL_HAS_MOVE_ACCESSORS 1
# else
# define OPTIONAL_HAS_MOVE_ACCESSORS 0
@ -270,7 +269,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)...) {}
@ -285,7 +284,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)...) {}
@ -300,7 +299,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) {}
@ -323,7 +322,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) {}
@ -398,8 +397,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>()
@ -524,15 +523,15 @@ namespace std{
}
constexpr T const& value() const& {
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
}
OPTIONAL_MUTABLE_CONSTEXPR T& value() & {
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
}
OPTIONAL_MUTABLE_CONSTEXPR T&& value() && {
if (!initialized()) valijson::throwRuntimeError("bad optional access");
if (!initialized()) throw bad_optional_access("bad optional access");
return std::move(contained_val());
}
@ -553,11 +552,11 @@ namespace std{
}
constexpr T const& value() const {
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
}
T& value() {
return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val());
}
# endif
@ -686,7 +685,7 @@ namespace std{
}
constexpr T& value() const {
return ref ? *ref : (valijson::throwRuntimeError("bad optional access"), *ref);
return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref);
}
explicit constexpr operator bool() const noexcept {
@ -1040,4 +1039,4 @@ namespace std
# undef TR2_OPTIONAL_REQUIRES
# undef TR2_OPTIONAL_ASSERTED_EXPRESSION
# endif //OPTIONAL_HPP
# endif //___OPTIONAL_HPP___

View File

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

View File

@ -1,724 +0,0 @@
/**
* @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

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

View File

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

View File

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

View File

@ -26,206 +26,21 @@
#pragma once
#include <string>
#include <nlohmann/json.hpp>
#include <json.hpp>
#include <valijson/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
#include <utility>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
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.
*
@ -237,17 +52,16 @@ template <class ValueType> class NlohmannJsonObjectMemberIterator
* 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<ValueType> const_iterator;
typedef NlohmannJsonArrayValueIterator<ValueType> iterator;
typedef NlohmannJsonArrayValueIterator const_iterator;
typedef NlohmannJsonArrayValueIterator iterator;
/// Construct a NlohmannJsonArray referencing an empty array.
NlohmannJsonArray()
: m_value(emptyArray()) { }
: value(emptyArray()) { }
/**
* @brief Construct a NlohmannJsonArray referencing a specific NlohmannJson
@ -259,10 +73,10 @@ public:
* an array.
*/
NlohmannJsonArray(const nlohmann::json &value)
: m_value(value)
: value(value)
{
if (!value.is_array()) {
throwRuntimeError("Value is not an array.");
throw std::runtime_error("Value is not an array.");
}
}
@ -272,10 +86,7 @@ public:
* The iterator return by this function is effectively the iterator
* returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonArrayValueIterator<ValueType> begin() const {
return m_value.begin();
}
NlohmannJsonArrayValueIterator begin() const;
/**
* @brief Return an iterator for one-past the last element of the array.
@ -283,14 +94,12 @@ public:
* The iterator return by this function is effectively the iterator
* returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonArrayValueIterator<ValueType> end() const {
return m_value.end();
}
NlohmannJsonArrayValueIterator end() const;
/// Return the number of elements in the array
size_t size() const
{
return m_value.size();
return value.size();
}
private:
@ -307,7 +116,7 @@ private:
}
/// Reference to the contained value
const nlohmann::json &m_value;
const nlohmann::json &value;
};
/**
@ -325,12 +134,12 @@ class NlohmannJsonObject
{
public:
typedef NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> const_iterator;
typedef NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> iterator;
typedef NlohmannJsonObjectMemberIterator const_iterator;
typedef NlohmannJsonObjectMemberIterator iterator;
/// Construct a NlohmannJsonObject referencing an empty object singleton.
NlohmannJsonObject()
: m_value(emptyObject()) { }
: value(emptyObject()) { }
/**
* @brief Construct a NlohmannJsonObject referencing a specific NlohmannJson
@ -342,10 +151,10 @@ public:
* an object.
*/
NlohmannJsonObject(const nlohmann::json &value)
: m_value(value)
: value(value)
{
if (!value.is_object()) {
throwRuntimeError("Value is not an object.");
throw std::runtime_error("Value is not an object.");
}
}
@ -355,7 +164,7 @@ public:
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> begin() const;
NlohmannJsonObjectMemberIterator begin() const;
/**
* @brief Return an iterator for an invalid object member that indicates
@ -364,7 +173,7 @@ public:
* The iterator return by this function is effectively a wrapper around
* the iterator value returned by the underlying NlohmannJson implementation.
*/
NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember> end() const;
NlohmannJsonObjectMemberIterator end() const;
/**
* @brief Return an iterator for the object member with the specified
@ -375,13 +184,12 @@ public:
*
* @param propertyName property name to search for
*/
NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
find(const std::string &propertyName) const;
NlohmannJsonObjectMemberIterator find(const std::string &propertyName) const;
/// Returns the number of members belonging to this object.
size_t size() const
{
return m_value.size();
return value.size();
}
private:
@ -398,7 +206,7 @@ private:
}
/// Reference to the contained object
const nlohmann::json &m_value;
const nlohmann::json &value;
};
@ -420,20 +228,20 @@ public:
*
* @param source the NlohmannJson value to be copied
*/
explicit NlohmannJsonFrozenValue(nlohmann::json source)
: m_value(std::move(source)) { }
explicit NlohmannJsonFrozenValue(const nlohmann::json &source)
: value(source) { }
FrozenValue * clone() const override
virtual FrozenValue * clone() const
{
return new NlohmannJsonFrozenValue(m_value);
return new NlohmannJsonFrozenValue(value);
}
bool equalTo(const Adapter &other, bool strict) const override;
virtual bool equalTo(const Adapter &other, bool strict) const;
private:
/// Stored NlohmannJson value
nlohmann::json m_value;
nlohmann::json value;
};
@ -451,18 +259,17 @@ private:
*
* @see BasicAdapter
*/
template<class ValueType>
class NlohmannJsonValue
{
public:
/// Construct a wrapper for the empty object singleton
NlohmannJsonValue()
: m_value(emptyObject()) { }
: value(emptyObject()) { }
/// Construct a wrapper for a specific NlohmannJson value
NlohmannJsonValue(const nlohmann::json &value)
: m_value(value) { }
: value(value) { }
/**
* @brief Create a new NlohmannJsonFrozenValue instance that contains the
@ -473,7 +280,7 @@ public:
*/
FrozenValue * freeze() const
{
return new NlohmannJsonFrozenValue(m_value);
return new NlohmannJsonFrozenValue(value);
}
/**
@ -485,13 +292,13 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<NlohmannJsonArray<ValueType>> getArrayOptional() const
opt::optional<NlohmannJsonArray> getArrayOptional() const
{
if (m_value.is_array()) {
return opt::make_optional(NlohmannJsonArray<ValueType>(m_value));
if (value.is_array()) {
return opt::make_optional(NlohmannJsonArray(value));
}
return {};
return opt::optional<NlohmannJsonArray>();
}
/**
@ -507,8 +314,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (m_value.is_array()) {
result = m_value.size();
if (value.is_array()) {
result = value.size();
return true;
}
@ -517,8 +324,8 @@ public:
bool getBool(bool &result) const
{
if (m_value.is_boolean()) {
result = m_value.get<bool>();
if (value.is_boolean()) {
result = value.get<bool>();
return true;
}
@ -527,8 +334,8 @@ public:
bool getDouble(double &result) const
{
if (m_value.is_number_float()) {
result = m_value.get<double>();
if (value.is_number_float()) {
result = value.get<double>();
return true;
}
@ -537,8 +344,8 @@ public:
bool getInteger(int64_t &result) const
{
if(m_value.is_number_integer()) {
result = m_value.get<int64_t>();
if(value.is_number_integer()) {
result = value.get<int64_t>();
return true;
}
return false;
@ -553,7 +360,14 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<NlohmannJsonObject> getObjectOptional() const;
opt::optional<NlohmannJsonObject> getObjectOptional() const
{
if (value.is_object()) {
return opt::make_optional(NlohmannJsonObject(value));
}
return opt::optional<NlohmannJsonObject>();
}
/**
* @brief Retrieve the number of members in the object
@ -568,8 +382,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (m_value.is_object()) {
result = m_value.size();
if (value.is_object()) {
result = value.size();
return true;
}
@ -578,8 +392,8 @@ public:
bool getString(std::string &result) const
{
if (m_value.is_string()) {
result = m_value.get<std::string>();
if (value.is_string()) {
result = value.get<std::string>();
return true;
}
@ -593,42 +407,42 @@ public:
bool isArray() const
{
return m_value.is_array();
return value.is_array();
}
bool isBool() const
{
return m_value.is_boolean();
return value.is_boolean();
}
bool isDouble() const
{
return m_value.is_number_float();
return value.is_number_float();
}
bool isInteger() const
{
return m_value.is_number_integer();
return value.is_number_integer();
}
bool isNull() const
{
return m_value.is_null();
return value.is_null();
}
bool isNumber() const
{
return m_value.is_number();
return value.is_number();
}
bool isObject() const
{
return m_value.is_object();
return value.is_object();
}
bool isString() const
{
return m_value.is_string();
return value.is_string();
}
private:
@ -641,7 +455,7 @@ private:
}
/// Reference to the contained NlohmannJson value.
const nlohmann::json &m_value;
const nlohmann::json &value;
};
/**
@ -653,35 +467,198 @@ private:
* @see Adapter
* @see BasicAdapter
*/
class NlohmannJsonAdapter
: public BasicAdapter<NlohmannJsonAdapter,
NlohmannJsonArray<NlohmannJsonAdapter>,
NlohmannJsonObjectMember, NlohmannJsonObject,
NlohmannJsonValue<NlohmannJsonAdapter>>
class NlohmannJsonAdapter:
public BasicAdapter<NlohmannJsonAdapter,
NlohmannJsonArray,
NlohmannJsonObjectMember,
NlohmannJsonObject,
NlohmannJsonValue>
{
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<NlohmannJsonAdapter>{value})
{
}
: BasicAdapter(NlohmannJsonValue{value}) { }
};
template <class ValueType>
opt::optional<NlohmannJsonObject>
NlohmannJsonValue<ValueType>::getObjectOptional() const
/**
* @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
{
if (m_value.is_object()) {
return opt::make_optional(NlohmannJsonObject(m_value));
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);
}
return {};
}
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;
};
/// Specialisation of the AdapterTraits template struct for NlohmannJsonAdapter.
template<>
@ -697,27 +674,33 @@ struct AdapterTraits<valijson::adapters::NlohmannJsonAdapter>
inline bool NlohmannJsonFrozenValue::equalTo(const Adapter &other, bool strict) const
{
return NlohmannJsonAdapter(m_value).equalTo(other, strict);
return NlohmannJsonAdapter(value).equalTo(other, strict);
}
inline NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
NlohmannJsonObject::begin() const
inline NlohmannJsonArrayValueIterator NlohmannJsonArray::begin() const
{
return m_value.begin();
return value.begin();
}
inline NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
NlohmannJsonObject::end() const
inline NlohmannJsonArrayValueIterator NlohmannJsonArray::end() const
{
return m_value.end();
return value.end();
}
inline NlohmannJsonObjectMemberIterator<NlohmannJsonObjectMember>
NlohmannJsonObject::find(
inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::begin() const
{
return value.begin();
}
inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::end() const
{
return value.end();
}
inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::find(
const std::string &propertyName) const
{
return m_value.find(propertyName);
return value.find(propertyName);
}
} // namespace adapters

View File

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

View File

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

View File

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

View File

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

View File

@ -43,30 +43,11 @@
#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/internal/adapter.hpp>
#include <valijson/internal/basic_adapter.hpp>
#include <valijson/internal/frozen_value.hpp>
#include <valijson/exceptions.hpp>
#include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp>
namespace valijson {
namespace adapters {
@ -83,10 +64,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(
@ -116,7 +97,7 @@ public:
/// Construct a RapidJsonArray referencing an empty array singleton.
GenericRapidJsonArray()
: m_value(emptyArray()) { }
: value(emptyArray()) { }
/**
* @brief Construct a RapidJsonArray referencing a specific RapidJson
@ -128,10 +109,10 @@ public:
* an array.
*/
GenericRapidJsonArray(const ValueType &value)
: m_value(value)
: value(value)
{
if (!value.IsArray()) {
throwRuntimeError("Value is not an array.");
throw std::runtime_error("Value is not an array.");
}
}
@ -144,7 +125,7 @@ public:
/// Return the number of elements in the array
size_t size() const
{
return m_value.Size();
return value.Size();
}
private:
@ -161,7 +142,7 @@ private:
}
/// Reference to the contained value
const ValueType &m_value;
const ValueType &value;
};
/**
@ -185,7 +166,7 @@ public:
/// Construct a GenericRapidJsonObject referencing an empty object singleton.
GenericRapidJsonObject()
: m_value(emptyObject()) { }
: value(emptyObject()) { }
/**
* @brief Construct a GenericRapidJsonObject referencing a specific
@ -197,10 +178,10 @@ public:
* an object.
*/
GenericRapidJsonObject(const ValueType &value)
: m_value(value)
: value(value)
{
if (!value.IsObject()) {
throwRuntimeError("Value is not an object.");
throw std::runtime_error("Value is not an object.");
}
}
@ -235,7 +216,7 @@ public:
/// Returns the number of members belonging to this object.
size_t size() const
{
return m_value.MemberEnd() - m_value.MemberBegin();
return value.MemberEnd() - value.MemberBegin();
}
private:
@ -252,7 +233,7 @@ private:
}
/// Reference to the contained object
const ValueType &m_value;
const ValueType &value;
};
/**
@ -273,12 +254,12 @@ public:
explicit GenericRapidJsonFrozenValue(const char *str)
{
m_value.SetString(str, m_allocator);
value.SetString(str, allocator);
}
explicit GenericRapidJsonFrozenValue(const std::string &str)
{
m_value.SetString(str.c_str(), (unsigned int)str.length(), m_allocator);
value.SetString(str.c_str(), (unsigned int)str.length(), allocator);
}
/**
@ -288,17 +269,17 @@ public:
*/
explicit GenericRapidJsonFrozenValue(const ValueType &source)
{
if (!copy(source, m_value, m_allocator)) {
throwRuntimeError("Failed to copy ValueType");
if (!copy(source, value, allocator)) {
throw std::runtime_error("Failed to copy ValueType");
}
}
FrozenValue * clone() const override
virtual FrozenValue * clone() const
{
return new GenericRapidJsonFrozenValue(m_value);
return new GenericRapidJsonFrozenValue(value);
}
bool equalTo(const Adapter &other, bool strict) const override;
virtual bool equalTo(const Adapter &other, bool strict) const;
private:
@ -330,7 +311,8 @@ 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);
@ -369,10 +351,10 @@ private:
}
/// Local memory allocator for RapidJson value
typename ValueType::AllocatorType m_allocator;
typename ValueType::AllocatorType allocator;
/// Local RapidJson value
ValueType m_value;
ValueType value;
};
/**
@ -395,11 +377,11 @@ class GenericRapidJsonValue
public:
/// Construct a wrapper for the empty object singleton
GenericRapidJsonValue()
: m_value(emptyObject()) { }
: value(emptyObject()) { }
/// Construct a wrapper for a specific RapidJson value
GenericRapidJsonValue(const ValueType &value)
: m_value(value) { }
: value(value) { }
/**
* @brief Create a new GenericRapidJsonFrozenValue instance that contains
@ -410,7 +392,7 @@ public:
*/
FrozenValue * freeze() const
{
return new GenericRapidJsonFrozenValue<ValueType>(m_value);
return new GenericRapidJsonFrozenValue<ValueType>(value);
}
/**
@ -422,13 +404,13 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<GenericRapidJsonArray<ValueType>> getArrayOptional() const
opt::optional<GenericRapidJsonArray<ValueType> > getArrayOptional() const
{
if (m_value.IsArray()) {
return opt::make_optional(GenericRapidJsonArray<ValueType>(m_value));
if (value.IsArray()) {
return opt::make_optional(GenericRapidJsonArray<ValueType>(value));
}
return {};
return opt::optional<GenericRapidJsonArray<ValueType> >();
}
/**
@ -444,8 +426,8 @@ public:
*/
bool getArraySize(size_t &result) const
{
if (m_value.IsArray()) {
result = m_value.Size();
if (value.IsArray()) {
result = value.Size();
return true;
}
@ -454,8 +436,8 @@ public:
bool getBool(bool &result) const
{
if (m_value.IsBool()) {
result = m_value.GetBool();
if (value.IsBool()) {
result = value.GetBool();
return true;
}
@ -464,8 +446,8 @@ public:
bool getDouble(double &result) const
{
if (m_value.IsDouble()) {
result = m_value.GetDouble();
if (value.IsDouble()) {
result = value.GetDouble();
return true;
}
@ -474,17 +456,17 @@ public:
bool getInteger(int64_t &result) const
{
if (m_value.IsInt()) {
result = m_value.GetInt();
if (value.IsInt()) {
result = value.GetInt();
return true;
} else if (m_value.IsInt64()) {
result = m_value.GetInt64();
} else if (value.IsInt64()) {
result = value.GetInt64();
return true;
} else if (m_value.IsUint()) {
result = static_cast<int64_t>(m_value.GetUint());
} else if (value.IsUint()) {
result = static_cast<int64_t>(value.GetUint());
return true;
} else if (m_value.IsUint64()) {
result = static_cast<int64_t>(m_value.GetUint64());
} else if (value.IsUint64()) {
result = static_cast<int64_t>(value.GetUint64());
return true;
}
@ -500,13 +482,13 @@ public:
*
* Otherwise it will return an empty optional.
*/
opt::optional<GenericRapidJsonObject<ValueType>> getObjectOptional() const
opt::optional<GenericRapidJsonObject<ValueType> > getObjectOptional() const
{
if (m_value.IsObject()) {
return opt::make_optional(GenericRapidJsonObject<ValueType>(m_value));
if (value.IsObject()) {
return opt::make_optional(GenericRapidJsonObject<ValueType>(value));
}
return {};
return opt::optional<GenericRapidJsonObject<ValueType> >();
}
/**
@ -522,8 +504,8 @@ public:
*/
bool getObjectSize(size_t &result) const
{
if (m_value.IsObject()) {
result = m_value.MemberEnd() - m_value.MemberBegin();
if (value.IsObject()) {
result = value.MemberEnd() - value.MemberBegin();
return true;
}
@ -532,8 +514,8 @@ public:
bool getString(std::string &result) const
{
if (m_value.IsString()) {
result.assign(m_value.GetString(), m_value.GetStringLength());
if (value.IsString()) {
result.assign(value.GetString(), value.GetStringLength());
return true;
}
@ -547,42 +529,43 @@ public:
bool isArray() const
{
return m_value.IsArray();
return value.IsArray();
}
bool isBool() const
{
return m_value.IsBool();
return value.IsBool();
}
bool isDouble() const
{
return m_value.IsDouble();
return value.IsDouble();
}
bool isInteger() const
{
return m_value.IsInt() || m_value.IsInt64() || m_value.IsUint() || m_value.IsUint64();
return value.IsInt() || value.IsInt64() || value.IsUint() ||
value.IsUint64();
}
bool isNull() const
{
return m_value.IsNull();
return value.IsNull();
}
bool isNumber() const
{
return m_value.IsNumber();
return value.IsNumber();
}
bool isObject() const
{
return m_value.IsObject();
return value.IsObject();
}
bool isString() const
{
return m_value.IsString();
return value.IsString();
}
private:
@ -595,7 +578,7 @@ private:
}
/// Reference to the contained RapidJson value.
const ValueType &m_value;
const ValueType &value;
};
/**
@ -613,7 +596,7 @@ class GenericRapidJsonAdapter:
GenericRapidJsonArray<ValueType>,
GenericRapidJsonObjectMember<ValueType>,
GenericRapidJsonObject<ValueType>,
GenericRapidJsonValue<ValueType>>
GenericRapidJsonValue<ValueType> >
{
public:
@ -623,7 +606,7 @@ public:
GenericRapidJsonArray<ValueType>,
GenericRapidJsonObjectMember<ValueType>,
GenericRapidJsonObject<ValueType>,
GenericRapidJsonValue<ValueType>>() { }
GenericRapidJsonValue<ValueType> >() { }
/// Construct a RapidJsonAdapter containing a specific RapidJson value
GenericRapidJsonAdapter(const ValueType &value)
@ -631,26 +614,25 @@ 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.
* RapidJsonAdapter representing a value stored in the array. It has been
* implemented using the std::iterator template.
*
* @see RapidJsonArray
*/
template<class ValueType>
class GenericRapidJsonArrayValueIterator
class GenericRapidJsonArrayValueIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
GenericRapidJsonAdapter<ValueType> > // value type
{
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
@ -660,19 +642,19 @@ public:
*/
GenericRapidJsonArrayValueIterator(
const typename ValueType::ConstValueIterator &itr)
: m_itr(itr) { }
: itr(itr) { }
/// Returns a GenericRapidJsonAdapter that contains the value of the current
/// element.
GenericRapidJsonAdapter<ValueType> operator*() const
{
return GenericRapidJsonAdapter<ValueType>(*m_itr);
return GenericRapidJsonAdapter<ValueType>(*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);
}
/**
@ -688,47 +670,47 @@ public:
*/
bool operator==(const GenericRapidJsonArrayValueIterator<ValueType> &other) const
{
return m_itr == other.m_itr;
return itr == other.itr;
}
bool operator!=(const GenericRapidJsonArrayValueIterator<ValueType>& other) const
{
return m_itr != other.m_itr;
return !(itr == other.itr);
}
GenericRapidJsonArrayValueIterator<ValueType>& operator++()
{
m_itr++;
itr++;
return *this;
}
GenericRapidJsonArrayValueIterator<ValueType> operator++(int) {
GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(m_itr);
GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(itr);
++(*this);
return iterator_pre;
}
GenericRapidJsonArrayValueIterator<ValueType>& operator--()
{
m_itr--;
itr--;
return *this;
}
void advance(std::ptrdiff_t n)
{
m_itr += n;
itr += n;
}
std::ptrdiff_t difference(const GenericRapidJsonArrayValueIterator<ValueType> &other)
{
return std::distance(m_itr, other.m_itr);
return std::distance(itr, other.itr);
}
private:
typename ValueType::ConstValueIterator m_itr;
typename ValueType::ConstValueIterator itr;
};
/**
@ -736,20 +718,18 @@ private:
*
* This class provides a JSON object iterator that dereferences as an instance
* of GenericRapidJsonObjectMember representing one of the members of the
* object.
* object. It has been implemented using the std::iterator template.
*
* @see GenericRapidJsonObject
* @see GenericRapidJsonObjectMember
*/
template<class ValueType>
class GenericRapidJsonObjectMemberIterator
class GenericRapidJsonObjectMemberIterator:
public std::iterator<
std::bidirectional_iterator_tag, // bi-directional iterator
GenericRapidJsonObjectMember<ValueType> > // value type
{
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.
@ -758,7 +738,7 @@ public:
*/
GenericRapidJsonObjectMemberIterator(
const typename ValueType::ConstMemberIterator &itr)
: m_itr(itr) { }
: itr(itr) { }
/**
@ -768,14 +748,14 @@ public:
GenericRapidJsonObjectMember<ValueType> operator*() const
{
return GenericRapidJsonObjectMember<ValueType>(
std::string(m_itr->name.GetString(), m_itr->name.GetStringLength()),
m_itr->value);
std::string(itr->name.GetString(), itr->name.GetStringLength()),
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);
}
/**
@ -791,77 +771,85 @@ public:
*/
bool operator==(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
{
return m_itr == other.m_itr;
return itr == other.itr;
}
bool operator!=(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
{
return m_itr != other.m_itr;
return !(itr == other.itr);
}
GenericRapidJsonObjectMemberIterator<ValueType>& operator++()
{
m_itr++;
itr++;
return *this;
}
GenericRapidJsonObjectMemberIterator<ValueType> operator++(int)
{
GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(m_itr);
GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(itr);
++(*this);
return iterator_pre;
}
GenericRapidJsonObjectMemberIterator<ValueType>& operator--()
{
m_itr--;
itr--;
return *this;
}
std::ptrdiff_t difference(const GenericRapidJsonObjectMemberIterator &other)
{
return std::distance(m_itr, other.m_itr);
return std::distance(itr, other.itr);
}
private:
/// Internal copy of the original RapidJson iterator
typename ValueType::ConstMemberIterator m_itr;
/// Iternal copy of the original RapidJson iterator
typename ValueType::ConstMemberIterator 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>(m_value).equalTo(other, strict);
return GenericRapidJsonAdapter<ValueType>(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 m_value.Begin();
return value.Begin();
}
template<class ValueType>
inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::end() const
inline typename GenericRapidJsonArray<ValueType>::iterator
GenericRapidJsonArray<ValueType>::end() const
{
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();
return value.End();
}
template<class ValueType>
inline typename GenericRapidJsonObject<ValueType>::iterator
GenericRapidJsonObject<ValueType>::find(const std::string &propertyName) const
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
{
// Hack to support older versions of rapidjson where pointers are used as
// the built in iterator type. In those versions, the FindMember function
@ -878,18 +866,20 @@ 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 = m_value.MemberBegin(); itr != m_value.MemberEnd(); ++itr) {
for (typename ValueType::ConstMemberIterator itr = value.MemberBegin();
itr != 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 m_value.MemberEnd();
return value.MemberEnd();
}
return m_value.FindMember(propertyName.c_str()); // Times are good.
return value.FindMember(propertyName.c_str()); // Times are good.
}
typedef GenericRapidJsonAdapter<> RapidJsonAdapter;
@ -916,16 +906,18 @@ 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

@ -1,491 +0,0 @@
/**
* @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

@ -1,694 +0,0 @@
/**
* @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() = default;
virtual ~ConstraintBuilder() {}
virtual constraints::Constraint * make(const adapters::Adapter &) const = 0;
};

View File

@ -2,59 +2,63 @@
#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()
: m_allocator() { }
: allocator() { }
BasicConstraint(Allocator::CustomAlloc allocFn, Allocator::CustomFree freeFn)
: m_allocator(allocFn, freeFn) { }
: allocator(allocFn, freeFn) { }
BasicConstraint(const BasicConstraint &other)
: m_allocator(other.m_allocator) { }
: allocator(other.allocator) { }
~BasicConstraint() override = default;
virtual ~BasicConstraint<ConstraintType>() { }
bool accept(ConstraintVisitor &visitor) const override
virtual bool accept(ConstraintVisitor &visitor) const
{
return visitor.visit(*static_cast<const ConstraintType*>(this));
}
OwningPointer clone(CustomAlloc allocFn, CustomFree freeFn) const override
virtual Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const
{
// 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);
void *ptr = allocFn(sizeof(ConstraintType));
if (!ptr) {
throwRuntimeError("Failed to allocate memory for cloned constraint");
throw std::runtime_error(
"Failed to allocate memory for cloned constraint");
}
// 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;
try {
return new (ptr) ConstraintType(
*static_cast<const ConstraintType*>(this));
} catch (...) {
freeFn(ptr);
throw;
}
}
protected:
Allocator m_allocator;
Allocator allocator;
};
} // namespace constraints

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,5 @@
#pragma once
#include <memory>
#include <type_traits>
namespace valijson {
namespace constraints {
@ -21,32 +18,10 @@ 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() = default;
virtual ~Constraint() { }
/**
* @brief Perform an action on the constraint using the visitor pattern.
@ -67,7 +42,7 @@ struct Constraint
*
* @returns an owning-pointer to the new constraint.
*/
virtual OwningPointer clone(CustomAlloc, CustomFree) const = 0;
virtual Constraint * clone(CustomAlloc, CustomFree) const = 0;
};

View File

@ -5,12 +5,8 @@ namespace constraints {
class AllOfConstraint;
class AnyOfConstraint;
class ConditionalConstraint;
class ConstConstraint;
class ContainsConstraint;
class DependenciesConstraint;
class EnumConstraint;
class FormatConstraint;
class LinearItemsConstraint;
class MaxItemsConstraint;
class MaximumConstraint;
@ -27,7 +23,6 @@ class OneOfConstraint;
class PatternConstraint;
class PolyConstraint;
class PropertiesConstraint;
class PropertyNamesConstraint;
class RequiredConstraint;
class SingularItemsConstraint;
class TypeConstraint;
@ -37,17 +32,13 @@ class UniqueItemsConstraint;
class ConstraintVisitor
{
protected:
virtual ~ConstraintVisitor() = default;
virtual ~ConstraintVisitor() {}
// 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;
@ -64,7 +55,6 @@ 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;
@ -74,12 +64,8 @@ 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;
@ -96,7 +82,6 @@ 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

@ -1,39 +0,0 @@
#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

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

View File

@ -7,14 +7,8 @@
#include <stdexcept>
#include <string>
#include <valijson/internal/adapter.hpp>
#include <valijson/adapters/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 {
@ -49,17 +43,17 @@ inline void replaceAllInPlace(std::string& subject, const char* search,
inline char decodePercentEncodedChar(const std::string &digits)
{
if (digits.length() != 2) {
throwRuntimeError("Failed to decode %-encoded character '" +
throw std::runtime_error("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 = nullptr;
char *end = NULL;
const unsigned long value = strtoul(begin, &end, 16);
if (end != begin && *end != '\0') {
throwRuntimeError("Failed to decode %-encoded character '" +
throw std::runtime_error("Failed to decode %-encoded character '" +
digits + "'");
}
@ -107,17 +101,14 @@ 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, 1, c);
#if VALIJSON_USE_EXCEPTIONS
token.replace(n, 3, &c, 1);
} catch (const std::runtime_error &e) {
throwRuntimeError(
throw std::runtime_error(
std::string(e.what()) + "; in token: " + token);
}
#endif
}
return token;
@ -133,7 +124,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 the name of an object member. The validity of a
* an array index or as an the name 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.
@ -168,7 +159,7 @@ inline AdapterType resolveJsonPointer(
// Reference tokens must begin with a leading slash
if (*jsonPointerItr != '/') {
throwRuntimeError("Expected reference token to begin with "
throw std::runtime_error("Expected reference token to begin with "
"leading slash; remaining tokens: " +
std::string(jsonPointerItr, jsonPointerEnd));
}
@ -187,29 +178,25 @@ inline AdapterType resolveJsonPointer(
return resolveJsonPointer(node, jsonPointer, jsonPointerNext);
} else if (node.isArray()) {
if (referenceToken == "-") {
throwRuntimeError("Hyphens cannot be used as array indices "
if (referenceToken.compare("-") == 0) {
throw std::runtime_error("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;
const Array arr = node.asArray();
typename Array::const_iterator itr = arr.begin();
const uint64_t arrSize = arr.size();
typename Array::const_iterator itr = node.asArray().begin();
if (arrSize == 0 || index > arrSize - 1) {
throwRuntimeError("Expected reference token to identify "
if (index > node.asArray().size() - 1) {
throw std::runtime_error("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())) {
throwRuntimeError("Array index out of bounds; hard "
throw std::runtime_error("Array index out of bounds; hard "
"limit is " + std::to_string(
std::numeric_limits<std::ptrdiff_t>::max()));
}
@ -219,35 +206,30 @@ inline AdapterType resolveJsonPointer(
// Recursively process the remaining tokens
return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext);
#if VALIJSON_USE_EXCEPTIONS
} catch (std::invalid_argument &) {
throwRuntimeError("Expected reference token to contain a "
throw std::runtime_error("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;
const Object object = node.asObject();
typename Object::const_iterator itr = object.find(
typename Object::const_iterator itr = node.asObject().find(
referenceToken);
if (itr == object.end()) {
throwRuntimeError("Expected reference token to identify an "
if (itr == node.asObject().end()) {
throw std::runtime_error("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);
}
throwRuntimeError("Expected end of JSON Pointer, but at least "
throw std::runtime_error("Expected end of JSON Pointer, but at least "
"one reference token has not been processed; remaining tokens: " +
std::string(jsonPointerNext, jsonPointerEnd));
abort();
}
/**
@ -269,7 +251,3 @@ inline AdapterType resolveJsonPointer(
} // namespace json_pointer
} // namespace internal
} // namespace valijson
#ifdef _MSC_VER
#pragma warning( pop )
#endif

View File

@ -13,13 +13,14 @@ 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
@ -46,7 +47,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

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

View File

@ -1,27 +0,0 @@
#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,8 +2,6 @@
#include <string>
#include <valijson/internal/regex.hpp>
namespace valijson {
namespace internal {
namespace uri {
@ -21,20 +19,8 @@ inline bool isUriAbsolute(const std::string &documentUri)
}
/**
* @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
*/
* 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,7 +4,6 @@
#include <set>
#include <valijson/subschema.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
@ -36,72 +35,29 @@ 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.
*/
~Schema() override
virtual ~Schema()
{
if(sharedEmptySubschema != nullptr)
{
sharedEmptySubschema->~Subschema();
m_freeFn(const_cast<Subschema *>(sharedEmptySubschema));
sharedEmptySubschema = nullptr;
}
sharedEmptySubschema->~Subschema();
freeFn(const_cast<Subschema *>(sharedEmptySubschema));
sharedEmptySubschema = NULL;
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
for (auto subschema : subschemaSet) {
for (std::set<Subschema *>::iterator itr = subschemaSet.begin();
itr != subschemaSet.end(); ++itr) {
Subschema *subschema = *itr;
subschema->~Subschema();
m_freeFn(subschema);
freeFn(subschema);
}
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::exception &e) {
fprintf(stderr, "Caught an exception while destroying Schema: %s",
e.what());
}
#endif
}
/**
@ -118,7 +74,7 @@ public:
void addConstraintToSubschema(const Constraint &constraint,
const Subschema *subschema)
{
// TODO: Check hierarchy for subschemas that do not belong...
// TODO: Check heirarchy for subschemas that do not belong...
mutableSubschema(subschema)->addConstraint(constraint);
}
@ -132,20 +88,17 @@ public:
{
Subschema *subschema = newSubschema();
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
if (!subschemaSet.insert(subschema).second) {
throwRuntimeError(
throw std::runtime_error(
"Failed to store pointer for new sub-schema");
}
#if VALIJSON_USE_EXCEPTIONS
} catch (...) {
subschema->~Subschema();
m_freeFn(subschema);
freeFn(subschema);
throw;
}
#endif
return subschema;
}
@ -165,11 +118,6 @@ 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
@ -209,24 +157,26 @@ public:
private:
// Disable copy construction
Schema(const Schema &);
// Disable copy assignment
Schema & operator=(const Schema &);
Subschema *newSubschema()
{
void *ptr = m_allocFn(sizeof(Subschema));
void *ptr = allocFn(sizeof(Subschema));
if (!ptr) {
throwRuntimeError(
throw std::runtime_error(
"Failed to allocate memory for shared empty sub-schema");
}
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
return new (ptr) Subschema();
#if VALIJSON_USE_EXCEPTIONS
} catch (...) {
m_freeFn(ptr);
freeFn(ptr);
throw;
}
#endif
}
Subschema * mutableSubschema(const Subschema *subschema)
@ -236,13 +186,13 @@ private:
}
if (subschema == sharedEmptySubschema) {
throwRuntimeError(
throw std::runtime_error(
"Cannot modify the shared empty sub-schema");
}
auto *noConst = const_cast<Subschema*>(subschema);
Subschema *noConst = const_cast<Subschema*>(subschema);
if (subschemaSet.find(noConst) == subschemaSet.end()) {
throwRuntimeError(
throw std::runtime_error(
"Subschema pointer is not owned by this Schema instance");
}

View File

@ -1,12 +0,0 @@
#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,12 +1,11 @@
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include <memory>
#include <valijson/constraints/constraint.hpp>
#include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
@ -23,7 +22,6 @@ namespace valijson {
class Subschema
{
public:
/// Typedef for custom new-/malloc-like function
typedef void * (*CustomAlloc)(size_t size);
@ -37,53 +35,12 @@ 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()
: m_allocFn([](size_t size) { return ::operator new(size, std::nothrow); })
, m_freeFn(::operator delete)
, m_alwaysInvalid(false) { }
: allocFn(::operator new)
, freeFn(::operator delete) { }
/**
* @brief Construct a new Subschema using custom memory management
@ -95,31 +52,26 @@ public:
* the `customAlloc` function
*/
Subschema(CustomAlloc allocFn, CustomFree 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;
}
: allocFn(allocFn)
, freeFn(freeFn) { }
/**
* @brief Clean up and free all memory managed by the Subschema
*/
virtual ~Subschema()
{
#if VALIJSON_USE_EXCEPTIONS
try {
#endif
m_constraints.clear();
#if VALIJSON_USE_EXCEPTIONS
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();
} catch (const std::exception &e) {
fprintf(stderr, "Caught an exception in Subschema destructor: %s",
e.what());
}
#endif
}
/**
@ -135,31 +87,32 @@ public:
*/
void addConstraint(const Constraint &constraint)
{
// 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));
Constraint *newConstraint = constraint.clone(allocFn, freeFn);
try {
constraints.push_back(newConstraint);
} catch (...) {
newConstraint->~Constraint();
freeFn(newConstraint);
throw;
}
}
/**
* @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 invocations returns \c false. However,
* if one or more invocations of the callback function return \c false,
* the Subschema, even if one of the invokations returns \c false. However,
* if one or more invokations of the callback function return \c false,
* this function will also return \c false.
*
* @returns \c true if all invocations of the callback function are
* @returns \c true if all invokations of the callback function are
* successful, \c false otherwise
*/
bool apply(ApplyFunction &applyFunction) const
{
bool allTrue = true;
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;
}
for (const Constraint *constraint : constraints) {
allTrue = allTrue && applyFunction(*constraint);
}
return allTrue;
@ -169,15 +122,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 invocations of the callback function return
* immediately if any of the invokations of the callback function return
* \c false.
*
* @returns \c true if all invocations of the callback function are
* @returns \c true if all invokations of the callback function are
* successful, \c false otherwise
*/
bool applyStrict(ApplyFunction &applyFunction) const
{
for (auto &&constraint : m_constraints) {
for (const Constraint *constraint : constraints) {
if (!applyFunction(*constraint)) {
return false;
}
@ -186,11 +139,6 @@ public:
return true;
}
bool getAlwaysInvalid() const
{
return m_alwaysInvalid;
}
/**
* @brief Get the description associated with this sub-schema
*
@ -200,11 +148,11 @@ public:
*/
std::string getDescription() const
{
if (m_description) {
return *m_description;
if (description) {
return *description;
}
throwRuntimeError("Schema does not have a description");
throw std::runtime_error("Schema does not have a description");
}
/**
@ -216,11 +164,11 @@ public:
*/
std::string getId() const
{
if (m_id) {
return *m_id;
if (id) {
return *id;
}
throwRuntimeError("Schema does not have an ID");
throw std::runtime_error("Schema does not have an ID");
}
/**
@ -232,11 +180,11 @@ public:
*/
std::string getTitle() const
{
if (m_title) {
return *m_title;
if (title) {
return *title;
}
throwRuntimeError("Schema does not have a title");
throw std::runtime_error("Schema does not have a title");
}
/**
@ -246,7 +194,7 @@ public:
*/
bool hasDescription() const
{
return static_cast<bool>(m_description);
return static_cast<bool>(description);
}
/**
@ -256,7 +204,7 @@ public:
*/
bool hasId() const
{
return static_cast<bool>(m_id);
return static_cast<bool>(id);
}
/**
@ -266,12 +214,7 @@ public:
*/
bool hasTitle() const
{
return static_cast<bool>(m_title);
}
void setAlwaysInvalid(bool value)
{
m_alwaysInvalid = value;
return static_cast<bool>(title);
}
/**
@ -286,12 +229,12 @@ public:
*/
void setDescription(const std::string &description)
{
m_description = description;
this->description = description;
}
void setId(const std::string &id)
{
m_id = id;
this->id = id;
}
/**
@ -306,30 +249,34 @@ public:
*/
void setTitle(const std::string &title)
{
m_title = title;
this->title = title;
}
protected:
CustomAlloc m_allocFn;
CustomAlloc allocFn;
CustomFree m_freeFn;
CustomFree freeFn;
private:
bool m_alwaysInvalid;
// Disable copy construction
Subschema(const Subschema &);
// Disable copy assignment
Subschema & operator=(const Subschema &);
/// List of pointers to constraints that apply to this schema.
std::vector<Constraint::OwningPointer> m_constraints;
std::vector<const Constraint *> constraints;
/// Schema description (optional)
opt::optional<std::string> m_description;
opt::optional<std::string> description;
/// ID to apply when resolving the schema URI
opt::optional<std::string> m_id;
/// Id to apply when resolving the schema URI
opt::optional<std::string> id;
/// Title string associated with the schema (optional)
opt::optional<std::string> m_title;
opt::optional<std::string> title;
};
} // namespace valijson

View File

@ -1,44 +0,0 @@
#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,8 +1,6 @@
#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <json/json.h>
@ -20,14 +18,14 @@ inline bool loadDocument(const std::string &path, Json::Value &document)
return false;
}
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;
Json::Reader reader;
bool parsingSuccessful = reader.parse(file, document);
if (!parsingSuccessful) {
std::cerr << "Jsoncpp parser failed to parse the document:" << std::endl
<< reader.getFormattedErrorMessages();
return false;
}
return true;
}

View File

@ -2,9 +2,8 @@
#include <iostream>
#include <nlohmann/json.hpp>
#include <json.hpp>
#include <valijson/utils/file_utils.hpp>
#include <valijson/exceptions.hpp>
namespace valijson {
namespace utils {
@ -20,7 +19,6 @@ 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) {
@ -28,13 +26,6 @@ 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,13 +2,7 @@
#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,68 +4,30 @@
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/throw_exception.hpp>
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wshadow"
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
# 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,7 +1,6 @@
#pragma once
#include <iostream>
#include <stdexcept>
#include <rapidjson/document.h>
@ -21,23 +20,13 @@ inline bool loadDocument(const std::string &path, rapidjson::GenericDocument<Enc
}
// Parse schema
#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) {
document.template Parse<0>(file.c_str());
if (document.HasParseError()) {
std::cerr << "RapidJson failed to parse the document:" << std::endl;
std::cerr << "Runtime error: " << e.what() << 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;
}
#endif
return true;
}

View File

@ -1,10 +1,6 @@
#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
@ -14,39 +10,51 @@
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)
{
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)
{
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;
}
/* 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) {
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;
}
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.");
}
s += seqLen;
count++;
}
return count;
}
} // namespace utils
} // namespace valijson
} // namespace utils
} // namespace valijson

View File

@ -1,29 +0,0 @@
#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,7 +2,6 @@
#include <deque>
#include <string>
#include <utility>
#include <vector>
namespace valijson {
@ -26,6 +25,21 @@ 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;
@ -38,7 +52,7 @@ public:
*/
std::deque<Error>::const_iterator begin() const
{
return m_errors.begin();
return errors.begin();
}
/**
@ -46,7 +60,7 @@ public:
*/
std::deque<Error>::const_iterator end() const
{
return m_errors.end();
return errors.end();
}
/**
@ -54,7 +68,7 @@ public:
*/
size_t numErrors() const
{
return m_errors.size();
return errors.size();
}
/**
@ -64,7 +78,7 @@ public:
*/
void pushError(const Error &error)
{
m_errors.push_back(error);
errors.push_back(error);
}
/**
@ -76,7 +90,7 @@ public:
void
pushError(const std::vector<std::string> &context, const std::string &description)
{
m_errors.push_back({context, description});
errors.push_back(Error(context, description));
}
/**
@ -89,19 +103,20 @@ public:
bool
popError(Error &error)
{
if (m_errors.empty()) {
if (errors.empty()) {
return false;
}
error = m_errors.front();
m_errors.pop_front();
error = errors.front();
errors.pop_front();
return true;
}
private:
/// FIFO queue of validation errors that have been reported
std::deque<Error> m_errors;
std::deque<Error> errors;
};
} // namespace valijson

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,10 @@ namespace valijson {
class Schema;
class ValidationResults;
/**
* @brief Class that provides validation functionality.
*
* @tparam RegexEngine regular expression engine used for pattern constraint validation.
* @brief Class that provides validation functionality.
*/
template <typename RegexEngine>
class ValidatorT
class Validator
{
public:
enum TypeCheckingMode
@ -25,29 +20,19 @@ public:
kWeakTypes
};
enum DateTimeMode
{
kStrictDateTime,
kPermissiveDateTime
};
/**
* @brief Construct a Validator that uses strong type checking by default
*/
ValidatorT()
: strictTypes(true)
, strictDateTime(true)
{ }
Validator()
: strictTypes(true) { }
/**
* @brief Construct a Validator using a specific type checking mode
*
* @param typeCheckingMode choice of strong or weak type checking
*/
ValidatorT(TypeCheckingMode typeCheckingMode, DateTimeMode dateTimeMode = kStrictDateTime)
: strictTypes(typeCheckingMode == kStrongTypes)
, strictDateTime(dateTimeMode == kStrictDateTime)
{ }
Validator(TypeCheckingMode typeCheckingMode)
: strictTypes(typeCheckingMode == kStrongTypes) { }
/**
* @brief Validate a JSON document and optionally return the results.
@ -73,13 +58,8 @@ public:
ValidationResults *results)
{
// Construct a ValidationVisitor to perform validation at the root level
ValidationVisitor<AdapterType, RegexEngine> v(
target,
std::vector<std::string>(1, "<root>"),
strictTypes,
strictDateTime,
results,
regexesCache);
ValidationVisitor<AdapterType> v(target,
std::vector<std::string>(1, "<root>"), strictTypes, results);
return v.validateSchema(schema);
}
@ -87,32 +67,8 @@ public:
private:
/// Flag indicating that strict type comparisons should be used
bool strictTypes;
const 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

View File

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

View File

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

@ -1,38 +0,0 @@
<?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

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

@ -1,28 +0,0 @@
#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

View File

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

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 KiB

View File

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

View File

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

View File

@ -1,14 +0,0 @@
#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();
}

View File

@ -1,223 +0,0 @@
#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()));
}

View File

@ -1,48 +0,0 @@
#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;
};

View File

@ -1,62 +0,0 @@
#!/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

@ -1,22 +0,0 @@
[
{
"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,8 +0,0 @@
{
"description": "Circular reference when parsing properties keyword",
"properties": {
"foo": {"$ref": "#/properties/bar"},
"bar": {"$ref": "#/properties/baz"},
"baz": {"$ref": "#/properties/foo"}
}
}

View File

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

View File

@ -1,78 +0,0 @@
#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;
}

View File

@ -1,32 +0,0 @@
#!/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,10 +1,4 @@
#ifdef _MSC_VER
#pragma warning(disable: 4706)
#include <picojson.h>
#pragma warning(default: 4706)
#else
#include <picojson.h>
#endif
#include <gtest/gtest.h>
@ -20,12 +14,7 @@
#include <valijson/utils/picojson_utils.hpp>
#include <valijson/utils/rapidjson_utils.hpp>
#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
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
#include <valijson/adapters/property_tree_adapter.hpp>
#include <valijson/utils/property_tree_utils.hpp>
#endif
@ -33,7 +22,6 @@
#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
@ -51,18 +39,19 @@ protected:
struct JsonFile
{
JsonFile(std::string path, int strictGroup, int looseGroup)
: m_path(std::move(path)),
m_strictGroup(strictGroup),
m_looseGroup(looseGroup) { }
JsonFile(const std::string &path, int strictGroup, int looseGroup)
: path(path),
strictGroup(strictGroup),
looseGroup(looseGroup) { }
std::string m_path;
int m_strictGroup;
int m_looseGroup;
std::string path;
int strictGroup;
int looseGroup;
};
static void SetUpTestCase()
{
static void SetUpTestCase() {
const std::string testDataDir(TEST_DATA_DIR);
//
@ -77,17 +66,17 @@ protected:
// strict types. However, only the first two files in the same strict
// group, which means that only they should be equal.
//
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.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_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_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_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);
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));
}
template<typename Adapter1, typename Adapter2>
@ -98,16 +87,16 @@ protected:
for(outerItr = jsonFiles.begin(); outerItr != jsonFiles.end() - 1; ++outerItr) {
for(innerItr = outerItr; innerItr != jsonFiles.end(); ++innerItr) {
const bool expectedStrict = (outerItr->m_strictGroup == innerItr->m_strictGroup);
const bool expectedLoose = (outerItr->m_looseGroup == innerItr->m_looseGroup);
const bool expectedStrict = (outerItr->strictGroup == innerItr->strictGroup);
const bool expectedLoose = (outerItr->looseGroup == innerItr->looseGroup);
typename AdapterTraits<Adapter1>::DocumentType document1;
ASSERT_TRUE( valijson::utils::loadDocument(outerItr->m_path, document1) );
ASSERT_TRUE( valijson::utils::loadDocument(outerItr->path, document1) );
const Adapter1 adapter1(document1);
const std::string adapter1Name = AdapterTraits<Adapter1>::adapterName();
typename AdapterTraits<Adapter2>::DocumentType document2;
ASSERT_TRUE( valijson::utils::loadDocument(innerItr->m_path, document2) );
ASSERT_TRUE( valijson::utils::loadDocument(innerItr->path, document2) );
const Adapter2 adapter2(document2);
const std::string adapter2Name = AdapterTraits<Adapter2>::adapterName();
@ -118,22 +107,22 @@ protected:
// of equality makes sense.
if (adapter1.hasStrictTypes() && adapter2.hasStrictTypes() && adapter1Name == adapter2Name) {
EXPECT_EQ(expectedStrict, adapter1.equalTo(adapter2, true))
<< "Comparing '" << outerItr->m_path << "' to '"
<< innerItr->m_path << "' "
<< "Comparing '" << outerItr->path << "' to '"
<< innerItr->path << "' "
<< "with strict comparison enabled";
EXPECT_EQ(expectedStrict, adapter2.equalTo(adapter1, true))
<< "Comparing '" << innerItr->m_path << "' to '"
<< outerItr->m_path << "' "
<< "Comparing '" << innerItr->path << "' to '"
<< outerItr->path << "' "
<< "with strict comparison enabled";
}
EXPECT_EQ(expectedLoose, adapter1.equalTo(adapter2, false))
<< "Comparing '" << outerItr->m_path << "' to '"
<< innerItr->m_path << "' "
<< "Comparing '" << outerItr->path << "' to '"
<< innerItr->path << "' "
<< "with strict comparison disabled";
EXPECT_EQ(expectedLoose, adapter2.equalTo(adapter1, false))
<< "Comparing '" << innerItr->m_path << "' to '"
<< outerItr->m_path << "' "
<< "Comparing '" << innerItr->path << "' to '"
<< outerItr->path << "' "
<< "with strict comparison disabled";
}
}
@ -162,18 +151,7 @@ TEST_F(TestAdapterComparison, JsonCppVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#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
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, JsonCppVsPropertyTree)
{
@ -182,7 +160,7 @@ TEST_F(TestAdapterComparison, JsonCppVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#endif
TEST_F(TestAdapterComparison, JsonCppVsRapidJson)
{
@ -200,49 +178,12 @@ 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<
@ -273,7 +214,7 @@ TEST_F(TestAdapterComparison, PropertyTreeVsRapidJsonCrtAlloc)
rapidjson::CrtAllocator> > >();
}
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#endif
//
// RapidJson vs X
@ -375,18 +316,7 @@ TEST_F(TestAdapterComparison, Json11VsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#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
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, Json11VsPropertyTree)
{
@ -395,7 +325,7 @@ TEST_F(TestAdapterComparison, Json11VsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
//
// NlohmannJsonAdapter vs X
@ -445,18 +375,7 @@ TEST_F(TestAdapterComparison, NlohmannJsonVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#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
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, NlohmannJsonVsPropertyTree)
{
@ -465,7 +384,7 @@ TEST_F(TestAdapterComparison, NlohmannJsonVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
//
// QtJsonAdapter vs X
@ -509,18 +428,7 @@ TEST_F(TestAdapterComparison, QtJsonVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#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
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, QtJsonVsPropertyTree)
{
@ -529,7 +437,7 @@ TEST_F(TestAdapterComparison, QtJsonVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, QtJsonVsJson11)
{
@ -590,18 +498,7 @@ TEST_F(TestAdapterComparison, PocoJsonVsPicoJson)
valijson::adapters::PicoJsonAdapter>();
}
#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
#ifdef VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, PocoJsonVsPropertyTree)
{
@ -610,7 +507,7 @@ TEST_F(TestAdapterComparison, PocoJsonVsPropertyTree)
valijson::adapters::PropertyTreeAdapter>();
}
#endif // VALIJSON_BUILD_BOOST_PROPERTY_TREE_ADAPTER
#endif // VALIJSON_BUILD_PROPERTY_TREE_ADAPTER
TEST_F(TestAdapterComparison, PocoJsonVsJson11)
{

View File

@ -1,89 +0,0 @@
#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

@ -1,69 +0,0 @@
#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 TestFetchAbsoluteUriDocumentCallback : public ::testing::Test
class TestFetchDocumentCallback : public ::testing::Test
{
};
const rapidjson::Document * fetchAbsoluteUriDocument(const std::string &uri)
const rapidjson::Document * fetchDocument(const std::string &uri)
{
EXPECT_STREQ("http://localhost:1234/", uri.c_str());
@ -43,12 +43,12 @@ const rapidjson::Document * fetchAbsoluteUriDocument(const std::string &uri)
return fetchedRoot;
}
void freeAbsoluteUriDocument(const rapidjson::Document *adapter)
void freeDocument(const rapidjson::Document *adapter)
{
delete adapter;
}
TEST_F(TestFetchAbsoluteUriDocumentCallback, Basics)
TEST_F(TestFetchDocumentCallback, Basics)
{
// Define schema
rapidjson::Document schemaDocument;
@ -60,8 +60,8 @@ TEST_F(TestFetchAbsoluteUriDocumentCallback, Basics)
// Parse schema document
Schema schema;
SchemaParser schemaParser;
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchAbsoluteUriDocument,
freeAbsoluteUriDocument);
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchDocument,
freeDocument);
// Test resulting schema with a valid document
rapidjson::Document validDocument;

View File

@ -1,80 +0,0 @@
#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,13 +22,12 @@ 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() );
@ -60,13 +59,12 @@ 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,20 +3,14 @@
#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"
#include <valijson/adapters/rapidjson_adapter.hpp>
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
{
@ -25,6 +19,9 @@ class TestJsonPointer : public testing::Test
struct JsonPointerTestCase
{
JsonPointerTestCase(const std::string &description)
: description(description) { }
/// Description of test case
std::string description;
@ -46,93 +43,66 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
std::vector<TestCase> testCases;
TestCase testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '#' should cause an exception to be thrown";
TestCase testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '#' should cause an exception to be thrown");
testCase->value.SetNull();
testCase->jsonPointer = "#";
testCase->expectedValue = nullptr;
testCase->expectedValue = NULL;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving an empty string should return the root node";
testCase = std::make_shared<JsonPointerTestCase>(
"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>();
testCase->description = "Resolving '/' should return the root node";
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '/' should return the root node");
testCase->value.SetNull();
testCase->jsonPointer = "/";
testCase->expectedValue = &testCase->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '//' should return the root node";
testCase = std::make_shared<JsonPointerTestCase>(
"Resolving '//' should return the root node");
testCase->value.SetNull();
testCase->jsonPointer = "//";
testCase->expectedValue = &testCase->value;
testCases.push_back(testCase);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test' in object containing one member named 'test'";
testCase = std::make_shared<JsonPointerTestCase>(
"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>();
testCase->description = "Resolve '/test/' in object containing one member named 'test'";
testCase = std::make_shared<JsonPointerTestCase>(
"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>();
testCase->description = "Resolve '//test//' in object containing one member named 'test'";
testCase = std::make_shared<JsonPointerTestCase>(
"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>();
testCase->description = "Resolve '/missing' in object containing one member name 'test'";
testCase = std::make_shared<JsonPointerTestCase>(
"Resolve '/missing' in object containing one member name 'test'");
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/missing";
testCase->expectedValue = nullptr;
testCase->expectedValue = NULL;
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();
@ -140,8 +110,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/0' in object containing one member containing an array with 3 elements";
testCase = std::make_shared<JsonPointerTestCase>(
"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";
@ -156,8 +127,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/1' in object containing one member containing an array with 3 elements";
testCase = std::make_shared<JsonPointerTestCase>(
"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";
@ -172,8 +144,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolve '/test/2' in object containing one member containing an array with 3 elements";
testCase = std::make_shared<JsonPointerTestCase>(
"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";
@ -188,13 +161,13 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
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 = std::make_shared<JsonPointerTestCase>(
"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 = nullptr;
testCase->expectedValue = NULL;
testCases.push_back(testCase);
}
@ -219,12 +192,12 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
testArray.PushBack("test1", allocator);
testArray.PushBack("test2", allocator);
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 = std::make_shared<JsonPointerTestCase>(
"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 = nullptr;
testCase->expectedValue = NULL;
testCases.push_back(testCase);
}
@ -247,9 +220,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
rapidjson::Value value;
value.SetDouble(10.);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/hello~1world' in object containing one member named "
"'hello/world' should return the associated value";
testCase = std::make_shared<JsonPointerTestCase>(
"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";
@ -261,9 +234,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
rapidjson::Value value;
value.SetDouble(10.);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/hello~0world' in object containing one member named "
"'hello~world' should return the associated value";
testCase = std::make_shared<JsonPointerTestCase>(
"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";
@ -275,9 +248,9 @@ std::vector<std::shared_ptr<JsonPointerTestCase> >
rapidjson::Value value;
value.SetDouble(10.);
testCase = std::make_shared<JsonPointerTestCase>();
testCase->description = "Resolving '/hello~01world' in object containing one member named "
"'hello~1world' should return the associated value";
testCase = std::make_shared<JsonPointerTestCase>(
"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";
@ -297,33 +270,21 @@ TEST_F(TestJsonPointer, JsonPointerTestCases)
TestCases testCases = testCasesForSingleLevelObjectPointers(allocator);
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;
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;
} else {
// 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
EXPECT_THROW(
resolveJsonPointer(valueAdapter, jsonPointer),
std::runtime_error) <<
(*itr)->description;
}
}
}
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,13 +21,12 @@ 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() );
@ -58,13 +57,11 @@ 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() );

View File

@ -21,13 +21,11 @@ TEST_F(TestNlohmannJsonAdapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types
valijson::adapters::NlohmannJsonAdapter 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() );
@ -58,13 +56,11 @@ TEST_F(TestNlohmannJsonAdapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types
valijson::adapters::NlohmannJsonAdapter 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