From e4e7b1f32a17d5d6765ad6a96ce4ec3d9166521c Mon Sep 17 00:00:00 2001 From: Matthew Bartenschlag Date: Fri, 28 Jun 2019 13:55:51 -0400 Subject: [PATCH] Initial commit of biqt. --- .clang-format | 228 ++ .gitignore | 9 + CMakeLists.txt | 168 ++ INSTALL.md | 96 + LICENSE | 209 ++ README.md | 82 + cxx/BIQT-cli.cpp | 423 +++ cxx/BIQT.cpp | 362 +++ cxx/BIQT.h | 80 + cxx/ProviderInterface.h | 249 ++ cxx/jsoncpp/.clang-format | 47 + cxx/jsoncpp/.gitattributes | 11 + cxx/jsoncpp/.gitignore | 55 + cxx/jsoncpp/.travis.yml | 55 + cxx/jsoncpp/AUTHORS | 111 + cxx/jsoncpp/CMakeLists.txt | 159 + cxx/jsoncpp/LICENSE | 55 + cxx/jsoncpp/README.md | 131 + cxx/jsoncpp/dev.makefile | 35 + cxx/jsoncpp/devtools/__init__.py | 6 + cxx/jsoncpp/devtools/agent_vmw7.json | 33 + cxx/jsoncpp/devtools/agent_vmxp.json | 26 + cxx/jsoncpp/devtools/antglob.py | 205 ++ cxx/jsoncpp/devtools/batchbuild.py | 278 ++ cxx/jsoncpp/devtools/fixeol.py | 70 + cxx/jsoncpp/devtools/licenseupdater.py | 94 + cxx/jsoncpp/devtools/tarball.py | 52 + cxx/jsoncpp/include/CMakeLists.txt | 2 + cxx/jsoncpp/include/json/allocator.h | 98 + cxx/jsoncpp/include/json/assertions.h | 54 + cxx/jsoncpp/include/json/autolink.h | 25 + cxx/jsoncpp/include/json/config.h | 187 ++ cxx/jsoncpp/include/json/features.h | 61 + cxx/jsoncpp/include/json/forwards.h | 37 + cxx/jsoncpp/include/json/json.h | 15 + cxx/jsoncpp/include/json/reader.h | 411 +++ cxx/jsoncpp/include/json/value.h | 887 ++++++ cxx/jsoncpp/include/json/version.h | 20 + cxx/jsoncpp/include/json/writer.h | 337 +++ cxx/jsoncpp/makefiles/vs71/jsontest.vcproj | 119 + cxx/jsoncpp/makefiles/vs71/lib_json.vcproj | 205 ++ .../makefiles/vs71/test_lib_json.vcproj | 130 + cxx/jsoncpp/pkg-config/jsoncpp.pc.in | 9 + cxx/jsoncpp/src/CMakeLists.txt | 5 + cxx/jsoncpp/src/jsontestrunner/CMakeLists.txt | 25 + cxx/jsoncpp/src/jsontestrunner/main.cpp | 331 +++ cxx/jsoncpp/src/lib_json/CMakeLists.txt | 117 + cxx/jsoncpp/src/lib_json/json_reader.cpp | 2064 +++++++++++++ cxx/jsoncpp/src/lib_json/json_tool.h | 117 + cxx/jsoncpp/src/lib_json/json_value.cpp | 1662 +++++++++++ .../src/lib_json/json_valueiterator.inl | 167 ++ cxx/jsoncpp/src/lib_json/json_writer.cpp | 1223 ++++++++ cxx/jsoncpp/src/lib_json/version.h.in | 20 + cxx/jsoncpp/src/test_lib_json/CMakeLists.txt | 38 + cxx/jsoncpp/src/test_lib_json/jsontest.cpp | 457 +++ cxx/jsoncpp/src/test_lib_json/jsontest.h | 286 ++ cxx/jsoncpp/src/test_lib_json/main.cpp | 2594 +++++++++++++++++ cxx/jsoncpp/test/cleantests.py | 16 + cxx/jsoncpp/test/data/fail_test_array_01.json | 1 + .../test/data/fail_test_stack_limit.json | 1 + cxx/jsoncpp/test/data/test_array_01.expected | 1 + cxx/jsoncpp/test/data/test_array_01.json | 1 + cxx/jsoncpp/test/data/test_array_02.expected | 2 + cxx/jsoncpp/test/data/test_array_02.json | 1 + cxx/jsoncpp/test/data/test_array_03.expected | 6 + cxx/jsoncpp/test/data/test_array_03.json | 1 + cxx/jsoncpp/test/data/test_array_04.expected | 5 + cxx/jsoncpp/test/data/test_array_04.json | 1 + cxx/jsoncpp/test/data/test_array_05.expected | 100 + cxx/jsoncpp/test/data/test_array_05.json | 1 + cxx/jsoncpp/test/data/test_array_06.expected | 5 + cxx/jsoncpp/test/data/test_array_06.json | 4 + cxx/jsoncpp/test/data/test_array_07.expected | 2122 ++++++++++++++ cxx/jsoncpp/test/data/test_array_07.json | 2 + cxx/jsoncpp/test/data/test_basic_01.expected | 1 + cxx/jsoncpp/test/data/test_basic_01.json | 1 + cxx/jsoncpp/test/data/test_basic_02.expected | 1 + cxx/jsoncpp/test/data/test_basic_02.json | 1 + cxx/jsoncpp/test/data/test_basic_03.expected | 3 + cxx/jsoncpp/test/data/test_basic_03.json | 3 + cxx/jsoncpp/test/data/test_basic_04.expected | 2 + cxx/jsoncpp/test/data/test_basic_04.json | 2 + cxx/jsoncpp/test/data/test_basic_05.expected | 2 + cxx/jsoncpp/test/data/test_basic_05.json | 2 + cxx/jsoncpp/test/data/test_basic_06.expected | 2 + cxx/jsoncpp/test/data/test_basic_06.json | 2 + cxx/jsoncpp/test/data/test_basic_07.expected | 2 + cxx/jsoncpp/test/data/test_basic_07.json | 2 + cxx/jsoncpp/test/data/test_basic_08.expected | 3 + cxx/jsoncpp/test/data/test_basic_08.json | 3 + cxx/jsoncpp/test/data/test_basic_09.expected | 4 + cxx/jsoncpp/test/data/test_basic_09.json | 4 + .../test/data/test_comment_00.expected | 4 + cxx/jsoncpp/test/data/test_comment_00.json | 5 + .../test/data/test_comment_01.expected | 10 + cxx/jsoncpp/test/data/test_comment_01.json | 10 + .../test/data/test_comment_02.expected | 23 + cxx/jsoncpp/test/data/test_comment_02.json | 26 + .../test/data/test_complex_01.expected | 20 + cxx/jsoncpp/test/data/test_complex_01.json | 17 + .../test/data/test_integer_01.expected | 2 + cxx/jsoncpp/test/data/test_integer_01.json | 2 + .../test/data/test_integer_02.expected | 2 + cxx/jsoncpp/test/data/test_integer_02.json | 2 + .../test/data/test_integer_03.expected | 2 + cxx/jsoncpp/test/data/test_integer_03.json | 2 + .../test/data/test_integer_04.expected | 3 + cxx/jsoncpp/test/data/test_integer_04.json | 3 + .../test/data/test_integer_05.expected | 2 + cxx/jsoncpp/test/data/test_integer_05.json | 2 + .../test/data/test_integer_06_64bits.expected | 1 + .../test/data/test_integer_06_64bits.json | 2 + .../test/data/test_integer_07_64bits.expected | 1 + .../test/data/test_integer_07_64bits.json | 2 + .../test/data/test_integer_08_64bits.expected | 1 + .../test/data/test_integer_08_64bits.json | 2 + cxx/jsoncpp/test/data/test_large_01.expected | 2122 ++++++++++++++ cxx/jsoncpp/test/data/test_large_01.json | 2 + cxx/jsoncpp/test/data/test_object_01.expected | 1 + cxx/jsoncpp/test/data/test_object_01.json | 1 + cxx/jsoncpp/test/data/test_object_02.expected | 2 + cxx/jsoncpp/test/data/test_object_02.json | 1 + cxx/jsoncpp/test/data/test_object_03.expected | 4 + cxx/jsoncpp/test/data/test_object_03.json | 5 + cxx/jsoncpp/test/data/test_object_04.expected | 2 + cxx/jsoncpp/test/data/test_object_04.json | 3 + .../data/test_preserve_comment_01.expected | 11 + .../test/data/test_preserve_comment_01.json | 14 + cxx/jsoncpp/test/data/test_real_01.expected | 3 + cxx/jsoncpp/test/data/test_real_01.json | 3 + cxx/jsoncpp/test/data/test_real_02.expected | 3 + cxx/jsoncpp/test/data/test_real_02.json | 3 + cxx/jsoncpp/test/data/test_real_03.expected | 3 + cxx/jsoncpp/test/data/test_real_03.json | 3 + cxx/jsoncpp/test/data/test_real_04.expected | 3 + cxx/jsoncpp/test/data/test_real_04.json | 3 + cxx/jsoncpp/test/data/test_real_05.expected | 4 + cxx/jsoncpp/test/data/test_real_05.json | 3 + cxx/jsoncpp/test/data/test_real_06.expected | 4 + cxx/jsoncpp/test/data/test_real_06.json | 3 + cxx/jsoncpp/test/data/test_real_07.expected | 4 + cxx/jsoncpp/test/data/test_real_07.json | 3 + cxx/jsoncpp/test/data/test_real_08.expected | 4 + cxx/jsoncpp/test/data/test_real_08.json | 4 + cxx/jsoncpp/test/data/test_real_09.expected | 4 + cxx/jsoncpp/test/data/test_real_09.json | 4 + cxx/jsoncpp/test/data/test_real_10.expected | 4 + cxx/jsoncpp/test/data/test_real_10.json | 4 + cxx/jsoncpp/test/data/test_real_11.expected | 4 + cxx/jsoncpp/test/data/test_real_11.json | 4 + cxx/jsoncpp/test/data/test_real_12.expected | 2 + cxx/jsoncpp/test/data/test_real_12.json | 2 + cxx/jsoncpp/test/data/test_string_01.expected | 1 + cxx/jsoncpp/test/data/test_string_01.json | 1 + cxx/jsoncpp/test/data/test_string_02.expected | 1 + cxx/jsoncpp/test/data/test_string_02.json | 1 + cxx/jsoncpp/test/data/test_string_03.expected | 1 + cxx/jsoncpp/test/data/test_string_03.json | 1 + cxx/jsoncpp/test/data/test_string_04.expected | 2 + cxx/jsoncpp/test/data/test_string_04.json | 2 + cxx/jsoncpp/test/data/test_string_05.expected | 2 + cxx/jsoncpp/test/data/test_string_05.json | 2 + .../test/data/test_string_unicode_01.expected | 1 + .../test/data/test_string_unicode_01.json | 1 + .../test/data/test_string_unicode_02.expected | 1 + .../test/data/test_string_unicode_02.json | 1 + .../test/data/test_string_unicode_03.expected | 1 + .../test/data/test_string_unicode_03.json | 1 + .../test/data/test_string_unicode_04.expected | 1 + .../test/data/test_string_unicode_04.json | 1 + .../test/data/test_string_unicode_05.expected | 2 + .../test/data/test_string_unicode_05.json | 1 + cxx/jsoncpp/test/generate_expected.py | 17 + cxx/jsoncpp/test/jsonchecker/fail1.json | 1 + cxx/jsoncpp/test/jsonchecker/fail10.json | 1 + cxx/jsoncpp/test/jsonchecker/fail11.json | 1 + cxx/jsoncpp/test/jsonchecker/fail12.json | 1 + cxx/jsoncpp/test/jsonchecker/fail13.json | 1 + cxx/jsoncpp/test/jsonchecker/fail14.json | 1 + cxx/jsoncpp/test/jsonchecker/fail15.json | 1 + cxx/jsoncpp/test/jsonchecker/fail16.json | 1 + cxx/jsoncpp/test/jsonchecker/fail17.json | 1 + cxx/jsoncpp/test/jsonchecker/fail18.json | 1 + cxx/jsoncpp/test/jsonchecker/fail19.json | 1 + cxx/jsoncpp/test/jsonchecker/fail2.json | 1 + cxx/jsoncpp/test/jsonchecker/fail20.json | 1 + cxx/jsoncpp/test/jsonchecker/fail21.json | 1 + cxx/jsoncpp/test/jsonchecker/fail22.json | 1 + cxx/jsoncpp/test/jsonchecker/fail23.json | 1 + cxx/jsoncpp/test/jsonchecker/fail24.json | 1 + cxx/jsoncpp/test/jsonchecker/fail25.json | 1 + cxx/jsoncpp/test/jsonchecker/fail26.json | 1 + cxx/jsoncpp/test/jsonchecker/fail27.json | 2 + cxx/jsoncpp/test/jsonchecker/fail28.json | 2 + cxx/jsoncpp/test/jsonchecker/fail29.json | 1 + cxx/jsoncpp/test/jsonchecker/fail3.json | 1 + cxx/jsoncpp/test/jsonchecker/fail30.json | 1 + cxx/jsoncpp/test/jsonchecker/fail31.json | 1 + cxx/jsoncpp/test/jsonchecker/fail32.json | 1 + cxx/jsoncpp/test/jsonchecker/fail33.json | 1 + cxx/jsoncpp/test/jsonchecker/fail4.json | 1 + cxx/jsoncpp/test/jsonchecker/fail5.json | 1 + cxx/jsoncpp/test/jsonchecker/fail6.json | 1 + cxx/jsoncpp/test/jsonchecker/fail7.json | 1 + cxx/jsoncpp/test/jsonchecker/fail8.json | 1 + cxx/jsoncpp/test/jsonchecker/fail9.json | 1 + cxx/jsoncpp/test/jsonchecker/pass1.json | 58 + cxx/jsoncpp/test/jsonchecker/pass2.json | 1 + cxx/jsoncpp/test/jsonchecker/pass3.json | 6 + cxx/jsoncpp/test/jsonchecker/readme.txt | 3 + cxx/jsoncpp/test/pyjsontestrunner.py | 71 + cxx/jsoncpp/test/runjsontests.py | 174 ++ cxx/jsoncpp/test/rununittests.py | 84 + cxx/jsoncpp/version | 1 + cxx/jsoncpp/version.in | 1 + cxx/windows/dirent.h | 1094 +++++++ cxx/windows/getopt.h | 641 ++++ cxx/windows/libgen.h | 27 + doc/biqt.png | Bin 0 -> 9635 bytes doc/biqt.vsd | Bin 0 -> 61440 bytes java/pom.xml | 91 + java/src/c/CMakeLists.txt | 26 + java/src/c/java_provider.cpp | 140 + java/src/c/java_provider.h | 26 + java/src/c/jnihelper.c | 120 + java/src/c/jnihelper.h | 31 + java/src/c/org_mitre_biqt_BIQT.cpp | 160 + java/src/c/org_mitre_biqt_BIQT.h | 63 + .../main/java/cz/adamh/utils/NativeUtils.java | 151 + java/src/main/java/org/mitre/biqt/BIQT.java | 163 ++ .../main/java/org/mitre/biqt/Provider.java | 60 + .../java/org/mitre/biqt/ProviderInfo.java | 64 + .../test/java/org/mitre/biqt/TestBIQT.java | 44 + setup_provider.py | 57 + templates/CMakeLists.txt | 75 + templates/Provider.cpp | 54 + templates/Provider.h | 28 + templates/descriptor.json | 27 + 238 files changed, 23355 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 INSTALL.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 cxx/BIQT-cli.cpp create mode 100644 cxx/BIQT.cpp create mode 100644 cxx/BIQT.h create mode 100644 cxx/ProviderInterface.h create mode 100644 cxx/jsoncpp/.clang-format create mode 100644 cxx/jsoncpp/.gitattributes create mode 100644 cxx/jsoncpp/.gitignore create mode 100644 cxx/jsoncpp/.travis.yml create mode 100644 cxx/jsoncpp/AUTHORS create mode 100644 cxx/jsoncpp/CMakeLists.txt create mode 100644 cxx/jsoncpp/LICENSE create mode 100644 cxx/jsoncpp/README.md create mode 100644 cxx/jsoncpp/dev.makefile create mode 100644 cxx/jsoncpp/devtools/__init__.py create mode 100644 cxx/jsoncpp/devtools/agent_vmw7.json create mode 100644 cxx/jsoncpp/devtools/agent_vmxp.json create mode 100644 cxx/jsoncpp/devtools/antglob.py create mode 100644 cxx/jsoncpp/devtools/batchbuild.py create mode 100644 cxx/jsoncpp/devtools/fixeol.py create mode 100644 cxx/jsoncpp/devtools/licenseupdater.py create mode 100644 cxx/jsoncpp/devtools/tarball.py create mode 100644 cxx/jsoncpp/include/CMakeLists.txt create mode 100644 cxx/jsoncpp/include/json/allocator.h create mode 100644 cxx/jsoncpp/include/json/assertions.h create mode 100644 cxx/jsoncpp/include/json/autolink.h create mode 100644 cxx/jsoncpp/include/json/config.h create mode 100644 cxx/jsoncpp/include/json/features.h create mode 100644 cxx/jsoncpp/include/json/forwards.h create mode 100644 cxx/jsoncpp/include/json/json.h create mode 100644 cxx/jsoncpp/include/json/reader.h create mode 100644 cxx/jsoncpp/include/json/value.h create mode 100644 cxx/jsoncpp/include/json/version.h create mode 100644 cxx/jsoncpp/include/json/writer.h create mode 100644 cxx/jsoncpp/makefiles/vs71/jsontest.vcproj create mode 100644 cxx/jsoncpp/makefiles/vs71/lib_json.vcproj create mode 100644 cxx/jsoncpp/makefiles/vs71/test_lib_json.vcproj create mode 100644 cxx/jsoncpp/pkg-config/jsoncpp.pc.in create mode 100644 cxx/jsoncpp/src/CMakeLists.txt create mode 100644 cxx/jsoncpp/src/jsontestrunner/CMakeLists.txt create mode 100644 cxx/jsoncpp/src/jsontestrunner/main.cpp create mode 100644 cxx/jsoncpp/src/lib_json/CMakeLists.txt create mode 100644 cxx/jsoncpp/src/lib_json/json_reader.cpp create mode 100644 cxx/jsoncpp/src/lib_json/json_tool.h create mode 100644 cxx/jsoncpp/src/lib_json/json_value.cpp create mode 100644 cxx/jsoncpp/src/lib_json/json_valueiterator.inl create mode 100644 cxx/jsoncpp/src/lib_json/json_writer.cpp create mode 100644 cxx/jsoncpp/src/lib_json/version.h.in create mode 100644 cxx/jsoncpp/src/test_lib_json/CMakeLists.txt create mode 100644 cxx/jsoncpp/src/test_lib_json/jsontest.cpp create mode 100644 cxx/jsoncpp/src/test_lib_json/jsontest.h create mode 100644 cxx/jsoncpp/src/test_lib_json/main.cpp create mode 100644 cxx/jsoncpp/test/cleantests.py create mode 100644 cxx/jsoncpp/test/data/fail_test_array_01.json create mode 100644 cxx/jsoncpp/test/data/fail_test_stack_limit.json create mode 100644 cxx/jsoncpp/test/data/test_array_01.expected create mode 100644 cxx/jsoncpp/test/data/test_array_01.json create mode 100644 cxx/jsoncpp/test/data/test_array_02.expected create mode 100644 cxx/jsoncpp/test/data/test_array_02.json create mode 100644 cxx/jsoncpp/test/data/test_array_03.expected create mode 100644 cxx/jsoncpp/test/data/test_array_03.json create mode 100644 cxx/jsoncpp/test/data/test_array_04.expected create mode 100644 cxx/jsoncpp/test/data/test_array_04.json create mode 100644 cxx/jsoncpp/test/data/test_array_05.expected create mode 100644 cxx/jsoncpp/test/data/test_array_05.json create mode 100644 cxx/jsoncpp/test/data/test_array_06.expected create mode 100644 cxx/jsoncpp/test/data/test_array_06.json create mode 100644 cxx/jsoncpp/test/data/test_array_07.expected create mode 100644 cxx/jsoncpp/test/data/test_array_07.json create mode 100644 cxx/jsoncpp/test/data/test_basic_01.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_01.json create mode 100644 cxx/jsoncpp/test/data/test_basic_02.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_02.json create mode 100644 cxx/jsoncpp/test/data/test_basic_03.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_03.json create mode 100644 cxx/jsoncpp/test/data/test_basic_04.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_04.json create mode 100644 cxx/jsoncpp/test/data/test_basic_05.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_05.json create mode 100644 cxx/jsoncpp/test/data/test_basic_06.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_06.json create mode 100644 cxx/jsoncpp/test/data/test_basic_07.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_07.json create mode 100644 cxx/jsoncpp/test/data/test_basic_08.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_08.json create mode 100644 cxx/jsoncpp/test/data/test_basic_09.expected create mode 100644 cxx/jsoncpp/test/data/test_basic_09.json create mode 100644 cxx/jsoncpp/test/data/test_comment_00.expected create mode 100644 cxx/jsoncpp/test/data/test_comment_00.json create mode 100644 cxx/jsoncpp/test/data/test_comment_01.expected create mode 100644 cxx/jsoncpp/test/data/test_comment_01.json create mode 100644 cxx/jsoncpp/test/data/test_comment_02.expected create mode 100644 cxx/jsoncpp/test/data/test_comment_02.json create mode 100644 cxx/jsoncpp/test/data/test_complex_01.expected create mode 100644 cxx/jsoncpp/test/data/test_complex_01.json create mode 100644 cxx/jsoncpp/test/data/test_integer_01.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_01.json create mode 100644 cxx/jsoncpp/test/data/test_integer_02.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_02.json create mode 100644 cxx/jsoncpp/test/data/test_integer_03.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_03.json create mode 100644 cxx/jsoncpp/test/data/test_integer_04.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_04.json create mode 100644 cxx/jsoncpp/test/data/test_integer_05.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_05.json create mode 100644 cxx/jsoncpp/test/data/test_integer_06_64bits.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_06_64bits.json create mode 100644 cxx/jsoncpp/test/data/test_integer_07_64bits.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_07_64bits.json create mode 100644 cxx/jsoncpp/test/data/test_integer_08_64bits.expected create mode 100644 cxx/jsoncpp/test/data/test_integer_08_64bits.json create mode 100644 cxx/jsoncpp/test/data/test_large_01.expected create mode 100644 cxx/jsoncpp/test/data/test_large_01.json create mode 100644 cxx/jsoncpp/test/data/test_object_01.expected create mode 100644 cxx/jsoncpp/test/data/test_object_01.json create mode 100644 cxx/jsoncpp/test/data/test_object_02.expected create mode 100644 cxx/jsoncpp/test/data/test_object_02.json create mode 100644 cxx/jsoncpp/test/data/test_object_03.expected create mode 100644 cxx/jsoncpp/test/data/test_object_03.json create mode 100644 cxx/jsoncpp/test/data/test_object_04.expected create mode 100644 cxx/jsoncpp/test/data/test_object_04.json create mode 100644 cxx/jsoncpp/test/data/test_preserve_comment_01.expected create mode 100644 cxx/jsoncpp/test/data/test_preserve_comment_01.json create mode 100644 cxx/jsoncpp/test/data/test_real_01.expected create mode 100644 cxx/jsoncpp/test/data/test_real_01.json create mode 100644 cxx/jsoncpp/test/data/test_real_02.expected create mode 100644 cxx/jsoncpp/test/data/test_real_02.json create mode 100644 cxx/jsoncpp/test/data/test_real_03.expected create mode 100644 cxx/jsoncpp/test/data/test_real_03.json create mode 100644 cxx/jsoncpp/test/data/test_real_04.expected create mode 100644 cxx/jsoncpp/test/data/test_real_04.json create mode 100644 cxx/jsoncpp/test/data/test_real_05.expected create mode 100644 cxx/jsoncpp/test/data/test_real_05.json create mode 100644 cxx/jsoncpp/test/data/test_real_06.expected create mode 100644 cxx/jsoncpp/test/data/test_real_06.json create mode 100644 cxx/jsoncpp/test/data/test_real_07.expected create mode 100644 cxx/jsoncpp/test/data/test_real_07.json create mode 100644 cxx/jsoncpp/test/data/test_real_08.expected create mode 100644 cxx/jsoncpp/test/data/test_real_08.json create mode 100644 cxx/jsoncpp/test/data/test_real_09.expected create mode 100644 cxx/jsoncpp/test/data/test_real_09.json create mode 100644 cxx/jsoncpp/test/data/test_real_10.expected create mode 100644 cxx/jsoncpp/test/data/test_real_10.json create mode 100644 cxx/jsoncpp/test/data/test_real_11.expected create mode 100644 cxx/jsoncpp/test/data/test_real_11.json create mode 100644 cxx/jsoncpp/test/data/test_real_12.expected create mode 100644 cxx/jsoncpp/test/data/test_real_12.json create mode 100644 cxx/jsoncpp/test/data/test_string_01.expected create mode 100644 cxx/jsoncpp/test/data/test_string_01.json create mode 100644 cxx/jsoncpp/test/data/test_string_02.expected create mode 100644 cxx/jsoncpp/test/data/test_string_02.json create mode 100644 cxx/jsoncpp/test/data/test_string_03.expected create mode 100644 cxx/jsoncpp/test/data/test_string_03.json create mode 100644 cxx/jsoncpp/test/data/test_string_04.expected create mode 100644 cxx/jsoncpp/test/data/test_string_04.json create mode 100644 cxx/jsoncpp/test/data/test_string_05.expected create mode 100644 cxx/jsoncpp/test/data/test_string_05.json create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_01.expected create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_01.json create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_02.expected create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_02.json create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_03.expected create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_03.json create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_04.expected create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_04.json create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_05.expected create mode 100644 cxx/jsoncpp/test/data/test_string_unicode_05.json create mode 100644 cxx/jsoncpp/test/generate_expected.py create mode 100644 cxx/jsoncpp/test/jsonchecker/fail1.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail10.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail11.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail12.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail13.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail14.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail15.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail16.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail17.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail18.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail19.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail2.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail20.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail21.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail22.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail23.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail24.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail25.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail26.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail27.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail28.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail29.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail3.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail30.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail31.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail32.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail33.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail4.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail5.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail6.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail7.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail8.json create mode 100644 cxx/jsoncpp/test/jsonchecker/fail9.json create mode 100644 cxx/jsoncpp/test/jsonchecker/pass1.json create mode 100644 cxx/jsoncpp/test/jsonchecker/pass2.json create mode 100644 cxx/jsoncpp/test/jsonchecker/pass3.json create mode 100644 cxx/jsoncpp/test/jsonchecker/readme.txt create mode 100644 cxx/jsoncpp/test/pyjsontestrunner.py create mode 100644 cxx/jsoncpp/test/runjsontests.py create mode 100644 cxx/jsoncpp/test/rununittests.py create mode 100644 cxx/jsoncpp/version create mode 100644 cxx/jsoncpp/version.in create mode 100644 cxx/windows/dirent.h create mode 100644 cxx/windows/getopt.h create mode 100644 cxx/windows/libgen.h create mode 100644 doc/biqt.png create mode 100644 doc/biqt.vsd create mode 100644 java/pom.xml create mode 100644 java/src/c/CMakeLists.txt create mode 100644 java/src/c/java_provider.cpp create mode 100644 java/src/c/java_provider.h create mode 100644 java/src/c/jnihelper.c create mode 100644 java/src/c/jnihelper.h create mode 100644 java/src/c/org_mitre_biqt_BIQT.cpp create mode 100644 java/src/c/org_mitre_biqt_BIQT.h create mode 100644 java/src/main/java/cz/adamh/utils/NativeUtils.java create mode 100644 java/src/main/java/org/mitre/biqt/BIQT.java create mode 100644 java/src/main/java/org/mitre/biqt/Provider.java create mode 100644 java/src/main/java/org/mitre/biqt/ProviderInfo.java create mode 100644 java/src/test/java/org/mitre/biqt/TestBIQT.java create mode 100644 setup_provider.py create mode 100644 templates/CMakeLists.txt create mode 100644 templates/Provider.cpp create mode 100644 templates/Provider.h create mode 100644 templates/descriptor.json diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..3c48510 --- /dev/null +++ b/.clang-format @@ -0,0 +1,228 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Stroustrup +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +RawStringFormats: + - Delimiter: pb + Language: TextProto + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + +--- +Language: Java +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +RawStringFormats: + - Delimiter: pb + Language: TextProto + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f529f07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.o +*.so +*.dll +*.dylib +*.lib +build +target +.idea +cmake-build-debug diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b2d741b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,168 @@ +# ####################################################################### +# NOTICE +# +# This software (or technical data) was produced for the U.S. Government +# under contract, and is subject to the Rights in Data-General Clause +# 52.227-14, Alt. IV (DEC 2007). +# +# Copyright 2019 The MITRE Corporation. All Rights Reserved. +# ####################################################################### + +cmake_minimum_required(VERSION 3.1) +project(biqt) +set(CMAKE_CXX_STANDARD 11) + +# OPTIONS ##################################################################### + +OPTION(BUILD_SHARED_LIBS "Builds shared libraries for certain dependencies. Recommended: ON" ON) +OPTION(BUILD_STATIC_LIBS "Builds static libraries for certain dependencies. Recommended: OFF" OFF) +OPTION(WITH_JAVA "Builds Java bindings. Requires a JDK installation. Default: ON" ON) +OPTION(SKIP_PROFILE "Do not set up environment variables on Linux (turn on if you do not have root access)" OFF) + +set(BIQT_VERSION "0.1" + CACHE STRING "Build version or tag associated with this BIQT release.") + +message("BIQT v${BIQT_VERSION}") +add_definitions(-DBIQT_VERSION="${BIQT_VERSION}") + +if(NOT WIN32) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + set(CMAKE_CXX_FLAGS "-g -fPIC") +else() + include_directories(cxx/windows) +endif() + +include_directories(cxx/ + cxx/jsoncpp/include + ${EXTRA_INCLUDES}) + +set(CPACK_PACKAGE_VERSION ${VERSION}) +set(CPACK_GENERATOR "RPM") +set(CPACK_PACKAGE_NAME "biqt") +set(CPACK_PACKAGE_VERSION_MAJOR 0) +set(CPACK_PACKAGE_VERSION_MINOR 1) +set(CPACK_PACKAGE_VERSION_PATCH 0) +set(CPACK_PACKAGE_VERSION 0.1) +set(CPACK_PACKAGE_RELEASE 1) +set(CPACK_PACKAGE_CONTACT "MITRE Corporation") +set(CPACK_PACKAGE_VENDOR "MITRE Corporation") +set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}.${CMAKE_SYSTEM_PROCESSOR}") +set(CPACK_RPM_PACKAGE_PROVIDES "jsoncpp == 1.8.3") +include(CPack) + +if(WITH_JAVA) + # Java bindings have been requested. + find_package(JNI REQUIRED) + add_definitions(-DBIQT_JAVA_SUPPORT) + + # Add Java-related includes and C/C++ source files. + include_directories(java/src/c ${JNI_INCLUDE_DIRS}) + set(JAVA_LIBRARY_FILES java/src/c/jnihelper.c + java/src/c/java_provider.cpp) + + # Add the Java maven project which builds the BIQT jar file. + add_subdirectory(java/src/c java/src/main/resources) +else() + remove_definitions(-DBIQT_JAVA_SUPPORT) + unset(JAVA_LIBRARY_FILES) +endif() + +# BUILD JSONCPP DEPENDENCY #################################################### + +add_subdirectory(cxx/jsoncpp) + +# BUILD THE BIQT LIBRARY FILE ################################################# +set(LIBRARY_FILES cxx/BIQT.cpp) +add_library(biqtapi SHARED ${LIBRARY_FILES} ${JAVA_LIBRARY_FILES}) + +# BUILD THE BIQT COMMAND LINE EXECUTABLE ###################################### + +set(SOURCE_FILES cxx/BIQT-cli.cpp) +add_executable(biqt ${SOURCE_FILES}) + +# BUILD JAVA BINDINGS (IF REQUESTED) ########################################## + +if(WITH_JAVA) + + # Create the resources directory if it doesn't exist. + FILE(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/java/src/main/resources/) + + # Locate the maven executable. + find_program(MAVEN NAMES mvn mvnw) + + if(NOT MAVEN) + message(FATAL_ERROR "Failed to find the Maven executable named mvn or mvnw. Please add it to the PATH or specify its location in CMAKE_PREFIX_PATH.") + endif() + + add_custom_command( + OUTPUT "${CMAKE_BINARY_DIR}/biqt-${BIQT_VERSION}.jar" + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_SOURCE_DIR}/java/src/main/resources/ COMMENT "Copying library files to Java resources..." + COMMAND ${MAVEN} -f ${CMAKE_SOURCE_DIR}/java/pom.xml -DskipTests -Dbiqt.version=${BIQT_VERSION} -Doutput.directory=${CMAKE_BINARY_DIR} package COMMENT "Running maven..." + ) + + add_custom_target(biqt_java_jar ALL + DEPENDS "${CMAKE_BINARY_DIR}/biqt-${BIQT_VERSION}.jar" + ) +endif() + +target_link_libraries(biqtapi ${CMAKE_DL_LIBS} jsoncpp_lib ${JAVA_JVM_LIBRARY}) +target_link_libraries(biqt biqtapi ${CMAKE_DL_LIBS} jsoncpp_lib) + +# INSTALLATION ################################################################ + +file(GLOB BIQT_INCLUDES "cxx/*.h") + +if(WIN32) + file(TO_CMAKE_PATH ${CMAKE_INSTALL_PREFIX} CMAKE_INSTALL_PREFIX_WINDOWS) + file(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX} CMAKE_INSTALL_PREFIX_NATIVE) + string(REPLACE "\\" "\\\\" CMAKE_INSTALL_PREFIX_NATIVE_ESCAPED ${CMAKE_INSTALL_PREFIX_NATIVE}) + + # On Windows, most content is installed directly into the install prefix. + install(TARGETS biqt biqtapi + ARCHIVE DESTINATION lib + LIBRARY DESTINATION bin + RUNTIME DESTINATION bin + ) + + install(CODE "FILE(MAKE_DIRECTORY \"${CMAKE_INSTALL_PREFIX_WINDOWS}/providers\")") + if(WITH_JAVA) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/biqt-${BIQT_VERSION}.jar" DESTINATION ".") + endif() + install(FILES setup_provider.py DESTINATION "./scripts") + install(DIRECTORY templates DESTINATION "./scripts") + install(FILES ${BIQT_INCLUDES} DESTINATION "./include") + + # Try to set BIQT_HOME and PATH. If this fails, rely on the output messages. + install(CODE "message(\"Remember that you must set or update the BIQT_HOME and PATH system environment variables.\")") + install(CODE "message(\"You may execute `SET \\\"BIQT_HOME=${CMAKE_INSTALL_PREFIX_NATIVE_ESCAPED}\\\"` to define BIQT_HOME temporarily, but it will not be saved for future use.\")") + install(CODE "message(\"You may execute `SET PATH=%JAVA_HOME%\\\\bin\\\\server;%BIQT_HOME%\\\\bin;%PATH%` to update PATH temporarily, but it will not be saved for future use.\")") +else() + # On Linux, files are installed to different locations. + # * Providers install to ${CMAKE_INSTALL_PREFIX}/share/biqt/providers. + # * BIQT Java JAR installs to ${CMAKE_INSTALL_PREFIX}/share/biqt. + # * Scripts install to ${CMAKE_INSTALL_PREFIX}/share/biqt/scripts. + install(TARGETS biqt biqtapi + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/biqt.sh "export BIQT_HOME=\"${CMAKE_INSTALL_PREFIX}/share/biqt\";\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/biqt.sh "export PATH=$PATH:\"${CMAKE_INSTALL_PREFIX}/bin\";\n") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/biqt.sh "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:\"${CMAKE_INSTALL_PREFIX}/lib\":\"${CMAKE_INSTALL_PREFIX}/lib64\";\n") + install(CODE "FILE(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/share/biqt/providers)") + + install(FILES setup_provider.py DESTINATION "./share/biqt/scripts") + install(DIRECTORY templates DESTINATION "./share/biqt/scripts") + install(FILES ${BIQT_INCLUDES} DESTINATION "./include") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/biqt.sh" DESTINATION "./share/biqt") + if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR NOT ${SKIP_PROFILE}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/biqt.sh" DESTINATION "/etc/profile.d" OPTIONAL) + MESSAGE("You may need to log out or run `source /etc/profile.d/biqt.sh` before running BIQT.") + else() + MESSAGE("You should add `source ${CMAKE_INSTALL_PREFIX}/share/biqt/biqt.sh` to your ~/.bashrc file.") + endif() + if(WITH_JAVA) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/biqt-${BIQT_VERSION}.jar" DESTINATION "./share/biqt/") + endif() +endif() diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..724527a --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,96 @@ +# Linux (CentOS Linux 7.4) + +## Prerequisites + +This guide targets CentOS Linux 7.4. + +This provider relies on OpenCV and other core development tools including gcc. These dependencies can be installed from +the [Extra Packages for Enterprise Linux (EPEL)](https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F) +repository using the following commands: + +```bash +sudo yum groupinstall "Development Tools" +sudo yum install -y cmake3 maven +``` + +## Building and Installing + +The following commands clone the BIQT source code, build the framework, +and install it to the default location `/usr/local/`. Note that installation +requires superuser privileges. + +```bash +git clone git@github.com:mitre/biqt +cd biqt +mkdir build +cd build +cmake3 -DCMAKE_BUILD_TYPE=Release .. +make -j4 +sudo make install +``` + +Remember to open a new console window or explicitly call `source /etc/profile.d/biqt` before attempting +to start BIQT! + +## Running BIQT + +```bash +$> biqt --version +BIQT v0.1 +``` + +# Windows 10 + +## Prerequisites + +This guide targets Microsoft Windows 10. + +The following tools are required to build BIQT from source. When installing CMake and Git, +please select the option to add the executables to the system's `PATH` environment variable. + * [CMake 3.9+](https://cmake.org/files/v3.9/cmake-3.9.2-win64-x64.msi) + * [Git 2.16+](https://git-scm.com/) + * [Microsoft Visual Studio Community Edition 2013](https://www.visualstudio.com/vs/older-downloads/) (Registration required.) + +The following software is required to build the Java bindings for BIQT. + * [Apache Maven 3.5.2](https://maven.apache.org/download.cgi) + * [Java SE JDK 9](http://www.oracle.com/technetwork/java/javase/downloads/index.html) + +After installing Apache Maven and a Java JDK, set the following environment variables according to the example below. Note that +these examples may need to be changed depending on the software versions you install and where you install them. + * Set `JAVA_HOME` to `C:\Program Files\Java\jdk-9.0.4`. + * Update `PATH` to include `C:\apache-maven-3.5.2\bin` and `C:\Program Files\Java\jdk-9.0.4\bin\server`. + +## Building and Installing + +As an administrator, execute the following commands from the VS2013 x64 Cross Tools Command Prompt. By default, a shortcut to +this prompt can be found by browsing to `C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts`. Right-click +on the shortcut and select 'Run as administrator' from the popup menu. + +**Note:** Using the VS2012 x64 Cross Tools Command Prompt Start Menu shortcut will not work! + +By default, CMake will attempt to build the BIQT Java bindings. Java bindings can be disabled by adding +`-DWITH_JAVA=OFF` to the `cmake` command. + +``` +git clone git@github.com:mitre/biqt biqt +cd biqt +mkdir build +cmake -G "NMake Makefiles" -DBUILD_STATIC_LIBS=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release .. +nmake +nmake install +``` + +By default, BIQT will be installed to `C:\Program Files\biqt`. During installation, you will be reminded to set +the `BIQT_HOME` and `PATH` environment variables as follows: + * Set `BIQT_HOME` to `C:\Program Files\biqt`. + * Update `PATH` to include `C:\Program Files\biqt\bin`. + +## Verifying installation. + +After installation, you can invoke the BIQT CLI from any command prompt. If you encounter any errors, +please verify that `JAVA_HOME` and the `PATH` variables are assigned correctly. + +``` +$> biqt --version +BIQT v0.1 +``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..48e887f --- /dev/null +++ b/LICENSE @@ -0,0 +1,209 @@ +NOTICE + +This software (or technical data) was produced for the U. S. Government under contract, and is subject to the Rights in Data-General Clause 52.227-14, Alt. IV (DEC 2007) + +(C) 2019 The MITRE Corporation. All Rights Reserved. + +--- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 The MITRE Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7377d37 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +> NOTICE +> +> This software (or technical data) was produced for the U. S. Government under contract, and is subject to the Rights in Data-General Clause 52.227-14, Alt. IV (DEC 2007) +> +> (C) 2019 The MITRE Corporation. All Rights Reserved. +> Approved for Public Release; Distribution Unlimited. Public Release Case Number 18-0812. + +### Overview + +The Biometric Image Quality Toolkit (BIQT) is an extensible framework for +evaluating the quality of biometric images. It exposes a vendor-agnostic +interface through which new modalities and algorithms can be integrated into the +framework, and it also exposes a high-level Quality API which can be used to +integrate the framework into larger systems. + +![The BIQT Architecture](doc/biqt.png) + +### Installation + +The framework targets Windows 10 and CentOS Linux 7.4. + +Build and install instructions for CentOS Linux 7.4 and Windows 10 can be found in [INSTALL.md](INSTALL.md). + +### Integrating Providers + +The BIQT Framework can easily be extended to integrate additional quality libraries. In general, providers +must conform to the following requirements: + * Providers must include a `descriptor.json` file so that metadata about the provider can be communicated to users. + * Providers must be installed to `$BIQT_HOME/providers` (Linux) or `%BIQT_HOME%/providers` (Windows). + * The name of the provider directory, the provider library name, and the name given in a the provider's descriptor must match. + +### Setting Up a New Provider + +The `setup_provider.py` python script generates a directory structure with template files which +serve as the basis for a new provider. The following example demonstrates how to generate a +new provider named `MyNewProvider`. + +**CentOS Linux 7.4** +``` +python $BIQT_HOME/scripts/setup_provider.py MyNewProvider +``` + +**Windows 10** +``` +python %BIQT_HOME%/scripts/setup_provider.py MyNewProvider +``` + +In the above example, the script creates a directory named `MyNewProvider` in the current directory and populates it with a +minimal descriptor, header file, code file, and CMakeLists.txt. TODO elements in each of these files indicate areas +which must be addressed. + +Once implemented, providers can be built and installed into the framework using the following commands. Note that the BIQT +framework must already be installed and the BIQT_HOME environment variable must be set. + + +**CentOS Linux 7.4** + +```bash +cd ~/MyProvider +mkdir build +cd build +cmake3 -DCMAKE_BUILD_TYPE=Release .. +make +make install +``` + +**Windows 10** + +``` +cd C:\Users\user\MyProvider +mkdir build +cd build +cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release .. +nmake +nmake install +``` + +### Related Resources + +Reference image quality libraries for face and iris images are available on GitHub. + * [BIQTFace](https://github.com/mitre/biqt-face) + * [BIQTIris](https://github.com/mitre/biqt-iris) diff --git a/cxx/BIQT-cli.cpp b/cxx/BIQT-cli.cpp new file mode 100644 index 0000000..03f4992 --- /dev/null +++ b/cxx/BIQT-cli.cpp @@ -0,0 +1,423 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#include +#include +#include + +#include "BIQT.h" + +#ifndef _MSC_VER /* Check for microsoft compiler */ +#include +#include +#else +#include "windows/getopt.h" +#include "windows/libgen.h" +#define setenv(name, value, opt) _putenv_s(name, value) +#endif + +void usage() +{ + std::cout << "SYNOPSIS\n" + " biqt [OPTIONS | COMMAND file]\n\n" + "OPTIONS\n" + " --help\n" + " Prints this usage information.\n\n" + " -P MODALITY | --providers[=MODALITY]\n" + " Lists the Provider plugins known to this BIQT " + "installation. If `MODALITY` is provided, only Providers " + "matching that type are returned.\n\n" + " -V|--version\n" + " Prints the version information associated with BIQT and " + "the CLI. For simplicity, assume that the CLI and the BIQT " + "framework are always released together as a single " + "package.\n\n" + "COMMANDS\n" + " -m MODALITY|--modality=MODALITY\n" + " Evaluates the given file using all of the providers " + "associated with the given modality.\n\n" + " -p PROVIDER|--provider=PROVIDER\n" + " Evaluates the given file using a specific provider.\n\n" + "INPUT BEHAVIORS\n" + " -l|--file-list\n" + " Indicates that the file path contains a " + "newline-separated list of input file paths (relative the " + "working directory). If this is not provided, it is assumed " + "that file should be parsed as-is.\n" + "OUTPUT BEHAVIORS\n" + " -f (json|text)|--output-format=(json|text)\n" + " Controls how output is returned to the user. By default, " + "text is used.\n" + << std::endl; +} + +void write_text(std::ostream &outputStream, const std::string &imageName, + const Provider::EvaluationResult &result) +{ + // Write header + std::string delim = ","; + outputStream << "Provider" << delim << "Image" << delim << "Detection" + << delim << "AttributeType" << delim << "Key" << delim + << "Value" << std::endl; + + // Loop through every detection + int d = 1; + for (const auto &qualityResult : result.qualityResult) { + // Metric map + for (const auto &metric : qualityResult.metrics) { + outputStream << result.provider << delim << imageName << delim << d + << delim << "Metric" << delim << metric.first << delim + << metric.second << std::endl; + } + // Feature map + for (const auto &feature : qualityResult.features) { + outputStream << result.provider << delim << imageName << delim << d + << delim << "Feature" << delim << feature.first + << delim << feature.second << std::endl; + } + d = d + 1; + } +} + +void write_text2(std::ostream &outputStream, const std::string &imageName, + const Provider::EvaluationResult &result) +{ + std::string delim = ","; + // Loop through every detection + int d = 1; + for (const auto &qualityResult : result.qualityResult) { + // Metric map + for (const auto &metric : qualityResult.metrics) { + outputStream << result.provider << delim << imageName << delim << d + << delim << "Metric" << delim << metric.first << delim + << metric.second << std::endl; + } + // Feature map + for (const auto &feature : qualityResult.features) { + outputStream << result.provider << delim << imageName << delim << d + << delim << "Feature" << delim << feature.first + << delim << feature.second << std::endl; + } + d = d + 1; + } +} + +void to_text(const std::string &imageName, + const Provider::EvaluationResult &result, + const std::string &outputPath) +{ + // Create the file if it does not exist + if (outputPath != "-") { + std::ofstream outputStream(outputPath, std::ofstream::app); + write_text(outputStream, imageName, result); + outputStream.close(); + } + else { + write_text(std::cout, imageName, result); + } +} + +void to_text2(const std::string &imageName, + const std::map &results, + const std::string &outputPath) +{ + std::string delim = ","; + // Create the file if it does not exist + if (outputPath != "-") { + std::ofstream outputStream(outputPath, std::ofstream::app); + outputStream << "Provider" << delim << "Image" << delim << "Detection" + << delim << "AttributeType" << delim << "Key" << delim + << "Value" << std::endl; + for (const auto &kv : results) { + write_text2(outputStream, imageName, kv.second); + } + outputStream.close(); + } + else { + std::cout << "Provider" << delim << "Image" << delim << "Detection" + << delim << "AttributeType" << delim << "Key" << delim + << "Value" << std::endl; + for (const auto &kv : results) { + write_text2(std::cout, imageName, kv.second); + } + } +} + +int to_json(const std::string &imageName, + const Provider::EvaluationResult &result, + const std::string &outputPath) +{ + Json::Value jsonResult; + Json::Value vec(Json::arrayValue); + + // Read from module_jsonResult to Json object jsonResult + for (const auto &qualityResult : result.qualityResult) { + Json::Value dResult; + + for (const auto &metric : qualityResult.metrics) { + dResult["metrics"][metric.first] = metric.second; + } + + for (const auto &feature : qualityResult.features) { + dResult["features"][feature.first] = feature.second; + } + + vec.append(std::move(dResult)); + } + + jsonResult[imageName][result.provider] = std::move(vec); + + // Write Json object to file + if (outputPath != "-") { + std::ofstream outputStream(outputPath, std::ofstream::app); + outputStream << jsonResult << std::endl; + outputStream.close(); + } + else { + std::cout << jsonResult << std::endl; + } + return 0; +} + +int to_json2(const std::string &imageName, + const std::map &results, + const std::string &outputPath) +{ + Json::Value jsonResult; + for (const auto &kv : results) { + Provider::EvaluationResult result = kv.second; + Json::Value vec(Json::arrayValue); + + // Read from module_jsonResult to Json object jsonResult + for (const auto &qualityResult : result.qualityResult) { + Json::Value dResult; + + for (const auto &metric : qualityResult.metrics) { + dResult["metrics"][metric.first] = metric.second; + } + + for (const auto &feature : qualityResult.features) { + dResult["features"][feature.first] = feature.second; + } + + vec.append(std::move(dResult)); + } + + jsonResult[imageName][result.provider] = std::move(vec); + } + + // Write Json object to file + if (outputPath != "-") { + std::ofstream outputStream(outputPath, std::ofstream::app); + outputStream << jsonResult << std::endl; + outputStream.close(); + } + else { + std::cout << jsonResult << std::endl; + } + return 0; +} + +int run_provider(BIQT &app, bool modality, const std::string &inputFile, + const std::string &outputFile, const std::string &mod_arg, + const std::string &output_type) +{ + if (modality) { + // Iterate through map + std::map results = + app.runModality(mod_arg, inputFile); + + for (const auto &kv : results) { + std::string provider = kv.first; + Provider::EvaluationResult result = kv.second; + + // Evaluate individual result + if (result.errorCode) { + return result.errorCode; + } + } + + if (results.size()) { + if (output_type == "json") + to_json2(inputFile, results, outputFile); + else + to_text2(inputFile, results, outputFile); + } + } + + else { + Provider::EvaluationResult result = app.runProvider(mod_arg, inputFile); + if (result.errorCode) { + return result.errorCode; + } + if (output_type == "json") + to_json(inputFile, result, outputFile); + else + to_text(inputFile, result, outputFile); + } + + return 0; +} + +int main(int argc, char **argv) +{ + std::string output_type = "text"; + std::string outputFile = "-"; + std::string inputFile; + std::string mod_arg; + bool found_matching_providers = false; + bool modality_flag = false; + bool provider_flag = false; + bool file_list_flag = false; + + BIQT app; + + while (true) { + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"providers", optional_argument, 0, 'P'}, + {"modality", required_argument, 0, 'm'}, + {"provider", required_argument, 0, 'p'}, + {"output-format", required_argument, 0, 'f'}, + {"file-list", no_argument, 0, 'l'}, + {0, 0, 0, 0}}; + + int option_index = 0; + int c = getopt_long(argc, argv, "f:hlVP::m:p:", long_options, + &option_index); + + if (argc == 1) { + std::cout << "Please provide input arguments. Run 'biqt --help' to " + "see correct usage." + << std::endl; + exit(0); + } + + if (c == -1) + break; + + switch (c) { + case 0: { + break; + } + case 'h': { + usage(); + exit(0); + } + case 'V': { + std::cout << "BIQT v" << __BIQT_VERSION__ << std::endl; // TODO: + exit(0); + } + case 'f': { + output_type = optarg; + break; + } + case 'o': { + outputFile = optarg; + break; + } + case 'l': { + file_list_flag = true; + break; + } + case 'P': { + // Correct for optarg if space used + // https://linux.die.net/man/1/getopt + if (optarg == NULL && argv[optind] != NULL) { + optarg = argv[optind]; + } + + // Error for no installed providers + if (app.getProviders().empty()) { + std::cerr << "No provider libraries were found." << std::endl; + exit(0); + } + + // Error for no installed providers matching specified modality + for (const auto &p : app.getProviders()) { + if (!optarg || p->modality == optarg) { + found_matching_providers = true; + } + } + if (!found_matching_providers) { + std::cerr << "No provider libraries matching the provided modality were found." << std::endl; + exit(0); + } + + // Normal behavior, print results + if (!app.getProviders().empty()) { + std::cout << std::endl + << "Provider\tVersion\tModality\tDescription" + << std::endl; + for (const auto &p : app.getProviders()) { + if (!optarg || p->modality == optarg) { + std::cout << p->name << "\t" << p->version << "\t" + << p->modality << "\t" << p->description << "\t" + << std::endl; + } + } + std::cout << std::endl; + } + // No providers found! + else { + std::cerr << "No providers found in '" << app.modulePath << "'!" + << std::endl; + } + exit(0); + } + case 'm': { + if (optind >= argc) { + std::cout << "Please input a valid modality, followed by your " + "desired input image/directory." + << std::endl; + break; + } + mod_arg = optarg; + modality_flag = true; + break; + } + case 'p': { + if (optind >= argc) { + std::cout << "Please input a valid provider, followed by your " + "desired input image/directory." + << std::endl; + break; + } + mod_arg = optarg; + provider_flag = true; + break; + } + } + } + + inputFile = argv[argc - 1]; + + if (!modality_flag && !provider_flag) { + std::cout << "Invalid arguments detected. Run 'biqt --help' to see " + "correct usage." + << std::endl; + return -1; + } + + if (file_list_flag) { + std::ifstream fileList(inputFile); + std::string imageFile; + while (getline(fileList, imageFile)) { + run_provider(app, modality_flag, imageFile, outputFile, mod_arg, + output_type); + } + } + else { + run_provider(app, modality_flag, inputFile, outputFile, mod_arg, + output_type); + } + return 0; +} diff --git a/cxx/BIQT.cpp b/cxx/BIQT.cpp new file mode 100644 index 0000000..116e21e --- /dev/null +++ b/cxx/BIQT.cpp @@ -0,0 +1,362 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include "windows/dirent.h" +#include "windows/libgen.h" +#include +#define dlopen(name, flag) LoadLibraryEx(name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) +#define dlhandle(name) GetModuleHandle(name) +#define dlsym(handle, symbol) GetProcAddress(handle, symbol) +#define dlclose(name) FreeLibrary(name) +#define dlerror() GetLastError() +#define setenv(key, val, int) _putenv_s(key, val) +#define PATHSEP ";" +#define DIRSEP "\\" +#else +#define dlhandle(name) dlopen(name, RTLD_NOLOAD) +#include +#include +#include +#define PATHSEP ":" +#define DIRSEP "/" +#endif + +#include "BIQT.h" +#include "ProviderInterface.h" +#ifdef BIQT_JAVA_SUPPORT +#include "java_provider.h" +#endif + +ProviderInfo::ProviderInfo(std::string modulePath, std::string lib) +{ + Json::Value desc; + this->soPath = modulePath + DIRSEP + "providers" DIRSEP + lib + DIRSEP + +#if defined(_WIN32) + lib + ".dll"; +#elif defined(__APPLE__) + "lib" + lib + ".dylib"; +#else + "lib" + lib + ".so"; +#endif + if (BIQT::fileExists(this->soPath)) { + this->handle = dlopen(this->soPath.c_str(), RTLD_NOW); + if (!this->handle) { + throw std::runtime_error( + "Provider Read error: Unable to load the shared object"); + } + } + + std::string desc_path = + modulePath + "/providers/" + lib + "/descriptor.json"; + std::ifstream desc_file(desc_path.c_str(), std::ifstream::binary); + desc_file >> desc; + + this->name = std::string((desc["name"]).asString()); + this->version = std::string((desc["version"]).asString()); + this->description = std::string((desc["description"]).asString()); + this->modality = std::string((desc["modality"]).asString()); + this->sourceLanguage = std::string((desc["sourceLanguage"]).asString()); +#ifdef BIQT_JAVA_SUPPORT + if (this->sourceLanguage == "java") { + this->className = std::string((desc["className"]).asString()); + this->classPath = this->getClassPath(modulePath + "/providers/" + lib); + } else { +#endif + this->eval = (evaluator)dlsym(this->handle, "provider_eval"); + if (!this->eval) { + throw std::runtime_error("Provider API Error:" + "Unable to locate the provider_eval function"); + } +#ifdef BIQT_JAVA_SUPPORT + } +#endif +} + +#ifdef BIQT_JAVA_SUPPORT +std::string ProviderInfo::getClassPath(std::string providerPath) +{ + struct dirent *module; + std::set paths; + std::string classPath = ""; + int extension; + DIR *dir; + std::string biqt_home = getenv("BIQT_HOME"); + + if (!BIQT::fileExists(providerPath)) { + return ""; + } + /* find the BIQT jar files */ + dir = opendir(biqt_home.c_str()); + while ((module = readdir(dir)) != nullptr) { + extension = strlen(module->d_name) - 4; + if (!strcmp(module->d_name + extension, ".jar")) { + paths.insert(biqt_home + DIRSEP + module->d_name); + } + } + closedir(dir); + /* find the jar files for the provider */ + dir = opendir(providerPath.c_str()); + while ((module = readdir(dir)) != nullptr) { + extension = strlen(module->d_name) - 4; + if (!strcmp(module->d_name + extension, ".jar")) { + paths.insert(providerPath + DIRSEP + module->d_name); + } + } + closedir(dir); + for (const auto &path : paths) { + if (classPath.length()) { + classPath += PATHSEP; + } + classPath += path; + } + return classPath; +} +#endif + +ProviderInfo::~ProviderInfo() +{ + this->eval = nullptr; + if (this->handle) { + dlclose(this->handle); + } +} + +const char *ProviderInfo::evaluate(std::string filename) const +{ +#ifdef BIQT_JAVA_SUPPORT + const char *returnvalue; + if (this->sourceLanguage == "java") { + returnvalue = java_provider_eval(filename.c_str(), this->name.c_str(), + this->className.c_str(), this->classPath.c_str()); + if (!returnvalue) { + std::cerr << "An error occurred indicating a problem with the" + " selected provider: " << this->name << ". Please " + "check with the provider vendor for updates." + << std::endl; + } + return returnvalue; + } + else +#endif + if (this->eval) { + return this->eval(filename.c_str()); + } + else { + std::cerr << "ERROR: Missing provider evaluator for " << this->name + << "." << std::endl; + return nullptr; + } +} + +BIQT::BIQT() +{ + /* Check default installation paths */ + char *biqt_home = getenv("BIQT_HOME"); + + /* if BIQT_HOME is already set, look for the providers directory */ + if ((biqt_home)) { + this->modulePath = std::string(biqt_home); + if (!this->fileExists(std::string(biqt_home) + "/providers")) { + std::cerr << "ERROR: BIQT_HOME set to '" << biqt_home + << "', but no providers directory found!" << std::endl; + } + } + else { + /* BIQT_HOME is not set or providers directory missing, + * try the current directory */ + std::cerr << "WARNING: BIQT_HOME is not set; using the current " + "directory instead. This may not be what you want!" << std::endl; + setenv("BIQT_HOME", ".", 1); + this->modulePath = std::string("."); + } + this->getProviders(); +} + +BIQT::~BIQT() +{ + for (const auto p : this->providers) { + delete p; + } +} + +/** + * Returns the BIQT version number + * + * @return The current version number. + */ +std::string BIQT::version() const { return __BIQT_VERSION__; } + +/** + * Determines whether a file or directory exists and is readable. + * + * @param filename The path to the desired file or directory. + * @return true if it exists and is readable, false otherwise. + */ +bool BIQT::fileExists(const std::string &filename) +{ + struct stat info; + if (stat(filename.c_str(), &info)) + return false; +#ifdef _WIN32 + return (bool)(info.st_mode); +#else + return (bool)(info.st_mode & (S_IXOTH | S_IROTH)); +#endif +} + +std::set BIQT::providerLibs() +{ + std::set returnValue; + std::string provider_path = this->modulePath + "/providers"; + struct dirent *pro; + + DIR *dir = opendir(provider_path.c_str()); + if (dir) { + while ((pro = readdir(dir)) != nullptr) { + if (pro->d_name[0] != '.') { + returnValue.insert(std::string(pro->d_name)); + } + } + closedir(dir); + } + return returnValue; +} + +/** + * Creates a vector of application providers and stores it in the object. + * + * @return The newly created vector. + */ +std::vector BIQT::getProviders() +{ + std::set libs; + std::string providerPath; + Json::Value desc; + + if (!this->providers.empty()) { + return this->providers; + } + + libs = this->providerLibs(); + for (const auto &lib : libs) { + try { + ProviderInfo *p = new ProviderInfo(this->modulePath, lib); + this->providers.push_back(p); + } + catch (std::runtime_error e) { + std::cerr << e.what(); + } + } + return this->providers; +} + +/** + * Gets a single provider by name + * + * @param pname The name of the provider + * @return The requested provider, or NULL if no such provider exists. + */ +const ProviderInfo *BIQT::getProvider(const std::string &pname) +{ + for (auto &provider : this->providers) { + if (provider->name == pname) + return provider; + } + return nullptr; +} + +/** + * Runs a particular provider with the given arguments. + * + * @param pName The name of the provider to run. + * + * @return The return status of the provider. + */ +Provider::EvaluationResult BIQT::runProvider(const std::string &pName, + const std::string &filePath) +{ + Provider::EvaluationResult result; + const ProviderInfo *p = getProvider(pName); + if (p) { + result = this->runProvider(p, filePath); + } + else { + std::cerr << "Provider '" << pName << "' not found." << std::endl; + } + return result; +} + +Provider::EvaluationResult BIQT::runProvider(const ProviderInfo *p, + const std::string &filePath) +{ + Provider::EvaluationResult result = {0}; + try { + // const char* cFilePath = filePath.c_str(); + std::string result_str = p->evaluate(filePath); + result = Provider::deserializeResult(result_str.c_str()); + result.provider = p->name; + } + catch (...) { + std::cerr << "Abnormal termination, unhandled error type from provider." + << std::endl; + if (result.errorCode == 0) + result.errorCode = -1; + } + + if (result.errorCode != 0) { + std::cerr << "There was an error evaluating " << filePath + << " for provider " << p->name << ". "; + std::cerr << "Error code: " << result.errorCode; + std::cerr << std::endl; + } + return result; +} + +/** + * Runs a provider based on modality. + * + * @param modality The modality of the provider to run. + * + * @return The return status of the provider. + */ +std::map +BIQT::runModality(const std::string &modality, const std::string &filePath) +{ + int providerCount = 0; + std::map results; + Provider::EvaluationResult result; + for (const auto provider : getProviders()) { + if (provider->modality == modality) { + providerCount++; + result = runProvider(provider, filePath); + if (!result.errorCode) { + results.insert( + std::pair( + provider->name, result)); + } + } + } + if (!providerCount) { + std::cerr << "No available providers found with the modality '" + << modality << "'." << std::endl; + } + return results; +} diff --git a/cxx/BIQT.h b/cxx/BIQT.h new file mode 100644 index 0000000..6e8a256 --- /dev/null +++ b/cxx/BIQT.h @@ -0,0 +1,80 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#ifndef APPLICATION_H +#define APPLICATION_H + +#include +#include +#include +#include +#include + +#include "ProviderInterface.h" + +#define __BIQT_VERSION__ BIQT_VERSION + +#ifdef _WIN32 +#include +#define LIB_HANDLE HINSTANCE +#else +#define LIB_HANDLE void * +#endif + +typedef char *(*evaluator)(const char *filePath); + +class DLL_EXPORT ProviderInfo { + public: + ProviderInfo(std::string modulePath, std::string lib); + ~ProviderInfo(); + const char *evaluate(std::string filename) const; + std::string name; + std::string version; + std::string description; + std::string modality; + std::string sourceLanguage; + std::string className; + evaluator eval; + + private: +#ifdef BIQT_JAVA_SUPPORT + std::string getClassPath(std::string modulePath); + std::string classPath; +#endif + std::string soPath; + LIB_HANDLE handle = nullptr; +}; + +class DLL_EXPORT BIQT { + + public: + BIQT(); + ~BIQT(); + + std::string version() const; + std::string modulePath; + + std::vector getProviders(); + Provider::EvaluationResult runProvider(const std::string &pName, + const std::string &filePath); + Provider::EvaluationResult runProvider(const ProviderInfo *p, + const std::string &filePath); + std::map + runModality(const std::string &modality, const std::string &filePath); + static bool fileExists(const std::string &filename); + + private: + + const ProviderInfo *getProvider(const std::string &p); + std::vector providers; + std::set providerLibs(); +}; + +#endif diff --git a/cxx/ProviderInterface.h b/cxx/ProviderInterface.h new file mode 100644 index 0000000..01c95de --- /dev/null +++ b/cxx/ProviderInterface.h @@ -0,0 +1,249 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#ifndef PROVIDERINTERFACE_H +#define PROVIDERINTERFACE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#define DLL_EXPORT __declspec(dllexport) +#else +#define DLL_EXPORT +#endif + +/** + * A class for implementing a provider. + */ +class Provider { + + public: + struct QualityResult { + std::map + metrics; /* A map containing the quality metrics */ + std::map features; /* A map containing detection + features (EyePosition, + FaceHeight, etc.) */ + }; + + struct EvaluationResult { + int errorCode; /* Non-zero values indicate errors */ + std::string provider; /* The provider name */ + std::string + message; /* Used to bubble up messages from the provider to the + application */ + std::vector + qualityResult; /* A vector of QualityResults, in the case of + multiple detections. */ + }; + + virtual ~Provider() = default; + + // Provider metadata + /** + * Returns the name of this provider. + * + * @return the name of the provider. + */ + virtual std::string name() { return DescriptorObject["name"].asString(); } + + /** + * Returns the version number of this provider. + * + * @return the provider version number. + */ + virtual std::string version() + { + return DescriptorObject["version"].asString(); + } + + /** + * Returns a description of this provider. + * + * @return the provider description. + */ + virtual std::string description() + { + return DescriptorObject["description"].asString(); + } + + /** + * Returns the modality of this provider. + * + * @return the provider modality + */ + virtual std::string modality() + { + return DescriptorObject["modality"].asString(); + } + + /** + * Returns a vector of provider attributes. + * + * @return the provider attributes. + */ + virtual std::vector attributes() + { + Json::Value attrs = DescriptorObject["attributes"]; + std::vector attr_list; + for (const auto &attr : attrs) { + attr_list.push_back(attr["name"].asString()); + } + return attr_list; + } + + /** + * + * @param attribute The description of a particular attribute of the + * provider + * + * @return the attribute description. + */ + virtual std::string describeAttribute(const std::string &attribute) + { + Json::Value attrs = DescriptorObject["attributes"]; + + for (const auto &attr : attrs) { + if (attr["name"].asString() == attribute) { + return attr["description"].asString(); + } + } + + return "This module does not support the specified attribute."; + } + + /* Provider functions */ + + /** + * Runs the provider to evaluate the given file. + * + * @param file The input file to evaluate. + * + * @return The result of the evaluation. + */ + virtual EvaluationResult evaluate(const std::string &file) = 0; + + /** + * Deserializes a JSON char array to populate an EvaluationResult struct + * + * @param result_str The JSON string + * + * @return The deserialized EvaluationResult + */ + static EvaluationResult deserializeResult(const char *result_str) + { + EvaluationResult result; + // String to JSON + Json::Value result_json; + Json::Reader reader; + bool parsingSuccessful = reader.parse(result_str, result_json); + if (!parsingSuccessful) { + std::cout << "Failed to parse" + << reader.getFormattedErrorMessages(); + } + + // JSON to Evaluation::Result + result.errorCode = result_json["errorCode"].asInt(); + result.provider = result_json["provider"].asString(); + result.message = result_json["message"].asString(); + + // Vector of QualityResults json + for (const auto &qualityResult : result_json["qualityResult"]) { + Provider::QualityResult quality_result; + for (const auto &metric : + qualityResult["metrics"].getMemberNames()) { + quality_result.metrics[metric] = + qualityResult["metrics"][metric].asFloat(); + } + for (const auto &feature : + qualityResult["features"].getMemberNames()) { + quality_result.features[feature] = + qualityResult["features"][feature].asFloat(); + } + + result.qualityResult.push_back(std::move(quality_result)); + } + return result; + } + + /** + * Serializes an EvaluationResult struct into a JSON char array. delete[] + * should be called on the return value to avoid memory leaks + * + * @param result_str The EvaluationResult struct + * + * @return The serialized JSON string + */ + static char *serializeResult(const Provider::EvaluationResult &result) + { + // Write result to JSON format + Json::Value result_json; + result_json["errorCode"] = result.errorCode; + result_json["provider"] = result.provider; + result_json["message"] = result.message; + + // Vector of QualityResults + Json::Value vec(Json::arrayValue); + for (const auto &qualityResult : result.qualityResult) { + Json::Value quality_result; + Json::Value metrics_map; + Json::Value features_map; + + for (const auto &metric : qualityResult.metrics) { + metrics_map[metric.first] = metric.second; + } + + for (const auto &feature : qualityResult.features) { + features_map[feature.first] = feature.second; + } + + quality_result["metrics"] = std::move(metrics_map); + quality_result["features"] = std::move(features_map); + vec.append(std::move(quality_result)); + } + result_json["qualityResult"] = std::move(vec); + + // Return as string + std::string result_str = result_json.toStyledString(); + char *result_cstr = new char[result_str.length() + 1]; + strncpy(result_cstr, result_str.c_str(), result_str.length() + 1); + return result_cstr; + } + + protected: + // Descriptor object + Json::Value DescriptorObject; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A single function to begin provider analysis. + * + * @param filePath The path to the input file. + * + * @return The return status of the provider. + */ +DLL_EXPORT const char *provider_eval(const char *filePath); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cxx/jsoncpp/.clang-format b/cxx/jsoncpp/.clang-format new file mode 100644 index 0000000..dd51247 --- /dev/null +++ b/cxx/jsoncpp/.clang-format @@ -0,0 +1,47 @@ +--- +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +ConstructorInitializerIndentWidth: 4 +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: false +AlwaysBreakBeforeMultilineStrings: false +BreakBeforeBinaryOperators: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BinPackParameters: false +ColumnLimit: 80 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +DerivePointerBinding: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 60 +PenaltyBreakString: 1000 +PenaltyBreakFirstLessLess: 120 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerBindsToType: true +SpacesBeforeTrailingComments: 1 +Cpp11BracedListStyle: false +Standard: Cpp03 +IndentWidth: 2 +TabWidth: 8 +UseTab: Never +BreakBeforeBraces: Attach +IndentFunctionDeclarationAfterType: false +SpacesInParentheses: false +SpacesInAngles: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpaceAfterControlStatementKeyword: true +SpaceBeforeAssignmentOperators: true +ContinuationIndentWidth: 4 +... + diff --git a/cxx/jsoncpp/.gitattributes b/cxx/jsoncpp/.gitattributes new file mode 100644 index 0000000..22d2b7a --- /dev/null +++ b/cxx/jsoncpp/.gitattributes @@ -0,0 +1,11 @@ +* text=auto +*.h text +*.cpp text +*.json text +*.in text +*.sh eol=lf +*.bat eol=crlf +*.vcproj eol=crlf +*.vcxproj eol=crlf +*.sln eol=crlf +devtools/agent_vm* eol=crlf diff --git a/cxx/jsoncpp/.gitignore b/cxx/jsoncpp/.gitignore new file mode 100644 index 0000000..7420697 --- /dev/null +++ b/cxx/jsoncpp/.gitignore @@ -0,0 +1,55 @@ +/build/ +/build-*/ +*.pyc +*.swp +*.actual +*.actual-rewrite +*.process-output +*.rewrite +/bin/ +/libs/ +/doc/doxyfile +/dist/ +#/version +#/include/json/version.h + +# MSVC project files: +*.sln +*.vcxproj +*.filters +*.user +*.sdf +*.opensdf +*.suo + +# MSVC build files: +*.lib +*.obj +*.tlog/ +*.pdb + +# CMake-generated files: +CMakeFiles/ +*.cmake +/pkg-config/jsoncpp.pc +jsoncpp_lib_static.dir/ + +# In case someone runs cmake in the root-dir: +/CMakeCache.txt +/Makefile +/include/Makefile +/src/Makefile +/src/jsontestrunner/Makefile +/src/jsontestrunner/jsontestrunner_exe +/src/lib_json/Makefile +/src/test_lib_json/Makefile +/src/test_lib_json/jsoncpp_test +*.a + +# eclipse project files +.project +.cproject +/.settings/ + +# DS_Store +.DS_Store diff --git a/cxx/jsoncpp/.travis.yml b/cxx/jsoncpp/.travis.yml new file mode 100644 index 0000000..c81095f --- /dev/null +++ b/cxx/jsoncpp/.travis.yml @@ -0,0 +1,55 @@ +# Build matrix / environment variable are explained on: +# http://about.travis-ci.org/docs/user/build-configuration/ +# This file can be validated on: +# http://lint.travis-ci.org/ +# See also +# http://stackoverflow.com/questions/22111549/travis-ci-with-clang-3-4-and-c11/30925448#30925448 +# to allow C++11, though we are not yet building with -std=c++11 + +install: +- if [[ $TRAVIS_OS_NAME == osx ]]; then + brew update; + brew install python3 ninja; + python3 -m venv venv; + source venv/bin/activate; + elif [[ $TRAVIS_OS_NAME == linux ]]; then + wget https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip; + unzip -q ninja-linux.zip -d build; + fi +- pip3 install meson +# /usr/bin/gcc is 4.6 always, but gcc-X.Y is available. +- if [[ $CXX = g++ ]]; then export CXX="g++-4.9" CC="gcc-4.9"; fi +# /usr/bin/clang has a conflict with gcc, so use clang-X.Y. +- if [[ $CXX = clang++ ]]; then export CXX="clang++-3.5" CC="clang-3.5"; fi +- echo ${PATH} +- ls /usr/local +- ls /usr/local/bin +- export PATH="${PWD}"/build:/usr/local/bin:/usr/bin:${PATH} +- echo ${CXX} +- ${CXX} --version +- which valgrind +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + packages: + - gcc-4.9 + - g++-4.9 + - clang-3.5 + - valgrind +os: + - linux +language: cpp +compiler: + - gcc + - clang +script: ./travis.sh +env: + matrix: + - LIB_TYPE=static BUILD_TYPE=release + - LIB_TYPE=shared BUILD_TYPE=debug +notifications: + email: false +dist: trusty +sudo: false diff --git a/cxx/jsoncpp/AUTHORS b/cxx/jsoncpp/AUTHORS new file mode 100644 index 0000000..5747e61 --- /dev/null +++ b/cxx/jsoncpp/AUTHORS @@ -0,0 +1,111 @@ +Baptiste Lepilleur + +Aaron Jacobs +Aaron Jacobs +Adam Boseley +Adam Boseley +Aleksandr Derbenev <13alexac@gmail.com> +Alexander Gazarov +Alexander V. Brezgin +Alexandr Brezgin +Alexey Kruchinin +Anton Indrawan +Baptiste Jonglez +Baptiste Lepilleur +Baruch Siach +Ben Boeckel +Benjamin Knecht +Bernd Kuhls +Billy Donahue +Braden McDorman +Brandon Myers +Brendan Drew +chason +Chris Gilling +Christopher Dawes +Christopher Dunn +Chuck Atkins +Cody P Schafer +Connor Manning +Cory Quammen +Cristóvão B da Cruz e Silva +Daniel Krügler +Dani-Hub +Dan Liu +datadiode +datadiode +David Seifert +David West +dawesc +Dmitry Marakasov +dominicpezzuto +Don Milham +drgler +ds283 +Egor Tensin +eightnoteight +Evince +filipjs +findblar +Florian Meier +Gaëtan Lehmann +Gaurav +Gergely Nagy +Gida Pataki +I3ck +Iñaki Baz Castillo +Jacco +Jean-Christophe Fillion-Robin +Jonas Platte +Jörg Krause +Keith Lea +Kevin Grant +Kirill V. Lyadvinsky +Kirill V. Lyadvinsky +Kobi Gurkan +Magnus Bjerke Vik +Malay Shah +Mara Kim +Marek Kotewicz +Mark Lakata +Mark Zeren +Martin Buck +Martyn Gigg +Mattes D +Matthias Loy +Merlyn Morgan-Graham +Michael Shields +Michał Górny +Mike Naberezny +mloy +Motti +nnkur +Omkar Wagh +paulo +pavel.pimenov +Paweł Bylica +Péricles Lopes Machado +Peter Spiess-Knafl +pffang +Rémi Verschelde +renu555 +Robert Dailey +Sam Clegg +selaselah +Sergiy80 +sergzub +Stefan Schweter +Steffen Kieß +Steven Hahn +Stuart Eichert +SuperManitu +Techwolf +Tengiz Sharafiev +Tomasz Maciejewski +Vicente Olivert Riera +xiaoyur347 +ycqiu <429148848@qq.com> +yiqiju +Yu Xiaolei + +Google Inc. diff --git a/cxx/jsoncpp/CMakeLists.txt b/cxx/jsoncpp/CMakeLists.txt new file mode 100644 index 0000000..0cfaf53 --- /dev/null +++ b/cxx/jsoncpp/CMakeLists.txt @@ -0,0 +1,159 @@ +# vim: et ts=4 sts=4 sw=4 tw=0 + +CMAKE_MINIMUM_REQUIRED(VERSION 3.1) +PROJECT(jsoncpp) +ENABLE_TESTING() + +OPTION(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) +OPTION(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) +OPTION(JSONCPP_WITH_WARNING_AS_ERROR "Force compilation to fail if a warning occurs" OFF) +OPTION(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C and ISO C++" ON) +OPTION(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON) +OPTION(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" OFF) +OPTION(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) +OPTION(BUILD_STATIC_LIBS "Build jsoncpp_lib static library." ON) + +# Ensures that CMAKE_BUILD_TYPE is visible in cmake-gui on Unix +IF(NOT WIN32) + IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Release CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage." + FORCE) + ENDIF() +ENDIF() + +# Enable runtime search path support for dynamic libraries on OSX +IF(APPLE) + SET(CMAKE_MACOSX_RPATH 1) +ENDIF() + +# Adhere to GNU filesystem layout conventions +INCLUDE(GNUInstallDirs) + +SET(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build") + +# Set variable named ${VAR_NAME} to value ${VALUE} +FUNCTION(set_using_dynamic_name VAR_NAME VALUE) + SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE) +ENDFUNCTION() + +# Extract major, minor, patch from version text +# Parse a version string "X.Y.Z" and outputs +# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH. +# If parse succeeds then ${OUPUT_PREFIX}_FOUND is TRUE. +MACRO(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX) + SET(VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9_]+)?") + IF( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) + STRING(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_]+)" VERSION_PARTS ${VERSION_TEXT}) + LIST(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR) + LIST(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR) + LIST(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH) + set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE ) + ELSE( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} ) + set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE ) + ENDIF() +ENDMACRO() + +# Read out version from "version" file +#FILE(STRINGS "version" JSONCPP_VERSION) +#SET( JSONCPP_VERSION_MAJOR X ) +#SET( JSONCPP_VERSION_MINOR Y ) +#SET( JSONCPP_VERSION_PATCH Z ) +SET( JSONCPP_VERSION 1.8.3 ) +jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION ) +#IF(NOT JSONCPP_VERSION_FOUND) +# MESSAGE(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z") +#ENDIF(NOT JSONCPP_VERSION_FOUND) +SET( JSONCPP_SOVERSION 19 ) +SET( JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL" ) + +MESSAGE(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}") +# File version.h is only regenerated on CMake configure step +CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/src/lib_json/version.h.in" + "${PROJECT_SOURCE_DIR}/include/json/version.h" + NEWLINE_STYLE UNIX ) +CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/version.in" + "${PROJECT_SOURCE_DIR}/version" + NEWLINE_STYLE UNIX ) + +MACRO(UseCompilationWarningAsError) + IF(MSVC) + # Only enabled in debug because some old versions of VS STL generate + # warnings when compiled in release configuration. + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ") + ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + IF(JSONCPP_WITH_STRICT_ISO) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors") + ENDIF() + ENDIF() +ENDMACRO() + +# Include our configuration header +INCLUDE_DIRECTORIES( ${jsoncpp_SOURCE_DIR}/include ) + +IF(MSVC) + # Only enabled in debug because some old versions of VS STL generate + # unreachable code warning when compiled in release configuration. + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ") +ENDIF() + +# Require C++11 support, prefer ISO C++ over GNU variants, +# as relying solely on ISO C++ is more portable. +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) +SET(CMAKE_CXX_EXTENSIONS OFF) + +IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # using regular Clang or AppleClang + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare") +ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # using GCC + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra") + # not yet ready for -Wsign-conversion + + IF(JSONCPP_WITH_STRICT_ISO) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") + ENDIF() + IF(JSONCPP_WITH_WARNING_AS_ERROR) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=conversion") + ENDIF() +ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + # using Intel compiler + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra -Werror=conversion") + + IF(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") + ENDIF() +ENDIF() + +FIND_PROGRAM(CCACHE_FOUND ccache) +IF(CCACHE_FOUND) + SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) +ENDIF(CCACHE_FOUND) + +IF(JSONCPP_WITH_WARNING_AS_ERROR) + UseCompilationWarningAsError() +ENDIF() + +IF(JSONCPP_WITH_PKGCONFIG_SUPPORT) + CONFIGURE_FILE( + "pkg-config/jsoncpp.pc.in" + "pkg-config/jsoncpp.pc" + @ONLY) + INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkg-config/jsoncpp.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +ENDIF() + +IF(JSONCPP_WITH_CMAKE_PACKAGE) + INSTALL(EXPORT jsoncpp + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp + FILE jsoncppConfig.cmake) +ENDIF() + +# Build the different applications +ADD_SUBDIRECTORY( src ) + +#install the includes +ADD_SUBDIRECTORY( include ) diff --git a/cxx/jsoncpp/LICENSE b/cxx/jsoncpp/LICENSE new file mode 100644 index 0000000..89280a6 --- /dev/null +++ b/cxx/jsoncpp/LICENSE @@ -0,0 +1,55 @@ +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. diff --git a/cxx/jsoncpp/README.md b/cxx/jsoncpp/README.md new file mode 100644 index 0000000..6c5cf07 --- /dev/null +++ b/cxx/jsoncpp/README.md @@ -0,0 +1,131 @@ +# JsonCpp + +[![badge](https://img.shields.io/badge/conan.io-jsoncpp%2F1.8.0-green.svg?logo=data:image/png;base64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAA1VBMVEUAAABhlctjlstkl8tlmMtlmMxlmcxmmcxnmsxpnMxpnM1qnc1sn85voM91oM11oc1xotB2oc56pNF6pNJ2ptJ8ptJ8ptN9ptN8p9N5qNJ9p9N9p9R8qtOBqdSAqtOAqtR%2BrNSCrNJ/rdWDrNWCsNWCsNaJs9eLs9iRvNuVvdyVv9yXwd2Zwt6axN6dxt%2Bfx%2BChyeGiyuGjyuCjyuGly%2BGlzOKmzOGozuKoz%2BKqz%2BOq0OOv1OWw1OWw1eWx1eWy1uay1%2Baz1%2Baz1%2Bez2Oe02Oe12ee22ujUGwH3AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBQkREyOxFIh/AAAAiklEQVQI12NgAAMbOwY4sLZ2NtQ1coVKWNvoc/Eq8XDr2wB5Ig62ekza9vaOqpK2TpoMzOxaFtwqZua2Bm4makIM7OzMAjoaCqYuxooSUqJALjs7o4yVpbowvzSUy87KqSwmxQfnsrPISyFzWeWAXCkpMaBVIC4bmCsOdgiUKwh3JojLgAQ4ZCE0AMm2D29tZwe6AAAAAElFTkSuQmCC)](http://www.conan.io/source/jsoncpp/1.8.0/theirix/ci) + +[JSON][json-org] is a lightweight data-interchange format. It can represent +numbers, strings, ordered sequences of values, and collections of name/value +pairs. + +[json-org]: http://json.org/ + +JsonCpp is a C++ library that allows manipulating JSON values, including +serialization and deserialization to and from strings. It can also preserve +existing comment in unserialization/serialization steps, making it a convenient +format to store user input files. + + +## Documentation + +[JsonCpp documentation][JsonCpp-documentation] is generated using [Doxygen][]. + +[JsonCpp-documentation]: http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html +[Doxygen]: http://www.doxygen.org + + +## A note on backward-compatibility + +* `1.y.z` is built with C++11. +* `0.y.z` can be used with older compilers. +* Major versions maintain binary-compatibility. + +## Contributing to JsonCpp + +### Building and testing with Meson/Ninja +Thanks to David Seifert (@SoapGentoo), we (the maintainers) now use [meson](http://mesonbuild.com/) and [ninja](https://ninja-build.org/) to build for debugging, as well as for continuous integration (see [`travis.sh`](travis.sh) ). Other systems may work, but minor things like version strings might break. + +First, install both meson (which requires Python3) and ninja. + +Then, + + cd jsoncpp/ + BUILD_TYPE=shared + #BUILD_TYPE=static + LIB_TYPE=debug + #LIB_TYPE=release + meson --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . build-${LIB_TYPE} + ninja -v -C build-${LIB_TYPE} test + +### Building and testing with other build systems +See https://github.com/open-source-parsers/jsoncpp/wiki/Building + +### Running the tests manually + +You need to run tests manually only if you are troubleshooting an issue. + +In the instructions below, replace `path/to/jsontest` with the path of the +`jsontest` executable that was compiled on your platform. + + cd test + # This will run the Reader/Writer tests + python runjsontests.py path/to/jsontest + + # This will run the Reader/Writer tests, using JSONChecker test suite + # (http://www.json.org/JSON_checker/). + # Notes: not all tests pass: JsonCpp is too lenient (for example, + # it allows an integer to start with '0'). The goal is to improve + # strict mode parsing to get all tests to pass. + python runjsontests.py --with-json-checker path/to/jsontest + + # This will run the unit tests (mostly Value) + python rununittests.py path/to/test_lib_json + + # You can run the tests using valgrind: + python rununittests.py --valgrind path/to/test_lib_json + +### Building the documentation + +Run the Python script `doxybuild.py` from the top directory: + + python doxybuild.py --doxygen=$(which doxygen) --open --with-dot + +See `doxybuild.py --help` for options. + +### Adding a reader/writer test + +To add a test, you need to create two files in test/data: + +* a `TESTNAME.json` file, that contains the input document in JSON format. +* a `TESTNAME.expected` file, that contains a flatened representation of the + input document. + +The `TESTNAME.expected` file format is as follows: + +* Each line represents a JSON element of the element tree represented by the + input document. +* Each line has two parts: the path to access the element separated from the + element value by `=`. Array and object values are always empty (i.e. + represented by either `[]` or `{}`). +* Element path `.` represents the root element, and is used to separate object + members. `[N]` is used to specify the value of an array element at index `N`. + +See the examples `test_complex_01.json` and `test_complex_01.expected` to better understand element paths. + +### Understanding reader/writer test output + +When a test is run, output files are generated beside the input test files. Below is a short description of the content of each file: + +* `test_complex_01.json`: input JSON document. +* `test_complex_01.expected`: flattened JSON element tree used to check if + parsing was corrected. +* `test_complex_01.actual`: flattened JSON element tree produced by `jsontest` + from reading `test_complex_01.json`. +* `test_complex_01.rewrite`: JSON document written by `jsontest` using the + `Json::Value` parsed from `test_complex_01.json` and serialized using + `Json::StyledWritter`. +* `test_complex_01.actual-rewrite`: flattened JSON element tree produced by + `jsontest` from reading `test_complex_01.rewrite`. +* `test_complex_01.process-output`: `jsontest` output, typically useful for + understanding parsing errors. + +## Using JsonCpp in your project + +### Amalgamated source +https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated + +### Other ways +If you have trouble, see the Wiki, or post a question as an Issue. + +## License + +See the `LICENSE` file for details. In summary, JsonCpp is licensed under the +MIT license, or public domain if desired and recognized in your jurisdiction. diff --git a/cxx/jsoncpp/dev.makefile b/cxx/jsoncpp/dev.makefile new file mode 100644 index 0000000..d288b16 --- /dev/null +++ b/cxx/jsoncpp/dev.makefile @@ -0,0 +1,35 @@ +# This is only for jsoncpp developers/contributors. +# We use this to sign releases, generate documentation, etc. +VER?=$(shell cat version) + +default: + @echo "VER=${VER}" +sign: jsoncpp-${VER}.tar.gz + gpg --armor --detach-sign $< + gpg --verify $<.asc + # Then upload .asc to the release. +jsoncpp-%.tar.gz: + curl https://github.com/open-source-parsers/jsoncpp/archive/$*.tar.gz -o $@ +dox: + python doxybuild.py --doxygen=$$(which doxygen) --in doc/web_doxyfile.in + rsync -va --delete dist/doxygen/jsoncpp-api-html-${VER}/ ../jsoncpp-docs/doxygen/ + # Then 'git add -A' and 'git push' in jsoncpp-docs. +build: + mkdir -p build/debug + cd build/debug; cmake -DCMAKE_BUILD_TYPE=debug -DBUILD_SHARED_LIBS=ON -G "Unix Makefiles" ../.. + make -C build/debug + +# Currently, this depends on include/json/version.h generated +# by cmake. +test-amalgamate: + python2.7 amalgamate.py + python3.4 amalgamate.py + cd dist; gcc -I. -c jsoncpp.cpp + +valgrind: + valgrind --error-exitcode=42 --leak-check=full ./build/debug/src/test_lib_json/jsoncpp_test + +clean: + \rm -rf *.gz *.asc dist/ + +.PHONY: build diff --git a/cxx/jsoncpp/devtools/__init__.py b/cxx/jsoncpp/devtools/__init__.py new file mode 100644 index 0000000..4a51e65 --- /dev/null +++ b/cxx/jsoncpp/devtools/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2010 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +# module diff --git a/cxx/jsoncpp/devtools/agent_vmw7.json b/cxx/jsoncpp/devtools/agent_vmw7.json new file mode 100644 index 0000000..cd7b777 --- /dev/null +++ b/cxx/jsoncpp/devtools/agent_vmw7.json @@ -0,0 +1,33 @@ +{ + "cmake_variants" : [ + {"name": "generator", + "generators": [ + {"generator": [ + "Visual Studio 7 .NET 2003", + "Visual Studio 9 2008", + "Visual Studio 9 2008 Win64", + "Visual Studio 10", + "Visual Studio 10 Win64", + "Visual Studio 11", + "Visual Studio 11 Win64" + ] + }, + {"generator": ["MinGW Makefiles"], + "env_prepend": [{"path": "c:/wut/prg/MinGW/bin"}] + } + ] + }, + {"name": "shared_dll", + "variables": [ + ["BUILD_SHARED_LIBS=true"], + ["BUILD_SHARED_LIBS=false"] + ] + }, + {"name": "build_type", + "build_types": [ + "debug", + "release" + ] + } + ] +} diff --git a/cxx/jsoncpp/devtools/agent_vmxp.json b/cxx/jsoncpp/devtools/agent_vmxp.json new file mode 100644 index 0000000..f82a077 --- /dev/null +++ b/cxx/jsoncpp/devtools/agent_vmxp.json @@ -0,0 +1,26 @@ +{ + "cmake_variants" : [ + {"name": "generator", + "generators": [ + {"generator": [ + "Visual Studio 6", + "Visual Studio 7", + "Visual Studio 8 2005" + ] + } + ] + }, + {"name": "shared_dll", + "variables": [ + ["BUILD_SHARED_LIBS=true"], + ["BUILD_SHARED_LIBS=false"] + ] + }, + {"name": "build_type", + "build_types": [ + "debug", + "release" + ] + } + ] +} diff --git a/cxx/jsoncpp/devtools/antglob.py b/cxx/jsoncpp/devtools/antglob.py new file mode 100644 index 0000000..9843765 --- /dev/null +++ b/cxx/jsoncpp/devtools/antglob.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Copyright 2009 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +from __future__ import print_function +from dircache import listdir +import re +import fnmatch +import os.path + + +# These fnmatch expressions are used by default to prune the directory tree +# while doing the recursive traversal in the glob_impl method of glob function. +prune_dirs = '.git .bzr .hg .svn _MTN _darcs CVS SCCS ' + +# These fnmatch expressions are used by default to exclude files and dirs +# while doing the recursive traversal in the glob_impl method of glob function. +##exclude_pats = prune_pats + '*~ #*# .#* %*% ._* .gitignore .cvsignore vssver.scc .DS_Store'.split() + +# These ant_glob expressions are used by default to exclude files and dirs and also prune the directory tree +# while doing the recursive traversal in the glob_impl method of glob function. +default_excludes = ''' +**/*~ +**/#*# +**/.#* +**/%*% +**/._* +**/CVS +**/CVS/** +**/.cvsignore +**/SCCS +**/SCCS/** +**/vssver.scc +**/.svn +**/.svn/** +**/.git +**/.git/** +**/.gitignore +**/.bzr +**/.bzr/** +**/.hg +**/.hg/** +**/_MTN +**/_MTN/** +**/_darcs +**/_darcs/** +**/.DS_Store ''' + +DIR = 1 +FILE = 2 +DIR_LINK = 4 +FILE_LINK = 8 +LINKS = DIR_LINK | FILE_LINK +ALL_NO_LINK = DIR | FILE +ALL = DIR | FILE | LINKS + +_ANT_RE = re.compile(r'(/\*\*/)|(\*\*/)|(/\*\*)|(\*)|(/)|([^\*/]*)') + +def ant_pattern_to_re(ant_pattern): + """Generates a regular expression from the ant pattern. + Matching convention: + **/a: match 'a', 'dir/a', 'dir1/dir2/a' + a/**/b: match 'a/b', 'a/c/b', 'a/d/c/b' + *.py: match 'script.py' but not 'a/script.py' + """ + rex = ['^'] + next_pos = 0 + sep_rex = r'(?:/|%s)' % re.escape(os.path.sep) +## print 'Converting', ant_pattern + for match in _ANT_RE.finditer(ant_pattern): +## print 'Matched', match.group() +## print match.start(0), next_pos + if match.start(0) != next_pos: + raise ValueError("Invalid ant pattern") + if match.group(1): # /**/ + rex.append(sep_rex + '(?:.*%s)?' % sep_rex) + elif match.group(2): # **/ + rex.append('(?:.*%s)?' % sep_rex) + elif match.group(3): # /** + rex.append(sep_rex + '.*') + elif match.group(4): # * + rex.append('[^/%s]*' % re.escape(os.path.sep)) + elif match.group(5): # / + rex.append(sep_rex) + else: # somepath + rex.append(re.escape(match.group(6))) + next_pos = match.end() + rex.append('$') + return re.compile(''.join(rex)) + +def _as_list(l): + if isinstance(l, basestring): + return l.split() + return l + +def glob(dir_path, + includes = '**/*', + excludes = default_excludes, + entry_type = FILE, + prune_dirs = prune_dirs, + max_depth = 25): + include_filter = [ant_pattern_to_re(p) for p in _as_list(includes)] + exclude_filter = [ant_pattern_to_re(p) for p in _as_list(excludes)] + prune_dirs = [p.replace('/',os.path.sep) for p in _as_list(prune_dirs)] + dir_path = dir_path.replace('/',os.path.sep) + entry_type_filter = entry_type + + def is_pruned_dir(dir_name): + for pattern in prune_dirs: + if fnmatch.fnmatch(dir_name, pattern): + return True + return False + + def apply_filter(full_path, filter_rexs): + """Return True if at least one of the filter regular expression match full_path.""" + for rex in filter_rexs: + if rex.match(full_path): + return True + return False + + def glob_impl(root_dir_path): + child_dirs = [root_dir_path] + while child_dirs: + dir_path = child_dirs.pop() + for entry in listdir(dir_path): + full_path = os.path.join(dir_path, entry) +## print 'Testing:', full_path, + is_dir = os.path.isdir(full_path) + if is_dir and not is_pruned_dir(entry): # explore child directory ? +## print '===> marked for recursion', + child_dirs.append(full_path) + included = apply_filter(full_path, include_filter) + rejected = apply_filter(full_path, exclude_filter) + if not included or rejected: # do not include entry ? +## print '=> not included or rejected' + continue + link = os.path.islink(full_path) + is_file = os.path.isfile(full_path) + if not is_file and not is_dir: +## print '=> unknown entry type' + continue + if link: + entry_type = is_file and FILE_LINK or DIR_LINK + else: + entry_type = is_file and FILE or DIR +## print '=> type: %d' % entry_type, + if (entry_type & entry_type_filter) != 0: +## print ' => KEEP' + yield os.path.join(dir_path, entry) +## else: +## print ' => TYPE REJECTED' + return list(glob_impl(dir_path)) + + +if __name__ == "__main__": + import unittest + + class AntPatternToRETest(unittest.TestCase): +## def test_conversion(self): +## self.assertEqual('^somepath$', ant_pattern_to_re('somepath').pattern) + + def test_matching(self): + test_cases = [ ('path', + ['path'], + ['somepath', 'pathsuffix', '/path', '/path']), + ('*.py', + ['source.py', 'source.ext.py', '.py'], + ['path/source.py', '/.py', 'dir.py/z', 'z.pyc', 'z.c']), + ('**/path', + ['path', '/path', '/a/path', 'c:/a/path', '/a/b/path', '//a/path', '/a/path/b/path'], + ['path/', 'a/path/b', 'dir.py/z', 'somepath', 'pathsuffix', 'a/somepath']), + ('path/**', + ['path/a', 'path/path/a', 'path//'], + ['path', 'somepath/a', 'a/path', 'a/path/a', 'pathsuffix/a']), + ('/**/path', + ['/path', '/a/path', '/a/b/path/path', '/path/path'], + ['path', 'path/', 'a/path', '/pathsuffix', '/somepath']), + ('a/b', + ['a/b'], + ['somea/b', 'a/bsuffix', 'a/b/c']), + ('**/*.py', + ['script.py', 'src/script.py', 'a/b/script.py', '/a/b/script.py'], + ['script.pyc', 'script.pyo', 'a.py/b']), + ('src/**/*.py', + ['src/a.py', 'src/dir/a.py'], + ['a/src/a.py', '/src/a.py']), + ] + for ant_pattern, accepted_matches, rejected_matches in list(test_cases): + def local_path(paths): + return [ p.replace('/',os.path.sep) for p in paths ] + test_cases.append((ant_pattern, local_path(accepted_matches), local_path(rejected_matches))) + for ant_pattern, accepted_matches, rejected_matches in test_cases: + rex = ant_pattern_to_re(ant_pattern) + print('ant_pattern:', ant_pattern, ' => ', rex.pattern) + for accepted_match in accepted_matches: + print('Accepted?:', accepted_match) + self.assertTrue(rex.match(accepted_match) is not None) + for rejected_match in rejected_matches: + print('Rejected?:', rejected_match) + self.assertTrue(rex.match(rejected_match) is None) + + unittest.main() diff --git a/cxx/jsoncpp/devtools/batchbuild.py b/cxx/jsoncpp/devtools/batchbuild.py new file mode 100644 index 0000000..0eb0690 --- /dev/null +++ b/cxx/jsoncpp/devtools/batchbuild.py @@ -0,0 +1,278 @@ +from __future__ import print_function +import collections +import itertools +import json +import os +import os.path +import re +import shutil +import string +import subprocess +import sys +import cgi + +class BuildDesc: + def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None): + self.prepend_envs = prepend_envs or [] # [ { "var": "value" } ] + self.variables = variables or [] + self.build_type = build_type + self.generator = generator + + def merged_with(self, build_desc): + """Returns a new BuildDesc by merging field content. + Prefer build_desc fields to self fields for single valued field. + """ + return BuildDesc(self.prepend_envs + build_desc.prepend_envs, + self.variables + build_desc.variables, + build_desc.build_type or self.build_type, + build_desc.generator or self.generator) + + def env(self): + environ = os.environ.copy() + for values_by_name in self.prepend_envs: + for var, value in list(values_by_name.items()): + var = var.upper() + if type(value) is unicode: + value = value.encode(sys.getdefaultencoding()) + if var in environ: + environ[var] = value + os.pathsep + environ[var] + else: + environ[var] = value + return environ + + def cmake_args(self): + args = ["-D%s" % var for var in self.variables] + # skip build type for Visual Studio solution as it cause warning + if self.build_type and 'Visual' not in self.generator: + args.append("-DCMAKE_BUILD_TYPE=%s" % self.build_type) + if self.generator: + args.extend(['-G', self.generator]) + return args + + def __repr__(self): + return "BuildDesc(%s, build_type=%s)" % (" ".join(self.cmake_args()), self.build_type) + +class BuildData: + def __init__(self, desc, work_dir, source_dir): + self.desc = desc + self.work_dir = work_dir + self.source_dir = source_dir + self.cmake_log_path = os.path.join(work_dir, 'batchbuild_cmake.log') + self.build_log_path = os.path.join(work_dir, 'batchbuild_build.log') + self.cmake_succeeded = False + self.build_succeeded = False + + def execute_build(self): + print('Build %s' % self.desc) + self._make_new_work_dir() + self.cmake_succeeded = self._generate_makefiles() + if self.cmake_succeeded: + self.build_succeeded = self._build_using_makefiles() + return self.build_succeeded + + def _generate_makefiles(self): + print(' Generating makefiles: ', end=' ') + cmd = ['cmake'] + self.desc.cmake_args() + [os.path.abspath(self.source_dir)] + succeeded = self._execute_build_subprocess(cmd, self.desc.env(), self.cmake_log_path) + print('done' if succeeded else 'FAILED') + return succeeded + + def _build_using_makefiles(self): + print(' Building:', end=' ') + cmd = ['cmake', '--build', self.work_dir] + if self.desc.build_type: + cmd += ['--config', self.desc.build_type] + succeeded = self._execute_build_subprocess(cmd, self.desc.env(), self.build_log_path) + print('done' if succeeded else 'FAILED') + return succeeded + + def _execute_build_subprocess(self, cmd, env, log_path): + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.work_dir, + env=env) + stdout, _ = process.communicate() + succeeded = (process.returncode == 0) + with open(log_path, 'wb') as flog: + log = ' '.join(cmd) + '\n' + stdout + '\nExit code: %r\n' % process.returncode + flog.write(fix_eol(log)) + return succeeded + + def _make_new_work_dir(self): + if os.path.isdir(self.work_dir): + print(' Removing work directory', self.work_dir) + shutil.rmtree(self.work_dir, ignore_errors=True) + if not os.path.isdir(self.work_dir): + os.makedirs(self.work_dir) + +def fix_eol(stdout): + """Fixes wrong EOL produced by cmake --build on Windows (\r\r\n instead of \r\n). + """ + return re.sub('\r*\n', os.linesep, stdout) + +def load_build_variants_from_config(config_path): + with open(config_path, 'rb') as fconfig: + data = json.load(fconfig) + variants = data[ 'cmake_variants' ] + build_descs_by_axis = collections.defaultdict(list) + for axis in variants: + axis_name = axis["name"] + build_descs = [] + if "generators" in axis: + for generator_data in axis["generators"]: + for generator in generator_data["generator"]: + build_desc = BuildDesc(generator=generator, + prepend_envs=generator_data.get("env_prepend")) + build_descs.append(build_desc) + elif "variables" in axis: + for variables in axis["variables"]: + build_desc = BuildDesc(variables=variables) + build_descs.append(build_desc) + elif "build_types" in axis: + for build_type in axis["build_types"]: + build_desc = BuildDesc(build_type=build_type) + build_descs.append(build_desc) + build_descs_by_axis[axis_name].extend(build_descs) + return build_descs_by_axis + +def generate_build_variants(build_descs_by_axis): + """Returns a list of BuildDesc generated for the partial BuildDesc for each axis.""" + axis_names = list(build_descs_by_axis.keys()) + build_descs = [] + for axis_name, axis_build_descs in list(build_descs_by_axis.items()): + if len(build_descs): + # for each existing build_desc and each axis build desc, create a new build_desc + new_build_descs = [] + for prototype_build_desc, axis_build_desc in itertools.product(build_descs, axis_build_descs): + new_build_descs.append(prototype_build_desc.merged_with(axis_build_desc)) + build_descs = new_build_descs + else: + build_descs = axis_build_descs + return build_descs + +HTML_TEMPLATE = string.Template(''' + + $title + + + + + + + + $th_vars + + + + $th_build_types + + + +$tr_builds + +
Variables
Build type
+''') + +def generate_html_report(html_report_path, builds): + report_dir = os.path.dirname(html_report_path) + # Vertical axis: generator + # Horizontal: variables, then build_type + builds_by_generator = collections.defaultdict(list) + variables = set() + build_types_by_variable = collections.defaultdict(set) + build_by_pos_key = {} # { (generator, var_key, build_type): build } + for build in builds: + builds_by_generator[build.desc.generator].append(build) + var_key = tuple(sorted(build.desc.variables)) + variables.add(var_key) + build_types_by_variable[var_key].add(build.desc.build_type) + pos_key = (build.desc.generator, var_key, build.desc.build_type) + build_by_pos_key[pos_key] = build + variables = sorted(variables) + th_vars = [] + th_build_types = [] + for variable in variables: + build_types = sorted(build_types_by_variable[variable]) + nb_build_type = len(build_types_by_variable[variable]) + th_vars.append('%s' % (nb_build_type, cgi.escape(' '.join(variable)))) + for build_type in build_types: + th_build_types.append('%s' % cgi.escape(build_type)) + tr_builds = [] + for generator in sorted(builds_by_generator): + tds = [ '%s\n' % cgi.escape(generator) ] + for variable in variables: + build_types = sorted(build_types_by_variable[variable]) + for build_type in build_types: + pos_key = (generator, variable, build_type) + build = build_by_pos_key.get(pos_key) + if build: + cmake_status = 'ok' if build.cmake_succeeded else 'FAILED' + build_status = 'ok' if build.build_succeeded else 'FAILED' + cmake_log_url = os.path.relpath(build.cmake_log_path, report_dir) + build_log_url = os.path.relpath(build.build_log_path, report_dir) + td = 'CMake: %s' % ( build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status) + if build.cmake_succeeded: + td += '
Build: %s' % ( build_log_url, build_status.lower(), build_status) + td += '' + else: + td = '' + tds.append(td) + tr_builds.append('%s' % '\n'.join(tds)) + html = HTML_TEMPLATE.substitute( title='Batch build report', + th_vars=' '.join(th_vars), + th_build_types=' '.join(th_build_types), + tr_builds='\n'.join(tr_builds)) + with open(html_report_path, 'wt') as fhtml: + fhtml.write(html) + print('HTML report generated in:', html_report_path) + +def main(): + usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...] +Build a given CMake based project located in SOURCE_DIR with multiple generators/options.dry_run +as described in CONFIG_JSON_PATH building in WORK_DIR. + +Example of call: +python devtools\batchbuild.py e:\buildbots\jsoncpp\build . devtools\agent_vmw7.json +""" + from optparse import OptionParser + parser = OptionParser(usage=usage) + parser.allow_interspersed_args = True +# parser.add_option('-v', '--verbose', dest="verbose", action='store_true', +# help="""Be verbose.""") + parser.enable_interspersed_args() + options, args = parser.parse_args() + if len(args) < 3: + parser.error("Missing one of WORK_DIR SOURCE_DIR CONFIG_JSON_PATH.") + work_dir = args[0] + source_dir = args[1].rstrip('/\\') + config_paths = args[2:] + for config_path in config_paths: + if not os.path.isfile(config_path): + parser.error("Can not read: %r" % config_path) + + # generate build variants + build_descs = [] + for config_path in config_paths: + build_descs_by_axis = load_build_variants_from_config(config_path) + build_descs.extend(generate_build_variants(build_descs_by_axis)) + print('Build variants (%d):' % len(build_descs)) + # assign build directory for each variant + if not os.path.isdir(work_dir): + os.makedirs(work_dir) + builds = [] + with open(os.path.join(work_dir, 'matrix-dir-map.txt'), 'wt') as fmatrixmap: + for index, build_desc in enumerate(build_descs): + build_desc_work_dir = os.path.join(work_dir, '%03d' % (index+1)) + builds.append(BuildData(build_desc, build_desc_work_dir, source_dir)) + fmatrixmap.write('%s: %s\n' % (build_desc_work_dir, build_desc)) + for build in builds: + build.execute_build() + html_report_path = os.path.join(work_dir, 'batchbuild-report.html') + generate_html_report(html_report_path, builds) + print('Done') + + +if __name__ == '__main__': + main() + diff --git a/cxx/jsoncpp/devtools/fixeol.py b/cxx/jsoncpp/devtools/fixeol.py new file mode 100644 index 0000000..45252a0 --- /dev/null +++ b/cxx/jsoncpp/devtools/fixeol.py @@ -0,0 +1,70 @@ +# Copyright 2010 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +from __future__ import print_function +import os.path +import sys + +def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'): + """Makes sure that all sources have the specified eol sequence (default: unix).""" + if not os.path.isfile(path): + raise ValueError('Path "%s" is not a file' % path) + try: + f = open(path, 'rb') + except IOError as msg: + print("%s: I/O Error: %s" % (file, str(msg)), file=sys.stderr) + return False + try: + raw_lines = f.readlines() + finally: + f.close() + fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines] + if raw_lines != fixed_lines: + print('%s =>' % path, end=' ') + if not is_dry_run: + f = open(path, "wb") + try: + f.writelines(fixed_lines) + finally: + f.close() + if verbose: + print(is_dry_run and ' NEED FIX' or ' FIXED') + return True +## +## +## +##def _do_fix(is_dry_run = True): +## from waftools import antglob +## python_sources = antglob.glob('.', +## includes = '**/*.py **/wscript **/wscript_build', +## excludes = antglob.default_excludes + './waf.py', +## prune_dirs = antglob.prune_dirs + 'waf-* ./build') +## for path in python_sources: +## _fix_python_source(path, is_dry_run) +## +## cpp_sources = antglob.glob('.', +## includes = '**/*.cpp **/*.h **/*.inl', +## prune_dirs = antglob.prune_dirs + 'waf-* ./build') +## for path in cpp_sources: +## _fix_source_eol(path, is_dry_run) +## +## +##def dry_fix(context): +## _do_fix(is_dry_run = True) +## +##def fix(context): +## _do_fix(is_dry_run = False) +## +##def shutdown(): +## pass +## +##def check(context): +## # Unit tests are run when "check" target is used +## ut = UnitTest.unit_test() +## ut.change_to_testfile_dir = True +## ut.want_to_see_test_output = True +## ut.want_to_see_test_error = True +## ut.run() +## ut.print_results() diff --git a/cxx/jsoncpp/devtools/licenseupdater.py b/cxx/jsoncpp/devtools/licenseupdater.py new file mode 100644 index 0000000..36bdb5c --- /dev/null +++ b/cxx/jsoncpp/devtools/licenseupdater.py @@ -0,0 +1,94 @@ +"""Updates the license text in source file. +""" +from __future__ import print_function + +# An existing license is found if the file starts with the string below, +# and ends with the first blank line. +LICENSE_BEGIN = "// Copyright " + +BRIEF_LICENSE = LICENSE_BEGIN + """2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +""".replace('\r\n','\n') + +def update_license(path, dry_run, show_diff): + """Update the license statement in the specified file. + Parameters: + path: path of the C++ source file to update. + dry_run: if True, just print the path of the file that would be updated, + but don't change it. + show_diff: if True, print the path of the file that would be modified, + as well as the change made to the file. + """ + with open(path, 'rt') as fin: + original_text = fin.read().replace('\r\n','\n') + newline = fin.newlines and fin.newlines[0] or '\n' + if not original_text.startswith(LICENSE_BEGIN): + # No existing license found => prepend it + new_text = BRIEF_LICENSE + original_text + else: + license_end_index = original_text.index('\n\n') # search first blank line + new_text = BRIEF_LICENSE + original_text[license_end_index+2:] + if original_text != new_text: + if not dry_run: + with open(path, 'wb') as fout: + fout.write(new_text.replace('\n', newline)) + print('Updated', path) + if show_diff: + import difflib + print('\n'.join(difflib.unified_diff(original_text.split('\n'), + new_text.split('\n')))) + return True + return False + +def update_license_in_source_directories(source_dirs, dry_run, show_diff): + """Updates license text in C++ source files found in directory source_dirs. + Parameters: + source_dirs: list of directory to scan for C++ sources. Directories are + scanned recursively. + dry_run: if True, just print the path of the file that would be updated, + but don't change it. + show_diff: if True, print the path of the file that would be modified, + as well as the change made to the file. + """ + from devtools import antglob + prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist' + for source_dir in source_dirs: + cpp_sources = antglob.glob(source_dir, + includes = '''**/*.h **/*.cpp **/*.inl''', + prune_dirs = prune_dirs) + for source in cpp_sources: + update_license(source, dry_run, show_diff) + +def main(): + usage = """%prog DIR [DIR2...] +Updates license text in sources of the project in source files found +in the directory specified on the command-line. + +Example of call: +python devtools\licenseupdater.py include src -n --diff +=> Show change that would be made to the sources. + +python devtools\licenseupdater.py include src +=> Update license statement on all sources in directories include/ and src/. +""" + from optparse import OptionParser + parser = OptionParser(usage=usage) + parser.allow_interspersed_args = False + parser.add_option('-n', '--dry-run', dest="dry_run", action='store_true', default=False, + help="""Only show what files are updated, do not update the files""") + parser.add_option('--diff', dest="show_diff", action='store_true', default=False, + help="""On update, show change made to the file.""") + parser.enable_interspersed_args() + options, args = parser.parse_args() + update_license_in_source_directories(args, options.dry_run, options.show_diff) + print('Done') + +if __name__ == '__main__': + import sys + import os.path + sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + main() + diff --git a/cxx/jsoncpp/devtools/tarball.py b/cxx/jsoncpp/devtools/tarball.py new file mode 100644 index 0000000..3c0ba65 --- /dev/null +++ b/cxx/jsoncpp/devtools/tarball.py @@ -0,0 +1,52 @@ +# Copyright 2010 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +from contextlib import closing +import os +import tarfile + +TARGZ_DEFAULT_COMPRESSION_LEVEL = 9 + +def make_tarball(tarball_path, sources, base_dir, prefix_dir=''): + """Parameters: + tarball_path: output path of the .tar.gz file + sources: list of sources to include in the tarball, relative to the current directory + base_dir: if a source file is in a sub-directory of base_dir, then base_dir is stripped + from path in the tarball. + prefix_dir: all files stored in the tarball be sub-directory of prefix_dir. Set to '' + to make them child of root. + """ + base_dir = os.path.normpath(os.path.abspath(base_dir)) + def archive_name(path): + """Makes path relative to base_dir.""" + path = os.path.normpath(os.path.abspath(path)) + common_path = os.path.commonprefix((base_dir, path)) + archive_name = path[len(common_path):] + if os.path.isabs(archive_name): + archive_name = archive_name[1:] + return os.path.join(prefix_dir, archive_name) + def visit(tar, dirname, names): + for name in names: + path = os.path.join(dirname, name) + if os.path.isfile(path): + path_in_tar = archive_name(path) + tar.add(path, path_in_tar) + compression = TARGZ_DEFAULT_COMPRESSION_LEVEL + with closing(tarfile.TarFile.open(tarball_path, 'w:gz', + compresslevel=compression)) as tar: + for source in sources: + source_path = source + if os.path.isdir(source): + for dirpath, dirnames, filenames in os.walk(source_path): + visit(tar, dirpath, filenames) + else: + path_in_tar = archive_name(source_path) + tar.add(source_path, path_in_tar) # filename, arcname + +def decompress(tarball_path, base_dir): + """Decompress the gzipped tarball into directory base_dir. + """ + with closing(tarfile.TarFile.open(tarball_path)) as tar: + tar.extractall(base_dir) diff --git a/cxx/jsoncpp/include/CMakeLists.txt b/cxx/jsoncpp/include/CMakeLists.txt new file mode 100644 index 0000000..cc866f1 --- /dev/null +++ b/cxx/jsoncpp/include/CMakeLists.txt @@ -0,0 +1,2 @@ +FILE(GLOB INCLUDE_FILES "json/*.h") +INSTALL(FILES ${INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/json) diff --git a/cxx/jsoncpp/include/json/allocator.h b/cxx/jsoncpp/include/json/allocator.h new file mode 100644 index 0000000..9c7e573 --- /dev/null +++ b/cxx/jsoncpp/include/json/allocator.h @@ -0,0 +1,98 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED +#define CPPTL_JSON_ALLOCATOR_H_INCLUDED + +#include +#include + +#pragma pack(push, 8) + +namespace Json { +template +class SecureAllocator { + public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + * The pointer argument is tagged as "volatile" to prevent the + * compiler optimizing out this critical step. + */ + void deallocate(volatile pointer p, size_type n) { + std::memset(p, 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template + void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast(p)) T(std::forward(args)...); + } + + size_type max_size() const { + return size_t(-1) / sizeof(T); + } + + pointer address( reference x ) const { + return std::addressof(x); + } + + const_pointer address( const_reference x ) const { + return std::addressof(x); + } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template SecureAllocator(const SecureAllocator&) {} + template struct rebind { using other = SecureAllocator; }; +}; + + +template +bool operator==(const SecureAllocator&, const SecureAllocator&) { + return true; +} + +template +bool operator!=(const SecureAllocator&, const SecureAllocator&) { + return false; +} + +} //namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/assertions.h b/cxx/jsoncpp/include/json/assertions.h new file mode 100644 index 0000000..1cca28d --- /dev/null +++ b/cxx/jsoncpp/include/json/assertions.h @@ -0,0 +1,54 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/autolink.h b/cxx/jsoncpp/include/json/autolink.h new file mode 100644 index 0000000..b2c0f00 --- /dev/null +++ b/cxx/jsoncpp/include/json/autolink.h @@ -0,0 +1,25 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_AUTOLINK_H_INCLUDED +#define JSON_AUTOLINK_H_INCLUDED + +#include "config.h" + +#ifdef JSON_IN_CPPTL +#include +#endif + +#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \ + !defined(JSON_IN_CPPTL) +#define CPPTL_AUTOLINK_NAME "json" +#undef CPPTL_AUTOLINK_DLL +#ifdef JSON_DLL +#define CPPTL_AUTOLINK_DLL +#endif +#include "autolink.h" +#endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/config.h b/cxx/jsoncpp/include/json/config.h new file mode 100644 index 0000000..c83e78a --- /dev/null +++ b/cxx/jsoncpp/include/json/config.h @@ -0,0 +1,187 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typedef String +#include //typedef int64_t, uint64_t + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +# if _MSC_VER <= 1200 // MSVC 6 + // Microsoft Visual Studio 6 only support conversion from __int64 to double + // (no conversion from unsigned __int64). +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT throw() +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#else +# define JSONCPP_OVERRIDE +# define JSONCPP_NOEXCEPT throw() +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/features.h b/cxx/jsoncpp/include/json/features.h new file mode 100644 index 0000000..72eb6a8 --- /dev/null +++ b/cxx/jsoncpp/include/json/features.h @@ -0,0 +1,61 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/forwards.h b/cxx/jsoncpp/include/json/forwards.h new file mode 100644 index 0000000..70bbe19 --- /dev/null +++ b/cxx/jsoncpp/include/json/forwards.h @@ -0,0 +1,37 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/json.h b/cxx/jsoncpp/include/json/json.h new file mode 100644 index 0000000..3d2798a --- /dev/null +++ b/cxx/jsoncpp/include/json/json.h @@ -0,0 +1,15 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED + +#include "autolink.h" +#include "value.h" +#include "reader.h" +#include "writer.h" +#include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/reader.h b/cxx/jsoncpp/include/json/reader.h new file mode 100644 index 0000000..82859fd --- /dev/null +++ b/cxx/jsoncpp/include/json/reader.h @@ -0,0 +1,411 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + JSONCPP_STRING getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/value.h b/cxx/jsoncpp/include/json/value.h new file mode 100644 index 0000000..ebca175 --- /dev/null +++ b/cxx/jsoncpp/include/json/value.h @@ -0,0 +1,887 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(const CZString& other); + +#if JSON_HAS_RVALUE_REFERENCES + CZString& operator=(CZString&& other); +#endif + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value& operator=(Value other); + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex size); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + +#if JSON_HAS_RVALUE_REFERENCES + Value& append(Value&& value); +#endif + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + /// \deprecated + JSONCPP_DEPRECATED("") + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + JSONCPP_DEPRECATED("") + Value removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const JSONCPP_STRING& key); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + JSONCPP_STRING key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const JSONCPP_STRING& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const JSONCPP_STRING& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/version.h b/cxx/jsoncpp/include/json/version.h new file mode 100644 index 0000000..b1d2a5f --- /dev/null +++ b/cxx/jsoncpp/include/json/version.h @@ -0,0 +1,20 @@ +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "1.8.3" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 8 +# define JSONCPP_VERSION_PATCH 3 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED diff --git a/cxx/jsoncpp/include/json/writer.h b/cxx/jsoncpp/include/json/writer.h new file mode 100644 index 0000000..f258cbf --- /dev/null +++ b/cxx/jsoncpp/include/json/writer.h @@ -0,0 +1,337 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +public: + virtual ~Writer(); + + virtual JSONCPP_STRING write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter : public Writer { + +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's Javascript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatiblityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledStreamWriter { +public: +/** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED diff --git a/cxx/jsoncpp/makefiles/vs71/jsontest.vcproj b/cxx/jsoncpp/makefiles/vs71/jsontest.vcproj new file mode 100644 index 0000000..562c71f --- /dev/null +++ b/cxx/jsoncpp/makefiles/vs71/jsontest.vcproj @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cxx/jsoncpp/makefiles/vs71/lib_json.vcproj b/cxx/jsoncpp/makefiles/vs71/lib_json.vcproj new file mode 100644 index 0000000..24c5dd4 --- /dev/null +++ b/cxx/jsoncpp/makefiles/vs71/lib_json.vcproj @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cxx/jsoncpp/makefiles/vs71/test_lib_json.vcproj b/cxx/jsoncpp/makefiles/vs71/test_lib_json.vcproj new file mode 100644 index 0000000..9ebb986 --- /dev/null +++ b/cxx/jsoncpp/makefiles/vs71/test_lib_json.vcproj @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cxx/jsoncpp/pkg-config/jsoncpp.pc.in b/cxx/jsoncpp/pkg-config/jsoncpp.pc.in new file mode 100644 index 0000000..dea51f5 --- /dev/null +++ b/cxx/jsoncpp/pkg-config/jsoncpp.pc.in @@ -0,0 +1,9 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ + +Name: jsoncpp +Description: A C++ library for interacting with JSON +Version: @JSONCPP_VERSION@ +URL: https://github.com/open-source-parsers/jsoncpp +Libs: -L${libdir} -ljsoncpp +Cflags: -I${includedir} diff --git a/cxx/jsoncpp/src/CMakeLists.txt b/cxx/jsoncpp/src/CMakeLists.txt new file mode 100644 index 0000000..ca8ac15 --- /dev/null +++ b/cxx/jsoncpp/src/CMakeLists.txt @@ -0,0 +1,5 @@ +ADD_SUBDIRECTORY(lib_json) +IF(JSONCPP_WITH_TESTS) + ADD_SUBDIRECTORY(jsontestrunner) + ADD_SUBDIRECTORY(test_lib_json) +ENDIF() diff --git a/cxx/jsoncpp/src/jsontestrunner/CMakeLists.txt b/cxx/jsoncpp/src/jsontestrunner/CMakeLists.txt new file mode 100644 index 0000000..20d01e6 --- /dev/null +++ b/cxx/jsoncpp/src/jsontestrunner/CMakeLists.txt @@ -0,0 +1,25 @@ +FIND_PACKAGE(PythonInterp 2.6) + +ADD_EXECUTABLE(jsontestrunner_exe + main.cpp + ) + +IF(BUILD_SHARED_LIBS) + ADD_DEFINITIONS( -DJSON_DLL ) + TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib) +ELSE(BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib_static) +ENDIF() + +SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe) + +IF(PYTHONINTERP_FOUND) + # Run end to end parser/writer tests + SET(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../test) + SET(RUNJSONTESTS_PATH ${TEST_DIR}/runjsontests.py) + ADD_CUSTOM_TARGET(jsoncpp_readerwriter_tests + "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $ "${TEST_DIR}/data" + DEPENDS jsontestrunner_exe jsoncpp_test + ) + ADD_CUSTOM_TARGET(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests) +ENDIF() diff --git a/cxx/jsoncpp/src/jsontestrunner/main.cpp b/cxx/jsoncpp/src/jsontestrunner/main.cpp new file mode 100644 index 0000000..d24d7cf --- /dev/null +++ b/cxx/jsoncpp/src/jsontestrunner/main.cpp @@ -0,0 +1,331 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +/* This executable is used for testing parser/writer using real JSON files. + */ + +#include +#include // sort +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1310 +#pragma warning(disable : 4996) // disable fopen deprecation warning +#endif + +struct Options +{ + JSONCPP_STRING path; + Json::Features features; + bool parseOnly; + typedef JSONCPP_STRING (*writeFuncType)(Json::Value const&); + writeFuncType write; +}; + +static JSONCPP_STRING normalizeFloatingPointStr(double value) { + char buffer[32]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) + sprintf_s(buffer, sizeof(buffer), "%.16g", value); +#else + snprintf(buffer, sizeof(buffer), "%.16g", value); +#endif + buffer[sizeof(buffer) - 1] = 0; + JSONCPP_STRING s(buffer); + JSONCPP_STRING::size_type index = s.find_last_of("eE"); + if (index != JSONCPP_STRING::npos) { + JSONCPP_STRING::size_type hasSign = + (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0; + JSONCPP_STRING::size_type exponentStartIndex = index + 1 + hasSign; + JSONCPP_STRING normalized = s.substr(0, exponentStartIndex); + JSONCPP_STRING::size_type indexDigit = + s.find_first_not_of('0', exponentStartIndex); + JSONCPP_STRING exponent = "0"; + if (indexDigit != + JSONCPP_STRING::npos) // There is an exponent different from 0 + { + exponent = s.substr(indexDigit); + } + return normalized + exponent; + } + return s; +} + +static JSONCPP_STRING readInputTestFile(const char* path) { + FILE* file = fopen(path, "rb"); + if (!file) + return JSONCPP_STRING(""); + fseek(file, 0, SEEK_END); + long const size = ftell(file); + unsigned long const usize = static_cast(size); + fseek(file, 0, SEEK_SET); + JSONCPP_STRING text; + char* buffer = new char[size + 1]; + buffer[size] = 0; + if (fread(buffer, 1, usize, file) == usize) + text = buffer; + fclose(file); + delete[] buffer; + return text; +} + +static void +printValueTree(FILE* fout, Json::Value& value, const JSONCPP_STRING& path = ".") { + if (value.hasComment(Json::commentBefore)) { + fprintf(fout, "%s\n", value.getComment(Json::commentBefore).c_str()); + } + switch (value.type()) { + case Json::nullValue: + fprintf(fout, "%s=null\n", path.c_str()); + break; + case Json::intValue: + fprintf(fout, + "%s=%s\n", + path.c_str(), + Json::valueToString(value.asLargestInt()).c_str()); + break; + case Json::uintValue: + fprintf(fout, + "%s=%s\n", + path.c_str(), + Json::valueToString(value.asLargestUInt()).c_str()); + break; + case Json::realValue: + fprintf(fout, + "%s=%s\n", + path.c_str(), + normalizeFloatingPointStr(value.asDouble()).c_str()); + break; + case Json::stringValue: + fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str()); + break; + case Json::booleanValue: + fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false"); + break; + case Json::arrayValue: { + fprintf(fout, "%s=[]\n", path.c_str()); + Json::ArrayIndex size = value.size(); + for (Json::ArrayIndex index = 0; index < size; ++index) { + static char buffer[16]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) + sprintf_s(buffer, sizeof(buffer), "[%d]", index); +#else + snprintf(buffer, sizeof(buffer), "[%d]", index); +#endif + printValueTree(fout, value[index], path + buffer); + } + } break; + case Json::objectValue: { + fprintf(fout, "%s={}\n", path.c_str()); + Json::Value::Members members(value.getMemberNames()); + std::sort(members.begin(), members.end()); + JSONCPP_STRING suffix = *(path.end() - 1) == '.' ? "" : "."; + for (Json::Value::Members::iterator it = members.begin(); + it != members.end(); + ++it) { + const JSONCPP_STRING name = *it; + printValueTree(fout, value[name], path + suffix + name); + } + } break; + default: + break; + } + + if (value.hasComment(Json::commentAfter)) { + fprintf(fout, "%s\n", value.getComment(Json::commentAfter).c_str()); + } +} + +static int parseAndSaveValueTree(const JSONCPP_STRING& input, + const JSONCPP_STRING& actual, + const JSONCPP_STRING& kind, + const Json::Features& features, + bool parseOnly, + Json::Value* root) +{ + Json::Reader reader(features); + bool parsingSuccessful = reader.parse(input.data(), input.data() + input.size(), *root); + if (!parsingSuccessful) { + printf("Failed to parse %s file: \n%s\n", + kind.c_str(), + reader.getFormattedErrorMessages().c_str()); + return 1; + } + if (!parseOnly) { + FILE* factual = fopen(actual.c_str(), "wt"); + if (!factual) { + printf("Failed to create %s actual file.\n", kind.c_str()); + return 2; + } + printValueTree(factual, *root); + fclose(factual); + } + return 0; +} +// static JSONCPP_STRING useFastWriter(Json::Value const& root) { +// Json::FastWriter writer; +// writer.enableYAMLCompatibility(); +// return writer.write(root); +// } +static JSONCPP_STRING useStyledWriter( + Json::Value const& root) +{ + Json::StyledWriter writer; + return writer.write(root); +} +static JSONCPP_STRING useStyledStreamWriter( + Json::Value const& root) +{ + Json::StyledStreamWriter writer; + JSONCPP_OSTRINGSTREAM sout; + writer.write(sout, root); + return sout.str(); +} +static JSONCPP_STRING useBuiltStyledStreamWriter( + Json::Value const& root) +{ + Json::StreamWriterBuilder builder; + return Json::writeString(builder, root); +} +static int rewriteValueTree( + const JSONCPP_STRING& rewritePath, + const Json::Value& root, + Options::writeFuncType write, + JSONCPP_STRING* rewrite) +{ + *rewrite = write(root); + FILE* fout = fopen(rewritePath.c_str(), "wt"); + if (!fout) { + printf("Failed to create rewrite file: %s\n", rewritePath.c_str()); + return 2; + } + fprintf(fout, "%s\n", rewrite->c_str()); + fclose(fout); + return 0; +} + +static JSONCPP_STRING removeSuffix(const JSONCPP_STRING& path, + const JSONCPP_STRING& extension) { + if (extension.length() >= path.length()) + return JSONCPP_STRING(""); + JSONCPP_STRING suffix = path.substr(path.length() - extension.length()); + if (suffix != extension) + return JSONCPP_STRING(""); + return path.substr(0, path.length() - extension.length()); +} + +static void printConfig() { +// Print the configuration used to compile JsonCpp +#if defined(JSON_NO_INT64) + printf("JSON_NO_INT64=1\n"); +#else + printf("JSON_NO_INT64=0\n"); +#endif +} + +static int printUsage(const char* argv[]) { + printf("Usage: %s [--strict] input-json-file", argv[0]); + return 3; +} + +static int parseCommandLine( + int argc, const char* argv[], Options* opts) +{ + opts->parseOnly = false; + opts->write = &useStyledWriter; + if (argc < 2) { + return printUsage(argv); + } + int index = 1; + if (JSONCPP_STRING(argv[index]) == "--json-checker") { + opts->features = Json::Features::strictMode(); + opts->parseOnly = true; + ++index; + } + if (JSONCPP_STRING(argv[index]) == "--json-config") { + printConfig(); + return 3; + } + if (JSONCPP_STRING(argv[index]) == "--json-writer") { + ++index; + JSONCPP_STRING const writerName(argv[index++]); + if (writerName == "StyledWriter") { + opts->write = &useStyledWriter; + } else if (writerName == "StyledStreamWriter") { + opts->write = &useStyledStreamWriter; + } else if (writerName == "BuiltStyledStreamWriter") { + opts->write = &useBuiltStyledStreamWriter; + } else { + printf("Unknown '--json-writer %s'\n", writerName.c_str()); + return 4; + } + } + if (index == argc || index + 1 < argc) { + return printUsage(argv); + } + opts->path = argv[index]; + return 0; +} +static int runTest(Options const& opts) +{ + int exitCode = 0; + + JSONCPP_STRING input = readInputTestFile(opts.path.c_str()); + if (input.empty()) { + printf("Failed to read input or empty input: %s\n", opts.path.c_str()); + return 3; + } + + JSONCPP_STRING basePath = removeSuffix(opts.path, ".json"); + if (!opts.parseOnly && basePath.empty()) { + printf("Bad input path. Path does not end with '.expected':\n%s\n", + opts.path.c_str()); + return 3; + } + + JSONCPP_STRING const actualPath = basePath + ".actual"; + JSONCPP_STRING const rewritePath = basePath + ".rewrite"; + JSONCPP_STRING const rewriteActualPath = basePath + ".actual-rewrite"; + + Json::Value root; + exitCode = parseAndSaveValueTree( + input, actualPath, "input", + opts.features, opts.parseOnly, &root); + if (exitCode || opts.parseOnly) { + return exitCode; + } + JSONCPP_STRING rewrite; + exitCode = rewriteValueTree(rewritePath, root, opts.write, &rewrite); + if (exitCode) { + return exitCode; + } + Json::Value rewriteRoot; + exitCode = parseAndSaveValueTree( + rewrite, rewriteActualPath, "rewrite", + opts.features, opts.parseOnly, &rewriteRoot); + if (exitCode) { + return exitCode; + } + return 0; +} +int main(int argc, const char* argv[]) { + Options opts; + try { + int exitCode = parseCommandLine(argc, argv, &opts); + if (exitCode != 0) { + printf("Failed to parse command-line."); + return exitCode; + } + return runTest(opts); + } + catch (const std::exception& e) { + printf("Unhandled exception:\n%s\n", e.what()); + return 1; + } +} + +#pragma GCC diagnostic pop diff --git a/cxx/jsoncpp/src/lib_json/CMakeLists.txt b/cxx/jsoncpp/src/lib_json/CMakeLists.txt new file mode 100644 index 0000000..9730e9a --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/CMakeLists.txt @@ -0,0 +1,117 @@ +IF( CMAKE_COMPILER_IS_GNUCXX ) + #Get compiler version. + EXECUTE_PROCESS( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion + OUTPUT_VARIABLE GNUCXX_VERSION ) + + #-Werror=* was introduced -after- GCC 4.1.2 + IF( GNUCXX_VERSION VERSION_GREATER 4.1.2 ) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing") + ENDIF() +ENDIF( CMAKE_COMPILER_IS_GNUCXX ) + +INCLUDE(CheckIncludeFileCXX) +INCLUDE(CheckTypeSize) +INCLUDE(CheckStructHasMember) +INCLUDE(CheckCXXSymbolExists) + +check_include_file_cxx(clocale HAVE_CLOCALE) +check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV) + +IF(CMAKE_VERSION VERSION_LESS 3.0.0) + # The "LANGUAGE CXX" parameter is not supported in CMake versions below 3, + # so the C compiler and header has to be used. + check_include_file(locale.h HAVE_LOCALE_H) + SET(CMAKE_EXTRA_INCLUDE_FILES locale.h) + check_type_size("struct lconv" LCONV_SIZE) + UNSET(CMAKE_EXTRA_INCLUDE_FILES) + check_struct_has_member("struct lconv" decimal_point locale.h HAVE_DECIMAL_POINT) +ELSE() + SET(CMAKE_EXTRA_INCLUDE_FILES clocale) + check_type_size(lconv LCONV_SIZE LANGUAGE CXX) + UNSET(CMAKE_EXTRA_INCLUDE_FILES) + check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX) +ENDIF() + +IF(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV)) + MESSAGE(WARNING "Locale functionality is not supported") + ADD_DEFINITIONS(-DJSONCPP_NO_LOCALE_SUPPORT) +ENDIF() + +SET( JSONCPP_INCLUDE_DIR ../../include ) + +SET( PUBLIC_HEADERS + ${JSONCPP_INCLUDE_DIR}/json/config.h + ${JSONCPP_INCLUDE_DIR}/json/forwards.h + ${JSONCPP_INCLUDE_DIR}/json/features.h + ${JSONCPP_INCLUDE_DIR}/json/value.h + ${JSONCPP_INCLUDE_DIR}/json/reader.h + ${JSONCPP_INCLUDE_DIR}/json/writer.h + ${JSONCPP_INCLUDE_DIR}/json/assertions.h + ${JSONCPP_INCLUDE_DIR}/json/version.h + ) + +SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} ) + +SET(jsoncpp_sources + json_tool.h + json_reader.cpp + json_valueiterator.inl + json_value.cpp + json_writer.cpp + version.h.in) + +# Install instructions for this target +IF(JSONCPP_WITH_CMAKE_PACKAGE) + SET(INSTALL_EXPORT EXPORT jsoncpp) +ELSE(JSONCPP_WITH_CMAKE_PACKAGE) + SET(INSTALL_EXPORT) +ENDIF() + +IF(BUILD_SHARED_LIBS) + ADD_DEFINITIONS( -DJSON_DLL_BUILD ) + ADD_LIBRARY(jsoncpp_lib SHARED ${PUBLIC_HEADERS} ${jsoncpp_sources}) + SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION}) + SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp + DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX} ) + + # Set library's runtime search path on OSX + IF(APPLE) + SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES INSTALL_RPATH "@loader_path/." ) + ENDIF() + + INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC + $ + $) + ENDIF() + +ENDIF() + +IF(BUILD_STATIC_LIBS) + ADD_LIBRARY(jsoncpp_lib_static STATIC ${PUBLIC_HEADERS} ${jsoncpp_sources}) + SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION}) + # avoid name clashes on windows as the shared import lib is also named jsoncpp.lib + if (NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) + set (STATIC_SUFFIX "_static") + endif () + set_target_properties (jsoncpp_lib_static PROPERTIES OUTPUT_NAME jsoncpp${STATIC_SUFFIX} + DEBUG_OUTPUT_NAME jsoncpp${STATIC_SUFFIX}${DEBUG_LIBNAME_SUFFIX}) + + INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib_static PUBLIC + $ + $ + ) + ENDIF() + +ENDIF() diff --git a/cxx/jsoncpp/src/lib_json/json_reader.cpp b/cxx/jsoncpp/src/lib_json/json_reader.cpp new file mode 100644 index 0000000..9e346ae --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/json_reader.cpp @@ -0,0 +1,2064 @@ +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool +Reader::parse(const std::string& document, Value& root, bool collectComments) { + document_.assign(document.begin(), document.end()); + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { + // std::istream_iterator begin(sin); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(sin, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). + // parse() executes one nodes_.push(), so > instead of >=. + if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +bool Reader::readString() { + Char c = '\0'; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& tokenStart) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool Reader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool +Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + size_t const errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +JSONCPP_STRING Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector Reader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { + return !errors_.size(); +} + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), + features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + // To preserve the old behaviour we cast size_t to int. + if (static_cast(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else continue + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& tokenStart) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool OurReader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } else { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool +OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector OurReader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { + return !errors_.size(); +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) +{ + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_STRING doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json diff --git a/cxx/jsoncpp/src/lib_json/json_tool.h b/cxx/jsoncpp/src/lib_json/json_tool.h new file mode 100644 index 0000000..4316178 --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/json_tool.h @@ -0,0 +1,117 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include +#endif + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { +static char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned interger to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +static inline void fixNumericLocaleInput(char* begin, char* end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint != '\0' && decimalPoint != '.') { + while (begin < end) { + if (*begin == '.') { + *begin = decimalPoint; + } + ++begin; + } + } +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED diff --git a/cxx/jsoncpp/src/lib_json/json_value.cpp b/cxx/jsoncpp/src/lib_json/json_value.cpp new file mode 100644 index 0000000..2a53138 --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/json_value.cpp @@ -0,0 +1,1662 @@ +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // size_t +#include // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +//const unsigned char& kNullRef = kNull[0]; +//const Value& Value::null = reinterpret_cast(kNullRef); +//const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() +{ + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but DO NOT +// use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + //return d >= static_cast(min) && d <= static_cast(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + static_cast(Int64(value & 1)); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, + size_t length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length==0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + free(value); +} +static inline void releaseStringValue(char* value, unsigned) { + free(value); +} +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(JSONCPP_STRING const& msg) + : msg_(msg) +{} +Exception::~Exception() JSONCPP_NOEXCEPT +{} +char const* Exception::what() const JSONCPP_NOEXCEPT +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +LogicError::LogicError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) +{} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_, 0u); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = static_cast(other.cstr_ + ? (static_cast(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast(other.storage_.policy_)) & 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString& Value::CZString::operator=(CZString&& other) { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; + return *this; +} +#endif + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType vtype) { + static char const emptyString[] = ""; + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast(static_cast(emptyString)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); +} + +Value::Value(const JSONCPP_STRING& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0), start_(other.start_), limit_(other.limit_) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment( + otherComment.comment_, strlen(otherComment.comment_)); + } + } +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + delete[] comments_; + + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(Value& other) { + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2 & 0x1; +} + +void Value::copyPayload(const Value& other) { + type_ = other.type_; + value_ = other.value_; + allocated_ = other.allocated_; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +void Value::copy(const Value& other) { + copyPayload(other); + comments_ = other.comments_; + start_ = other.start_; + limit_ = other.limit_; +} + +ValueType Value::type() const { return type_; } + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +JSONCPP_STRING Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return JSONCPP_STRING(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString().empty()) || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +bool Value::operator!() const { return isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + (*this)[newSize - 1]; + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(cend-key), CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullSingleton(); + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_STRING& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +#if JSON_HAS_RVALUE_REFERENCES + Value& Value::append(Value&& value) { return (*this)[size()] = value; } +#endif + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullSingleton(); + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const JSONCPP_STRING& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(JSONCPP_STRING const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(JSONCPP_STRING((*it).first.data(), + (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif + case uintValue: +#if defined(JSON_HAS_INT64) + return value_.uint_ <= maxUInt; +#else + return true; +#endif + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { + switch (type_) { + case intValue: + case uintValue: + return true; + case realValue: +#if defined(JSON_HAS_INT64) + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); +#else + return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; +} + +bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; } + +bool Value::isNumeric() const { return isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { + StreamWriterBuilder builder; + + JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += "\n"; + + return out; +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_STRING& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.reserve(5); + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *++current != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.' || *current == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_STRING& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg++); + } +} + +void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + return Value::null; + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json diff --git a/cxx/jsoncpp/src/lib_json/json_valueiterator.inl b/cxx/jsoncpp/src/lib_json/json_valueiterator.inl new file mode 100644 index 0000000..5243bfe --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/json_valueiterator.inl @@ -0,0 +1,167 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json diff --git a/cxx/jsoncpp/src/lib_json/json_writer.cpp b/cxx/jsoncpp/src/lib_json/json_writer.cpp new file mode 100644 index 0000000..802f96c --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/json_writer.cpp @@ -0,0 +1,1223 @@ +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include +#define isfinite finite +#endif +#endif +#else +#include +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__BORLANDC__) +#include +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[36]; + int len = -1; + + char formatString[15]; + snprintf(formatString, sizeof(formatString), "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + fixNumericLocale(buffer, buffer + len); + + // try to ensure we preserve the fact that this was given to us as a double on input + if (!strchr(buffer, '.') && !strchr(buffer, 'e')) { + strcat(buffer, ".0"); + } + + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + } + assert(len >= 0); + return buffer; +} +} + +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +JSONCPP_STRING valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c = value; *c != 0; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_.clear(); + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_STRING StyledWriter::write(const Value& root) { + document_.clear(); + addChildValues_ = false; + indentString_.clear(); + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += "\n"; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + ((iter+1) != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_.clear(); + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + ((iter+1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_.clear(); + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + ((iter+1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol.clear(); + } + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json diff --git a/cxx/jsoncpp/src/lib_json/version.h.in b/cxx/jsoncpp/src/lib_json/version.h.in new file mode 100644 index 0000000..47aac69 --- /dev/null +++ b/cxx/jsoncpp/src/lib_json/version.h.in @@ -0,0 +1,20 @@ +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "@JSONCPP_VERSION@" +# define JSONCPP_VERSION_MAJOR @JSONCPP_VERSION_MAJOR@ +# define JSONCPP_VERSION_MINOR @JSONCPP_VERSION_MINOR@ +# define JSONCPP_VERSION_PATCH @JSONCPP_VERSION_PATCH@ +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY @JSONCPP_USE_SECURE_MEMORY@ +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED diff --git a/cxx/jsoncpp/src/test_lib_json/CMakeLists.txt b/cxx/jsoncpp/src/test_lib_json/CMakeLists.txt new file mode 100644 index 0000000..7000264 --- /dev/null +++ b/cxx/jsoncpp/src/test_lib_json/CMakeLists.txt @@ -0,0 +1,38 @@ +# vim: et ts=4 sts=4 sw=4 tw=0 + +ADD_EXECUTABLE( jsoncpp_test + jsontest.cpp + jsontest.h + main.cpp + ) + + +IF(BUILD_SHARED_LIBS) + ADD_DEFINITIONS( -DJSON_DLL ) + TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib) +ELSE(BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib_static) +ENDIF() + +# another way to solve issue #90 +#set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store) + +# Run unit tests in post-build +# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?) +IF(JSONCPP_WITH_POST_BUILD_UNITTEST) + IF(BUILD_SHARED_LIBS) + # First, copy the shared lib, for Microsoft. + # Then, run the test executable. + ADD_CUSTOM_COMMAND( TARGET jsoncpp_test + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + COMMAND $) + ELSE(BUILD_SHARED_LIBS) + # Just run the test executable. + ADD_CUSTOM_COMMAND( TARGET jsoncpp_test + POST_BUILD + COMMAND $) + ENDIF() +ENDIF() + +SET_TARGET_PROPERTIES(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test) diff --git a/cxx/jsoncpp/src/test_lib_json/jsontest.cpp b/cxx/jsoncpp/src/test_lib_json/jsontest.cpp new file mode 100644 index 0000000..f8c0767 --- /dev/null +++ b/cxx/jsoncpp/src/test_lib_json/jsontest.cpp @@ -0,0 +1,457 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC +#include "jsontest.h" +#include +#include + +#if defined(_MSC_VER) +// Used to install a report hook that prevent dialog on assertion and error. +#include +#endif // if defined(_MSC_VER) + +#if defined(_WIN32) +// Used to prevent dialog on memory fault. +// Limits headers included by Windows.h +#define WIN32_LEAN_AND_MEAN +#define NOSERVICE +#define NOMCX +#define NOIME +#define NOSOUND +#define NOCOMM +#define NORPC +#define NOGDI +#define NOUSER +#define NODRIVERS +#define NOLOGERROR +#define NOPROFILER +#define NOMEMMGR +#define NOLFILEIO +#define NOOPENFILE +#define NORESOURCE +#define NOATOM +#define NOLANGUAGE +#define NOLSTRING +#define NODBCS +#define NOKEYBOARDINFO +#define NOGDICAPMASKS +#define NOCOLOR +#define NOGDIOBJ +#define NODRAWTEXT +#define NOTEXTMETRIC +#define NOSCALABLEFONT +#define NOBITMAP +#define NORASTEROPS +#define NOMETAFILE +#define NOSYSMETRICS +#define NOSYSTEMPARAMSINFO +#define NOMSG +#define NOWINSTYLES +#define NOWINOFFSETS +#define NOSHOWWINDOW +#define NODEFERWINDOWPOS +#define NOVIRTUALKEYCODES +#define NOKEYSTATES +#define NOWH +#define NOMENUS +#define NOSCROLL +#define NOCLIPBOARD +#define NOICONS +#define NOMB +#define NOSYSCOMMANDS +#define NOMDI +#define NOCTLMGR +#define NOWINMESSAGES +#include +#endif // if defined(_WIN32) + +namespace JsonTest { + +// class TestResult +// ////////////////////////////////////////////////////////////////// + +TestResult::TestResult() + : predicateId_(1), lastUsedPredicateId_(0), messageTarget_(0) { + // The root predicate has id 0 + rootPredicateNode_.id_ = 0; + rootPredicateNode_.next_ = 0; + predicateStackTail_ = &rootPredicateNode_; +} + +void TestResult::setTestName(const JSONCPP_STRING& name) { name_ = name; } + +TestResult& +TestResult::addFailure(const char* file, unsigned int line, const char* expr) { + /// Walks the PredicateContext stack adding them to failures_ if not already + /// added. + unsigned int nestingLevel = 0; + PredicateContext* lastNode = rootPredicateNode_.next_; + for (; lastNode != 0; lastNode = lastNode->next_) { + if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext + { + lastUsedPredicateId_ = lastNode->id_; + addFailureInfo( + lastNode->file_, lastNode->line_, lastNode->expr_, nestingLevel); + // Link the PredicateContext to the failure for message target when + // popping the PredicateContext. + lastNode->failure_ = &(failures_.back()); + } + ++nestingLevel; + } + + // Adds the failed assertion + addFailureInfo(file, line, expr, nestingLevel); + messageTarget_ = &(failures_.back()); + return *this; +} + +void TestResult::addFailureInfo(const char* file, + unsigned int line, + const char* expr, + unsigned int nestingLevel) { + Failure failure; + failure.file_ = file; + failure.line_ = line; + if (expr) { + failure.expr_ = expr; + } + failure.nestingLevel_ = nestingLevel; + failures_.push_back(failure); +} + +TestResult& TestResult::popPredicateContext() { + PredicateContext* lastNode = &rootPredicateNode_; + while (lastNode->next_ != 0 && lastNode->next_->next_ != 0) { + lastNode = lastNode->next_; + } + // Set message target to popped failure + PredicateContext* tail = lastNode->next_; + if (tail != 0 && tail->failure_ != 0) { + messageTarget_ = tail->failure_; + } + // Remove tail from list + predicateStackTail_ = lastNode; + lastNode->next_ = 0; + return *this; +} + +bool TestResult::failed() const { return !failures_.empty(); } + +unsigned int TestResult::getAssertionNestingLevel() const { + unsigned int level = 0; + const PredicateContext* lastNode = &rootPredicateNode_; + while (lastNode->next_ != 0) { + lastNode = lastNode->next_; + ++level; + } + return level; +} + +void TestResult::printFailure(bool printTestName) const { + if (failures_.empty()) { + return; + } + + if (printTestName) { + printf("* Detail of %s test failure:\n", name_.c_str()); + } + + // Print in reverse to display the callstack in the right order + Failures::const_iterator itEnd = failures_.end(); + for (Failures::const_iterator it = failures_.begin(); it != itEnd; ++it) { + const Failure& failure = *it; + JSONCPP_STRING indent(failure.nestingLevel_ * 2, ' '); + if (failure.file_) { + printf("%s%s(%d): ", indent.c_str(), failure.file_, failure.line_); + } + if (!failure.expr_.empty()) { + printf("%s\n", failure.expr_.c_str()); + } else if (failure.file_) { + printf("\n"); + } + if (!failure.message_.empty()) { + JSONCPP_STRING reindented = indentText(failure.message_, indent + " "); + printf("%s\n", reindented.c_str()); + } + } +} + +JSONCPP_STRING TestResult::indentText(const JSONCPP_STRING& text, + const JSONCPP_STRING& indent) { + JSONCPP_STRING reindented; + JSONCPP_STRING::size_type lastIndex = 0; + while (lastIndex < text.size()) { + JSONCPP_STRING::size_type nextIndex = text.find('\n', lastIndex); + if (nextIndex == JSONCPP_STRING::npos) { + nextIndex = text.size() - 1; + } + reindented += indent; + reindented += text.substr(lastIndex, nextIndex - lastIndex + 1); + lastIndex = nextIndex + 1; + } + return reindented; +} + +TestResult& TestResult::addToLastFailure(const JSONCPP_STRING& message) { + if (messageTarget_ != 0) { + messageTarget_->message_ += message; + } + return *this; +} + +TestResult& TestResult::operator<<(Json::Int64 value) { + return addToLastFailure(Json::valueToString(value)); +} + +TestResult& TestResult::operator<<(Json::UInt64 value) { + return addToLastFailure(Json::valueToString(value)); +} + +TestResult& TestResult::operator<<(bool value) { + return addToLastFailure(value ? "true" : "false"); +} + +// class TestCase +// ////////////////////////////////////////////////////////////////// + +TestCase::TestCase() : result_(0) {} + +TestCase::~TestCase() {} + +void TestCase::run(TestResult& result) { + result_ = &result; + runTestCase(); +} + +// class Runner +// ////////////////////////////////////////////////////////////////// + +Runner::Runner() {} + +Runner& Runner::add(TestCaseFactory factory) { + tests_.push_back(factory); + return *this; +} + +unsigned int Runner::testCount() const { + return static_cast(tests_.size()); +} + +JSONCPP_STRING Runner::testNameAt(unsigned int index) const { + TestCase* test = tests_[index](); + JSONCPP_STRING name = test->testName(); + delete test; + return name; +} + +void Runner::runTestAt(unsigned int index, TestResult& result) const { + TestCase* test = tests_[index](); + result.setTestName(test->testName()); + printf("Testing %s: ", test->testName()); + fflush(stdout); +#if JSON_USE_EXCEPTION + try { +#endif // if JSON_USE_EXCEPTION + test->run(result); +#if JSON_USE_EXCEPTION + } + catch (const std::exception& e) { + result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:") + << e.what(); + } +#endif // if JSON_USE_EXCEPTION + delete test; + const char* status = result.failed() ? "FAILED" : "OK"; + printf("%s\n", status); + fflush(stdout); +} + +bool Runner::runAllTest(bool printSummary) const { + unsigned int count = testCount(); + std::deque failures; + for (unsigned int index = 0; index < count; ++index) { + TestResult result; + runTestAt(index, result); + if (result.failed()) { + failures.push_back(result); + } + } + + if (failures.empty()) { + if (printSummary) { + printf("All %d tests passed\n", count); + } + return true; + } else { + for (unsigned int index = 0; index < failures.size(); ++index) { + TestResult& result = failures[index]; + result.printFailure(count > 1); + } + + if (printSummary) { + unsigned int failedCount = static_cast(failures.size()); + unsigned int passedCount = count - failedCount; + printf("%d/%d tests passed (%d failure(s))\n", + passedCount, + count, + failedCount); + } + return false; + } +} + +bool Runner::testIndex(const JSONCPP_STRING& testName, + unsigned int& indexOut) const { + unsigned int count = testCount(); + for (unsigned int index = 0; index < count; ++index) { + if (testNameAt(index) == testName) { + indexOut = index; + return true; + } + } + return false; +} + +void Runner::listTests() const { + unsigned int count = testCount(); + for (unsigned int index = 0; index < count; ++index) { + printf("%s\n", testNameAt(index).c_str()); + } +} + +int Runner::runCommandLine(int argc, const char* argv[]) const { + // typedef std::deque TestNames; + Runner subrunner; + for (int index = 1; index < argc; ++index) { + JSONCPP_STRING opt = argv[index]; + if (opt == "--list-tests") { + listTests(); + return 0; + } else if (opt == "--test-auto") { + preventDialogOnCrash(); + } else if (opt == "--test") { + ++index; + if (index < argc) { + unsigned int testNameIndex; + if (testIndex(argv[index], testNameIndex)) { + subrunner.add(tests_[testNameIndex]); + } else { + fprintf(stderr, "Test '%s' does not exist!\n", argv[index]); + return 2; + } + } else { + printUsage(argv[0]); + return 2; + } + } else { + printUsage(argv[0]); + return 2; + } + } + bool succeeded; + if (subrunner.testCount() > 0) { + succeeded = subrunner.runAllTest(subrunner.testCount() > 1); + } else { + succeeded = runAllTest(true); + } + return succeeded ? 0 : 1; +} + +#if defined(_MSC_VER) && defined(_DEBUG) +// Hook MSVCRT assertions to prevent dialog from appearing +static int +msvcrtSilentReportHook(int reportType, char* message, int* /*returnValue*/) { + // The default CRT handling of error and assertion is to display + // an error dialog to the user. + // Instead, when an error or an assertion occurs, we force the + // application to terminate using abort() after display + // the message on stderr. + if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) { + // calling abort() cause the ReportHook to be called + // The following is used to detect this case and let's the + // error handler fallback on its default behaviour ( + // display a warning message) + static volatile bool isAborting = false; + if (isAborting) { + return TRUE; + } + isAborting = true; + + fprintf(stderr, "CRT Error/Assert:\n%s\n", message); + fflush(stderr); + abort(); + } + // Let's other reportType (_CRT_WARNING) be handled as they would by default + return FALSE; +} +#endif // if defined(_MSC_VER) + +void Runner::preventDialogOnCrash() { +#if defined(_MSC_VER) && defined(_DEBUG) + // Install a hook to prevent MSVCRT error and assertion from + // popping a dialog + // This function a NO-OP in release configuration + // (which cause warning since msvcrtSilentReportHook is not referenced) + _CrtSetReportHook(&msvcrtSilentReportHook); +#endif // if defined(_MSC_VER) + +// @todo investiguate this handler (for buffer overflow) +// _set_security_error_handler + +#if defined(_WIN32) + // Prevents the system from popping a dialog for debugging if the + // application fails due to invalid memory access. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); +#endif // if defined(_WIN32) +} + +void Runner::printUsage(const char* appName) { + printf("Usage: %s [options]\n" + "\n" + "If --test is not specified, then all the test cases be run.\n" + "\n" + "Valid options:\n" + "--list-tests: print the name of all test cases on the standard\n" + " output and exit.\n" + "--test TESTNAME: executes the test case with the specified name.\n" + " May be repeated.\n" + "--test-auto: prevent dialog prompting for debugging on crash.\n", + appName); +} + +// Assertion functions +// ////////////////////////////////////////////////////////////////// + +JSONCPP_STRING ToJsonString(const char* toConvert) { + return JSONCPP_STRING(toConvert); +} + +JSONCPP_STRING ToJsonString(JSONCPP_STRING in) { + return in; +} + +#if JSONCPP_USING_SECURE_MEMORY +JSONCPP_STRING ToJsonString(std::string in) { + return JSONCPP_STRING(in.data(), in.data() + in.length()); +} +#endif + +TestResult& checkStringEqual(TestResult& result, + const JSONCPP_STRING& expected, + const JSONCPP_STRING& actual, + const char* file, + unsigned int line, + const char* expr) { + if (expected != actual) { + result.addFailure(file, line, expr); + result << "Expected: '" << expected << "'\n"; + result << "Actual : '" << actual << "'"; + } + return result; +} + +} // namespace JsonTest diff --git a/cxx/jsoncpp/src/test_lib_json/jsontest.h b/cxx/jsoncpp/src/test_lib_json/jsontest.h new file mode 100644 index 0000000..955317d --- /dev/null +++ b/cxx/jsoncpp/src/test_lib_json/jsontest.h @@ -0,0 +1,286 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSONTEST_H_INCLUDED +#define JSONTEST_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// Mini Unit Testing framework +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/** \brief Unit testing framework. + * \warning: all assertions are non-aborting, test case execution will continue + * even if an assertion namespace. + * This constraint is for portability: the framework needs to compile + * on Visual Studio 6 and must not require exception usage. + */ +namespace JsonTest { + +class Failure { +public: + const char* file_; + unsigned int line_; + JSONCPP_STRING expr_; + JSONCPP_STRING message_; + unsigned int nestingLevel_; +}; + +/// Context used to create the assertion callstack on failure. +/// Must be a POD to allow inline initialisation without stepping +/// into the debugger. +struct PredicateContext { + typedef unsigned int Id; + Id id_; + const char* file_; + unsigned int line_; + const char* expr_; + PredicateContext* next_; + /// Related Failure, set when the PredicateContext is converted + /// into a Failure. + Failure* failure_; +}; + +class TestResult { +public: + TestResult(); + + /// \internal Implementation detail for assertion macros + /// Not encapsulated to prevent step into when debugging failed assertions + /// Incremented by one on assertion predicate entry, decreased by one + /// by addPredicateContext(). + PredicateContext::Id predicateId_; + + /// \internal Implementation detail for predicate macros + PredicateContext* predicateStackTail_; + + void setTestName(const JSONCPP_STRING& name); + + /// Adds an assertion failure. + TestResult& + addFailure(const char* file, unsigned int line, const char* expr = 0); + + /// Removes the last PredicateContext added to the predicate stack + /// chained list. + /// Next messages will be targed at the PredicateContext that was removed. + TestResult& popPredicateContext(); + + bool failed() const; + + void printFailure(bool printTestName) const; + + // Generic operator that will work with anything ostream can deal with. + template TestResult& operator<<(const T& value) { + JSONCPP_OSTRINGSTREAM oss; + oss.precision(16); + oss.setf(std::ios_base::floatfield); + oss << value; + return addToLastFailure(oss.str()); + } + + // Specialized versions. + TestResult& operator<<(bool value); + // std:ostream does not support 64bits integers on all STL implementation + TestResult& operator<<(Json::Int64 value); + TestResult& operator<<(Json::UInt64 value); + +private: + TestResult& addToLastFailure(const JSONCPP_STRING& message); + unsigned int getAssertionNestingLevel() const; + /// Adds a failure or a predicate context + void addFailureInfo(const char* file, + unsigned int line, + const char* expr, + unsigned int nestingLevel); + static JSONCPP_STRING indentText(const JSONCPP_STRING& text, + const JSONCPP_STRING& indent); + + typedef std::deque Failures; + Failures failures_; + JSONCPP_STRING name_; + PredicateContext rootPredicateNode_; + PredicateContext::Id lastUsedPredicateId_; + /// Failure which is the target of the messages added using operator << + Failure* messageTarget_; +}; + +class TestCase { +public: + TestCase(); + + virtual ~TestCase(); + + void run(TestResult& result); + + virtual const char* testName() const = 0; + +protected: + TestResult* result_; + +private: + virtual void runTestCase() = 0; +}; + +/// Function pointer type for TestCase factory +typedef TestCase* (*TestCaseFactory)(); + +class Runner { +public: + Runner(); + + /// Adds a test to the suite + Runner& add(TestCaseFactory factory); + + /// Runs test as specified on the command-line + /// If no command-line arguments are provided, run all tests. + /// If --list-tests is provided, then print the list of all test cases + /// If --test is provided, then run test testname. + int runCommandLine(int argc, const char* argv[]) const; + + /// Runs all the test cases + bool runAllTest(bool printSummary) const; + + /// Returns the number of test case in the suite + unsigned int testCount() const; + + /// Returns the name of the test case at the specified index + JSONCPP_STRING testNameAt(unsigned int index) const; + + /// Runs the test case at the specified index using the specified TestResult + void runTestAt(unsigned int index, TestResult& result) const; + + static void printUsage(const char* appName); + +private: // prevents copy construction and assignment + Runner(const Runner& other); + Runner& operator=(const Runner& other); + +private: + void listTests() const; + bool testIndex(const JSONCPP_STRING& testName, unsigned int& index) const; + static void preventDialogOnCrash(); + +private: + typedef std::deque Factories; + Factories tests_; +}; + +template +TestResult& checkEqual(TestResult& result, + T expected, + U actual, + const char* file, + unsigned int line, + const char* expr) { + if (static_cast(expected) != actual) { + result.addFailure(file, line, expr); + result << "Expected: " << static_cast(expected) << "\n"; + result << "Actual : " << actual; + } + return result; +} + +JSONCPP_STRING ToJsonString(const char* toConvert); +JSONCPP_STRING ToJsonString(JSONCPP_STRING in); +#if JSONCPP_USING_SECURE_MEMORY +JSONCPP_STRING ToJsonString(std::string in); +#endif + +TestResult& checkStringEqual(TestResult& result, + const JSONCPP_STRING& expected, + const JSONCPP_STRING& actual, + const char* file, + unsigned int line, + const char* expr); + +} // namespace JsonTest + +/// \brief Asserts that the given expression is true. +/// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y; +/// JSONTEST_ASSERT( x == y ); +#define JSONTEST_ASSERT(expr) \ + if (expr) { \ + } else \ + result_->addFailure(__FILE__, __LINE__, #expr) + +/// \brief Asserts that the given predicate is true. +/// The predicate may do other assertions and be a member function of the +/// fixture. +#define JSONTEST_ASSERT_PRED(expr) \ + { \ + JsonTest::PredicateContext _minitest_Context = { \ + result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL \ + }; \ + result_->predicateStackTail_->next_ = &_minitest_Context; \ + result_->predicateId_ += 1; \ + result_->predicateStackTail_ = &_minitest_Context; \ + (expr); \ + result_->popPredicateContext(); \ + } + +/// \brief Asserts that two values are equals. +#define JSONTEST_ASSERT_EQUAL(expected, actual) \ + JsonTest::checkEqual(*result_, \ + expected, \ + actual, \ + __FILE__, \ + __LINE__, \ + #expected " == " #actual) + +/// \brief Asserts that two values are equals. +#define JSONTEST_ASSERT_STRING_EQUAL(expected, actual) \ + JsonTest::checkStringEqual(*result_, \ + JsonTest::ToJsonString(expected), \ + JsonTest::ToJsonString(actual), \ + __FILE__, \ + __LINE__, \ + #expected " == " #actual) + +/// \brief Asserts that a given expression throws an exception +#define JSONTEST_ASSERT_THROWS(expr) \ + { \ + bool _threw = false; \ + try { \ + expr; \ + } \ + catch (...) { \ + _threw = true; \ + } \ + if (!_threw) \ + result_->addFailure( \ + __FILE__, __LINE__, "expected exception thrown: " #expr); \ + } + +/// \brief Begin a fixture test case. +#define JSONTEST_FIXTURE(FixtureType, name) \ + class Test##FixtureType##name : public FixtureType { \ + public: \ + static JsonTest::TestCase* factory() { \ + return new Test##FixtureType##name(); \ + } \ + \ + public: /* overidden from TestCase */ \ + const char* testName() const JSONCPP_OVERRIDE { return #FixtureType "/" #name; } \ + void runTestCase() JSONCPP_OVERRIDE; \ + }; \ + \ + void Test##FixtureType##name::runTestCase() + +#define JSONTEST_FIXTURE_FACTORY(FixtureType, name) \ + &Test##FixtureType##name::factory + +#define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name) \ + (runner).add(JSONTEST_FIXTURE_FACTORY(FixtureType, name)) + +#endif // ifndef JSONTEST_H_INCLUDED diff --git a/cxx/jsoncpp/src/test_lib_json/main.cpp b/cxx/jsoncpp/src/test_lib_json/main.cpp new file mode 100644 index 0000000..26e01cd --- /dev/null +++ b/cxx/jsoncpp/src/test_lib_json/main.cpp @@ -0,0 +1,2594 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#include "jsontest.h" +#include +#include +#include +#include +#include +#include +#include + +// Make numeric limits more convenient to talk about. +// Assumes int type in 32 bits. +#define kint32max Json::Value::maxInt +#define kint32min Json::Value::minInt +#define kuint32max Json::Value::maxUInt +#define kint64max Json::Value::maxInt64 +#define kint64min Json::Value::minInt64 +#define kuint64max Json::Value::maxUInt64 + +//static const double kdint64max = double(kint64max); +//static const float kfint64max = float(kint64max); +static const float kfint32max = float(kint32max); +static const float kfuint32max = float(kuint32max); + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// Json Library test cases +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double uint64ToDouble(Json::UInt64 value) { + return static_cast(value); +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double uint64ToDouble(Json::UInt64 value) { + return static_cast(Json::Int64(value / 2)) * 2.0 + + static_cast(Json::Int64(value & 1)); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +struct ValueTest : JsonTest::TestCase { + Json::Value null_; + Json::Value emptyArray_; + Json::Value emptyObject_; + Json::Value integer_; + Json::Value unsignedInteger_; + Json::Value smallUnsignedInteger_; + Json::Value real_; + Json::Value float_; + Json::Value array1_; + Json::Value object1_; + Json::Value emptyString_; + Json::Value string1_; + Json::Value string_; + Json::Value true_; + Json::Value false_; + + ValueTest() + : emptyArray_(Json::arrayValue), emptyObject_(Json::objectValue), + integer_(123456789), unsignedInteger_(34567890u), + smallUnsignedInteger_(Json::Value::UInt(Json::Value::maxInt)), + real_(1234.56789), float_(0.00390625f), emptyString_(""), string1_("a"), + string_("sometext with space"), true_(true), false_(false) { + array1_.append(1234); + object1_["id"] = 1234; + } + + struct IsCheck { + /// Initialize all checks to \c false by default. + IsCheck(); + + bool isObject_; + bool isArray_; + bool isBool_; + bool isString_; + bool isNull_; + + bool isInt_; + bool isInt64_; + bool isUInt_; + bool isUInt64_; + bool isIntegral_; + bool isDouble_; + bool isNumeric_; + }; + + void checkConstMemberCount(const Json::Value& value, + unsigned int expectedCount); + + void checkMemberCount(Json::Value& value, unsigned int expectedCount); + + void checkIs(const Json::Value& value, const IsCheck& check); + + void checkIsLess(const Json::Value& x, const Json::Value& y); + + void checkIsEqual(const Json::Value& x, const Json::Value& y); + + /// Normalize the representation of floating-point number by stripped leading + /// 0 in exponent. + static JSONCPP_STRING normalizeFloatingPointStr(const JSONCPP_STRING& s); +}; + +JSONCPP_STRING ValueTest::normalizeFloatingPointStr(const JSONCPP_STRING& s) { + JSONCPP_STRING::size_type index = s.find_last_of("eE"); + if (index != JSONCPP_STRING::npos) { + JSONCPP_STRING::size_type hasSign = + (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0; + JSONCPP_STRING::size_type exponentStartIndex = index + 1 + hasSign; + JSONCPP_STRING normalized = s.substr(0, exponentStartIndex); + JSONCPP_STRING::size_type indexDigit = + s.find_first_not_of('0', exponentStartIndex); + JSONCPP_STRING exponent = "0"; + if (indexDigit != + JSONCPP_STRING::npos) // There is an exponent different from 0 + { + exponent = s.substr(indexDigit); + } + return normalized + exponent; + } + return s; +} + +JSONTEST_FIXTURE(ValueTest, checkNormalizeFloatingPointStr) { + JSONTEST_ASSERT_STRING_EQUAL("0.0", normalizeFloatingPointStr("0.0")); + JSONTEST_ASSERT_STRING_EQUAL("0e0", normalizeFloatingPointStr("0e0")); + JSONTEST_ASSERT_STRING_EQUAL("1234.0", normalizeFloatingPointStr("1234.0")); + JSONTEST_ASSERT_STRING_EQUAL("1234.0e0", + normalizeFloatingPointStr("1234.0e0")); + JSONTEST_ASSERT_STRING_EQUAL("1234.0e+0", + normalizeFloatingPointStr("1234.0e+0")); + JSONTEST_ASSERT_STRING_EQUAL("1234e-1", normalizeFloatingPointStr("1234e-1")); + JSONTEST_ASSERT_STRING_EQUAL("1234e10", normalizeFloatingPointStr("1234e10")); + JSONTEST_ASSERT_STRING_EQUAL("1234e10", + normalizeFloatingPointStr("1234e010")); + JSONTEST_ASSERT_STRING_EQUAL("1234e+10", + normalizeFloatingPointStr("1234e+010")); + JSONTEST_ASSERT_STRING_EQUAL("1234e-10", + normalizeFloatingPointStr("1234e-010")); + JSONTEST_ASSERT_STRING_EQUAL("1234e+100", + normalizeFloatingPointStr("1234e+100")); + JSONTEST_ASSERT_STRING_EQUAL("1234e-100", + normalizeFloatingPointStr("1234e-100")); + JSONTEST_ASSERT_STRING_EQUAL("1234e+1", + normalizeFloatingPointStr("1234e+001")); +} + +JSONTEST_FIXTURE(ValueTest, memberCount) { + JSONTEST_ASSERT_PRED(checkMemberCount(emptyArray_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(emptyObject_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(array1_, 1)); + JSONTEST_ASSERT_PRED(checkMemberCount(object1_, 1)); + JSONTEST_ASSERT_PRED(checkMemberCount(null_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(integer_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(unsignedInteger_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(smallUnsignedInteger_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(real_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(emptyString_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(string_, 0)); + JSONTEST_ASSERT_PRED(checkMemberCount(true_, 0)); +} + +JSONTEST_FIXTURE(ValueTest, objects) { + // Types + IsCheck checks; + checks.isObject_ = true; + JSONTEST_ASSERT_PRED(checkIs(emptyObject_, checks)); + JSONTEST_ASSERT_PRED(checkIs(object1_, checks)); + + JSONTEST_ASSERT_EQUAL(Json::objectValue, emptyObject_.type()); + + // Empty object okay + JSONTEST_ASSERT(emptyObject_.isConvertibleTo(Json::nullValue)); + + // Non-empty object not okay + JSONTEST_ASSERT(!object1_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(emptyObject_.isConvertibleTo(Json::objectValue)); + + // Never okay + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::stringValue)); + + // Access through const reference + const Json::Value& constObject = object1_; + + JSONTEST_ASSERT_EQUAL(Json::Value(1234), constObject["id"]); + JSONTEST_ASSERT_EQUAL(Json::Value(), constObject["unknown id"]); + + // Access through non-const reference + JSONTEST_ASSERT_EQUAL(Json::Value(1234), object1_["id"]); + JSONTEST_ASSERT_EQUAL(Json::Value(), object1_["unknown id"]); + + object1_["some other id"] = "foo"; + JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]); + JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]); + + // Remove. + Json::Value got; + bool did; + did = object1_.removeMember("some other id", &got); + JSONTEST_ASSERT_EQUAL(Json::Value("foo"), got); + JSONTEST_ASSERT_EQUAL(true, did); + got = Json::Value("bar"); + did = object1_.removeMember("some other id", &got); + JSONTEST_ASSERT_EQUAL(Json::Value("bar"), got); + JSONTEST_ASSERT_EQUAL(false, did); +} + +JSONTEST_FIXTURE(ValueTest, arrays) { + const unsigned int index0 = 0; + + // Types + IsCheck checks; + checks.isArray_ = true; + JSONTEST_ASSERT_PRED(checkIs(emptyArray_, checks)); + JSONTEST_ASSERT_PRED(checkIs(array1_, checks)); + + JSONTEST_ASSERT_EQUAL(Json::arrayValue, array1_.type()); + + // Empty array okay + JSONTEST_ASSERT(emptyArray_.isConvertibleTo(Json::nullValue)); + + // Non-empty array not okay + JSONTEST_ASSERT(!array1_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(emptyArray_.isConvertibleTo(Json::arrayValue)); + + // Never okay + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::objectValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::stringValue)); + + // Access through const reference + const Json::Value& constArray = array1_; + JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[index0]); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[0]); + + // Access through non-const reference + JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[index0]); + JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[0]); + + array1_[2] = Json::Value(17); + JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]); + JSONTEST_ASSERT_EQUAL(Json::Value(17), array1_[2]); + Json::Value got; + JSONTEST_ASSERT_EQUAL(true, array1_.removeIndex(2, &got)); + JSONTEST_ASSERT_EQUAL(Json::Value(17), got); + JSONTEST_ASSERT_EQUAL(false, array1_.removeIndex(2, &got)); // gone now +} +JSONTEST_FIXTURE(ValueTest, arrayIssue252) +{ + int count = 5; + Json::Value root; + Json::Value item; + root["array"] = Json::Value::nullRef; + for (int i = 0; i < count; i++) + { + item["a"] = i; + item["b"] = i; + root["array"][i] = item; + } + //JSONTEST_ASSERT_EQUAL(5, root["array"].size()); +} + +JSONTEST_FIXTURE(ValueTest, null) { + JSONTEST_ASSERT_EQUAL(Json::nullValue, null_.type()); + + IsCheck checks; + checks.isNull_ = true; + JSONTEST_ASSERT_PRED(checkIs(null_, checks)); + + JSONTEST_ASSERT(null_.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(Json::Int(0), null_.asInt()); + JSONTEST_ASSERT_EQUAL(Json::LargestInt(0), null_.asLargestInt()); + JSONTEST_ASSERT_EQUAL(Json::UInt(0), null_.asUInt()); + JSONTEST_ASSERT_EQUAL(Json::LargestUInt(0), null_.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat()); + JSONTEST_ASSERT_STRING_EQUAL("", null_.asString()); + + JSONTEST_ASSERT_EQUAL(Json::Value::null, null_); +} + +JSONTEST_FIXTURE(ValueTest, strings) { + JSONTEST_ASSERT_EQUAL(Json::stringValue, string1_.type()); + + IsCheck checks; + checks.isString_ = true; + JSONTEST_ASSERT_PRED(checkIs(emptyString_, checks)); + JSONTEST_ASSERT_PRED(checkIs(string_, checks)); + JSONTEST_ASSERT_PRED(checkIs(string1_, checks)); + + // Empty string okay + JSONTEST_ASSERT(emptyString_.isConvertibleTo(Json::nullValue)); + + // Non-empty string not okay + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(string1_.isConvertibleTo(Json::stringValue)); + + // Never okay + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::objectValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::realValue)); + + JSONTEST_ASSERT_STRING_EQUAL("a", string1_.asString()); + JSONTEST_ASSERT_STRING_EQUAL("a", string1_.asCString()); +} + +JSONTEST_FIXTURE(ValueTest, bools) { + JSONTEST_ASSERT_EQUAL(Json::booleanValue, false_.type()); + + IsCheck checks; + checks.isBool_ = true; + JSONTEST_ASSERT_PRED(checkIs(false_, checks)); + JSONTEST_ASSERT_PRED(checkIs(true_, checks)); + + // False okay + JSONTEST_ASSERT(false_.isConvertibleTo(Json::nullValue)); + + // True not okay + JSONTEST_ASSERT(!true_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(true_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::stringValue)); + + // Never okay + JSONTEST_ASSERT(!true_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!true_.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(true, true_.asBool()); + JSONTEST_ASSERT_EQUAL(1, true_.asInt()); + JSONTEST_ASSERT_EQUAL(1, true_.asLargestInt()); + JSONTEST_ASSERT_EQUAL(1, true_.asUInt()); + JSONTEST_ASSERT_EQUAL(1, true_.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(1.0, true_.asDouble()); + JSONTEST_ASSERT_EQUAL(1.0, true_.asFloat()); + + JSONTEST_ASSERT_EQUAL(false, false_.asBool()); + JSONTEST_ASSERT_EQUAL(0, false_.asInt()); + JSONTEST_ASSERT_EQUAL(0, false_.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, false_.asUInt()); + JSONTEST_ASSERT_EQUAL(0, false_.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, false_.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, false_.asFloat()); +} + +JSONTEST_FIXTURE(ValueTest, integers) { + IsCheck checks; + Json::Value val; + + // Conversions that don't depend on the value. + JSONTEST_ASSERT(Json::Value(17).isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(Json::Value(17).isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(Json::Value(17).isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!Json::Value(17).isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!Json::Value(17).isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT(Json::Value(17U).isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(Json::Value(17U).isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(Json::Value(17U).isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!Json::Value(17U).isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!Json::Value(17U).isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT(Json::Value(17.0).isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(Json::Value(17.0).isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(Json::Value(17.0).isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!Json::Value(17.0).isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!Json::Value(17.0).isConvertibleTo(Json::objectValue)); + + // Default int + val = Json::Value(Json::intValue); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(0, val.asInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, val.asUInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); + + // Default uint + val = Json::Value(Json::uintValue); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(0, val.asInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, val.asUInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); + + // Default real + val = Json::Value(Json::realValue); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT_EQUAL(0, val.asInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, val.asUInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString()); + + // Zero (signed constructor arg) + val = Json::Value(0); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(0, val.asInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, val.asUInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); + + // Zero (unsigned constructor arg) + val = Json::Value(0u); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(0, val.asInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, val.asUInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); + + // Zero (floating-point constructor arg) + val = Json::Value(0.0); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(0, val.asInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, val.asUInt()); + JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString()); + + // 2^20 (signed constructor arg) + val = Json::Value(1 << 20); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL((1 << 20), val.asInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asUInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1048576", val.asString()); + + // 2^20 (unsigned constructor arg) + val = Json::Value(Json::UInt(1 << 20)); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL((1 << 20), val.asInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asUInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1048576", val.asString()); + + // 2^20 (floating-point constructor arg) + val = Json::Value((1 << 20) / 1.0); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL((1 << 20), val.asInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asUInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1048576.0", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // -2^20 + val = Json::Value(-(1 << 20)); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asInt()); + JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asDouble()); + JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-1048576", val.asString()); + + // int32 max + val = Json::Value(kint32max); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kint32max, val.asInt()); + JSONTEST_ASSERT_EQUAL(kint32max, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(kint32max, val.asUInt()); + JSONTEST_ASSERT_EQUAL(kint32max, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(kint32max, val.asDouble()); + JSONTEST_ASSERT_EQUAL(kfint32max, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("2147483647", val.asString()); + + // int32 min + val = Json::Value(kint32min); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kint32min, val.asInt()); + JSONTEST_ASSERT_EQUAL(kint32min, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(kint32min, val.asDouble()); + JSONTEST_ASSERT_EQUAL(kint32min, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-2147483648", val.asString()); + + // uint32 max + val = Json::Value(kuint32max); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + +#ifndef JSON_NO_INT64 + JSONTEST_ASSERT_EQUAL(kuint32max, val.asLargestInt()); +#endif + JSONTEST_ASSERT_EQUAL(kuint32max, val.asUInt()); + JSONTEST_ASSERT_EQUAL(kuint32max, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(kuint32max, val.asDouble()); + JSONTEST_ASSERT_EQUAL(kfuint32max, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("4294967295", val.asString()); + +#ifdef JSON_NO_INT64 + // int64 max + val = Json::Value(double(kint64max)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(double(kint64max), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(kint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("9.22337e+18", val.asString()); + + // int64 min + val = Json::Value(double(kint64min)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(double(kint64min), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(kint64min), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-9.22337e+18", val.asString()); + + // uint64 max + val = Json::Value(double(kuint64max)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(double(kuint64max), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(kuint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1.84467e+19", val.asString()); +#else // ifdef JSON_NO_INT64 + // 2^40 (signed constructor arg) + val = Json::Value(Json::Int64(1) << 40); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asUInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1099511627776", val.asString()); + + // 2^40 (unsigned constructor arg) + val = Json::Value(Json::UInt64(1) << 40); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asUInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1099511627776", val.asString()); + + // 2^40 (floating-point constructor arg) + val = Json::Value((Json::Int64(1) << 40) / 1.0); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asUInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1099511627776.0", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // -2^40 + val = Json::Value(-(Json::Int64(1) << 40)); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-1099511627776", val.asString()); + + // int64 max + val = Json::Value(Json::Int64(kint64max)); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kint64max, val.asInt64()); + JSONTEST_ASSERT_EQUAL(kint64max, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(kint64max, val.asUInt64()); + JSONTEST_ASSERT_EQUAL(kint64max, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(double(kint64max), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(kint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("9223372036854775807", val.asString()); + + // int64 max (floating point constructor). Note that kint64max is not exactly + // representable as a double, and will be rounded up to be higher. + val = Json::Value(double(kint64max)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asUInt64()); + JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(uint64ToDouble(Json::UInt64(1) << 63), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)), + val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("9.2233720368547758e+18", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // int64 min + val = Json::Value(Json::Int64(kint64min)); + + JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kint64min, val.asInt64()); + JSONTEST_ASSERT_EQUAL(kint64min, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(double(kint64min), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(kint64min), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-9223372036854775808", val.asString()); + + // int64 min (floating point constructor). Note that kint64min *is* exactly + // representable as a double. + val = Json::Value(double(kint64min)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kint64min, val.asInt64()); + JSONTEST_ASSERT_EQUAL(kint64min, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-9.2233720368547758e+18", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // 10^19 + const Json::UInt64 ten_to_19 = static_cast(1e19); + val = Json::Value(Json::UInt64(ten_to_19)); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(ten_to_19, val.asUInt64()); + JSONTEST_ASSERT_EQUAL(ten_to_19, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(uint64ToDouble(ten_to_19), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(ten_to_19)), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("10000000000000000000", val.asString()); + + // 10^19 (double constructor). Note that 10^19 is not exactly representable + // as a double. + val = Json::Value(uint64ToDouble(ten_to_19)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(1e19, val.asDouble()); + JSONTEST_ASSERT_EQUAL(1e19, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1e+19", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // uint64 max + val = Json::Value(Json::UInt64(kuint64max)); + + JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); + + checks = IsCheck(); + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kuint64max, val.asUInt64()); + JSONTEST_ASSERT_EQUAL(kuint64max, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(uint64ToDouble(kuint64max), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(kuint64max)), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("18446744073709551615", val.asString()); + + // uint64 max (floating point constructor). Note that kuint64max is not + // exactly representable as a double, and will be rounded up to be higher. + val = Json::Value(uint64ToDouble(kuint64max)); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble()); + JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1.8446744073709552e+19", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); +#endif +} + +JSONTEST_FIXTURE(ValueTest, nonIntegers) { + IsCheck checks; + Json::Value val; + + // Small positive number + val = Json::Value(1.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(1.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(1.5, val.asFloat()); + JSONTEST_ASSERT_EQUAL(1, val.asInt()); + JSONTEST_ASSERT_EQUAL(1, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(1, val.asUInt()); + JSONTEST_ASSERT_EQUAL(1, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("1.5", val.asString()); + + // Small negative number + val = Json::Value(-1.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(-1.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(-1.5, val.asFloat()); + JSONTEST_ASSERT_EQUAL(-1, val.asInt()); + JSONTEST_ASSERT_EQUAL(-1, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("-1.5", val.asString()); + + // A bit over int32 max + val = Json::Value(kint32max + 0.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(2147483647.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(2147483647.5), val.asFloat()); + JSONTEST_ASSERT_EQUAL(2147483647U, val.asUInt()); +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL(2147483647L, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt()); +#endif + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("2147483647.5", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // A bit under int32 min + val = Json::Value(kint32min - 0.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat()); +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 31), val.asLargestInt()); +#endif + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("-2147483648.5", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // A bit over uint32 max + val = Json::Value(kuint32max + 0.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED(checkIs(val, checks)); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(4294967295.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(4294967295.5), val.asFloat()); +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 32) - 1, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::UInt64(1) << 32) - Json::UInt64(1), + val.asLargestUInt()); +#endif + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("4294967295.5", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + val = Json::Value(1.2345678901234); + JSONTEST_ASSERT_STRING_EQUAL("1.2345678901234001", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // A 16-digit floating point number. + val = Json::Value(2199023255552000.0f); + JSONTEST_ASSERT_EQUAL(float(2199023255552000.0f), val.asFloat()); + JSONTEST_ASSERT_STRING_EQUAL("2199023255552000.0", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // A very large floating point number. + val = Json::Value(3.402823466385289e38); + JSONTEST_ASSERT_EQUAL(float(3.402823466385289e38), val.asFloat()); + JSONTEST_ASSERT_STRING_EQUAL("3.402823466385289e+38", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); + + // An even larger floating point number. + val = Json::Value(1.2345678e300); + JSONTEST_ASSERT_EQUAL(double(1.2345678e300), val.asDouble()); + JSONTEST_ASSERT_STRING_EQUAL("1.2345678e+300", + normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); +} + +void ValueTest::checkConstMemberCount(const Json::Value& value, + unsigned int expectedCount) { + unsigned int count = 0; + Json::Value::const_iterator itEnd = value.end(); + for (Json::Value::const_iterator it = value.begin(); it != itEnd; ++it) { + ++count; + } + JSONTEST_ASSERT_EQUAL(expectedCount, count) << "Json::Value::const_iterator"; +} + +void ValueTest::checkMemberCount(Json::Value& value, + unsigned int expectedCount) { + JSONTEST_ASSERT_EQUAL(expectedCount, value.size()); + + unsigned int count = 0; + Json::Value::iterator itEnd = value.end(); + for (Json::Value::iterator it = value.begin(); it != itEnd; ++it) { + ++count; + } + JSONTEST_ASSERT_EQUAL(expectedCount, count) << "Json::Value::iterator"; + + JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount)); +} + +ValueTest::IsCheck::IsCheck() + : isObject_(false), isArray_(false), isBool_(false), isString_(false), + isNull_(false), isInt_(false), isInt64_(false), isUInt_(false), + isUInt64_(false), isIntegral_(false), isDouble_(false), + isNumeric_(false) {} + +void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) { + JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject()); + JSONTEST_ASSERT_EQUAL(check.isArray_, value.isArray()); + JSONTEST_ASSERT_EQUAL(check.isBool_, value.isBool()); + JSONTEST_ASSERT_EQUAL(check.isDouble_, value.isDouble()); + JSONTEST_ASSERT_EQUAL(check.isInt_, value.isInt()); + JSONTEST_ASSERT_EQUAL(check.isUInt_, value.isUInt()); + JSONTEST_ASSERT_EQUAL(check.isIntegral_, value.isIntegral()); + JSONTEST_ASSERT_EQUAL(check.isNumeric_, value.isNumeric()); + JSONTEST_ASSERT_EQUAL(check.isString_, value.isString()); + JSONTEST_ASSERT_EQUAL(check.isNull_, value.isNull()); + +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL(check.isInt64_, value.isInt64()); + JSONTEST_ASSERT_EQUAL(check.isUInt64_, value.isUInt64()); +#else + JSONTEST_ASSERT_EQUAL(false, value.isInt64()); + JSONTEST_ASSERT_EQUAL(false, value.isUInt64()); +#endif +} + +JSONTEST_FIXTURE(ValueTest, compareNull) { + JSONTEST_ASSERT_PRED(checkIsEqual(Json::Value(), Json::Value())); +} + +JSONTEST_FIXTURE(ValueTest, compareInt) { + JSONTEST_ASSERT_PRED(checkIsLess(0, 10)); + JSONTEST_ASSERT_PRED(checkIsEqual(10, 10)); + JSONTEST_ASSERT_PRED(checkIsEqual(-10, -10)); + JSONTEST_ASSERT_PRED(checkIsLess(-10, 0)); +} + +JSONTEST_FIXTURE(ValueTest, compareUInt) { + JSONTEST_ASSERT_PRED(checkIsLess(0u, 10u)); + JSONTEST_ASSERT_PRED(checkIsLess(0u, Json::Value::maxUInt)); + JSONTEST_ASSERT_PRED(checkIsEqual(10u, 10u)); +} + +JSONTEST_FIXTURE(ValueTest, compareDouble) { + JSONTEST_ASSERT_PRED(checkIsLess(0.0, 10.0)); + JSONTEST_ASSERT_PRED(checkIsEqual(10.0, 10.0)); + JSONTEST_ASSERT_PRED(checkIsEqual(-10.0, -10.0)); + JSONTEST_ASSERT_PRED(checkIsLess(-10.0, 0.0)); +} + +JSONTEST_FIXTURE(ValueTest, compareString) { + JSONTEST_ASSERT_PRED(checkIsLess("", " ")); + JSONTEST_ASSERT_PRED(checkIsLess("", "a")); + JSONTEST_ASSERT_PRED(checkIsLess("abcd", "zyui")); + JSONTEST_ASSERT_PRED(checkIsLess("abc", "abcd")); + JSONTEST_ASSERT_PRED(checkIsEqual("abcd", "abcd")); + JSONTEST_ASSERT_PRED(checkIsEqual(" ", " ")); + JSONTEST_ASSERT_PRED(checkIsLess("ABCD", "abcd")); + JSONTEST_ASSERT_PRED(checkIsEqual("ABCD", "ABCD")); +} + +JSONTEST_FIXTURE(ValueTest, compareBoolean) { + JSONTEST_ASSERT_PRED(checkIsLess(false, true)); + JSONTEST_ASSERT_PRED(checkIsEqual(false, false)); + JSONTEST_ASSERT_PRED(checkIsEqual(true, true)); +} + +JSONTEST_FIXTURE(ValueTest, compareArray) { + // array compare size then content + Json::Value emptyArray(Json::arrayValue); + Json::Value l1aArray; + l1aArray.append(0); + Json::Value l1bArray; + l1bArray.append(10); + Json::Value l2aArray; + l2aArray.append(0); + l2aArray.append(0); + Json::Value l2bArray; + l2bArray.append(0); + l2bArray.append(10); + JSONTEST_ASSERT_PRED(checkIsLess(emptyArray, l1aArray)); + JSONTEST_ASSERT_PRED(checkIsLess(emptyArray, l2aArray)); + JSONTEST_ASSERT_PRED(checkIsLess(l1aArray, l2aArray)); + JSONTEST_ASSERT_PRED(checkIsLess(l2aArray, l2bArray)); + JSONTEST_ASSERT_PRED(checkIsEqual(emptyArray, Json::Value(emptyArray))); + JSONTEST_ASSERT_PRED(checkIsEqual(l1aArray, Json::Value(l1aArray))); + JSONTEST_ASSERT_PRED(checkIsEqual(l2bArray, Json::Value(l2bArray))); +} + +JSONTEST_FIXTURE(ValueTest, compareObject) { + // object compare size then content + Json::Value emptyObject(Json::objectValue); + Json::Value l1aObject; + l1aObject["key1"] = 0; + Json::Value l1bObject; + l1aObject["key1"] = 10; + Json::Value l2aObject; + l2aObject["key1"] = 0; + l2aObject["key2"] = 0; + JSONTEST_ASSERT_PRED(checkIsLess(emptyObject, l1aObject)); + JSONTEST_ASSERT_PRED(checkIsLess(emptyObject, l2aObject)); + JSONTEST_ASSERT_PRED(checkIsLess(l1aObject, l2aObject)); + JSONTEST_ASSERT_PRED(checkIsEqual(emptyObject, Json::Value(emptyObject))); + JSONTEST_ASSERT_PRED(checkIsEqual(l1aObject, Json::Value(l1aObject))); + JSONTEST_ASSERT_PRED(checkIsEqual(l2aObject, Json::Value(l2aObject))); +} + +JSONTEST_FIXTURE(ValueTest, compareType) { + // object of different type are ordered according to their type + JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(), Json::Value(1))); + JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1), Json::Value(1u))); + JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1u), Json::Value(1.0))); + JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1.0), Json::Value("a"))); + JSONTEST_ASSERT_PRED(checkIsLess(Json::Value("a"), Json::Value(true))); + JSONTEST_ASSERT_PRED( + checkIsLess(Json::Value(true), Json::Value(Json::arrayValue))); + JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(Json::arrayValue), + Json::Value(Json::objectValue))); +} + +void ValueTest::checkIsLess(const Json::Value& x, const Json::Value& y) { + JSONTEST_ASSERT(x < y); + JSONTEST_ASSERT(y > x); + JSONTEST_ASSERT(x <= y); + JSONTEST_ASSERT(y >= x); + JSONTEST_ASSERT(!(x == y)); + JSONTEST_ASSERT(!(y == x)); + JSONTEST_ASSERT(!(x >= y)); + JSONTEST_ASSERT(!(y <= x)); + JSONTEST_ASSERT(!(x > y)); + JSONTEST_ASSERT(!(y < x)); + JSONTEST_ASSERT(x.compare(y) < 0); + JSONTEST_ASSERT(y.compare(x) >= 0); +} + +void ValueTest::checkIsEqual(const Json::Value& x, const Json::Value& y) { + JSONTEST_ASSERT(x == y); + JSONTEST_ASSERT(y == x); + JSONTEST_ASSERT(x <= y); + JSONTEST_ASSERT(y <= x); + JSONTEST_ASSERT(x >= y); + JSONTEST_ASSERT(y >= x); + JSONTEST_ASSERT(!(x < y)); + JSONTEST_ASSERT(!(y < x)); + JSONTEST_ASSERT(!(x > y)); + JSONTEST_ASSERT(!(y > x)); + JSONTEST_ASSERT(x.compare(y) == 0); + JSONTEST_ASSERT(y.compare(x) == 0); +} + +JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) { +#if JSON_USE_EXCEPTION + + Json::Value intVal(1); + Json::Value strVal("Test"); + Json::Value objVal(Json::objectValue); + Json::Value arrVal(Json::arrayValue); + + JSONTEST_ASSERT_THROWS(intVal["test"]); + JSONTEST_ASSERT_THROWS(strVal["test"]); + JSONTEST_ASSERT_THROWS(arrVal["test"]); + + JSONTEST_ASSERT_THROWS(intVal.removeMember("test")); + JSONTEST_ASSERT_THROWS(strVal.removeMember("test")); + JSONTEST_ASSERT_THROWS(arrVal.removeMember("test")); + + JSONTEST_ASSERT_THROWS(intVal.getMemberNames()); + JSONTEST_ASSERT_THROWS(strVal.getMemberNames()); + JSONTEST_ASSERT_THROWS(arrVal.getMemberNames()); + + JSONTEST_ASSERT_THROWS(intVal[0]); + JSONTEST_ASSERT_THROWS(objVal[0]); + JSONTEST_ASSERT_THROWS(strVal[0]); + + JSONTEST_ASSERT_THROWS(intVal.clear()); + + JSONTEST_ASSERT_THROWS(intVal.resize(1)); + JSONTEST_ASSERT_THROWS(strVal.resize(1)); + JSONTEST_ASSERT_THROWS(objVal.resize(1)); + + JSONTEST_ASSERT_THROWS(intVal.asCString()); + + JSONTEST_ASSERT_THROWS(objVal.asString()); + JSONTEST_ASSERT_THROWS(arrVal.asString()); + + JSONTEST_ASSERT_THROWS(strVal.asInt()); + JSONTEST_ASSERT_THROWS(objVal.asInt()); + JSONTEST_ASSERT_THROWS(arrVal.asInt()); + + JSONTEST_ASSERT_THROWS(strVal.asUInt()); + JSONTEST_ASSERT_THROWS(objVal.asUInt()); + JSONTEST_ASSERT_THROWS(arrVal.asUInt()); + + JSONTEST_ASSERT_THROWS(strVal.asInt64()); + JSONTEST_ASSERT_THROWS(objVal.asInt64()); + JSONTEST_ASSERT_THROWS(arrVal.asInt64()); + + JSONTEST_ASSERT_THROWS(strVal.asUInt64()); + JSONTEST_ASSERT_THROWS(objVal.asUInt64()); + JSONTEST_ASSERT_THROWS(arrVal.asUInt64()); + + JSONTEST_ASSERT_THROWS(strVal.asDouble()); + JSONTEST_ASSERT_THROWS(objVal.asDouble()); + JSONTEST_ASSERT_THROWS(arrVal.asDouble()); + + JSONTEST_ASSERT_THROWS(strVal.asFloat()); + JSONTEST_ASSERT_THROWS(objVal.asFloat()); + JSONTEST_ASSERT_THROWS(arrVal.asFloat()); + + JSONTEST_ASSERT_THROWS(strVal.asBool()); + JSONTEST_ASSERT_THROWS(objVal.asBool()); + JSONTEST_ASSERT_THROWS(arrVal.asBool()); + +#endif +} + +JSONTEST_FIXTURE(ValueTest, offsetAccessors) { + Json::Value x; + JSONTEST_ASSERT(x.getOffsetStart() == 0); + JSONTEST_ASSERT(x.getOffsetLimit() == 0); + x.setOffsetStart(10); + x.setOffsetLimit(20); + JSONTEST_ASSERT(x.getOffsetStart() == 10); + JSONTEST_ASSERT(x.getOffsetLimit() == 20); + Json::Value y(x); + JSONTEST_ASSERT(y.getOffsetStart() == 10); + JSONTEST_ASSERT(y.getOffsetLimit() == 20); + Json::Value z; + z.swap(y); + JSONTEST_ASSERT(z.getOffsetStart() == 10); + JSONTEST_ASSERT(z.getOffsetLimit() == 20); + JSONTEST_ASSERT(y.getOffsetStart() == 0); + JSONTEST_ASSERT(y.getOffsetLimit() == 0); +} + +JSONTEST_FIXTURE(ValueTest, StaticString) { + char mutant[] = "hello"; + Json::StaticString ss(mutant); + JSONCPP_STRING regular(mutant); + mutant[1] = 'a'; + JSONTEST_ASSERT_STRING_EQUAL("hallo", ss.c_str()); + JSONTEST_ASSERT_STRING_EQUAL("hello", regular.c_str()); + { + Json::Value root; + root["top"] = ss; + JSONTEST_ASSERT_STRING_EQUAL("hallo", root["top"].asString()); + mutant[1] = 'u'; + JSONTEST_ASSERT_STRING_EQUAL("hullo", root["top"].asString()); + } + { + Json::Value root; + root["top"] = regular; + JSONTEST_ASSERT_STRING_EQUAL("hello", root["top"].asString()); + mutant[1] = 'u'; + JSONTEST_ASSERT_STRING_EQUAL("hello", root["top"].asString()); + } +} + +JSONTEST_FIXTURE(ValueTest, CommentBefore) { + Json::Value val; // fill val + val.setComment(JSONCPP_STRING("// this comment should appear before"), Json::commentBefore); + Json::StreamWriterBuilder wbuilder; + wbuilder.settings_["commentStyle"] = "All"; + { + char const expected[] = "// this comment should appear before\nnull"; + JSONCPP_STRING result = Json::writeString(wbuilder, val); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + JSONCPP_STRING res2 = val.toStyledString(); + JSONCPP_STRING exp2 = "\n"; + exp2 += expected; + exp2 += "\n"; + JSONTEST_ASSERT_STRING_EQUAL(exp2, res2); + } + Json::Value other = "hello"; + val.swapPayload(other); + { + char const expected[] = "// this comment should appear before\n\"hello\""; + JSONCPP_STRING result = Json::writeString(wbuilder, val); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + JSONCPP_STRING res2 = val.toStyledString(); + JSONCPP_STRING exp2 = "\n"; + exp2 += expected; + exp2 += "\n"; + JSONTEST_ASSERT_STRING_EQUAL(exp2, res2); + JSONTEST_ASSERT_STRING_EQUAL("null\n", other.toStyledString()); + } + val = "hello"; + // val.setComment("// this comment should appear before", Json::CommentPlacement::commentBefore); + // Assignment over-writes comments. + { + char const expected[] = "\"hello\""; + JSONCPP_STRING result = Json::writeString(wbuilder, val); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + JSONCPP_STRING res2 = val.toStyledString(); + JSONCPP_STRING exp2 = ""; + exp2 += expected; + exp2 += "\n"; + JSONTEST_ASSERT_STRING_EQUAL(exp2, res2); + } +} + +JSONTEST_FIXTURE(ValueTest, zeroes) { + char const cstr[] = "h\0i"; + JSONCPP_STRING binary(cstr, sizeof(cstr)); // include trailing 0 + JSONTEST_ASSERT_EQUAL(4U, binary.length()); + Json::StreamWriterBuilder b; + { + Json::Value root; + root = binary; + JSONTEST_ASSERT_STRING_EQUAL(binary, root.asString()); + } + { + char const top[] = "top"; + Json::Value root; + root[top] = binary; + JSONTEST_ASSERT_STRING_EQUAL(binary, root[top].asString()); + Json::Value removed; + bool did; + did = root.removeMember(top, top + sizeof(top) - 1U, + &removed); + JSONTEST_ASSERT(did); + JSONTEST_ASSERT_STRING_EQUAL(binary, removed.asString()); + did = root.removeMember(top, top + sizeof(top) - 1U, + &removed); + JSONTEST_ASSERT(!did); + JSONTEST_ASSERT_STRING_EQUAL(binary, removed.asString()); // still + } +} + +JSONTEST_FIXTURE(ValueTest, zeroesInKeys) { + char const cstr[] = "h\0i"; + JSONCPP_STRING binary(cstr, sizeof(cstr)); // include trailing 0 + JSONTEST_ASSERT_EQUAL(4U, binary.length()); + { + Json::Value root; + root[binary] = "there"; + JSONTEST_ASSERT_STRING_EQUAL("there", root[binary].asString()); + JSONTEST_ASSERT(!root.isMember("h")); + JSONTEST_ASSERT(root.isMember(binary)); + JSONTEST_ASSERT_STRING_EQUAL("there", root.get(binary, Json::Value::nullRef).asString()); + Json::Value removed; + bool did; + did = root.removeMember(binary.data(), binary.data() + binary.length(), + &removed); + JSONTEST_ASSERT(did); + JSONTEST_ASSERT_STRING_EQUAL("there", removed.asString()); + did = root.removeMember(binary.data(), binary.data() + binary.length(), + &removed); + JSONTEST_ASSERT(!did); + JSONTEST_ASSERT_STRING_EQUAL("there", removed.asString()); // still + JSONTEST_ASSERT(!root.isMember(binary)); + JSONTEST_ASSERT_STRING_EQUAL("", root.get(binary, Json::Value::nullRef).asString()); + } +} + +JSONTEST_FIXTURE(ValueTest, specialFloats) { + Json::StreamWriterBuilder b; + b.settings_["useSpecialFloats"] = true; + + Json::Value v = std::numeric_limits::quiet_NaN(); + JSONCPP_STRING expected = "NaN"; + JSONCPP_STRING result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = std::numeric_limits::infinity(); + expected = "Infinity"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = -std::numeric_limits::infinity(); + expected = "-Infinity"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); +} + +JSONTEST_FIXTURE(ValueTest, precision) { + Json::StreamWriterBuilder b; + b.settings_["precision"] = 5; + + Json::Value v = 100.0/3; + JSONCPP_STRING expected = "33.333"; + JSONCPP_STRING result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = 0.25000000; + expected = "0.25"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + v = 0.2563456; + expected = "0.25635"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 1; + expected = "0.3"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 17; + v = 1234857476305.256345694873740545068; + expected = "1234857476305.2563"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 24; + v = 0.256345694873740545068; + expected = "0.25634569487374054"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); +} + +struct WriterTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) { + Json::FastWriter writer; + Json::Value nullValue; + JSONTEST_ASSERT(writer.write(nullValue) == "null\n"); + + writer.dropNullPlaceholders(); + JSONTEST_ASSERT(writer.write(nullValue) == "\n"); +} + +struct StreamWriterTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) { + Json::StreamWriterBuilder b; + Json::Value nullValue; + b.settings_["dropNullPlaceholders"] = false; + JSONTEST_ASSERT(Json::writeString(b, nullValue) == "null"); + b.settings_["dropNullPlaceholders"] = true; + JSONTEST_ASSERT(Json::writeString(b, nullValue) == ""); +} + +JSONTEST_FIXTURE(StreamWriterTest, writeZeroes) { + JSONCPP_STRING binary("hi", 3); // include trailing 0 + JSONTEST_ASSERT_EQUAL(3, binary.length()); + JSONCPP_STRING expected("\"hi\\u0000\""); // unicoded zero + Json::StreamWriterBuilder b; + { + Json::Value root; + root = binary; + JSONTEST_ASSERT_STRING_EQUAL(binary, root.asString()); + JSONCPP_STRING out = Json::writeString(b, root); + JSONTEST_ASSERT_EQUAL(expected.size(), out.size()); + JSONTEST_ASSERT_STRING_EQUAL(expected, out); + } + { + Json::Value root; + root["top"] = binary; + JSONTEST_ASSERT_STRING_EQUAL(binary, root["top"].asString()); + JSONCPP_STRING out = Json::writeString(b, root["top"]); + JSONTEST_ASSERT_STRING_EQUAL(expected, out); + } +} + +struct ReaderTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) { + Json::Reader reader; + Json::Value root; + bool ok = reader.parse("{ \"property\" : \"value\" }", root); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); + JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0); +} + +JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) { + Json::Reader reader; + Json::Value root; + bool ok = reader.parse("{ \"property\" : [\"value\", \"value2\"], \"obj\" : " + "{ \"nested\" : 123, \"bool\" : true}, \"null\" : " + "null, \"false\" : false }", + root); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); + JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0); + JSONTEST_ASSERT(root["property"].getOffsetStart() == 15); + JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34); + JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16); + JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23); + JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25); + JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33); + JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44); + JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 76); + JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57); + JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 60); + JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 71); + JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 75); + JSONTEST_ASSERT(root["null"].getOffsetStart() == 87); + JSONTEST_ASSERT(root["null"].getOffsetLimit() == 91); + JSONTEST_ASSERT(root["false"].getOffsetStart() == 103); + JSONTEST_ASSERT(root["false"].getOffsetLimit() == 108); + JSONTEST_ASSERT(root.getOffsetStart() == 0); + JSONTEST_ASSERT(root.getOffsetLimit() == 110); +} + +JSONTEST_FIXTURE(ReaderTest, parseWithOneError) { + Json::Reader reader; + Json::Value root; + bool ok = reader.parse("{ \"property\" :: \"value\" }", root); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(reader.getFormattedErrorMessages() == + "* Line 1, Column 15\n Syntax error: value, object or array " + "expected.\n"); + std::vector errors = + reader.getStructuredErrors(); + JSONTEST_ASSERT(errors.size() == 1); + JSONTEST_ASSERT(errors.at(0).offset_start == 14); + JSONTEST_ASSERT(errors.at(0).offset_limit == 15); + JSONTEST_ASSERT(errors.at(0).message == + "Syntax error: value, object or array expected."); +} + +JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) { + Json::Reader reader; + Json::Value root; + bool ok = reader.parse("{ \"pr佐藤erty\" :: \"value\" }", root); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(reader.getFormattedErrorMessages() == + "* Line 1, Column 19\n Syntax error: value, object or array " + "expected.\n"); + std::vector errors = + reader.getStructuredErrors(); + JSONTEST_ASSERT(errors.size() == 1); + JSONTEST_ASSERT(errors.at(0).offset_start == 18); + JSONTEST_ASSERT(errors.at(0).offset_limit == 19); + JSONTEST_ASSERT(errors.at(0).message == + "Syntax error: value, object or array expected."); +} + +JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) { + Json::Reader reader; + Json::Value root; + bool ok = reader.parse("{ \"property\" : \"v\\alue\" }", root); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(reader.getFormattedErrorMessages() == + "* Line 1, Column 16\n Bad escape sequence in string\nSee " + "Line 1, Column 20 for detail.\n"); + std::vector errors = + reader.getStructuredErrors(); + JSONTEST_ASSERT(errors.size() == 1); + JSONTEST_ASSERT(errors.at(0).offset_start == 15); + JSONTEST_ASSERT(errors.at(0).offset_limit == 23); + JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string"); +} + +struct CharReaderTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrors) { + Json::CharReaderBuilder b; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + Json::Value root; + char const doc[] = "{ \"property\" : \"value\" }"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs.size() == 0); + delete reader; +} + +JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrorsTestingOffsets) { + Json::CharReaderBuilder b; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + Json::Value root; + char const doc[] = + "{ \"property\" : [\"value\", \"value2\"], \"obj\" : " + "{ \"nested\" : 123, \"bool\" : true}, \"null\" : " + "null, \"false\" : false }"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs.size() == 0); + delete reader; +} + +JSONTEST_FIXTURE(CharReaderTest, parseWithOneError) { + Json::CharReaderBuilder b; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + Json::Value root; + char const doc[] = + "{ \"property\" :: \"value\" }"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(errs == + "* Line 1, Column 15\n Syntax error: value, object or array " + "expected.\n"); + delete reader; +} + +JSONTEST_FIXTURE(CharReaderTest, parseChineseWithOneError) { + Json::CharReaderBuilder b; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + Json::Value root; + char const doc[] = + "{ \"pr佐藤erty\" :: \"value\" }"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(errs == + "* Line 1, Column 19\n Syntax error: value, object or array " + "expected.\n"); + delete reader; +} + +JSONTEST_FIXTURE(CharReaderTest, parseWithDetailError) { + Json::CharReaderBuilder b; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + Json::Value root; + char const doc[] = + "{ \"property\" : \"v\\alue\" }"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT(errs == + "* Line 1, Column 16\n Bad escape sequence in string\nSee " + "Line 1, Column 20 for detail.\n"); + delete reader; +} + +JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) { + Json::CharReaderBuilder b; + Json::Value root; + char const doc[] = + "{ \"property\" : \"value\" }"; + { + b.settings_["stackLimit"] = 2; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL("value", root["property"]); + delete reader; + } + { + b.settings_["stackLimit"] = 1; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + JSONTEST_ASSERT_THROWS(reader->parse( + doc, doc + std::strlen(doc), + &root, &errs)); + delete reader; + } +} + +struct CharReaderStrictModeTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderStrictModeTest, dupKeys) { + Json::CharReaderBuilder b; + Json::Value root; + char const doc[] = + "{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }"; + { + b.strictMode(&b.settings_); + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT_STRING_EQUAL( + "* Line 1, Column 41\n" + " Duplicate key: 'key'\n", + errs); + JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far + delete reader; + } +} +struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) { + // This is interpreted as a string value followed by a colon. + Json::CharReaderBuilder b; + Json::Value root; + char const doc[] = + " \"property\" : \"value\" }"; + { + b.settings_["failIfExtra"] = false; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL("property", root); + delete reader; + } + { + b.settings_["failIfExtra"] = true; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT_STRING_EQUAL(errs, + "* Line 1, Column 13\n" + " Extra non-whitespace after JSON value.\n"); + JSONTEST_ASSERT_EQUAL("property", root); + delete reader; + } + { + b.settings_["failIfExtra"] = false; + b.strictMode(&b.settings_); + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT_STRING_EQUAL(errs, + "* Line 1, Column 13\n" + " Extra non-whitespace after JSON value.\n"); + JSONTEST_ASSERT_EQUAL("property", root); + delete reader; + } +} +JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue107) { + // This is interpretted as an int value followed by a colon. + Json::CharReaderBuilder b; + Json::Value root; + char const doc[] = + "1:2:3"; + b.settings_["failIfExtra"] = true; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(!ok); + JSONTEST_ASSERT_STRING_EQUAL( + "* Line 1, Column 2\n" + " Extra non-whitespace after JSON value.\n", + errs); + JSONTEST_ASSERT_EQUAL(1, root.asInt()); + delete reader; +} +JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterObject) { + Json::CharReaderBuilder b; + Json::Value root; + { + char const doc[] = + "{ \"property\" : \"value\" } //trailing\n//comment\n"; + b.settings_["failIfExtra"] = true; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL("value", root["property"]); + delete reader; + } +} +JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterArray) { + Json::CharReaderBuilder b; + Json::Value root; + char const doc[] = + "[ \"property\" , \"value\" ] //trailing\n//comment\n"; + b.settings_["failIfExtra"] = true; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL("value", root[1u]); + delete reader; +} +JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterBool) { + Json::CharReaderBuilder b; + Json::Value root; + char const doc[] = + " true /*trailing\ncomment*/"; + b.settings_["failIfExtra"] = true; + Json::CharReader* reader(b.newCharReader()); + JSONCPP_STRING errs; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(true, root.asBool()); + delete reader; +} +struct CharReaderAllowDropNullTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderAllowDropNullTest, issue178) { + Json::CharReaderBuilder b; + b.settings_["allowDroppedNullPlaceholders"] = true; + Json::Value root; + JSONCPP_STRING errs; + Json::CharReader* reader(b.newCharReader()); + { + char const doc[] = "{\"a\":,\"b\":true}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true)); + } + { + char const doc[] = "{\"a\":}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(1u, root.size()); + JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true)); + } + { + char const doc[] = "[]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL(0u, root.size()); + JSONTEST_ASSERT_EQUAL(Json::arrayValue, root); + } + { + char const doc[] = "[null]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL(1u, root.size()); + } + { + char const doc[] = "[,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + } + { + char const doc[] = "[,,,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(4u, root.size()); + } + { + char const doc[] = "[null,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + } + { + char const doc[] = "[,null]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + } + { + char const doc[] = "[,,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(3u, root.size()); + } + { + char const doc[] = "[null,,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(3u, root.size()); + } + { + char const doc[] = "[,null,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(3u, root.size()); + } + { + char const doc[] = "[,,null]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL(3u, root.size()); + } + { + char const doc[] = "[[],,,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(4u, root.size()); + JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[0u]); + } + { + char const doc[] = "[,[],,]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(4u, root.size()); + JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[1u]); + } + { + char const doc[] = "[,,,[]]"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT(errs == ""); + JSONTEST_ASSERT_EQUAL(4u, root.size()); + JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[3u]); + } + delete reader; +} + +struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderAllowSingleQuotesTest, issue182) { + Json::CharReaderBuilder b; + b.settings_["allowSingleQuotes"] = true; + Json::Value root; + JSONCPP_STRING errs; + Json::CharReader* reader(b.newCharReader()); + { + char const doc[] = "{'a':true,\"b\":true}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_EQUAL(true, root.get("a", false)); + JSONTEST_ASSERT_EQUAL(true, root.get("b", false)); + } + { + char const doc[] = "{'a': 'x', \"b\":'y'}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); + JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); + } + delete reader; +} + +struct CharReaderAllowZeroesTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderAllowZeroesTest, issue176) { + Json::CharReaderBuilder b; + b.settings_["allowSingleQuotes"] = true; + Json::Value root; + JSONCPP_STRING errs; + Json::CharReader* reader(b.newCharReader()); + { + char const doc[] = "{'a':true,\"b\":true}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_EQUAL(true, root.get("a", false)); + JSONTEST_ASSERT_EQUAL(true, root.get("b", false)); + } + { + char const doc[] = "{'a': 'x', \"b\":'y'}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); + JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); + } + delete reader; +} + +struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(CharReaderAllowSpecialFloatsTest, issue209) { + Json::CharReaderBuilder b; + b.settings_["allowSpecialFloats"] = true; + Json::Value root; + JSONCPP_STRING errs; + Json::CharReader* reader(b.newCharReader()); + { + char const doc[] = "{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(3u, root.size()); + double n = root["a"].asDouble(); + JSONTEST_ASSERT(n != n); + JSONTEST_ASSERT_EQUAL(std::numeric_limits::infinity(), root.get("b", 0.0)); + JSONTEST_ASSERT_EQUAL(-std::numeric_limits::infinity(), root.get("c", 0.0)); + } + + struct TestData { + int line; + bool ok; + JSONCPP_STRING in; + }; + const TestData test_data[] = { + {__LINE__, 1, "{\"a\":9}"}, + {__LINE__, 0, "{\"a\":0Infinity}"}, + {__LINE__, 0, "{\"a\":1Infinity}"}, + {__LINE__, 0, "{\"a\":9Infinity}"}, + {__LINE__, 0, "{\"a\":0nfinity}"}, + {__LINE__, 0, "{\"a\":1nfinity}"}, + {__LINE__, 0, "{\"a\":9nfinity}"}, + {__LINE__, 0, "{\"a\":nfinity}"}, + {__LINE__, 0, "{\"a\":.nfinity}"}, + {__LINE__, 0, "{\"a\":9nfinity}"}, + {__LINE__, 0, "{\"a\":-nfinity}"}, + {__LINE__, 1, "{\"a\":Infinity}"}, + {__LINE__, 0, "{\"a\":.Infinity}"}, + {__LINE__, 0, "{\"a\":_Infinity}"}, + {__LINE__, 0, "{\"a\":_nfinity}"}, + {__LINE__, 1, "{\"a\":-Infinity}"} + }; + for (size_t tdi = 0; tdi < sizeof(test_data) / sizeof(*test_data); ++tdi) { + const TestData& td = test_data[tdi]; + bool ok = reader->parse(&*td.in.begin(), + &*td.in.begin() + td.in.size(), + &root, &errs); + JSONTEST_ASSERT(td.ok == ok) + << "line:" << td.line << "\n" + << " expected: {" + << "ok:" << td.ok + << ", in:\'" << td.in << "\'" + << "}\n" + << " actual: {" + << "ok:" << ok + << "}\n"; + } + + { + char const doc[] = "{\"posInf\": Infinity, \"NegInf\": -Infinity}"; + bool ok = reader->parse( + doc, doc + std::strlen(doc), + &root, &errs); + JSONTEST_ASSERT(ok); + JSONTEST_ASSERT_STRING_EQUAL("", errs); + JSONTEST_ASSERT_EQUAL(2u, root.size()); + JSONTEST_ASSERT_EQUAL(std::numeric_limits::infinity(), root["posInf"].asDouble()); + JSONTEST_ASSERT_EQUAL(-std::numeric_limits::infinity(), root["NegInf"].asDouble()); + } + delete reader; +} + +struct BuilderTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(BuilderTest, settings) { + { + Json::Value errs; + Json::CharReaderBuilder rb; + JSONTEST_ASSERT_EQUAL(false, rb.settings_.isMember("foo")); + JSONTEST_ASSERT_EQUAL(true, rb.validate(&errs)); + rb["foo"] = "bar"; + JSONTEST_ASSERT_EQUAL(true, rb.settings_.isMember("foo")); + JSONTEST_ASSERT_EQUAL(false, rb.validate(&errs)); + } + { + Json::Value errs; + Json::StreamWriterBuilder wb; + JSONTEST_ASSERT_EQUAL(false, wb.settings_.isMember("foo")); + JSONTEST_ASSERT_EQUAL(true, wb.validate(&errs)); + wb["foo"] = "bar"; + JSONTEST_ASSERT_EQUAL(true, wb.settings_.isMember("foo")); + JSONTEST_ASSERT_EQUAL(false, wb.validate(&errs)); + } +} + +struct IteratorTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(IteratorTest, distance) { + Json::Value json; + json["k1"] = "a"; + json["k2"] = "b"; + int dist = 0; + JSONCPP_STRING str; + for (Json::ValueIterator it = json.begin(); it != json.end(); ++it) { + dist = it - json.begin(); + str = it->asString().c_str(); + } + JSONTEST_ASSERT_EQUAL(1, dist); + JSONTEST_ASSERT_STRING_EQUAL("b", str); +} + +JSONTEST_FIXTURE(IteratorTest, names) { + Json::Value json; + json["k1"] = "a"; + json["k2"] = "b"; + Json::ValueIterator it = json.begin(); + JSONTEST_ASSERT(it != json.end()); + JSONTEST_ASSERT_EQUAL(Json::Value("k1"), it.key()); + JSONTEST_ASSERT_STRING_EQUAL("k1", it.name()); + JSONTEST_ASSERT_EQUAL(-1, it.index()); + ++it; + JSONTEST_ASSERT(it != json.end()); + JSONTEST_ASSERT_EQUAL(Json::Value("k2"), it.key()); + JSONTEST_ASSERT_STRING_EQUAL("k2", it.name()); + JSONTEST_ASSERT_EQUAL(-1, it.index()); + ++it; + JSONTEST_ASSERT(it == json.end()); +} + +JSONTEST_FIXTURE(IteratorTest, indexes) { + Json::Value json; + json[0] = "a"; + json[1] = "b"; + Json::ValueIterator it = json.begin(); + JSONTEST_ASSERT(it != json.end()); + JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(0)), it.key()); + JSONTEST_ASSERT_STRING_EQUAL("", it.name()); + JSONTEST_ASSERT_EQUAL(0, it.index()); + ++it; + JSONTEST_ASSERT(it != json.end()); + JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(1)), it.key()); + JSONTEST_ASSERT_STRING_EQUAL("", it.name()); + JSONTEST_ASSERT_EQUAL(1, it.index()); + ++it; + JSONTEST_ASSERT(it == json.end()); +} + +JSONTEST_FIXTURE(IteratorTest, const) { + Json::Value const v; + JSONTEST_ASSERT_THROWS( + Json::Value::iterator it(v.begin()) // Compile, but throw. + ); + + Json::Value value; + + for(int i = 9; i < 12; ++i) + { + JSONCPP_OSTRINGSTREAM out; + out << std::setw(2) << i; + JSONCPP_STRING str = out.str(); + value[str] = str; + } + + JSONCPP_OSTRINGSTREAM out; + //in old code, this will get a compile error + Json::Value::const_iterator iter = value.begin(); + for(; iter != value.end(); ++iter) + { + out << *iter << ','; + } + JSONCPP_STRING expected = "\" 9\",\"10\",\"11\","; + JSONTEST_ASSERT_STRING_EQUAL(expected, out.str()); +} + +struct RValueTest : JsonTest::TestCase {}; + +JSONTEST_FIXTURE(RValueTest, moveConstruction) { +#if JSON_HAS_RVALUE_REFERENCES + Json::Value json; + json["key"] = "value"; + Json::Value moved = std::move(json); + JSONTEST_ASSERT(moved != json); // Possibly not nullValue; definitely not equal. + JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type()); + JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type()); +#endif +} + +int main(int argc, const char* argv[]) { + JsonTest::Runner runner; + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, memberCount); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, objects); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, arrays); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, arrayIssue252); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, null); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, strings); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, bools); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, integers); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nonIntegers); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareNull); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareInt); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareUInt); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareDouble); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareString); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareBoolean); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, StaticString); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, CommentBefore); + //JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nulls); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, specialFloats); + JSONTEST_REGISTER_FIXTURE(runner, ValueTest, precision); + + JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders); + JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders); + JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, writeZeroes); + + JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors); + JSONTEST_REGISTER_FIXTURE( + runner, ReaderTest, parseWithNoErrorsTestingOffsets); + JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithOneError); + JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError); + JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithNoErrors); + JSONTEST_REGISTER_FIXTURE( + runner, CharReaderTest, parseWithNoErrorsTestingOffsets); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithOneError); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseChineseWithOneError); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderStrictModeTest, dupKeys); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterArray); + JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterBool); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowDropNullTest, issue178); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowSingleQuotesTest, issue182); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowZeroesTest, issue176); + + JSONTEST_REGISTER_FIXTURE(runner, CharReaderAllowSpecialFloatsTest, issue209); + + JSONTEST_REGISTER_FIXTURE(runner, BuilderTest, settings); + + JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, distance); + JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, names); + JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, indexes); + JSONTEST_REGISTER_FIXTURE(runner, IteratorTest, const); + + JSONTEST_REGISTER_FIXTURE(runner, RValueTest, moveConstruction); + + return runner.runCommandLine(argc, argv); +} + +#pragma GCC diagnostic pop diff --git a/cxx/jsoncpp/test/cleantests.py b/cxx/jsoncpp/test/cleantests.py new file mode 100644 index 0000000..36d5b9b --- /dev/null +++ b/cxx/jsoncpp/test/cleantests.py @@ -0,0 +1,16 @@ +# Copyright 2007 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +"""Removes all files created during testing.""" + +import glob +import os + +paths = [] +for pattern in [ '*.actual', '*.actual-rewrite', '*.rewrite', '*.process-output' ]: + paths += glob.glob('data/' + pattern) + +for path in paths: + os.unlink(path) diff --git a/cxx/jsoncpp/test/data/fail_test_array_01.json b/cxx/jsoncpp/test/data/fail_test_array_01.json new file mode 100644 index 0000000..f72a6d0 --- /dev/null +++ b/cxx/jsoncpp/test/data/fail_test_array_01.json @@ -0,0 +1 @@ +[ 1 2 3] diff --git a/cxx/jsoncpp/test/data/fail_test_stack_limit.json b/cxx/jsoncpp/test/data/fail_test_stack_limit.json new file mode 100644 index 0000000..7524e0b --- /dev/null +++ b/cxx/jsoncpp/test/data/fail_test_stack_limit.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/cxx/jsoncpp/test/data/test_array_01.expected b/cxx/jsoncpp/test/data/test_array_01.expected new file mode 100644 index 0000000..a341ff7 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_01.expected @@ -0,0 +1 @@ +.=[] diff --git a/cxx/jsoncpp/test/data/test_array_01.json b/cxx/jsoncpp/test/data/test_array_01.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_01.json @@ -0,0 +1 @@ +[] diff --git a/cxx/jsoncpp/test/data/test_array_02.expected b/cxx/jsoncpp/test/data/test_array_02.expected new file mode 100644 index 0000000..ef1f262 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_02.expected @@ -0,0 +1,2 @@ +.=[] +.[0]=1 diff --git a/cxx/jsoncpp/test/data/test_array_02.json b/cxx/jsoncpp/test/data/test_array_02.json new file mode 100644 index 0000000..7660873 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_02.json @@ -0,0 +1 @@ +[1] diff --git a/cxx/jsoncpp/test/data/test_array_03.expected b/cxx/jsoncpp/test/data/test_array_03.expected new file mode 100644 index 0000000..3d8dc18 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_03.expected @@ -0,0 +1,6 @@ +.=[] +.[0]=1 +.[1]=2 +.[2]=3 +.[3]=4 +.[4]=5 diff --git a/cxx/jsoncpp/test/data/test_array_03.json b/cxx/jsoncpp/test/data/test_array_03.json new file mode 100644 index 0000000..9b3f924 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_03.json @@ -0,0 +1 @@ +[ 1, 2 , 3,4,5] diff --git a/cxx/jsoncpp/test/data/test_array_04.expected b/cxx/jsoncpp/test/data/test_array_04.expected new file mode 100644 index 0000000..ad4add9 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_04.expected @@ -0,0 +1,5 @@ +.=[] +.[0]=1 +.[1]="abc" +.[2]=12.3 +.[3]=-4 diff --git a/cxx/jsoncpp/test/data/test_array_04.json b/cxx/jsoncpp/test/data/test_array_04.json new file mode 100644 index 0000000..ecca546 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_04.json @@ -0,0 +1 @@ +[1, "abc" , 12.3, -4] diff --git a/cxx/jsoncpp/test/data/test_array_05.expected b/cxx/jsoncpp/test/data/test_array_05.expected new file mode 100644 index 0000000..76cff87 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_05.expected @@ -0,0 +1,100 @@ +.=[] +.[0]=1 +.[1]=2 +.[2]=3 +.[3]=4 +.[4]=5 +.[5]=6 +.[6]=7 +.[7]=8 +.[8]=9 +.[9]=10 +.[10]=11 +.[11]=12 +.[12]=13 +.[13]=14 +.[14]=15 +.[15]=16 +.[16]=17 +.[17]=18 +.[18]=19 +.[19]=20 +.[20]=21 +.[21]=22 +.[22]=23 +.[23]=24 +.[24]=25 +.[25]=26 +.[26]=27 +.[27]=28 +.[28]=29 +.[29]=30 +.[30]=31 +.[31]=32 +.[32]=33 +.[33]=34 +.[34]=35 +.[35]=36 +.[36]=37 +.[37]=38 +.[38]=39 +.[39]=40 +.[40]=41 +.[41]=42 +.[42]=43 +.[43]=44 +.[44]=45 +.[45]=46 +.[46]=47 +.[47]=48 +.[48]=49 +.[49]=50 +.[50]=51 +.[51]=52 +.[52]=53 +.[53]=54 +.[54]=55 +.[55]=56 +.[56]=57 +.[57]=58 +.[58]=59 +.[59]=60 +.[60]=61 +.[61]=62 +.[62]=63 +.[63]=64 +.[64]=65 +.[65]=66 +.[66]=67 +.[67]=68 +.[68]=69 +.[69]=70 +.[70]=71 +.[71]=72 +.[72]=73 +.[73]=74 +.[74]=75 +.[75]=76 +.[76]=77 +.[77]=78 +.[78]=79 +.[79]=80 +.[80]=81 +.[81]=82 +.[82]=83 +.[83]=84 +.[84]=85 +.[85]=86 +.[86]=87 +.[87]=88 +.[88]=89 +.[89]=90 +.[90]=91 +.[91]=92 +.[92]=93 +.[93]=94 +.[94]=95 +.[95]=96 +.[96]=97 +.[97]=98 +.[98]=99 diff --git a/cxx/jsoncpp/test/data/test_array_05.json b/cxx/jsoncpp/test/data/test_array_05.json new file mode 100644 index 0000000..7809d6c --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_05.json @@ -0,0 +1 @@ +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99] \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_array_06.expected b/cxx/jsoncpp/test/data/test_array_06.expected new file mode 100644 index 0000000..5c9f48e --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_06.expected @@ -0,0 +1,5 @@ +.=[] +.[0]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +.[1]="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +.[2]="ccccccccccccccccccccccc" +.[3]="dddddddddddddddddddddddddddddddddddddddddddddddddddd" diff --git a/cxx/jsoncpp/test/data/test_array_06.json b/cxx/jsoncpp/test/data/test_array_06.json new file mode 100644 index 0000000..7f6c516 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_06.json @@ -0,0 +1,4 @@ +[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "ccccccccccccccccccccccc", + "dddddddddddddddddddddddddddddddddddddddddddddddddddd" ] \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_array_07.expected b/cxx/jsoncpp/test/data/test_array_07.expected new file mode 100644 index 0000000..ee2fafc --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_07.expected @@ -0,0 +1,2122 @@ +.=[] +.[0]=[] +.[0][0]="A" +.[0][1]=0 +.[0][2]=1 +.[0][3]=2 +.[0][4]=3 +.[0][5]=4 +.[0][6]=5 +.[0][7]=6 +.[0][8]=7 +.[0][9]=8 +.[0][10]=9 +.[0][11]=10 +.[0][12]=11 +.[0][13]=12 +.[0][14]=13 +.[0][15]=14 +.[0][16]=15 +.[0][17]=16 +.[0][18]=17 +.[0][19]=18 +.[0][20]=19 +.[0][21]=20 +.[0][22]=21 +.[0][23]=22 +.[0][24]=23 +.[0][25]=24 +.[0][26]=25 +.[0][27]=26 +.[0][28]=27 +.[0][29]=28 +.[0][30]=29 +.[0][31]=30 +.[0][32]=31 +.[0][33]=32 +.[0][34]=33 +.[0][35]=34 +.[0][36]=35 +.[0][37]=36 +.[0][38]=37 +.[0][39]=38 +.[0][40]=39 +.[0][41]=40 +.[0][42]=41 +.[0][43]=42 +.[0][44]=43 +.[0][45]=44 +.[0][46]=45 +.[0][47]=46 +.[0][48]=47 +.[0][49]=48 +.[0][50]=49 +.[0][51]=50 +.[0][52]=51 +.[0][53]=52 +.[0][54]=53 +.[0][55]=54 +.[0][56]=55 +.[0][57]=56 +.[0][58]=57 +.[0][59]=58 +.[0][60]=59 +.[0][61]=60 +.[0][62]=61 +.[0][63]=62 +.[0][64]=63 +.[0][65]=64 +.[0][66]=65 +.[0][67]=66 +.[0][68]=67 +.[0][69]=68 +.[0][70]=69 +.[0][71]=70 +.[0][72]=71 +.[0][73]=72 +.[0][74]=73 +.[0][75]=74 +.[0][76]=75 +.[0][77]=76 +.[0][78]=77 +.[0][79]=78 +.[0][80]=79 +.[0][81]=80 +.[0][82]=81 +.[0][83]=82 +.[0][84]=83 +.[0][85]=84 +.[0][86]=85 +.[0][87]=86 +.[0][88]=87 +.[0][89]=88 +.[0][90]=89 +.[0][91]=90 +.[0][92]=91 +.[0][93]=92 +.[0][94]=93 +.[0][95]=94 +.[0][96]=95 +.[0][97]=96 +.[0][98]=97 +.[0][99]=98 +.[0][100]=99 +.[0][101]=100 +.[0][102]=101 +.[0][103]=102 +.[0][104]=103 +.[0][105]=104 +.[0][106]=105 +.[0][107]=106 +.[0][108]=107 +.[0][109]=108 +.[0][110]=109 +.[0][111]=110 +.[0][112]=111 +.[0][113]=112 +.[0][114]=113 +.[0][115]=114 +.[0][116]=115 +.[0][117]=116 +.[0][118]=117 +.[0][119]=118 +.[0][120]=119 +.[0][121]=120 +.[0][122]=121 +.[0][123]=122 +.[0][124]=123 +.[0][125]=124 +.[0][126]=125 +.[0][127]=126 +.[0][128]=127 +.[0][129]=128 +.[0][130]=129 +.[0][131]=130 +.[0][132]=131 +.[0][133]=132 +.[0][134]=133 +.[0][135]=134 +.[0][136]=135 +.[0][137]=136 +.[0][138]=137 +.[0][139]=138 +.[0][140]=139 +.[0][141]=140 +.[0][142]=141 +.[0][143]=142 +.[0][144]=143 +.[0][145]=144 +.[0][146]=145 +.[0][147]=146 +.[0][148]=147 +.[0][149]=148 +.[0][150]=149 +.[0][151]=150 +.[0][152]=151 +.[0][153]=152 +.[0][154]=153 +.[0][155]=154 +.[0][156]=155 +.[0][157]=156 +.[0][158]=157 +.[0][159]=158 +.[0][160]=159 +.[0][161]=160 +.[0][162]=161 +.[0][163]=162 +.[0][164]=163 +.[0][165]=164 +.[0][166]=165 +.[0][167]=166 +.[0][168]=167 +.[0][169]=168 +.[0][170]=169 +.[0][171]=170 +.[0][172]=171 +.[0][173]=172 +.[0][174]=173 +.[0][175]=174 +.[0][176]=175 +.[0][177]=176 +.[0][178]=177 +.[0][179]=178 +.[0][180]=179 +.[0][181]=180 +.[0][182]=181 +.[0][183]=182 +.[0][184]=183 +.[0][185]=184 +.[0][186]=185 +.[0][187]=186 +.[0][188]=187 +.[0][189]=188 +.[0][190]=189 +.[0][191]=190 +.[0][192]=191 +.[0][193]=192 +.[0][194]=193 +.[0][195]=194 +.[0][196]=195 +.[0][197]=196 +.[0][198]=197 +.[0][199]=198 +.[0][200]=199 +.[0][201]=200 +.[0][202]=201 +.[0][203]=202 +.[0][204]=203 +.[0][205]=204 +.[0][206]=205 +.[0][207]=206 +.[0][208]=207 +.[0][209]=208 +.[0][210]=209 +.[0][211]=210 +.[0][212]=211 +.[0][213]=212 +.[0][214]=213 +.[0][215]=214 +.[0][216]=215 +.[0][217]=216 +.[0][218]=217 +.[0][219]=218 +.[0][220]=219 +.[0][221]=220 +.[0][222]=221 +.[0][223]=222 +.[0][224]=223 +.[0][225]=224 +.[0][226]=225 +.[0][227]=226 +.[0][228]=227 +.[0][229]=228 +.[0][230]=229 +.[0][231]=230 +.[0][232]=231 +.[0][233]=232 +.[0][234]=233 +.[0][235]=234 +.[0][236]=235 +.[0][237]=236 +.[0][238]=237 +.[0][239]=238 +.[0][240]=239 +.[0][241]=240 +.[0][242]=241 +.[0][243]=242 +.[0][244]=243 +.[0][245]=244 +.[0][246]=245 +.[0][247]=246 +.[0][248]=247 +.[0][249]=248 +.[0][250]=249 +.[0][251]=250 +.[0][252]=251 +.[0][253]=252 +.[0][254]=253 +.[0][255]=254 +.[0][256]=255 +.[0][257]=256 +.[0][258]=257 +.[0][259]=258 +.[0][260]=259 +.[0][261]=260 +.[0][262]=261 +.[0][263]=262 +.[0][264]=263 +.[0][265]=264 +.[0][266]=265 +.[0][267]=266 +.[0][268]=267 +.[0][269]=268 +.[0][270]=269 +.[0][271]=270 +.[0][272]=271 +.[0][273]=272 +.[0][274]=273 +.[0][275]=274 +.[0][276]=275 +.[0][277]=276 +.[0][278]=277 +.[0][279]=278 +.[0][280]=279 +.[0][281]=280 +.[0][282]=281 +.[0][283]=282 +.[0][284]=283 +.[0][285]=284 +.[0][286]=285 +.[0][287]=286 +.[0][288]=287 +.[0][289]=288 +.[0][290]=289 +.[0][291]=290 +.[0][292]=291 +.[0][293]=292 +.[0][294]=293 +.[0][295]=294 +.[0][296]=295 +.[0][297]=296 +.[0][298]=297 +.[0][299]=298 +.[0][300]=299 +.[0][301]=300 +.[0][302]=301 +.[0][303]=302 +.[0][304]=303 +.[0][305]=304 +.[0][306]=305 +.[0][307]=306 +.[0][308]=307 +.[0][309]=308 +.[0][310]=309 +.[0][311]=310 +.[0][312]=311 +.[0][313]=312 +.[0][314]=313 +.[0][315]=314 +.[0][316]=315 +.[0][317]=316 +.[0][318]=317 +.[0][319]=318 +.[0][320]=319 +.[0][321]=320 +.[0][322]=321 +.[0][323]=322 +.[0][324]=323 +.[0][325]=324 +.[0][326]=325 +.[0][327]=326 +.[0][328]=327 +.[0][329]=328 +.[0][330]=329 +.[0][331]=330 +.[0][332]=331 +.[0][333]=332 +.[0][334]=333 +.[0][335]=334 +.[0][336]=335 +.[0][337]=336 +.[0][338]=337 +.[0][339]=338 +.[0][340]=339 +.[0][341]=340 +.[0][342]=341 +.[0][343]=342 +.[0][344]=343 +.[0][345]=344 +.[0][346]=345 +.[0][347]=346 +.[0][348]=347 +.[0][349]=348 +.[0][350]=349 +.[0][351]=350 +.[0][352]=351 +.[0][353]=352 +.[0][354]=353 +.[0][355]=354 +.[0][356]=355 +.[0][357]=356 +.[0][358]=357 +.[0][359]=358 +.[0][360]=359 +.[0][361]=360 +.[0][362]=361 +.[0][363]=362 +.[0][364]=363 +.[0][365]=364 +.[0][366]=365 +.[0][367]=366 +.[0][368]=367 +.[0][369]=368 +.[0][370]=369 +.[0][371]=370 +.[0][372]=371 +.[0][373]=372 +.[0][374]=373 +.[0][375]=374 +.[0][376]=375 +.[0][377]=376 +.[0][378]=377 +.[0][379]=378 +.[0][380]=379 +.[0][381]=380 +.[0][382]=381 +.[0][383]=382 +.[0][384]=383 +.[0][385]=384 +.[0][386]=385 +.[0][387]=386 +.[0][388]=387 +.[0][389]=388 +.[0][390]=389 +.[0][391]=390 +.[0][392]=391 +.[0][393]=392 +.[0][394]=393 +.[0][395]=394 +.[0][396]=395 +.[0][397]=396 +.[0][398]=397 +.[0][399]=398 +.[0][400]=399 +.[0][401]=400 +.[0][402]=401 +.[0][403]=402 +.[0][404]=403 +.[0][405]=404 +.[0][406]=405 +.[0][407]=406 +.[0][408]=407 +.[0][409]=408 +.[0][410]=409 +.[0][411]=410 +.[0][412]=411 +.[0][413]=412 +.[0][414]=413 +.[0][415]=414 +.[0][416]=415 +.[0][417]=416 +.[0][418]=417 +.[0][419]=418 +.[0][420]=419 +.[0][421]=420 +.[0][422]=421 +.[0][423]=422 +.[0][424]=423 +.[0][425]=424 +.[0][426]=425 +.[0][427]=426 +.[0][428]=427 +.[0][429]=428 +.[0][430]=429 +.[0][431]=430 +.[0][432]=431 +.[0][433]=432 +.[0][434]=433 +.[0][435]=434 +.[0][436]=435 +.[0][437]=436 +.[0][438]=437 +.[0][439]=438 +.[0][440]=439 +.[0][441]=440 +.[0][442]=441 +.[0][443]=442 +.[0][444]=443 +.[0][445]=444 +.[0][446]=445 +.[0][447]=446 +.[0][448]=447 +.[0][449]=448 +.[0][450]=449 +.[0][451]=450 +.[0][452]=451 +.[0][453]=452 +.[0][454]=453 +.[0][455]=454 +.[0][456]=455 +.[0][457]=456 +.[0][458]=457 +.[0][459]=458 +.[0][460]=459 +.[0][461]=460 +.[0][462]=461 +.[0][463]=462 +.[0][464]=463 +.[0][465]=464 +.[0][466]=465 +.[0][467]=466 +.[0][468]=467 +.[0][469]=468 +.[0][470]=469 +.[0][471]=470 +.[0][472]=471 +.[0][473]=472 +.[0][474]=473 +.[0][475]=474 +.[0][476]=475 +.[0][477]=476 +.[0][478]=477 +.[0][479]=478 +.[0][480]=479 +.[0][481]=480 +.[0][482]=481 +.[0][483]=482 +.[0][484]=483 +.[0][485]=484 +.[0][486]=485 +.[0][487]=486 +.[0][488]=487 +.[0][489]=488 +.[0][490]=489 +.[0][491]=490 +.[0][492]=491 +.[0][493]=492 +.[0][494]=493 +.[0][495]=494 +.[0][496]=495 +.[0][497]=496 +.[0][498]=497 +.[0][499]=498 +.[0][500]=499 +.[0][501]=500 +.[0][502]=501 +.[0][503]=502 +.[0][504]=503 +.[0][505]=504 +.[0][506]=505 +.[0][507]=506 +.[0][508]=507 +.[0][509]=508 +.[0][510]=509 +.[0][511]=510 +.[0][512]=511 +.[0][513]=512 +.[0][514]=513 +.[0][515]=514 +.[0][516]=515 +.[0][517]=516 +.[0][518]=517 +.[0][519]=518 +.[0][520]=519 +.[0][521]=520 +.[0][522]=521 +.[0][523]=522 +.[0][524]=523 +.[0][525]=524 +.[0][526]=525 +.[0][527]=526 +.[0][528]=527 +.[0][529]=528 +.[0][530]=529 +.[0][531]=530 +.[0][532]=531 +.[0][533]=532 +.[0][534]=533 +.[0][535]=534 +.[0][536]=535 +.[0][537]=536 +.[0][538]=537 +.[0][539]=538 +.[0][540]=539 +.[0][541]=540 +.[0][542]=541 +.[0][543]=542 +.[0][544]=543 +.[0][545]=544 +.[0][546]=545 +.[0][547]=546 +.[0][548]=547 +.[0][549]=548 +.[0][550]=549 +.[0][551]=550 +.[0][552]=551 +.[0][553]=552 +.[0][554]=553 +.[0][555]=554 +.[0][556]=555 +.[0][557]=556 +.[0][558]=557 +.[0][559]=558 +.[0][560]=559 +.[0][561]=560 +.[0][562]=561 +.[0][563]=562 +.[0][564]=563 +.[0][565]=564 +.[0][566]=565 +.[0][567]=566 +.[0][568]=567 +.[0][569]=568 +.[0][570]=569 +.[0][571]=570 +.[0][572]=571 +.[0][573]=572 +.[0][574]=573 +.[0][575]=574 +.[0][576]=575 +.[0][577]=576 +.[0][578]=577 +.[0][579]=578 +.[0][580]=579 +.[0][581]=580 +.[0][582]=581 +.[0][583]=582 +.[0][584]=583 +.[0][585]=584 +.[0][586]=585 +.[0][587]=586 +.[0][588]=587 +.[0][589]=588 +.[0][590]=589 +.[0][591]=590 +.[0][592]=591 +.[0][593]=592 +.[0][594]=593 +.[0][595]=594 +.[0][596]=595 +.[0][597]=596 +.[0][598]=597 +.[0][599]=598 +.[0][600]=599 +.[0][601]=600 +.[0][602]=601 +.[0][603]=602 +.[0][604]=603 +.[0][605]=604 +.[0][606]=605 +.[0][607]=606 +.[0][608]=607 +.[0][609]=608 +.[0][610]=609 +.[0][611]=610 +.[0][612]=611 +.[0][613]=612 +.[0][614]=613 +.[0][615]=614 +.[0][616]=615 +.[0][617]=616 +.[0][618]=617 +.[0][619]=618 +.[0][620]=619 +.[0][621]=620 +.[0][622]=621 +.[0][623]=622 +.[0][624]=623 +.[0][625]=624 +.[0][626]=625 +.[0][627]=626 +.[0][628]=627 +.[0][629]=628 +.[0][630]=629 +.[0][631]=630 +.[0][632]=631 +.[0][633]=632 +.[0][634]=633 +.[0][635]=634 +.[0][636]=635 +.[0][637]=636 +.[0][638]=637 +.[0][639]=638 +.[0][640]=639 +.[0][641]=640 +.[0][642]=641 +.[0][643]=642 +.[0][644]=643 +.[0][645]=644 +.[0][646]=645 +.[0][647]=646 +.[0][648]=647 +.[0][649]=648 +.[0][650]=649 +.[0][651]=650 +.[0][652]=651 +.[0][653]=652 +.[0][654]=653 +.[0][655]=654 +.[0][656]=655 +.[0][657]=656 +.[0][658]=657 +.[0][659]=658 +.[0][660]=659 +.[0][661]=660 +.[0][662]=661 +.[0][663]=662 +.[0][664]=663 +.[0][665]=664 +.[0][666]=665 +.[0][667]=666 +.[0][668]=667 +.[0][669]=668 +.[0][670]=669 +.[0][671]=670 +.[0][672]=671 +.[0][673]=672 +.[0][674]=673 +.[0][675]=674 +.[0][676]=675 +.[0][677]=676 +.[0][678]=677 +.[0][679]=678 +.[0][680]=679 +.[0][681]=680 +.[0][682]=681 +.[0][683]=682 +.[0][684]=683 +.[0][685]=684 +.[0][686]=685 +.[0][687]=686 +.[0][688]=687 +.[0][689]=688 +.[0][690]=689 +.[0][691]=690 +.[0][692]=691 +.[0][693]=692 +.[0][694]=693 +.[0][695]=694 +.[0][696]=695 +.[0][697]=696 +.[0][698]=697 +.[0][699]=698 +.[0][700]=699 +.[0][701]=700 +.[0][702]=701 +.[0][703]=702 +.[0][704]=703 +.[0][705]=704 +.[0][706]=705 +.[0][707]=706 +.[0][708]=707 +.[0][709]=708 +.[0][710]=709 +.[0][711]=710 +.[0][712]=711 +.[0][713]=712 +.[0][714]=713 +.[0][715]=714 +.[0][716]=715 +.[0][717]=716 +.[0][718]=717 +.[0][719]=718 +.[0][720]=719 +.[0][721]=720 +.[0][722]=721 +.[0][723]=722 +.[0][724]=723 +.[0][725]=724 +.[0][726]=725 +.[0][727]=726 +.[0][728]=727 +.[0][729]=728 +.[0][730]=729 +.[0][731]=730 +.[0][732]=731 +.[0][733]=732 +.[0][734]=733 +.[0][735]=734 +.[0][736]=735 +.[0][737]=736 +.[0][738]=737 +.[0][739]=738 +.[0][740]=739 +.[0][741]=740 +.[0][742]=741 +.[0][743]=742 +.[0][744]=743 +.[0][745]=744 +.[0][746]=745 +.[0][747]=746 +.[0][748]=747 +.[0][749]=748 +.[0][750]=749 +.[0][751]=750 +.[0][752]=751 +.[0][753]=752 +.[0][754]=753 +.[0][755]=754 +.[0][756]=755 +.[0][757]=756 +.[0][758]=757 +.[0][759]=758 +.[0][760]=759 +.[0][761]=760 +.[0][762]=761 +.[0][763]=762 +.[0][764]=763 +.[0][765]=764 +.[0][766]=765 +.[0][767]=766 +.[0][768]=767 +.[0][769]=768 +.[0][770]=769 +.[0][771]=770 +.[0][772]=771 +.[0][773]=772 +.[0][774]=773 +.[0][775]=774 +.[0][776]=775 +.[0][777]=776 +.[0][778]=777 +.[0][779]=778 +.[0][780]=779 +.[0][781]=780 +.[0][782]=781 +.[0][783]=782 +.[0][784]=783 +.[0][785]=784 +.[0][786]=785 +.[0][787]=786 +.[0][788]=787 +.[0][789]=788 +.[0][790]=789 +.[0][791]=790 +.[0][792]=791 +.[0][793]=792 +.[0][794]=793 +.[0][795]=794 +.[0][796]=795 +.[0][797]=796 +.[0][798]=797 +.[0][799]=798 +.[0][800]=799 +.[0][801]=800 +.[0][802]=801 +.[0][803]=802 +.[0][804]=803 +.[0][805]=804 +.[0][806]=805 +.[0][807]=806 +.[0][808]=807 +.[0][809]=808 +.[0][810]=809 +.[0][811]=810 +.[0][812]=811 +.[0][813]=812 +.[0][814]=813 +.[0][815]=814 +.[0][816]=815 +.[0][817]=816 +.[0][818]=817 +.[0][819]=818 +.[0][820]=819 +.[0][821]=820 +.[0][822]=821 +.[0][823]=822 +.[0][824]=823 +.[0][825]=824 +.[0][826]=825 +.[0][827]=826 +.[0][828]=827 +.[0][829]=828 +.[0][830]=829 +.[0][831]=830 +.[0][832]=831 +.[0][833]=832 +.[0][834]=833 +.[0][835]=834 +.[0][836]=835 +.[0][837]=836 +.[0][838]=837 +.[0][839]=838 +.[0][840]=839 +.[0][841]=840 +.[0][842]=841 +.[0][843]=842 +.[0][844]=843 +.[0][845]=844 +.[0][846]=845 +.[0][847]=846 +.[0][848]=847 +.[0][849]=848 +.[0][850]=849 +.[0][851]=850 +.[0][852]=851 +.[0][853]=852 +.[0][854]=853 +.[0][855]=854 +.[0][856]=855 +.[0][857]=856 +.[0][858]=857 +.[0][859]=858 +.[0][860]=859 +.[0][861]=860 +.[0][862]=861 +.[0][863]=862 +.[0][864]=863 +.[0][865]=864 +.[0][866]=865 +.[0][867]=866 +.[0][868]=867 +.[0][869]=868 +.[0][870]=869 +.[0][871]=870 +.[0][872]=871 +.[0][873]=872 +.[0][874]=873 +.[0][875]=874 +.[0][876]=875 +.[0][877]=876 +.[0][878]=877 +.[0][879]=878 +.[0][880]=879 +.[0][881]=880 +.[0][882]=881 +.[0][883]=882 +.[0][884]=883 +.[0][885]=884 +.[0][886]=885 +.[0][887]=886 +.[0][888]=887 +.[0][889]=888 +.[0][890]=889 +.[0][891]=890 +.[0][892]=891 +.[0][893]=892 +.[0][894]=893 +.[0][895]=894 +.[0][896]=895 +.[0][897]=896 +.[0][898]=897 +.[0][899]=898 +.[0][900]=899 +.[0][901]=900 +.[0][902]=901 +.[0][903]=902 +.[0][904]=903 +.[0][905]=904 +.[0][906]=905 +.[0][907]=906 +.[0][908]=907 +.[0][909]=908 +.[0][910]=909 +.[0][911]=910 +.[0][912]=911 +.[0][913]=912 +.[0][914]=913 +.[0][915]=914 +.[0][916]=915 +.[0][917]=916 +.[0][918]=917 +.[0][919]=918 +.[0][920]=919 +.[0][921]=920 +.[0][922]=921 +.[0][923]=922 +.[0][924]=923 +.[0][925]=924 +.[0][926]=925 +.[0][927]=926 +.[0][928]=927 +.[0][929]=928 +.[0][930]=929 +.[0][931]=930 +.[0][932]=931 +.[0][933]=932 +.[0][934]=933 +.[0][935]=934 +.[0][936]=935 +.[0][937]=936 +.[0][938]=937 +.[0][939]=938 +.[0][940]=939 +.[0][941]=940 +.[0][942]=941 +.[0][943]=942 +.[0][944]=943 +.[0][945]=944 +.[0][946]=945 +.[0][947]=946 +.[0][948]=947 +.[0][949]=948 +.[0][950]=949 +.[0][951]=950 +.[0][952]=951 +.[0][953]=952 +.[0][954]=953 +.[0][955]=954 +.[0][956]=955 +.[0][957]=956 +.[0][958]=957 +.[0][959]=958 +.[0][960]=959 +.[0][961]=960 +.[0][962]=961 +.[0][963]=962 +.[0][964]=963 +.[0][965]=964 +.[0][966]=965 +.[0][967]=966 +.[0][968]=967 +.[0][969]=968 +.[0][970]=969 +.[0][971]=970 +.[0][972]=971 +.[0][973]=972 +.[0][974]=973 +.[0][975]=974 +.[0][976]=975 +.[0][977]=976 +.[0][978]=977 +.[0][979]=978 +.[0][980]=979 +.[0][981]=980 +.[0][982]=981 +.[0][983]=982 +.[0][984]=983 +.[0][985]=984 +.[0][986]=985 +.[0][987]=986 +.[0][988]=987 +.[0][989]=988 +.[0][990]=989 +.[0][991]=990 +.[0][992]=991 +.[0][993]=992 +.[0][994]=993 +.[0][995]=994 +.[0][996]=995 +.[0][997]=996 +.[0][998]=997 +.[0][999]=998 +.[0][1000]=999 +.[0][1001]=1000 +.[0][1002]=1001 +.[0][1003]=1002 +.[0][1004]=1003 +.[0][1005]=1004 +.[0][1006]=1005 +.[0][1007]=1006 +.[0][1008]=1007 +.[0][1009]=1008 +.[0][1010]=1009 +.[0][1011]=1010 +.[0][1012]=1011 +.[0][1013]=1012 +.[0][1014]=1013 +.[0][1015]=1014 +.[0][1016]=1015 +.[0][1017]=1016 +.[0][1018]=1017 +.[0][1019]=1018 +.[0][1020]=1019 +.[0][1021]=1020 +.[0][1022]=1021 +.[0][1023]=1022 +.[0][1024]=1023 +.[0][1025]=1024 +.[0][1026]=1025 +.[0][1027]=1026 +.[0][1028]=1027 +.[0][1029]=1028 +.[0][1030]=1029 +.[0][1031]=1030 +.[0][1032]=1031 +.[0][1033]=1032 +.[0][1034]=1033 +.[0][1035]=1034 +.[0][1036]=1035 +.[0][1037]=1036 +.[0][1038]=1037 +.[0][1039]=1038 +.[0][1040]=1039 +.[0][1041]=1040 +.[0][1042]=1041 +.[0][1043]=1042 +.[0][1044]=1043 +.[0][1045]=1044 +.[0][1046]=1045 +.[0][1047]=1046 +.[0][1048]=1047 +.[0][1049]=1048 +.[0][1050]=1049 +.[0][1051]=1050 +.[0][1052]=1051 +.[0][1053]=1052 +.[0][1054]=1053 +.[0][1055]=1054 +.[0][1056]=1055 +.[0][1057]=1056 +.[0][1058]=1057 +.[0][1059]=1058 +.[0][1060]=1059 +.[0][1061]=1060 +.[0][1062]=1061 +.[0][1063]=1062 +.[0][1064]=1063 +.[0][1065]=1064 +.[0][1066]=1065 +.[0][1067]=1066 +.[0][1068]=1067 +.[0][1069]=1068 +.[0][1070]=1069 +.[0][1071]=1070 +.[0][1072]=1071 +.[0][1073]=1072 +.[0][1074]=1073 +.[0][1075]=1074 +.[0][1076]=1075 +.[0][1077]=1076 +.[0][1078]=1077 +.[0][1079]=1078 +.[0][1080]=1079 +.[0][1081]=1080 +.[0][1082]=1081 +.[0][1083]=1082 +.[0][1084]=1083 +.[0][1085]=1084 +.[0][1086]=1085 +.[0][1087]=1086 +.[0][1088]=1087 +.[0][1089]=1088 +.[0][1090]=1089 +.[0][1091]=1090 +.[0][1092]=1091 +.[0][1093]=1092 +.[0][1094]=1093 +.[0][1095]=1094 +.[0][1096]=1095 +.[0][1097]=1096 +.[0][1098]=1097 +.[0][1099]=1098 +.[0][1100]=1099 +.[0][1101]=1100 +.[0][1102]=1101 +.[0][1103]=1102 +.[0][1104]=1103 +.[0][1105]=1104 +.[0][1106]=1105 +.[0][1107]=1106 +.[0][1108]=1107 +.[0][1109]=1108 +.[0][1110]=1109 +.[0][1111]=1110 +.[0][1112]=1111 +.[0][1113]=1112 +.[0][1114]=1113 +.[0][1115]=1114 +.[0][1116]=1115 +.[0][1117]=1116 +.[0][1118]=1117 +.[0][1119]=1118 +.[0][1120]=1119 +.[0][1121]=1120 +.[0][1122]=1121 +.[0][1123]=1122 +.[0][1124]=1123 +.[0][1125]=1124 +.[0][1126]=1125 +.[0][1127]=1126 +.[0][1128]=1127 +.[0][1129]=1128 +.[0][1130]=1129 +.[0][1131]=1130 +.[0][1132]=1131 +.[0][1133]=1132 +.[0][1134]=1133 +.[0][1135]=1134 +.[0][1136]=1135 +.[0][1137]=1136 +.[0][1138]=1137 +.[0][1139]=1138 +.[0][1140]=1139 +.[0][1141]=1140 +.[0][1142]=1141 +.[0][1143]=1142 +.[0][1144]=1143 +.[0][1145]=1144 +.[0][1146]=1145 +.[0][1147]=1146 +.[0][1148]=1147 +.[0][1149]=1148 +.[0][1150]=1149 +.[0][1151]=1150 +.[0][1152]=1151 +.[0][1153]=1152 +.[0][1154]=1153 +.[0][1155]=1154 +.[0][1156]=1155 +.[0][1157]=1156 +.[0][1158]=1157 +.[0][1159]=1158 +.[0][1160]=1159 +.[0][1161]=1160 +.[0][1162]=1161 +.[0][1163]=1162 +.[0][1164]=1163 +.[0][1165]=1164 +.[0][1166]=1165 +.[0][1167]=1166 +.[0][1168]=1167 +.[0][1169]=1168 +.[0][1170]=1169 +.[0][1171]=1170 +.[0][1172]=1171 +.[0][1173]=1172 +.[0][1174]=1173 +.[0][1175]=1174 +.[0][1176]=1175 +.[0][1177]=1176 +.[0][1178]=1177 +.[0][1179]=1178 +.[0][1180]=1179 +.[0][1181]=1180 +.[0][1182]=1181 +.[0][1183]=1182 +.[0][1184]=1183 +.[0][1185]=1184 +.[0][1186]=1185 +.[0][1187]=1186 +.[0][1188]=1187 +.[0][1189]=1188 +.[0][1190]=1189 +.[0][1191]=1190 +.[0][1192]=1191 +.[0][1193]=1192 +.[0][1194]=1193 +.[0][1195]=1194 +.[0][1196]=1195 +.[0][1197]=1196 +.[0][1198]=1197 +.[0][1199]=1198 +.[0][1200]=1199 +.[0][1201]=1200 +.[0][1202]=1201 +.[0][1203]=1202 +.[0][1204]=1203 +.[0][1205]=1204 +.[0][1206]=1205 +.[0][1207]=1206 +.[0][1208]=1207 +.[0][1209]=1208 +.[0][1210]=1209 +.[0][1211]=1210 +.[0][1212]=1211 +.[0][1213]=1212 +.[0][1214]=1213 +.[0][1215]=1214 +.[0][1216]=1215 +.[0][1217]=1216 +.[0][1218]=1217 +.[0][1219]=1218 +.[0][1220]=1219 +.[0][1221]=1220 +.[0][1222]=1221 +.[0][1223]=1222 +.[0][1224]=1223 +.[0][1225]=1224 +.[0][1226]=1225 +.[0][1227]=1226 +.[0][1228]=1227 +.[0][1229]=1228 +.[0][1230]=1229 +.[0][1231]=1230 +.[0][1232]=1231 +.[0][1233]=1232 +.[0][1234]=1233 +.[0][1235]=1234 +.[0][1236]=1235 +.[0][1237]=1236 +.[0][1238]=1237 +.[0][1239]=1238 +.[0][1240]=1239 +.[0][1241]=1240 +.[0][1242]=1241 +.[0][1243]=1242 +.[0][1244]=1243 +.[0][1245]=1244 +.[0][1246]=1245 +.[0][1247]=1246 +.[0][1248]=1247 +.[0][1249]=1248 +.[0][1250]=1249 +.[0][1251]=1250 +.[0][1252]=1251 +.[0][1253]=1252 +.[0][1254]=1253 +.[0][1255]=1254 +.[0][1256]=1255 +.[0][1257]=1256 +.[0][1258]=1257 +.[0][1259]=1258 +.[0][1260]=1259 +.[0][1261]=1260 +.[0][1262]=1261 +.[0][1263]=1262 +.[0][1264]=1263 +.[0][1265]=1264 +.[0][1266]=1265 +.[0][1267]=1266 +.[0][1268]=1267 +.[0][1269]=1268 +.[0][1270]=1269 +.[0][1271]=1270 +.[0][1272]=1271 +.[0][1273]=1272 +.[0][1274]=1273 +.[0][1275]=1274 +.[0][1276]=1275 +.[0][1277]=1276 +.[0][1278]=1277 +.[0][1279]=1278 +.[0][1280]=1279 +.[0][1281]=1280 +.[0][1282]=1281 +.[0][1283]=1282 +.[0][1284]=1283 +.[0][1285]=1284 +.[0][1286]=1285 +.[0][1287]=1286 +.[0][1288]=1287 +.[0][1289]=1288 +.[0][1290]=1289 +.[0][1291]=1290 +.[0][1292]=1291 +.[0][1293]=1292 +.[0][1294]=1293 +.[0][1295]=1294 +.[0][1296]=1295 +.[0][1297]=1296 +.[0][1298]=1297 +.[0][1299]=1298 +.[0][1300]=1299 +.[0][1301]=1300 +.[0][1302]=1301 +.[0][1303]=1302 +.[0][1304]=1303 +.[0][1305]=1304 +.[0][1306]=1305 +.[0][1307]=1306 +.[0][1308]=1307 +.[0][1309]=1308 +.[0][1310]=1309 +.[0][1311]=1310 +.[0][1312]=1311 +.[0][1313]=1312 +.[0][1314]=1313 +.[0][1315]=1314 +.[0][1316]=1315 +.[0][1317]=1316 +.[0][1318]=1317 +.[0][1319]=1318 +.[0][1320]=1319 +.[0][1321]=1320 +.[0][1322]=1321 +.[0][1323]=1322 +.[0][1324]=1323 +.[0][1325]=1324 +.[0][1326]=1325 +.[0][1327]=1326 +.[0][1328]=1327 +.[0][1329]=1328 +.[0][1330]=1329 +.[0][1331]=1330 +.[0][1332]=1331 +.[0][1333]=1332 +.[0][1334]=1333 +.[0][1335]=1334 +.[0][1336]=1335 +.[0][1337]=1336 +.[0][1338]=1337 +.[0][1339]=1338 +.[0][1340]=1339 +.[0][1341]=1340 +.[0][1342]=1341 +.[0][1343]=1342 +.[0][1344]=1343 +.[0][1345]=1344 +.[0][1346]=1345 +.[0][1347]=1346 +.[0][1348]=1347 +.[0][1349]=1348 +.[0][1350]=1349 +.[0][1351]=1350 +.[0][1352]=1351 +.[0][1353]=1352 +.[0][1354]=1353 +.[0][1355]=1354 +.[0][1356]=1355 +.[0][1357]=1356 +.[0][1358]=1357 +.[0][1359]=1358 +.[0][1360]=1359 +.[0][1361]=1360 +.[0][1362]=1361 +.[0][1363]=1362 +.[0][1364]=1363 +.[0][1365]=1364 +.[0][1366]=1365 +.[0][1367]=1366 +.[0][1368]=1367 +.[0][1369]=1368 +.[0][1370]=1369 +.[0][1371]=1370 +.[0][1372]=1371 +.[0][1373]=1372 +.[0][1374]=1373 +.[0][1375]=1374 +.[0][1376]=1375 +.[0][1377]=1376 +.[0][1378]=1377 +.[0][1379]=1378 +.[0][1380]=1379 +.[0][1381]=1380 +.[0][1382]=1381 +.[0][1383]=1382 +.[0][1384]=1383 +.[0][1385]=1384 +.[0][1386]=1385 +.[0][1387]=1386 +.[0][1388]=1387 +.[0][1389]=1388 +.[0][1390]=1389 +.[0][1391]=1390 +.[0][1392]=1391 +.[0][1393]=1392 +.[0][1394]=1393 +.[0][1395]=1394 +.[0][1396]=1395 +.[0][1397]=1396 +.[0][1398]=1397 +.[0][1399]=1398 +.[0][1400]=1399 +.[0][1401]=1400 +.[0][1402]=1401 +.[0][1403]=1402 +.[0][1404]=1403 +.[0][1405]=1404 +.[0][1406]=1405 +.[0][1407]=1406 +.[0][1408]=1407 +.[0][1409]=1408 +.[0][1410]=1409 +.[0][1411]=1410 +.[0][1412]=1411 +.[0][1413]=1412 +.[0][1414]=1413 +.[0][1415]=1414 +.[0][1416]=1415 +.[0][1417]=1416 +.[0][1418]=1417 +.[0][1419]=1418 +.[0][1420]=1419 +.[0][1421]=1420 +.[0][1422]=1421 +.[0][1423]=1422 +.[0][1424]=1423 +.[0][1425]=1424 +.[0][1426]=1425 +.[0][1427]=1426 +.[0][1428]=1427 +.[0][1429]=1428 +.[0][1430]=1429 +.[0][1431]=1430 +.[0][1432]=1431 +.[0][1433]=1432 +.[0][1434]=1433 +.[0][1435]=1434 +.[0][1436]=1435 +.[0][1437]=1436 +.[0][1438]=1437 +.[0][1439]=1438 +.[0][1440]=1439 +.[0][1441]=1440 +.[0][1442]=1441 +.[0][1443]=1442 +.[0][1444]=1443 +.[0][1445]=1444 +.[0][1446]=1445 +.[0][1447]=1446 +.[0][1448]=1447 +.[0][1449]=1448 +.[0][1450]=1449 +.[0][1451]=1450 +.[0][1452]=1451 +.[0][1453]=1452 +.[0][1454]=1453 +.[0][1455]=1454 +.[0][1456]=1455 +.[0][1457]=1456 +.[0][1458]=1457 +.[0][1459]=1458 +.[0][1460]=1459 +.[0][1461]=1460 +.[0][1462]=1461 +.[0][1463]=1462 +.[0][1464]=1463 +.[0][1465]=1464 +.[0][1466]=1465 +.[0][1467]=1466 +.[0][1468]=1467 +.[0][1469]=1468 +.[0][1470]=1469 +.[0][1471]=1470 +.[0][1472]=1471 +.[0][1473]=1472 +.[0][1474]=1473 +.[0][1475]=1474 +.[0][1476]=1475 +.[0][1477]=1476 +.[0][1478]=1477 +.[0][1479]=1478 +.[0][1480]=1479 +.[0][1481]=1480 +.[0][1482]=1481 +.[0][1483]=1482 +.[0][1484]=1483 +.[0][1485]=1484 +.[0][1486]=1485 +.[0][1487]=1486 +.[0][1488]=1487 +.[0][1489]=1488 +.[0][1490]=1489 +.[0][1491]=1490 +.[0][1492]=1491 +.[0][1493]=1492 +.[0][1494]=1493 +.[0][1495]=1494 +.[0][1496]=1495 +.[0][1497]=1496 +.[0][1498]=1497 +.[0][1499]=1498 +.[0][1500]=1499 +.[0][1501]=1500 +.[0][1502]=1501 +.[0][1503]=1502 +.[0][1504]=1503 +.[0][1505]=1504 +.[0][1506]=1505 +.[0][1507]=1506 +.[0][1508]=1507 +.[0][1509]=1508 +.[0][1510]=1509 +.[0][1511]=1510 +.[0][1512]=1511 +.[0][1513]=1512 +.[0][1514]=1513 +.[0][1515]=1514 +.[0][1516]=1515 +.[0][1517]=1516 +.[0][1518]=1517 +.[0][1519]=1518 +.[0][1520]=1519 +.[0][1521]=1520 +.[0][1522]=1521 +.[0][1523]=1522 +.[0][1524]=1523 +.[0][1525]=1524 +.[0][1526]=1525 +.[0][1527]=1526 +.[0][1528]=1527 +.[0][1529]=1528 +.[0][1530]=1529 +.[0][1531]=1530 +.[0][1532]=1531 +.[0][1533]=1532 +.[0][1534]=1533 +.[0][1535]=1534 +.[0][1536]=1535 +.[0][1537]=1536 +.[0][1538]=1537 +.[0][1539]=1538 +.[0][1540]=1539 +.[0][1541]=1540 +.[0][1542]=1541 +.[0][1543]=1542 +.[0][1544]=1543 +.[0][1545]=1544 +.[0][1546]=1545 +.[0][1547]=1546 +.[0][1548]=1547 +.[0][1549]=1548 +.[0][1550]=1549 +.[0][1551]=1550 +.[0][1552]=1551 +.[0][1553]=1552 +.[0][1554]=1553 +.[0][1555]=1554 +.[0][1556]=1555 +.[0][1557]=1556 +.[0][1558]=1557 +.[0][1559]=1558 +.[0][1560]=1559 +.[0][1561]=1560 +.[0][1562]=1561 +.[0][1563]=1562 +.[0][1564]=1563 +.[0][1565]=1564 +.[0][1566]=1565 +.[0][1567]=1566 +.[0][1568]=1567 +.[0][1569]=1568 +.[0][1570]=1569 +.[0][1571]=1570 +.[0][1572]=1571 +.[0][1573]=1572 +.[0][1574]=1573 +.[0][1575]=1574 +.[0][1576]=1575 +.[0][1577]=1576 +.[0][1578]=1577 +.[0][1579]=1578 +.[0][1580]=1579 +.[0][1581]=1580 +.[0][1582]=1581 +.[0][1583]=1582 +.[0][1584]=1583 +.[0][1585]=1584 +.[0][1586]=1585 +.[0][1587]=1586 +.[0][1588]=1587 +.[0][1589]=1588 +.[0][1590]=1589 +.[0][1591]=1590 +.[0][1592]=1591 +.[0][1593]=1592 +.[0][1594]=1593 +.[0][1595]=1594 +.[0][1596]=1595 +.[0][1597]=1596 +.[0][1598]=1597 +.[0][1599]=1598 +.[0][1600]=1599 +.[0][1601]=1600 +.[0][1602]=1601 +.[0][1603]=1602 +.[0][1604]=1603 +.[0][1605]=1604 +.[0][1606]=1605 +.[0][1607]=1606 +.[0][1608]=1607 +.[0][1609]=1608 +.[0][1610]=1609 +.[0][1611]=1610 +.[0][1612]=1611 +.[0][1613]=1612 +.[0][1614]=1613 +.[0][1615]=1614 +.[0][1616]=1615 +.[0][1617]=1616 +.[0][1618]=1617 +.[0][1619]=1618 +.[0][1620]=1619 +.[0][1621]=1620 +.[0][1622]=1621 +.[0][1623]=1622 +.[0][1624]=1623 +.[0][1625]=1624 +.[0][1626]=1625 +.[0][1627]=1626 +.[0][1628]=1627 +.[0][1629]=1628 +.[0][1630]=1629 +.[0][1631]=1630 +.[0][1632]=1631 +.[0][1633]=1632 +.[0][1634]=1633 +.[0][1635]=1634 +.[0][1636]=1635 +.[0][1637]=1636 +.[0][1638]=1637 +.[0][1639]=1638 +.[0][1640]=1639 +.[0][1641]=1640 +.[0][1642]=1641 +.[0][1643]=1642 +.[0][1644]=1643 +.[0][1645]=1644 +.[0][1646]=1645 +.[0][1647]=1646 +.[0][1648]=1647 +.[0][1649]=1648 +.[0][1650]=1649 +.[0][1651]=1650 +.[0][1652]=1651 +.[0][1653]=1652 +.[0][1654]=1653 +.[0][1655]=1654 +.[0][1656]=1655 +.[0][1657]=1656 +.[0][1658]=1657 +.[0][1659]=1658 +.[0][1660]=1659 +.[0][1661]=1660 +.[0][1662]=1661 +.[0][1663]=1662 +.[0][1664]=1663 +.[0][1665]=1664 +.[0][1666]=1665 +.[0][1667]=1666 +.[0][1668]=1667 +.[0][1669]=1668 +.[0][1670]=1669 +.[0][1671]=1670 +.[0][1672]=1671 +.[0][1673]=1672 +.[0][1674]=1673 +.[0][1675]=1674 +.[0][1676]=1675 +.[0][1677]=1676 +.[0][1678]=1677 +.[0][1679]=1678 +.[0][1680]=1679 +.[0][1681]=1680 +.[0][1682]=1681 +.[0][1683]=1682 +.[0][1684]=1683 +.[0][1685]=1684 +.[0][1686]=1685 +.[0][1687]=1686 +.[0][1688]=1687 +.[0][1689]=1688 +.[0][1690]=1689 +.[0][1691]=1690 +.[0][1692]=1691 +.[0][1693]=1692 +.[0][1694]=1693 +.[0][1695]=1694 +.[0][1696]=1695 +.[0][1697]=1696 +.[0][1698]=1697 +.[0][1699]=1698 +.[0][1700]=1699 +.[0][1701]=1700 +.[0][1702]=1701 +.[0][1703]=1702 +.[0][1704]=1703 +.[0][1705]=1704 +.[0][1706]=1705 +.[0][1707]=1706 +.[0][1708]=1707 +.[0][1709]=1708 +.[0][1710]=1709 +.[0][1711]=1710 +.[0][1712]=1711 +.[0][1713]=1712 +.[0][1714]=1713 +.[0][1715]=1714 +.[0][1716]=1715 +.[0][1717]=1716 +.[0][1718]=1717 +.[0][1719]=1718 +.[0][1720]=1719 +.[0][1721]=1720 +.[0][1722]=1721 +.[0][1723]=1722 +.[0][1724]=1723 +.[0][1725]=1724 +.[0][1726]=1725 +.[0][1727]=1726 +.[0][1728]=1727 +.[0][1729]=1728 +.[0][1730]=1729 +.[0][1731]=1730 +.[0][1732]=1731 +.[0][1733]=1732 +.[0][1734]=1733 +.[0][1735]=1734 +.[0][1736]=1735 +.[0][1737]=1736 +.[0][1738]=1737 +.[0][1739]=1738 +.[0][1740]=1739 +.[0][1741]=1740 +.[0][1742]=1741 +.[0][1743]=1742 +.[0][1744]=1743 +.[0][1745]=1744 +.[0][1746]=1745 +.[0][1747]=1746 +.[0][1748]=1747 +.[0][1749]=1748 +.[0][1750]=1749 +.[0][1751]=1750 +.[0][1752]=1751 +.[0][1753]=1752 +.[0][1754]=1753 +.[0][1755]=1754 +.[0][1756]=1755 +.[0][1757]=1756 +.[0][1758]=1757 +.[0][1759]=1758 +.[0][1760]=1759 +.[0][1761]=1760 +.[0][1762]=1761 +.[0][1763]=1762 +.[0][1764]=1763 +.[0][1765]=1764 +.[0][1766]=1765 +.[0][1767]=1766 +.[0][1768]=1767 +.[0][1769]=1768 +.[0][1770]=1769 +.[0][1771]=1770 +.[0][1772]=1771 +.[0][1773]=1772 +.[0][1774]=1773 +.[0][1775]=1774 +.[0][1776]=1775 +.[0][1777]=1776 +.[0][1778]=1777 +.[0][1779]=1778 +.[0][1780]=1779 +.[0][1781]=1780 +.[0][1782]=1781 +.[0][1783]=1782 +.[0][1784]=1783 +.[0][1785]=1784 +.[0][1786]=1785 +.[0][1787]=1786 +.[0][1788]=1787 +.[0][1789]=1788 +.[0][1790]=1789 +.[0][1791]=1790 +.[0][1792]=1791 +.[0][1793]=1792 +.[0][1794]=1793 +.[0][1795]=1794 +.[0][1796]=1795 +.[0][1797]=1796 +.[0][1798]=1797 +.[0][1799]=1798 +.[0][1800]=1799 +.[0][1801]=1800 +.[0][1802]=1801 +.[0][1803]=1802 +.[0][1804]=1803 +.[0][1805]=1804 +.[0][1806]=1805 +.[0][1807]=1806 +.[0][1808]=1807 +.[0][1809]=1808 +.[0][1810]=1809 +.[0][1811]=1810 +.[0][1812]=1811 +.[0][1813]=1812 +.[0][1814]=1813 +.[0][1815]=1814 +.[0][1816]=1815 +.[0][1817]=1816 +.[0][1818]=1817 +.[0][1819]=1818 +.[0][1820]=1819 +.[0][1821]=1820 +.[0][1822]=1821 +.[0][1823]=1822 +.[0][1824]=1823 +.[0][1825]=1824 +.[0][1826]=1825 +.[0][1827]=1826 +.[0][1828]=1827 +.[0][1829]=1828 +.[0][1830]=1829 +.[0][1831]=1830 +.[0][1832]=1831 +.[0][1833]=1832 +.[0][1834]=1833 +.[0][1835]=1834 +.[0][1836]=1835 +.[0][1837]=1836 +.[0][1838]=1837 +.[0][1839]=1838 +.[0][1840]=1839 +.[0][1841]=1840 +.[0][1842]=1841 +.[0][1843]=1842 +.[0][1844]=1843 +.[0][1845]=1844 +.[0][1846]=1845 +.[0][1847]=1846 +.[0][1848]=1847 +.[0][1849]=1848 +.[0][1850]=1849 +.[0][1851]=1850 +.[0][1852]=1851 +.[0][1853]=1852 +.[0][1854]=1853 +.[0][1855]=1854 +.[0][1856]=1855 +.[0][1857]=1856 +.[0][1858]=1857 +.[0][1859]=1858 +.[0][1860]=1859 +.[0][1861]=1860 +.[0][1862]=1861 +.[0][1863]=1862 +.[0][1864]=1863 +.[0][1865]=1864 +.[0][1866]=1865 +.[0][1867]=1866 +.[0][1868]=1867 +.[0][1869]=1868 +.[0][1870]=1869 +.[0][1871]=1870 +.[0][1872]=1871 +.[0][1873]=1872 +.[0][1874]=1873 +.[0][1875]=1874 +.[0][1876]=1875 +.[0][1877]=1876 +.[0][1878]=1877 +.[0][1879]=1878 +.[0][1880]=1879 +.[0][1881]=1880 +.[0][1882]=1881 +.[0][1883]=1882 +.[0][1884]=1883 +.[0][1885]=1884 +.[0][1886]=1885 +.[0][1887]=1886 +.[0][1888]=1887 +.[0][1889]=1888 +.[0][1890]=1889 +.[0][1891]=1890 +.[0][1892]=1891 +.[0][1893]=1892 +.[0][1894]=1893 +.[0][1895]=1894 +.[0][1896]=1895 +.[0][1897]=1896 +.[0][1898]=1897 +.[0][1899]=1898 +.[0][1900]=1899 +.[0][1901]=1900 +.[0][1902]=1901 +.[0][1903]=1902 +.[0][1904]=1903 +.[0][1905]=1904 +.[0][1906]=1905 +.[0][1907]=1906 +.[0][1908]=1907 +.[0][1909]=1908 +.[0][1910]=1909 +.[0][1911]=1910 +.[0][1912]=1911 +.[0][1913]=1912 +.[0][1914]=1913 +.[0][1915]=1914 +.[0][1916]=1915 +.[0][1917]=1916 +.[0][1918]=1917 +.[0][1919]=1918 +.[0][1920]=1919 +.[0][1921]=1920 +.[0][1922]=1921 +.[0][1923]=1922 +.[0][1924]=1923 +.[0][1925]=1924 +.[0][1926]=1925 +.[0][1927]=1926 +.[0][1928]=1927 +.[0][1929]=1928 +.[0][1930]=1929 +.[0][1931]=1930 +.[0][1932]=1931 +.[0][1933]=1932 +.[0][1934]=1933 +.[0][1935]=1934 +.[0][1936]=1935 +.[0][1937]=1936 +.[0][1938]=1937 +.[0][1939]=1938 +.[0][1940]=1939 +.[0][1941]=1940 +.[0][1942]=1941 +.[0][1943]=1942 +.[0][1944]=1943 +.[0][1945]=1944 +.[0][1946]=1945 +.[0][1947]=1946 +.[0][1948]=1947 +.[0][1949]=1948 +.[0][1950]=1949 +.[0][1951]=1950 +.[0][1952]=1951 +.[0][1953]=1952 +.[0][1954]=1953 +.[0][1955]=1954 +.[0][1956]=1955 +.[0][1957]=1956 +.[0][1958]=1957 +.[0][1959]=1958 +.[0][1960]=1959 +.[0][1961]=1960 +.[0][1962]=1961 +.[0][1963]=1962 +.[0][1964]=1963 +.[0][1965]=1964 +.[0][1966]=1965 +.[0][1967]=1966 +.[0][1968]=1967 +.[0][1969]=1968 +.[0][1970]=1969 +.[0][1971]=1970 +.[0][1972]=1971 +.[0][1973]=1972 +.[0][1974]=1973 +.[0][1975]=1974 +.[0][1976]=1975 +.[0][1977]=1976 +.[0][1978]=1977 +.[0][1979]=1978 +.[0][1980]=1979 +.[0][1981]=1980 +.[0][1982]=1981 +.[0][1983]=1982 +.[0][1984]=1983 +.[0][1985]=1984 +.[0][1986]=1985 +.[0][1987]=1986 +.[0][1988]=1987 +.[0][1989]=1988 +.[0][1990]=1989 +.[0][1991]=1990 +.[0][1992]=1991 +.[0][1993]=1992 +.[0][1994]=1993 +.[0][1995]=1994 +.[0][1996]=1995 +.[0][1997]=1996 +.[0][1998]=1997 +.[0][1999]=1998 +.[0][2000]=1999 +.[0][2001]=2000 +.[0][2002]=2001 +.[0][2003]=2002 +.[0][2004]=2003 +.[0][2005]=2004 +.[0][2006]=2005 +.[0][2007]=2006 +.[0][2008]=2007 +.[0][2009]=2008 +.[0][2010]=2009 +.[0][2011]=2010 +.[0][2012]=2011 +.[0][2013]=2012 +.[0][2014]=2013 +.[0][2015]=2014 +.[0][2016]=2015 +.[0][2017]=2016 +.[0][2018]=2017 +.[0][2019]=2018 +.[0][2020]=2019 +.[0][2021]=2020 +.[0][2022]=2021 +.[0][2023]=2022 +.[0][2024]=2023 +.[0][2025]=2024 +.[0][2026]=2025 +.[0][2027]=2026 +.[0][2028]=2027 +.[0][2029]=2028 +.[0][2030]=2029 +.[0][2031]=2030 +.[0][2032]=2031 +.[0][2033]=2032 +.[0][2034]=2033 +.[0][2035]=2034 +.[0][2036]=2035 +.[0][2037]=2036 +.[0][2038]=2037 +.[0][2039]=2038 +.[0][2040]=2039 +.[0][2041]=2040 +.[0][2042]=2041 +.[0][2043]=2042 +.[0][2044]=2043 +.[0][2045]=2044 +.[0][2046]=2045 +.[0][2047]=2046 +.[0][2048]=2047 +.[0][2049]=2048 +.[0][2050]=2049 +.[0][2051]=2050 +.[0][2052]=2051 +.[0][2053]=2052 +.[0][2054]=2053 +.[0][2055]=2054 +.[0][2056]=2055 +.[0][2057]=2056 +.[0][2058]=2057 +.[0][2059]=2058 +.[0][2060]=2059 +.[0][2061]=2060 +.[0][2062]=2061 +.[0][2063]=2062 +.[0][2064]=2063 +.[0][2065]=2064 +.[0][2066]=2065 +.[0][2067]=2066 +.[0][2068]=2067 +.[0][2069]=2068 +.[0][2070]=2069 +.[0][2071]=2070 +.[0][2072]=2071 +.[0][2073]=2072 +.[0][2074]=2073 +.[0][2075]=2074 +.[0][2076]=2075 +.[0][2077]=2076 +.[0][2078]=2077 +.[0][2079]=2078 +.[0][2080]=2079 +.[0][2081]=2080 +.[0][2082]=2081 +.[0][2083]=2082 +.[0][2084]=2083 +.[0][2085]=2084 +.[0][2086]=2085 +.[0][2087]=2086 +.[0][2088]=2087 +.[0][2089]=2088 +.[0][2090]=2089 +.[0][2091]=2090 +.[0][2092]=2091 +.[0][2093]=2092 +.[0][2094]=2093 +.[0][2095]=2094 +.[0][2096]=2095 +.[0][2097]=2096 +.[0][2098]=2097 +.[0][2099]=2098 +.[0][2100]=2099 +.[0][2101]=2100 +.[0][2102]=2101 +.[0][2103]=2102 +.[0][2104]=2103 +.[0][2105]=2104 +.[0][2106]=2105 +.[0][2107]=2106 +.[0][2108]=2107 +.[0][2109]=2108 +.[0][2110]=2109 +.[0][2111]=2110 +.[0][2112]=2111 +.[0][2113]=2112 +.[0][2114]=2113 +.[0][2115]=2114 +.[0][2116]=2115 +.[0][2117]=2116 +.[0][2118]=2117 +.[0][2119]=2118 diff --git a/cxx/jsoncpp/test/data/test_array_07.json b/cxx/jsoncpp/test/data/test_array_07.json new file mode 100644 index 0000000..e4ab4cd --- /dev/null +++ b/cxx/jsoncpp/test/data/test_array_07.json @@ -0,0 +1,2 @@ +[["A",0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118] +] \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_basic_01.expected b/cxx/jsoncpp/test/data/test_basic_01.expected new file mode 100644 index 0000000..d761fce --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_01.expected @@ -0,0 +1 @@ +.=123456789 diff --git a/cxx/jsoncpp/test/data/test_basic_01.json b/cxx/jsoncpp/test/data/test_basic_01.json new file mode 100644 index 0000000..11f11f9 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_01.json @@ -0,0 +1 @@ +0123456789 diff --git a/cxx/jsoncpp/test/data/test_basic_02.expected b/cxx/jsoncpp/test/data/test_basic_02.expected new file mode 100644 index 0000000..650e37c --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_02.expected @@ -0,0 +1 @@ +.=-123456789 diff --git a/cxx/jsoncpp/test/data/test_basic_02.json b/cxx/jsoncpp/test/data/test_basic_02.json new file mode 100644 index 0000000..bf11bce --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_02.json @@ -0,0 +1 @@ +-0123456789 diff --git a/cxx/jsoncpp/test/data/test_basic_03.expected b/cxx/jsoncpp/test/data/test_basic_03.expected new file mode 100644 index 0000000..1da2d39 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_03.expected @@ -0,0 +1,3 @@ +.=1.2345678 + + diff --git a/cxx/jsoncpp/test/data/test_basic_03.json b/cxx/jsoncpp/test/data/test_basic_03.json new file mode 100644 index 0000000..a92b6bd --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_03.json @@ -0,0 +1,3 @@ +1.2345678 + + diff --git a/cxx/jsoncpp/test/data/test_basic_04.expected b/cxx/jsoncpp/test/data/test_basic_04.expected new file mode 100644 index 0000000..013f424 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_04.expected @@ -0,0 +1,2 @@ +.="abcdef" + diff --git a/cxx/jsoncpp/test/data/test_basic_04.json b/cxx/jsoncpp/test/data/test_basic_04.json new file mode 100644 index 0000000..17eeb99 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_04.json @@ -0,0 +1,2 @@ +"abcdef" + diff --git a/cxx/jsoncpp/test/data/test_basic_05.expected b/cxx/jsoncpp/test/data/test_basic_05.expected new file mode 100644 index 0000000..c8db822 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_05.expected @@ -0,0 +1,2 @@ +.=null + diff --git a/cxx/jsoncpp/test/data/test_basic_05.json b/cxx/jsoncpp/test/data/test_basic_05.json new file mode 100644 index 0000000..d0aaea2 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_05.json @@ -0,0 +1,2 @@ +null + diff --git a/cxx/jsoncpp/test/data/test_basic_06.expected b/cxx/jsoncpp/test/data/test_basic_06.expected new file mode 100644 index 0000000..49be55a --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_06.expected @@ -0,0 +1,2 @@ +.=true + diff --git a/cxx/jsoncpp/test/data/test_basic_06.json b/cxx/jsoncpp/test/data/test_basic_06.json new file mode 100644 index 0000000..7eead1e --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_06.json @@ -0,0 +1,2 @@ +true + diff --git a/cxx/jsoncpp/test/data/test_basic_07.expected b/cxx/jsoncpp/test/data/test_basic_07.expected new file mode 100644 index 0000000..fe55a6a --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_07.expected @@ -0,0 +1,2 @@ +.=false + diff --git a/cxx/jsoncpp/test/data/test_basic_07.json b/cxx/jsoncpp/test/data/test_basic_07.json new file mode 100644 index 0000000..a864bc4 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_07.json @@ -0,0 +1,2 @@ +false + diff --git a/cxx/jsoncpp/test/data/test_basic_08.expected b/cxx/jsoncpp/test/data/test_basic_08.expected new file mode 100644 index 0000000..caf5352 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_08.expected @@ -0,0 +1,3 @@ +// C++ style comment +.=null + diff --git a/cxx/jsoncpp/test/data/test_basic_08.json b/cxx/jsoncpp/test/data/test_basic_08.json new file mode 100644 index 0000000..fd78837 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_08.json @@ -0,0 +1,3 @@ +// C++ style comment +null + diff --git a/cxx/jsoncpp/test/data/test_basic_09.expected b/cxx/jsoncpp/test/data/test_basic_09.expected new file mode 100644 index 0000000..8b129da --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_09.expected @@ -0,0 +1,4 @@ +/* C style comment + */ +.=null + diff --git a/cxx/jsoncpp/test/data/test_basic_09.json b/cxx/jsoncpp/test/data/test_basic_09.json new file mode 100644 index 0000000..fc95f0f --- /dev/null +++ b/cxx/jsoncpp/test/data/test_basic_09.json @@ -0,0 +1,4 @@ +/* C style comment + */ +null + diff --git a/cxx/jsoncpp/test/data/test_comment_00.expected b/cxx/jsoncpp/test/data/test_comment_00.expected new file mode 100644 index 0000000..284a797 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_comment_00.expected @@ -0,0 +1,4 @@ +// Comment for array +.=[] +// Comment within array +.[0]="one-element" diff --git a/cxx/jsoncpp/test/data/test_comment_00.json b/cxx/jsoncpp/test/data/test_comment_00.json new file mode 100644 index 0000000..4df577a --- /dev/null +++ b/cxx/jsoncpp/test/data/test_comment_00.json @@ -0,0 +1,5 @@ +// Comment for array +[ + // Comment within array + "one-element" +] diff --git a/cxx/jsoncpp/test/data/test_comment_01.expected b/cxx/jsoncpp/test/data/test_comment_01.expected new file mode 100644 index 0000000..1ed01ba --- /dev/null +++ b/cxx/jsoncpp/test/data/test_comment_01.expected @@ -0,0 +1,10 @@ +.={} +// Comment for array +.test=[] +// Comment within array +.test[0]={} +.test[0].a="aaa" +.test[1]={} +.test[1].b="bbb" +.test[2]={} +.test[2].c="ccc" diff --git a/cxx/jsoncpp/test/data/test_comment_01.json b/cxx/jsoncpp/test/data/test_comment_01.json new file mode 100644 index 0000000..6defe40 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_comment_01.json @@ -0,0 +1,10 @@ +{ + "test": + // Comment for array + [ + // Comment within array + { "a" : "aaa" }, // Comment for a + { "b" : "bbb" }, // Comment for b + { "c" : "ccc" } // Comment for c + ] +} diff --git a/cxx/jsoncpp/test/data/test_comment_02.expected b/cxx/jsoncpp/test/data/test_comment_02.expected new file mode 100644 index 0000000..8986dba --- /dev/null +++ b/cxx/jsoncpp/test/data/test_comment_02.expected @@ -0,0 +1,23 @@ +.={} +/* C-style comment + + C-style-2 comment */ +.c-test={} +.c-test.a=1 +/* Internal comment c-style */ +.c-test.b=2 +// C++-style comment +.cpp-test={} +// Multiline comment cpp-style +// Second line +.cpp-test.c=3 +// Comment before double +.cpp-test.d=4.1 +// Comment before string +.cpp-test.e="e-string" +// Comment before true +.cpp-test.f=true +// Comment before false +.cpp-test.g=false +// Comment before null +.cpp-test.h=null diff --git a/cxx/jsoncpp/test/data/test_comment_02.json b/cxx/jsoncpp/test/data/test_comment_02.json new file mode 100644 index 0000000..f5042e0 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_comment_02.json @@ -0,0 +1,26 @@ +{ + /* C-style comment + + C-style-2 comment */ + "c-test" : { + "a" : 1, + /* Internal comment c-style */ + "b" : 2 + }, + // C++-style comment + "cpp-test" : { + // Multiline comment cpp-style + // Second line + "c" : 3, + // Comment before double + "d" : 4.1, + // Comment before string + "e" : "e-string", + // Comment before true + "f" : true, + // Comment before false + "g" : false, + // Comment before null + "h" : null + } +} diff --git a/cxx/jsoncpp/test/data/test_complex_01.expected b/cxx/jsoncpp/test/data/test_complex_01.expected new file mode 100644 index 0000000..7573c88 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_complex_01.expected @@ -0,0 +1,20 @@ +.={} +.attribute=[] +.attribute[0]="random" +.attribute[1]="short" +.attribute[2]="bold" +.attribute[3]=12 +.attribute[4]={} +.attribute[4].height=7 +.attribute[4].width=64 +.count=1234 +.name={} +.name.aka="T.E.S.T." +.name.id=123987 +.test={} +.test.1={} +.test.1.2={} +.test.1.2.3={} +.test.1.2.3.coord=[] +.test.1.2.3.coord[0]=1 +.test.1.2.3.coord[1]=2 diff --git a/cxx/jsoncpp/test/data/test_complex_01.json b/cxx/jsoncpp/test/data/test_complex_01.json new file mode 100644 index 0000000..cc0f30f --- /dev/null +++ b/cxx/jsoncpp/test/data/test_complex_01.json @@ -0,0 +1,17 @@ +{ + "count" : 1234, + "name" : { "aka" : "T.E.S.T.", "id" : 123987 }, + "attribute" : [ + "random", + "short", + "bold", + 12, + { "height" : 7, "width" : 64 } + ], + "test": { "1" : + { "2" : + { "3" : { "coord" : [ 1,2] } + } + } + } +} diff --git a/cxx/jsoncpp/test/data/test_integer_01.expected b/cxx/jsoncpp/test/data/test_integer_01.expected new file mode 100644 index 0000000..463e149 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_01.expected @@ -0,0 +1,2 @@ +// Max signed integer +.=2147483647 diff --git a/cxx/jsoncpp/test/data/test_integer_01.json b/cxx/jsoncpp/test/data/test_integer_01.json new file mode 100644 index 0000000..5ab12ff --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_01.json @@ -0,0 +1,2 @@ +// Max signed integer +2147483647 diff --git a/cxx/jsoncpp/test/data/test_integer_02.expected b/cxx/jsoncpp/test/data/test_integer_02.expected new file mode 100644 index 0000000..0773e08 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_02.expected @@ -0,0 +1,2 @@ +// Min signed integer +.=-2147483648 diff --git a/cxx/jsoncpp/test/data/test_integer_02.json b/cxx/jsoncpp/test/data/test_integer_02.json new file mode 100644 index 0000000..056c850 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_02.json @@ -0,0 +1,2 @@ +// Min signed integer +-2147483648 diff --git a/cxx/jsoncpp/test/data/test_integer_03.expected b/cxx/jsoncpp/test/data/test_integer_03.expected new file mode 100644 index 0000000..c7efff7 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_03.expected @@ -0,0 +1,2 @@ +// Max unsigned integer +.=4294967295 diff --git a/cxx/jsoncpp/test/data/test_integer_03.json b/cxx/jsoncpp/test/data/test_integer_03.json new file mode 100644 index 0000000..12ef3fb --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_03.json @@ -0,0 +1,2 @@ +// Max unsigned integer +4294967295 diff --git a/cxx/jsoncpp/test/data/test_integer_04.expected b/cxx/jsoncpp/test/data/test_integer_04.expected new file mode 100644 index 0000000..39f8567 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_04.expected @@ -0,0 +1,3 @@ +// Min unsigned integer +.=0 + diff --git a/cxx/jsoncpp/test/data/test_integer_04.json b/cxx/jsoncpp/test/data/test_integer_04.json new file mode 100644 index 0000000..bf81499 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_04.json @@ -0,0 +1,3 @@ +// Min unsigned integer +0 + diff --git a/cxx/jsoncpp/test/data/test_integer_05.expected b/cxx/jsoncpp/test/data/test_integer_05.expected new file mode 100644 index 0000000..0caea9d --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_05.expected @@ -0,0 +1,2 @@ +.=1 + diff --git a/cxx/jsoncpp/test/data/test_integer_05.json b/cxx/jsoncpp/test/data/test_integer_05.json new file mode 100644 index 0000000..d474e1b --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_05.json @@ -0,0 +1,2 @@ +1 + diff --git a/cxx/jsoncpp/test/data/test_integer_06_64bits.expected b/cxx/jsoncpp/test/data/test_integer_06_64bits.expected new file mode 100644 index 0000000..131b085 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_06_64bits.expected @@ -0,0 +1 @@ +.=9223372036854775808 diff --git a/cxx/jsoncpp/test/data/test_integer_06_64bits.json b/cxx/jsoncpp/test/data/test_integer_06_64bits.json new file mode 100644 index 0000000..cfedfe5 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_06_64bits.json @@ -0,0 +1,2 @@ +9223372036854775808 + diff --git a/cxx/jsoncpp/test/data/test_integer_07_64bits.expected b/cxx/jsoncpp/test/data/test_integer_07_64bits.expected new file mode 100644 index 0000000..c8524a3 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_07_64bits.expected @@ -0,0 +1 @@ +.=-9223372036854775808 diff --git a/cxx/jsoncpp/test/data/test_integer_07_64bits.json b/cxx/jsoncpp/test/data/test_integer_07_64bits.json new file mode 100644 index 0000000..a964ad2 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_07_64bits.json @@ -0,0 +1,2 @@ +-9223372036854775808 + diff --git a/cxx/jsoncpp/test/data/test_integer_08_64bits.expected b/cxx/jsoncpp/test/data/test_integer_08_64bits.expected new file mode 100644 index 0000000..321bba5 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_08_64bits.expected @@ -0,0 +1 @@ +.=18446744073709551615 diff --git a/cxx/jsoncpp/test/data/test_integer_08_64bits.json b/cxx/jsoncpp/test/data/test_integer_08_64bits.json new file mode 100644 index 0000000..4c15a01 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_integer_08_64bits.json @@ -0,0 +1,2 @@ +18446744073709551615 + diff --git a/cxx/jsoncpp/test/data/test_large_01.expected b/cxx/jsoncpp/test/data/test_large_01.expected new file mode 100644 index 0000000..ee2fafc --- /dev/null +++ b/cxx/jsoncpp/test/data/test_large_01.expected @@ -0,0 +1,2122 @@ +.=[] +.[0]=[] +.[0][0]="A" +.[0][1]=0 +.[0][2]=1 +.[0][3]=2 +.[0][4]=3 +.[0][5]=4 +.[0][6]=5 +.[0][7]=6 +.[0][8]=7 +.[0][9]=8 +.[0][10]=9 +.[0][11]=10 +.[0][12]=11 +.[0][13]=12 +.[0][14]=13 +.[0][15]=14 +.[0][16]=15 +.[0][17]=16 +.[0][18]=17 +.[0][19]=18 +.[0][20]=19 +.[0][21]=20 +.[0][22]=21 +.[0][23]=22 +.[0][24]=23 +.[0][25]=24 +.[0][26]=25 +.[0][27]=26 +.[0][28]=27 +.[0][29]=28 +.[0][30]=29 +.[0][31]=30 +.[0][32]=31 +.[0][33]=32 +.[0][34]=33 +.[0][35]=34 +.[0][36]=35 +.[0][37]=36 +.[0][38]=37 +.[0][39]=38 +.[0][40]=39 +.[0][41]=40 +.[0][42]=41 +.[0][43]=42 +.[0][44]=43 +.[0][45]=44 +.[0][46]=45 +.[0][47]=46 +.[0][48]=47 +.[0][49]=48 +.[0][50]=49 +.[0][51]=50 +.[0][52]=51 +.[0][53]=52 +.[0][54]=53 +.[0][55]=54 +.[0][56]=55 +.[0][57]=56 +.[0][58]=57 +.[0][59]=58 +.[0][60]=59 +.[0][61]=60 +.[0][62]=61 +.[0][63]=62 +.[0][64]=63 +.[0][65]=64 +.[0][66]=65 +.[0][67]=66 +.[0][68]=67 +.[0][69]=68 +.[0][70]=69 +.[0][71]=70 +.[0][72]=71 +.[0][73]=72 +.[0][74]=73 +.[0][75]=74 +.[0][76]=75 +.[0][77]=76 +.[0][78]=77 +.[0][79]=78 +.[0][80]=79 +.[0][81]=80 +.[0][82]=81 +.[0][83]=82 +.[0][84]=83 +.[0][85]=84 +.[0][86]=85 +.[0][87]=86 +.[0][88]=87 +.[0][89]=88 +.[0][90]=89 +.[0][91]=90 +.[0][92]=91 +.[0][93]=92 +.[0][94]=93 +.[0][95]=94 +.[0][96]=95 +.[0][97]=96 +.[0][98]=97 +.[0][99]=98 +.[0][100]=99 +.[0][101]=100 +.[0][102]=101 +.[0][103]=102 +.[0][104]=103 +.[0][105]=104 +.[0][106]=105 +.[0][107]=106 +.[0][108]=107 +.[0][109]=108 +.[0][110]=109 +.[0][111]=110 +.[0][112]=111 +.[0][113]=112 +.[0][114]=113 +.[0][115]=114 +.[0][116]=115 +.[0][117]=116 +.[0][118]=117 +.[0][119]=118 +.[0][120]=119 +.[0][121]=120 +.[0][122]=121 +.[0][123]=122 +.[0][124]=123 +.[0][125]=124 +.[0][126]=125 +.[0][127]=126 +.[0][128]=127 +.[0][129]=128 +.[0][130]=129 +.[0][131]=130 +.[0][132]=131 +.[0][133]=132 +.[0][134]=133 +.[0][135]=134 +.[0][136]=135 +.[0][137]=136 +.[0][138]=137 +.[0][139]=138 +.[0][140]=139 +.[0][141]=140 +.[0][142]=141 +.[0][143]=142 +.[0][144]=143 +.[0][145]=144 +.[0][146]=145 +.[0][147]=146 +.[0][148]=147 +.[0][149]=148 +.[0][150]=149 +.[0][151]=150 +.[0][152]=151 +.[0][153]=152 +.[0][154]=153 +.[0][155]=154 +.[0][156]=155 +.[0][157]=156 +.[0][158]=157 +.[0][159]=158 +.[0][160]=159 +.[0][161]=160 +.[0][162]=161 +.[0][163]=162 +.[0][164]=163 +.[0][165]=164 +.[0][166]=165 +.[0][167]=166 +.[0][168]=167 +.[0][169]=168 +.[0][170]=169 +.[0][171]=170 +.[0][172]=171 +.[0][173]=172 +.[0][174]=173 +.[0][175]=174 +.[0][176]=175 +.[0][177]=176 +.[0][178]=177 +.[0][179]=178 +.[0][180]=179 +.[0][181]=180 +.[0][182]=181 +.[0][183]=182 +.[0][184]=183 +.[0][185]=184 +.[0][186]=185 +.[0][187]=186 +.[0][188]=187 +.[0][189]=188 +.[0][190]=189 +.[0][191]=190 +.[0][192]=191 +.[0][193]=192 +.[0][194]=193 +.[0][195]=194 +.[0][196]=195 +.[0][197]=196 +.[0][198]=197 +.[0][199]=198 +.[0][200]=199 +.[0][201]=200 +.[0][202]=201 +.[0][203]=202 +.[0][204]=203 +.[0][205]=204 +.[0][206]=205 +.[0][207]=206 +.[0][208]=207 +.[0][209]=208 +.[0][210]=209 +.[0][211]=210 +.[0][212]=211 +.[0][213]=212 +.[0][214]=213 +.[0][215]=214 +.[0][216]=215 +.[0][217]=216 +.[0][218]=217 +.[0][219]=218 +.[0][220]=219 +.[0][221]=220 +.[0][222]=221 +.[0][223]=222 +.[0][224]=223 +.[0][225]=224 +.[0][226]=225 +.[0][227]=226 +.[0][228]=227 +.[0][229]=228 +.[0][230]=229 +.[0][231]=230 +.[0][232]=231 +.[0][233]=232 +.[0][234]=233 +.[0][235]=234 +.[0][236]=235 +.[0][237]=236 +.[0][238]=237 +.[0][239]=238 +.[0][240]=239 +.[0][241]=240 +.[0][242]=241 +.[0][243]=242 +.[0][244]=243 +.[0][245]=244 +.[0][246]=245 +.[0][247]=246 +.[0][248]=247 +.[0][249]=248 +.[0][250]=249 +.[0][251]=250 +.[0][252]=251 +.[0][253]=252 +.[0][254]=253 +.[0][255]=254 +.[0][256]=255 +.[0][257]=256 +.[0][258]=257 +.[0][259]=258 +.[0][260]=259 +.[0][261]=260 +.[0][262]=261 +.[0][263]=262 +.[0][264]=263 +.[0][265]=264 +.[0][266]=265 +.[0][267]=266 +.[0][268]=267 +.[0][269]=268 +.[0][270]=269 +.[0][271]=270 +.[0][272]=271 +.[0][273]=272 +.[0][274]=273 +.[0][275]=274 +.[0][276]=275 +.[0][277]=276 +.[0][278]=277 +.[0][279]=278 +.[0][280]=279 +.[0][281]=280 +.[0][282]=281 +.[0][283]=282 +.[0][284]=283 +.[0][285]=284 +.[0][286]=285 +.[0][287]=286 +.[0][288]=287 +.[0][289]=288 +.[0][290]=289 +.[0][291]=290 +.[0][292]=291 +.[0][293]=292 +.[0][294]=293 +.[0][295]=294 +.[0][296]=295 +.[0][297]=296 +.[0][298]=297 +.[0][299]=298 +.[0][300]=299 +.[0][301]=300 +.[0][302]=301 +.[0][303]=302 +.[0][304]=303 +.[0][305]=304 +.[0][306]=305 +.[0][307]=306 +.[0][308]=307 +.[0][309]=308 +.[0][310]=309 +.[0][311]=310 +.[0][312]=311 +.[0][313]=312 +.[0][314]=313 +.[0][315]=314 +.[0][316]=315 +.[0][317]=316 +.[0][318]=317 +.[0][319]=318 +.[0][320]=319 +.[0][321]=320 +.[0][322]=321 +.[0][323]=322 +.[0][324]=323 +.[0][325]=324 +.[0][326]=325 +.[0][327]=326 +.[0][328]=327 +.[0][329]=328 +.[0][330]=329 +.[0][331]=330 +.[0][332]=331 +.[0][333]=332 +.[0][334]=333 +.[0][335]=334 +.[0][336]=335 +.[0][337]=336 +.[0][338]=337 +.[0][339]=338 +.[0][340]=339 +.[0][341]=340 +.[0][342]=341 +.[0][343]=342 +.[0][344]=343 +.[0][345]=344 +.[0][346]=345 +.[0][347]=346 +.[0][348]=347 +.[0][349]=348 +.[0][350]=349 +.[0][351]=350 +.[0][352]=351 +.[0][353]=352 +.[0][354]=353 +.[0][355]=354 +.[0][356]=355 +.[0][357]=356 +.[0][358]=357 +.[0][359]=358 +.[0][360]=359 +.[0][361]=360 +.[0][362]=361 +.[0][363]=362 +.[0][364]=363 +.[0][365]=364 +.[0][366]=365 +.[0][367]=366 +.[0][368]=367 +.[0][369]=368 +.[0][370]=369 +.[0][371]=370 +.[0][372]=371 +.[0][373]=372 +.[0][374]=373 +.[0][375]=374 +.[0][376]=375 +.[0][377]=376 +.[0][378]=377 +.[0][379]=378 +.[0][380]=379 +.[0][381]=380 +.[0][382]=381 +.[0][383]=382 +.[0][384]=383 +.[0][385]=384 +.[0][386]=385 +.[0][387]=386 +.[0][388]=387 +.[0][389]=388 +.[0][390]=389 +.[0][391]=390 +.[0][392]=391 +.[0][393]=392 +.[0][394]=393 +.[0][395]=394 +.[0][396]=395 +.[0][397]=396 +.[0][398]=397 +.[0][399]=398 +.[0][400]=399 +.[0][401]=400 +.[0][402]=401 +.[0][403]=402 +.[0][404]=403 +.[0][405]=404 +.[0][406]=405 +.[0][407]=406 +.[0][408]=407 +.[0][409]=408 +.[0][410]=409 +.[0][411]=410 +.[0][412]=411 +.[0][413]=412 +.[0][414]=413 +.[0][415]=414 +.[0][416]=415 +.[0][417]=416 +.[0][418]=417 +.[0][419]=418 +.[0][420]=419 +.[0][421]=420 +.[0][422]=421 +.[0][423]=422 +.[0][424]=423 +.[0][425]=424 +.[0][426]=425 +.[0][427]=426 +.[0][428]=427 +.[0][429]=428 +.[0][430]=429 +.[0][431]=430 +.[0][432]=431 +.[0][433]=432 +.[0][434]=433 +.[0][435]=434 +.[0][436]=435 +.[0][437]=436 +.[0][438]=437 +.[0][439]=438 +.[0][440]=439 +.[0][441]=440 +.[0][442]=441 +.[0][443]=442 +.[0][444]=443 +.[0][445]=444 +.[0][446]=445 +.[0][447]=446 +.[0][448]=447 +.[0][449]=448 +.[0][450]=449 +.[0][451]=450 +.[0][452]=451 +.[0][453]=452 +.[0][454]=453 +.[0][455]=454 +.[0][456]=455 +.[0][457]=456 +.[0][458]=457 +.[0][459]=458 +.[0][460]=459 +.[0][461]=460 +.[0][462]=461 +.[0][463]=462 +.[0][464]=463 +.[0][465]=464 +.[0][466]=465 +.[0][467]=466 +.[0][468]=467 +.[0][469]=468 +.[0][470]=469 +.[0][471]=470 +.[0][472]=471 +.[0][473]=472 +.[0][474]=473 +.[0][475]=474 +.[0][476]=475 +.[0][477]=476 +.[0][478]=477 +.[0][479]=478 +.[0][480]=479 +.[0][481]=480 +.[0][482]=481 +.[0][483]=482 +.[0][484]=483 +.[0][485]=484 +.[0][486]=485 +.[0][487]=486 +.[0][488]=487 +.[0][489]=488 +.[0][490]=489 +.[0][491]=490 +.[0][492]=491 +.[0][493]=492 +.[0][494]=493 +.[0][495]=494 +.[0][496]=495 +.[0][497]=496 +.[0][498]=497 +.[0][499]=498 +.[0][500]=499 +.[0][501]=500 +.[0][502]=501 +.[0][503]=502 +.[0][504]=503 +.[0][505]=504 +.[0][506]=505 +.[0][507]=506 +.[0][508]=507 +.[0][509]=508 +.[0][510]=509 +.[0][511]=510 +.[0][512]=511 +.[0][513]=512 +.[0][514]=513 +.[0][515]=514 +.[0][516]=515 +.[0][517]=516 +.[0][518]=517 +.[0][519]=518 +.[0][520]=519 +.[0][521]=520 +.[0][522]=521 +.[0][523]=522 +.[0][524]=523 +.[0][525]=524 +.[0][526]=525 +.[0][527]=526 +.[0][528]=527 +.[0][529]=528 +.[0][530]=529 +.[0][531]=530 +.[0][532]=531 +.[0][533]=532 +.[0][534]=533 +.[0][535]=534 +.[0][536]=535 +.[0][537]=536 +.[0][538]=537 +.[0][539]=538 +.[0][540]=539 +.[0][541]=540 +.[0][542]=541 +.[0][543]=542 +.[0][544]=543 +.[0][545]=544 +.[0][546]=545 +.[0][547]=546 +.[0][548]=547 +.[0][549]=548 +.[0][550]=549 +.[0][551]=550 +.[0][552]=551 +.[0][553]=552 +.[0][554]=553 +.[0][555]=554 +.[0][556]=555 +.[0][557]=556 +.[0][558]=557 +.[0][559]=558 +.[0][560]=559 +.[0][561]=560 +.[0][562]=561 +.[0][563]=562 +.[0][564]=563 +.[0][565]=564 +.[0][566]=565 +.[0][567]=566 +.[0][568]=567 +.[0][569]=568 +.[0][570]=569 +.[0][571]=570 +.[0][572]=571 +.[0][573]=572 +.[0][574]=573 +.[0][575]=574 +.[0][576]=575 +.[0][577]=576 +.[0][578]=577 +.[0][579]=578 +.[0][580]=579 +.[0][581]=580 +.[0][582]=581 +.[0][583]=582 +.[0][584]=583 +.[0][585]=584 +.[0][586]=585 +.[0][587]=586 +.[0][588]=587 +.[0][589]=588 +.[0][590]=589 +.[0][591]=590 +.[0][592]=591 +.[0][593]=592 +.[0][594]=593 +.[0][595]=594 +.[0][596]=595 +.[0][597]=596 +.[0][598]=597 +.[0][599]=598 +.[0][600]=599 +.[0][601]=600 +.[0][602]=601 +.[0][603]=602 +.[0][604]=603 +.[0][605]=604 +.[0][606]=605 +.[0][607]=606 +.[0][608]=607 +.[0][609]=608 +.[0][610]=609 +.[0][611]=610 +.[0][612]=611 +.[0][613]=612 +.[0][614]=613 +.[0][615]=614 +.[0][616]=615 +.[0][617]=616 +.[0][618]=617 +.[0][619]=618 +.[0][620]=619 +.[0][621]=620 +.[0][622]=621 +.[0][623]=622 +.[0][624]=623 +.[0][625]=624 +.[0][626]=625 +.[0][627]=626 +.[0][628]=627 +.[0][629]=628 +.[0][630]=629 +.[0][631]=630 +.[0][632]=631 +.[0][633]=632 +.[0][634]=633 +.[0][635]=634 +.[0][636]=635 +.[0][637]=636 +.[0][638]=637 +.[0][639]=638 +.[0][640]=639 +.[0][641]=640 +.[0][642]=641 +.[0][643]=642 +.[0][644]=643 +.[0][645]=644 +.[0][646]=645 +.[0][647]=646 +.[0][648]=647 +.[0][649]=648 +.[0][650]=649 +.[0][651]=650 +.[0][652]=651 +.[0][653]=652 +.[0][654]=653 +.[0][655]=654 +.[0][656]=655 +.[0][657]=656 +.[0][658]=657 +.[0][659]=658 +.[0][660]=659 +.[0][661]=660 +.[0][662]=661 +.[0][663]=662 +.[0][664]=663 +.[0][665]=664 +.[0][666]=665 +.[0][667]=666 +.[0][668]=667 +.[0][669]=668 +.[0][670]=669 +.[0][671]=670 +.[0][672]=671 +.[0][673]=672 +.[0][674]=673 +.[0][675]=674 +.[0][676]=675 +.[0][677]=676 +.[0][678]=677 +.[0][679]=678 +.[0][680]=679 +.[0][681]=680 +.[0][682]=681 +.[0][683]=682 +.[0][684]=683 +.[0][685]=684 +.[0][686]=685 +.[0][687]=686 +.[0][688]=687 +.[0][689]=688 +.[0][690]=689 +.[0][691]=690 +.[0][692]=691 +.[0][693]=692 +.[0][694]=693 +.[0][695]=694 +.[0][696]=695 +.[0][697]=696 +.[0][698]=697 +.[0][699]=698 +.[0][700]=699 +.[0][701]=700 +.[0][702]=701 +.[0][703]=702 +.[0][704]=703 +.[0][705]=704 +.[0][706]=705 +.[0][707]=706 +.[0][708]=707 +.[0][709]=708 +.[0][710]=709 +.[0][711]=710 +.[0][712]=711 +.[0][713]=712 +.[0][714]=713 +.[0][715]=714 +.[0][716]=715 +.[0][717]=716 +.[0][718]=717 +.[0][719]=718 +.[0][720]=719 +.[0][721]=720 +.[0][722]=721 +.[0][723]=722 +.[0][724]=723 +.[0][725]=724 +.[0][726]=725 +.[0][727]=726 +.[0][728]=727 +.[0][729]=728 +.[0][730]=729 +.[0][731]=730 +.[0][732]=731 +.[0][733]=732 +.[0][734]=733 +.[0][735]=734 +.[0][736]=735 +.[0][737]=736 +.[0][738]=737 +.[0][739]=738 +.[0][740]=739 +.[0][741]=740 +.[0][742]=741 +.[0][743]=742 +.[0][744]=743 +.[0][745]=744 +.[0][746]=745 +.[0][747]=746 +.[0][748]=747 +.[0][749]=748 +.[0][750]=749 +.[0][751]=750 +.[0][752]=751 +.[0][753]=752 +.[0][754]=753 +.[0][755]=754 +.[0][756]=755 +.[0][757]=756 +.[0][758]=757 +.[0][759]=758 +.[0][760]=759 +.[0][761]=760 +.[0][762]=761 +.[0][763]=762 +.[0][764]=763 +.[0][765]=764 +.[0][766]=765 +.[0][767]=766 +.[0][768]=767 +.[0][769]=768 +.[0][770]=769 +.[0][771]=770 +.[0][772]=771 +.[0][773]=772 +.[0][774]=773 +.[0][775]=774 +.[0][776]=775 +.[0][777]=776 +.[0][778]=777 +.[0][779]=778 +.[0][780]=779 +.[0][781]=780 +.[0][782]=781 +.[0][783]=782 +.[0][784]=783 +.[0][785]=784 +.[0][786]=785 +.[0][787]=786 +.[0][788]=787 +.[0][789]=788 +.[0][790]=789 +.[0][791]=790 +.[0][792]=791 +.[0][793]=792 +.[0][794]=793 +.[0][795]=794 +.[0][796]=795 +.[0][797]=796 +.[0][798]=797 +.[0][799]=798 +.[0][800]=799 +.[0][801]=800 +.[0][802]=801 +.[0][803]=802 +.[0][804]=803 +.[0][805]=804 +.[0][806]=805 +.[0][807]=806 +.[0][808]=807 +.[0][809]=808 +.[0][810]=809 +.[0][811]=810 +.[0][812]=811 +.[0][813]=812 +.[0][814]=813 +.[0][815]=814 +.[0][816]=815 +.[0][817]=816 +.[0][818]=817 +.[0][819]=818 +.[0][820]=819 +.[0][821]=820 +.[0][822]=821 +.[0][823]=822 +.[0][824]=823 +.[0][825]=824 +.[0][826]=825 +.[0][827]=826 +.[0][828]=827 +.[0][829]=828 +.[0][830]=829 +.[0][831]=830 +.[0][832]=831 +.[0][833]=832 +.[0][834]=833 +.[0][835]=834 +.[0][836]=835 +.[0][837]=836 +.[0][838]=837 +.[0][839]=838 +.[0][840]=839 +.[0][841]=840 +.[0][842]=841 +.[0][843]=842 +.[0][844]=843 +.[0][845]=844 +.[0][846]=845 +.[0][847]=846 +.[0][848]=847 +.[0][849]=848 +.[0][850]=849 +.[0][851]=850 +.[0][852]=851 +.[0][853]=852 +.[0][854]=853 +.[0][855]=854 +.[0][856]=855 +.[0][857]=856 +.[0][858]=857 +.[0][859]=858 +.[0][860]=859 +.[0][861]=860 +.[0][862]=861 +.[0][863]=862 +.[0][864]=863 +.[0][865]=864 +.[0][866]=865 +.[0][867]=866 +.[0][868]=867 +.[0][869]=868 +.[0][870]=869 +.[0][871]=870 +.[0][872]=871 +.[0][873]=872 +.[0][874]=873 +.[0][875]=874 +.[0][876]=875 +.[0][877]=876 +.[0][878]=877 +.[0][879]=878 +.[0][880]=879 +.[0][881]=880 +.[0][882]=881 +.[0][883]=882 +.[0][884]=883 +.[0][885]=884 +.[0][886]=885 +.[0][887]=886 +.[0][888]=887 +.[0][889]=888 +.[0][890]=889 +.[0][891]=890 +.[0][892]=891 +.[0][893]=892 +.[0][894]=893 +.[0][895]=894 +.[0][896]=895 +.[0][897]=896 +.[0][898]=897 +.[0][899]=898 +.[0][900]=899 +.[0][901]=900 +.[0][902]=901 +.[0][903]=902 +.[0][904]=903 +.[0][905]=904 +.[0][906]=905 +.[0][907]=906 +.[0][908]=907 +.[0][909]=908 +.[0][910]=909 +.[0][911]=910 +.[0][912]=911 +.[0][913]=912 +.[0][914]=913 +.[0][915]=914 +.[0][916]=915 +.[0][917]=916 +.[0][918]=917 +.[0][919]=918 +.[0][920]=919 +.[0][921]=920 +.[0][922]=921 +.[0][923]=922 +.[0][924]=923 +.[0][925]=924 +.[0][926]=925 +.[0][927]=926 +.[0][928]=927 +.[0][929]=928 +.[0][930]=929 +.[0][931]=930 +.[0][932]=931 +.[0][933]=932 +.[0][934]=933 +.[0][935]=934 +.[0][936]=935 +.[0][937]=936 +.[0][938]=937 +.[0][939]=938 +.[0][940]=939 +.[0][941]=940 +.[0][942]=941 +.[0][943]=942 +.[0][944]=943 +.[0][945]=944 +.[0][946]=945 +.[0][947]=946 +.[0][948]=947 +.[0][949]=948 +.[0][950]=949 +.[0][951]=950 +.[0][952]=951 +.[0][953]=952 +.[0][954]=953 +.[0][955]=954 +.[0][956]=955 +.[0][957]=956 +.[0][958]=957 +.[0][959]=958 +.[0][960]=959 +.[0][961]=960 +.[0][962]=961 +.[0][963]=962 +.[0][964]=963 +.[0][965]=964 +.[0][966]=965 +.[0][967]=966 +.[0][968]=967 +.[0][969]=968 +.[0][970]=969 +.[0][971]=970 +.[0][972]=971 +.[0][973]=972 +.[0][974]=973 +.[0][975]=974 +.[0][976]=975 +.[0][977]=976 +.[0][978]=977 +.[0][979]=978 +.[0][980]=979 +.[0][981]=980 +.[0][982]=981 +.[0][983]=982 +.[0][984]=983 +.[0][985]=984 +.[0][986]=985 +.[0][987]=986 +.[0][988]=987 +.[0][989]=988 +.[0][990]=989 +.[0][991]=990 +.[0][992]=991 +.[0][993]=992 +.[0][994]=993 +.[0][995]=994 +.[0][996]=995 +.[0][997]=996 +.[0][998]=997 +.[0][999]=998 +.[0][1000]=999 +.[0][1001]=1000 +.[0][1002]=1001 +.[0][1003]=1002 +.[0][1004]=1003 +.[0][1005]=1004 +.[0][1006]=1005 +.[0][1007]=1006 +.[0][1008]=1007 +.[0][1009]=1008 +.[0][1010]=1009 +.[0][1011]=1010 +.[0][1012]=1011 +.[0][1013]=1012 +.[0][1014]=1013 +.[0][1015]=1014 +.[0][1016]=1015 +.[0][1017]=1016 +.[0][1018]=1017 +.[0][1019]=1018 +.[0][1020]=1019 +.[0][1021]=1020 +.[0][1022]=1021 +.[0][1023]=1022 +.[0][1024]=1023 +.[0][1025]=1024 +.[0][1026]=1025 +.[0][1027]=1026 +.[0][1028]=1027 +.[0][1029]=1028 +.[0][1030]=1029 +.[0][1031]=1030 +.[0][1032]=1031 +.[0][1033]=1032 +.[0][1034]=1033 +.[0][1035]=1034 +.[0][1036]=1035 +.[0][1037]=1036 +.[0][1038]=1037 +.[0][1039]=1038 +.[0][1040]=1039 +.[0][1041]=1040 +.[0][1042]=1041 +.[0][1043]=1042 +.[0][1044]=1043 +.[0][1045]=1044 +.[0][1046]=1045 +.[0][1047]=1046 +.[0][1048]=1047 +.[0][1049]=1048 +.[0][1050]=1049 +.[0][1051]=1050 +.[0][1052]=1051 +.[0][1053]=1052 +.[0][1054]=1053 +.[0][1055]=1054 +.[0][1056]=1055 +.[0][1057]=1056 +.[0][1058]=1057 +.[0][1059]=1058 +.[0][1060]=1059 +.[0][1061]=1060 +.[0][1062]=1061 +.[0][1063]=1062 +.[0][1064]=1063 +.[0][1065]=1064 +.[0][1066]=1065 +.[0][1067]=1066 +.[0][1068]=1067 +.[0][1069]=1068 +.[0][1070]=1069 +.[0][1071]=1070 +.[0][1072]=1071 +.[0][1073]=1072 +.[0][1074]=1073 +.[0][1075]=1074 +.[0][1076]=1075 +.[0][1077]=1076 +.[0][1078]=1077 +.[0][1079]=1078 +.[0][1080]=1079 +.[0][1081]=1080 +.[0][1082]=1081 +.[0][1083]=1082 +.[0][1084]=1083 +.[0][1085]=1084 +.[0][1086]=1085 +.[0][1087]=1086 +.[0][1088]=1087 +.[0][1089]=1088 +.[0][1090]=1089 +.[0][1091]=1090 +.[0][1092]=1091 +.[0][1093]=1092 +.[0][1094]=1093 +.[0][1095]=1094 +.[0][1096]=1095 +.[0][1097]=1096 +.[0][1098]=1097 +.[0][1099]=1098 +.[0][1100]=1099 +.[0][1101]=1100 +.[0][1102]=1101 +.[0][1103]=1102 +.[0][1104]=1103 +.[0][1105]=1104 +.[0][1106]=1105 +.[0][1107]=1106 +.[0][1108]=1107 +.[0][1109]=1108 +.[0][1110]=1109 +.[0][1111]=1110 +.[0][1112]=1111 +.[0][1113]=1112 +.[0][1114]=1113 +.[0][1115]=1114 +.[0][1116]=1115 +.[0][1117]=1116 +.[0][1118]=1117 +.[0][1119]=1118 +.[0][1120]=1119 +.[0][1121]=1120 +.[0][1122]=1121 +.[0][1123]=1122 +.[0][1124]=1123 +.[0][1125]=1124 +.[0][1126]=1125 +.[0][1127]=1126 +.[0][1128]=1127 +.[0][1129]=1128 +.[0][1130]=1129 +.[0][1131]=1130 +.[0][1132]=1131 +.[0][1133]=1132 +.[0][1134]=1133 +.[0][1135]=1134 +.[0][1136]=1135 +.[0][1137]=1136 +.[0][1138]=1137 +.[0][1139]=1138 +.[0][1140]=1139 +.[0][1141]=1140 +.[0][1142]=1141 +.[0][1143]=1142 +.[0][1144]=1143 +.[0][1145]=1144 +.[0][1146]=1145 +.[0][1147]=1146 +.[0][1148]=1147 +.[0][1149]=1148 +.[0][1150]=1149 +.[0][1151]=1150 +.[0][1152]=1151 +.[0][1153]=1152 +.[0][1154]=1153 +.[0][1155]=1154 +.[0][1156]=1155 +.[0][1157]=1156 +.[0][1158]=1157 +.[0][1159]=1158 +.[0][1160]=1159 +.[0][1161]=1160 +.[0][1162]=1161 +.[0][1163]=1162 +.[0][1164]=1163 +.[0][1165]=1164 +.[0][1166]=1165 +.[0][1167]=1166 +.[0][1168]=1167 +.[0][1169]=1168 +.[0][1170]=1169 +.[0][1171]=1170 +.[0][1172]=1171 +.[0][1173]=1172 +.[0][1174]=1173 +.[0][1175]=1174 +.[0][1176]=1175 +.[0][1177]=1176 +.[0][1178]=1177 +.[0][1179]=1178 +.[0][1180]=1179 +.[0][1181]=1180 +.[0][1182]=1181 +.[0][1183]=1182 +.[0][1184]=1183 +.[0][1185]=1184 +.[0][1186]=1185 +.[0][1187]=1186 +.[0][1188]=1187 +.[0][1189]=1188 +.[0][1190]=1189 +.[0][1191]=1190 +.[0][1192]=1191 +.[0][1193]=1192 +.[0][1194]=1193 +.[0][1195]=1194 +.[0][1196]=1195 +.[0][1197]=1196 +.[0][1198]=1197 +.[0][1199]=1198 +.[0][1200]=1199 +.[0][1201]=1200 +.[0][1202]=1201 +.[0][1203]=1202 +.[0][1204]=1203 +.[0][1205]=1204 +.[0][1206]=1205 +.[0][1207]=1206 +.[0][1208]=1207 +.[0][1209]=1208 +.[0][1210]=1209 +.[0][1211]=1210 +.[0][1212]=1211 +.[0][1213]=1212 +.[0][1214]=1213 +.[0][1215]=1214 +.[0][1216]=1215 +.[0][1217]=1216 +.[0][1218]=1217 +.[0][1219]=1218 +.[0][1220]=1219 +.[0][1221]=1220 +.[0][1222]=1221 +.[0][1223]=1222 +.[0][1224]=1223 +.[0][1225]=1224 +.[0][1226]=1225 +.[0][1227]=1226 +.[0][1228]=1227 +.[0][1229]=1228 +.[0][1230]=1229 +.[0][1231]=1230 +.[0][1232]=1231 +.[0][1233]=1232 +.[0][1234]=1233 +.[0][1235]=1234 +.[0][1236]=1235 +.[0][1237]=1236 +.[0][1238]=1237 +.[0][1239]=1238 +.[0][1240]=1239 +.[0][1241]=1240 +.[0][1242]=1241 +.[0][1243]=1242 +.[0][1244]=1243 +.[0][1245]=1244 +.[0][1246]=1245 +.[0][1247]=1246 +.[0][1248]=1247 +.[0][1249]=1248 +.[0][1250]=1249 +.[0][1251]=1250 +.[0][1252]=1251 +.[0][1253]=1252 +.[0][1254]=1253 +.[0][1255]=1254 +.[0][1256]=1255 +.[0][1257]=1256 +.[0][1258]=1257 +.[0][1259]=1258 +.[0][1260]=1259 +.[0][1261]=1260 +.[0][1262]=1261 +.[0][1263]=1262 +.[0][1264]=1263 +.[0][1265]=1264 +.[0][1266]=1265 +.[0][1267]=1266 +.[0][1268]=1267 +.[0][1269]=1268 +.[0][1270]=1269 +.[0][1271]=1270 +.[0][1272]=1271 +.[0][1273]=1272 +.[0][1274]=1273 +.[0][1275]=1274 +.[0][1276]=1275 +.[0][1277]=1276 +.[0][1278]=1277 +.[0][1279]=1278 +.[0][1280]=1279 +.[0][1281]=1280 +.[0][1282]=1281 +.[0][1283]=1282 +.[0][1284]=1283 +.[0][1285]=1284 +.[0][1286]=1285 +.[0][1287]=1286 +.[0][1288]=1287 +.[0][1289]=1288 +.[0][1290]=1289 +.[0][1291]=1290 +.[0][1292]=1291 +.[0][1293]=1292 +.[0][1294]=1293 +.[0][1295]=1294 +.[0][1296]=1295 +.[0][1297]=1296 +.[0][1298]=1297 +.[0][1299]=1298 +.[0][1300]=1299 +.[0][1301]=1300 +.[0][1302]=1301 +.[0][1303]=1302 +.[0][1304]=1303 +.[0][1305]=1304 +.[0][1306]=1305 +.[0][1307]=1306 +.[0][1308]=1307 +.[0][1309]=1308 +.[0][1310]=1309 +.[0][1311]=1310 +.[0][1312]=1311 +.[0][1313]=1312 +.[0][1314]=1313 +.[0][1315]=1314 +.[0][1316]=1315 +.[0][1317]=1316 +.[0][1318]=1317 +.[0][1319]=1318 +.[0][1320]=1319 +.[0][1321]=1320 +.[0][1322]=1321 +.[0][1323]=1322 +.[0][1324]=1323 +.[0][1325]=1324 +.[0][1326]=1325 +.[0][1327]=1326 +.[0][1328]=1327 +.[0][1329]=1328 +.[0][1330]=1329 +.[0][1331]=1330 +.[0][1332]=1331 +.[0][1333]=1332 +.[0][1334]=1333 +.[0][1335]=1334 +.[0][1336]=1335 +.[0][1337]=1336 +.[0][1338]=1337 +.[0][1339]=1338 +.[0][1340]=1339 +.[0][1341]=1340 +.[0][1342]=1341 +.[0][1343]=1342 +.[0][1344]=1343 +.[0][1345]=1344 +.[0][1346]=1345 +.[0][1347]=1346 +.[0][1348]=1347 +.[0][1349]=1348 +.[0][1350]=1349 +.[0][1351]=1350 +.[0][1352]=1351 +.[0][1353]=1352 +.[0][1354]=1353 +.[0][1355]=1354 +.[0][1356]=1355 +.[0][1357]=1356 +.[0][1358]=1357 +.[0][1359]=1358 +.[0][1360]=1359 +.[0][1361]=1360 +.[0][1362]=1361 +.[0][1363]=1362 +.[0][1364]=1363 +.[0][1365]=1364 +.[0][1366]=1365 +.[0][1367]=1366 +.[0][1368]=1367 +.[0][1369]=1368 +.[0][1370]=1369 +.[0][1371]=1370 +.[0][1372]=1371 +.[0][1373]=1372 +.[0][1374]=1373 +.[0][1375]=1374 +.[0][1376]=1375 +.[0][1377]=1376 +.[0][1378]=1377 +.[0][1379]=1378 +.[0][1380]=1379 +.[0][1381]=1380 +.[0][1382]=1381 +.[0][1383]=1382 +.[0][1384]=1383 +.[0][1385]=1384 +.[0][1386]=1385 +.[0][1387]=1386 +.[0][1388]=1387 +.[0][1389]=1388 +.[0][1390]=1389 +.[0][1391]=1390 +.[0][1392]=1391 +.[0][1393]=1392 +.[0][1394]=1393 +.[0][1395]=1394 +.[0][1396]=1395 +.[0][1397]=1396 +.[0][1398]=1397 +.[0][1399]=1398 +.[0][1400]=1399 +.[0][1401]=1400 +.[0][1402]=1401 +.[0][1403]=1402 +.[0][1404]=1403 +.[0][1405]=1404 +.[0][1406]=1405 +.[0][1407]=1406 +.[0][1408]=1407 +.[0][1409]=1408 +.[0][1410]=1409 +.[0][1411]=1410 +.[0][1412]=1411 +.[0][1413]=1412 +.[0][1414]=1413 +.[0][1415]=1414 +.[0][1416]=1415 +.[0][1417]=1416 +.[0][1418]=1417 +.[0][1419]=1418 +.[0][1420]=1419 +.[0][1421]=1420 +.[0][1422]=1421 +.[0][1423]=1422 +.[0][1424]=1423 +.[0][1425]=1424 +.[0][1426]=1425 +.[0][1427]=1426 +.[0][1428]=1427 +.[0][1429]=1428 +.[0][1430]=1429 +.[0][1431]=1430 +.[0][1432]=1431 +.[0][1433]=1432 +.[0][1434]=1433 +.[0][1435]=1434 +.[0][1436]=1435 +.[0][1437]=1436 +.[0][1438]=1437 +.[0][1439]=1438 +.[0][1440]=1439 +.[0][1441]=1440 +.[0][1442]=1441 +.[0][1443]=1442 +.[0][1444]=1443 +.[0][1445]=1444 +.[0][1446]=1445 +.[0][1447]=1446 +.[0][1448]=1447 +.[0][1449]=1448 +.[0][1450]=1449 +.[0][1451]=1450 +.[0][1452]=1451 +.[0][1453]=1452 +.[0][1454]=1453 +.[0][1455]=1454 +.[0][1456]=1455 +.[0][1457]=1456 +.[0][1458]=1457 +.[0][1459]=1458 +.[0][1460]=1459 +.[0][1461]=1460 +.[0][1462]=1461 +.[0][1463]=1462 +.[0][1464]=1463 +.[0][1465]=1464 +.[0][1466]=1465 +.[0][1467]=1466 +.[0][1468]=1467 +.[0][1469]=1468 +.[0][1470]=1469 +.[0][1471]=1470 +.[0][1472]=1471 +.[0][1473]=1472 +.[0][1474]=1473 +.[0][1475]=1474 +.[0][1476]=1475 +.[0][1477]=1476 +.[0][1478]=1477 +.[0][1479]=1478 +.[0][1480]=1479 +.[0][1481]=1480 +.[0][1482]=1481 +.[0][1483]=1482 +.[0][1484]=1483 +.[0][1485]=1484 +.[0][1486]=1485 +.[0][1487]=1486 +.[0][1488]=1487 +.[0][1489]=1488 +.[0][1490]=1489 +.[0][1491]=1490 +.[0][1492]=1491 +.[0][1493]=1492 +.[0][1494]=1493 +.[0][1495]=1494 +.[0][1496]=1495 +.[0][1497]=1496 +.[0][1498]=1497 +.[0][1499]=1498 +.[0][1500]=1499 +.[0][1501]=1500 +.[0][1502]=1501 +.[0][1503]=1502 +.[0][1504]=1503 +.[0][1505]=1504 +.[0][1506]=1505 +.[0][1507]=1506 +.[0][1508]=1507 +.[0][1509]=1508 +.[0][1510]=1509 +.[0][1511]=1510 +.[0][1512]=1511 +.[0][1513]=1512 +.[0][1514]=1513 +.[0][1515]=1514 +.[0][1516]=1515 +.[0][1517]=1516 +.[0][1518]=1517 +.[0][1519]=1518 +.[0][1520]=1519 +.[0][1521]=1520 +.[0][1522]=1521 +.[0][1523]=1522 +.[0][1524]=1523 +.[0][1525]=1524 +.[0][1526]=1525 +.[0][1527]=1526 +.[0][1528]=1527 +.[0][1529]=1528 +.[0][1530]=1529 +.[0][1531]=1530 +.[0][1532]=1531 +.[0][1533]=1532 +.[0][1534]=1533 +.[0][1535]=1534 +.[0][1536]=1535 +.[0][1537]=1536 +.[0][1538]=1537 +.[0][1539]=1538 +.[0][1540]=1539 +.[0][1541]=1540 +.[0][1542]=1541 +.[0][1543]=1542 +.[0][1544]=1543 +.[0][1545]=1544 +.[0][1546]=1545 +.[0][1547]=1546 +.[0][1548]=1547 +.[0][1549]=1548 +.[0][1550]=1549 +.[0][1551]=1550 +.[0][1552]=1551 +.[0][1553]=1552 +.[0][1554]=1553 +.[0][1555]=1554 +.[0][1556]=1555 +.[0][1557]=1556 +.[0][1558]=1557 +.[0][1559]=1558 +.[0][1560]=1559 +.[0][1561]=1560 +.[0][1562]=1561 +.[0][1563]=1562 +.[0][1564]=1563 +.[0][1565]=1564 +.[0][1566]=1565 +.[0][1567]=1566 +.[0][1568]=1567 +.[0][1569]=1568 +.[0][1570]=1569 +.[0][1571]=1570 +.[0][1572]=1571 +.[0][1573]=1572 +.[0][1574]=1573 +.[0][1575]=1574 +.[0][1576]=1575 +.[0][1577]=1576 +.[0][1578]=1577 +.[0][1579]=1578 +.[0][1580]=1579 +.[0][1581]=1580 +.[0][1582]=1581 +.[0][1583]=1582 +.[0][1584]=1583 +.[0][1585]=1584 +.[0][1586]=1585 +.[0][1587]=1586 +.[0][1588]=1587 +.[0][1589]=1588 +.[0][1590]=1589 +.[0][1591]=1590 +.[0][1592]=1591 +.[0][1593]=1592 +.[0][1594]=1593 +.[0][1595]=1594 +.[0][1596]=1595 +.[0][1597]=1596 +.[0][1598]=1597 +.[0][1599]=1598 +.[0][1600]=1599 +.[0][1601]=1600 +.[0][1602]=1601 +.[0][1603]=1602 +.[0][1604]=1603 +.[0][1605]=1604 +.[0][1606]=1605 +.[0][1607]=1606 +.[0][1608]=1607 +.[0][1609]=1608 +.[0][1610]=1609 +.[0][1611]=1610 +.[0][1612]=1611 +.[0][1613]=1612 +.[0][1614]=1613 +.[0][1615]=1614 +.[0][1616]=1615 +.[0][1617]=1616 +.[0][1618]=1617 +.[0][1619]=1618 +.[0][1620]=1619 +.[0][1621]=1620 +.[0][1622]=1621 +.[0][1623]=1622 +.[0][1624]=1623 +.[0][1625]=1624 +.[0][1626]=1625 +.[0][1627]=1626 +.[0][1628]=1627 +.[0][1629]=1628 +.[0][1630]=1629 +.[0][1631]=1630 +.[0][1632]=1631 +.[0][1633]=1632 +.[0][1634]=1633 +.[0][1635]=1634 +.[0][1636]=1635 +.[0][1637]=1636 +.[0][1638]=1637 +.[0][1639]=1638 +.[0][1640]=1639 +.[0][1641]=1640 +.[0][1642]=1641 +.[0][1643]=1642 +.[0][1644]=1643 +.[0][1645]=1644 +.[0][1646]=1645 +.[0][1647]=1646 +.[0][1648]=1647 +.[0][1649]=1648 +.[0][1650]=1649 +.[0][1651]=1650 +.[0][1652]=1651 +.[0][1653]=1652 +.[0][1654]=1653 +.[0][1655]=1654 +.[0][1656]=1655 +.[0][1657]=1656 +.[0][1658]=1657 +.[0][1659]=1658 +.[0][1660]=1659 +.[0][1661]=1660 +.[0][1662]=1661 +.[0][1663]=1662 +.[0][1664]=1663 +.[0][1665]=1664 +.[0][1666]=1665 +.[0][1667]=1666 +.[0][1668]=1667 +.[0][1669]=1668 +.[0][1670]=1669 +.[0][1671]=1670 +.[0][1672]=1671 +.[0][1673]=1672 +.[0][1674]=1673 +.[0][1675]=1674 +.[0][1676]=1675 +.[0][1677]=1676 +.[0][1678]=1677 +.[0][1679]=1678 +.[0][1680]=1679 +.[0][1681]=1680 +.[0][1682]=1681 +.[0][1683]=1682 +.[0][1684]=1683 +.[0][1685]=1684 +.[0][1686]=1685 +.[0][1687]=1686 +.[0][1688]=1687 +.[0][1689]=1688 +.[0][1690]=1689 +.[0][1691]=1690 +.[0][1692]=1691 +.[0][1693]=1692 +.[0][1694]=1693 +.[0][1695]=1694 +.[0][1696]=1695 +.[0][1697]=1696 +.[0][1698]=1697 +.[0][1699]=1698 +.[0][1700]=1699 +.[0][1701]=1700 +.[0][1702]=1701 +.[0][1703]=1702 +.[0][1704]=1703 +.[0][1705]=1704 +.[0][1706]=1705 +.[0][1707]=1706 +.[0][1708]=1707 +.[0][1709]=1708 +.[0][1710]=1709 +.[0][1711]=1710 +.[0][1712]=1711 +.[0][1713]=1712 +.[0][1714]=1713 +.[0][1715]=1714 +.[0][1716]=1715 +.[0][1717]=1716 +.[0][1718]=1717 +.[0][1719]=1718 +.[0][1720]=1719 +.[0][1721]=1720 +.[0][1722]=1721 +.[0][1723]=1722 +.[0][1724]=1723 +.[0][1725]=1724 +.[0][1726]=1725 +.[0][1727]=1726 +.[0][1728]=1727 +.[0][1729]=1728 +.[0][1730]=1729 +.[0][1731]=1730 +.[0][1732]=1731 +.[0][1733]=1732 +.[0][1734]=1733 +.[0][1735]=1734 +.[0][1736]=1735 +.[0][1737]=1736 +.[0][1738]=1737 +.[0][1739]=1738 +.[0][1740]=1739 +.[0][1741]=1740 +.[0][1742]=1741 +.[0][1743]=1742 +.[0][1744]=1743 +.[0][1745]=1744 +.[0][1746]=1745 +.[0][1747]=1746 +.[0][1748]=1747 +.[0][1749]=1748 +.[0][1750]=1749 +.[0][1751]=1750 +.[0][1752]=1751 +.[0][1753]=1752 +.[0][1754]=1753 +.[0][1755]=1754 +.[0][1756]=1755 +.[0][1757]=1756 +.[0][1758]=1757 +.[0][1759]=1758 +.[0][1760]=1759 +.[0][1761]=1760 +.[0][1762]=1761 +.[0][1763]=1762 +.[0][1764]=1763 +.[0][1765]=1764 +.[0][1766]=1765 +.[0][1767]=1766 +.[0][1768]=1767 +.[0][1769]=1768 +.[0][1770]=1769 +.[0][1771]=1770 +.[0][1772]=1771 +.[0][1773]=1772 +.[0][1774]=1773 +.[0][1775]=1774 +.[0][1776]=1775 +.[0][1777]=1776 +.[0][1778]=1777 +.[0][1779]=1778 +.[0][1780]=1779 +.[0][1781]=1780 +.[0][1782]=1781 +.[0][1783]=1782 +.[0][1784]=1783 +.[0][1785]=1784 +.[0][1786]=1785 +.[0][1787]=1786 +.[0][1788]=1787 +.[0][1789]=1788 +.[0][1790]=1789 +.[0][1791]=1790 +.[0][1792]=1791 +.[0][1793]=1792 +.[0][1794]=1793 +.[0][1795]=1794 +.[0][1796]=1795 +.[0][1797]=1796 +.[0][1798]=1797 +.[0][1799]=1798 +.[0][1800]=1799 +.[0][1801]=1800 +.[0][1802]=1801 +.[0][1803]=1802 +.[0][1804]=1803 +.[0][1805]=1804 +.[0][1806]=1805 +.[0][1807]=1806 +.[0][1808]=1807 +.[0][1809]=1808 +.[0][1810]=1809 +.[0][1811]=1810 +.[0][1812]=1811 +.[0][1813]=1812 +.[0][1814]=1813 +.[0][1815]=1814 +.[0][1816]=1815 +.[0][1817]=1816 +.[0][1818]=1817 +.[0][1819]=1818 +.[0][1820]=1819 +.[0][1821]=1820 +.[0][1822]=1821 +.[0][1823]=1822 +.[0][1824]=1823 +.[0][1825]=1824 +.[0][1826]=1825 +.[0][1827]=1826 +.[0][1828]=1827 +.[0][1829]=1828 +.[0][1830]=1829 +.[0][1831]=1830 +.[0][1832]=1831 +.[0][1833]=1832 +.[0][1834]=1833 +.[0][1835]=1834 +.[0][1836]=1835 +.[0][1837]=1836 +.[0][1838]=1837 +.[0][1839]=1838 +.[0][1840]=1839 +.[0][1841]=1840 +.[0][1842]=1841 +.[0][1843]=1842 +.[0][1844]=1843 +.[0][1845]=1844 +.[0][1846]=1845 +.[0][1847]=1846 +.[0][1848]=1847 +.[0][1849]=1848 +.[0][1850]=1849 +.[0][1851]=1850 +.[0][1852]=1851 +.[0][1853]=1852 +.[0][1854]=1853 +.[0][1855]=1854 +.[0][1856]=1855 +.[0][1857]=1856 +.[0][1858]=1857 +.[0][1859]=1858 +.[0][1860]=1859 +.[0][1861]=1860 +.[0][1862]=1861 +.[0][1863]=1862 +.[0][1864]=1863 +.[0][1865]=1864 +.[0][1866]=1865 +.[0][1867]=1866 +.[0][1868]=1867 +.[0][1869]=1868 +.[0][1870]=1869 +.[0][1871]=1870 +.[0][1872]=1871 +.[0][1873]=1872 +.[0][1874]=1873 +.[0][1875]=1874 +.[0][1876]=1875 +.[0][1877]=1876 +.[0][1878]=1877 +.[0][1879]=1878 +.[0][1880]=1879 +.[0][1881]=1880 +.[0][1882]=1881 +.[0][1883]=1882 +.[0][1884]=1883 +.[0][1885]=1884 +.[0][1886]=1885 +.[0][1887]=1886 +.[0][1888]=1887 +.[0][1889]=1888 +.[0][1890]=1889 +.[0][1891]=1890 +.[0][1892]=1891 +.[0][1893]=1892 +.[0][1894]=1893 +.[0][1895]=1894 +.[0][1896]=1895 +.[0][1897]=1896 +.[0][1898]=1897 +.[0][1899]=1898 +.[0][1900]=1899 +.[0][1901]=1900 +.[0][1902]=1901 +.[0][1903]=1902 +.[0][1904]=1903 +.[0][1905]=1904 +.[0][1906]=1905 +.[0][1907]=1906 +.[0][1908]=1907 +.[0][1909]=1908 +.[0][1910]=1909 +.[0][1911]=1910 +.[0][1912]=1911 +.[0][1913]=1912 +.[0][1914]=1913 +.[0][1915]=1914 +.[0][1916]=1915 +.[0][1917]=1916 +.[0][1918]=1917 +.[0][1919]=1918 +.[0][1920]=1919 +.[0][1921]=1920 +.[0][1922]=1921 +.[0][1923]=1922 +.[0][1924]=1923 +.[0][1925]=1924 +.[0][1926]=1925 +.[0][1927]=1926 +.[0][1928]=1927 +.[0][1929]=1928 +.[0][1930]=1929 +.[0][1931]=1930 +.[0][1932]=1931 +.[0][1933]=1932 +.[0][1934]=1933 +.[0][1935]=1934 +.[0][1936]=1935 +.[0][1937]=1936 +.[0][1938]=1937 +.[0][1939]=1938 +.[0][1940]=1939 +.[0][1941]=1940 +.[0][1942]=1941 +.[0][1943]=1942 +.[0][1944]=1943 +.[0][1945]=1944 +.[0][1946]=1945 +.[0][1947]=1946 +.[0][1948]=1947 +.[0][1949]=1948 +.[0][1950]=1949 +.[0][1951]=1950 +.[0][1952]=1951 +.[0][1953]=1952 +.[0][1954]=1953 +.[0][1955]=1954 +.[0][1956]=1955 +.[0][1957]=1956 +.[0][1958]=1957 +.[0][1959]=1958 +.[0][1960]=1959 +.[0][1961]=1960 +.[0][1962]=1961 +.[0][1963]=1962 +.[0][1964]=1963 +.[0][1965]=1964 +.[0][1966]=1965 +.[0][1967]=1966 +.[0][1968]=1967 +.[0][1969]=1968 +.[0][1970]=1969 +.[0][1971]=1970 +.[0][1972]=1971 +.[0][1973]=1972 +.[0][1974]=1973 +.[0][1975]=1974 +.[0][1976]=1975 +.[0][1977]=1976 +.[0][1978]=1977 +.[0][1979]=1978 +.[0][1980]=1979 +.[0][1981]=1980 +.[0][1982]=1981 +.[0][1983]=1982 +.[0][1984]=1983 +.[0][1985]=1984 +.[0][1986]=1985 +.[0][1987]=1986 +.[0][1988]=1987 +.[0][1989]=1988 +.[0][1990]=1989 +.[0][1991]=1990 +.[0][1992]=1991 +.[0][1993]=1992 +.[0][1994]=1993 +.[0][1995]=1994 +.[0][1996]=1995 +.[0][1997]=1996 +.[0][1998]=1997 +.[0][1999]=1998 +.[0][2000]=1999 +.[0][2001]=2000 +.[0][2002]=2001 +.[0][2003]=2002 +.[0][2004]=2003 +.[0][2005]=2004 +.[0][2006]=2005 +.[0][2007]=2006 +.[0][2008]=2007 +.[0][2009]=2008 +.[0][2010]=2009 +.[0][2011]=2010 +.[0][2012]=2011 +.[0][2013]=2012 +.[0][2014]=2013 +.[0][2015]=2014 +.[0][2016]=2015 +.[0][2017]=2016 +.[0][2018]=2017 +.[0][2019]=2018 +.[0][2020]=2019 +.[0][2021]=2020 +.[0][2022]=2021 +.[0][2023]=2022 +.[0][2024]=2023 +.[0][2025]=2024 +.[0][2026]=2025 +.[0][2027]=2026 +.[0][2028]=2027 +.[0][2029]=2028 +.[0][2030]=2029 +.[0][2031]=2030 +.[0][2032]=2031 +.[0][2033]=2032 +.[0][2034]=2033 +.[0][2035]=2034 +.[0][2036]=2035 +.[0][2037]=2036 +.[0][2038]=2037 +.[0][2039]=2038 +.[0][2040]=2039 +.[0][2041]=2040 +.[0][2042]=2041 +.[0][2043]=2042 +.[0][2044]=2043 +.[0][2045]=2044 +.[0][2046]=2045 +.[0][2047]=2046 +.[0][2048]=2047 +.[0][2049]=2048 +.[0][2050]=2049 +.[0][2051]=2050 +.[0][2052]=2051 +.[0][2053]=2052 +.[0][2054]=2053 +.[0][2055]=2054 +.[0][2056]=2055 +.[0][2057]=2056 +.[0][2058]=2057 +.[0][2059]=2058 +.[0][2060]=2059 +.[0][2061]=2060 +.[0][2062]=2061 +.[0][2063]=2062 +.[0][2064]=2063 +.[0][2065]=2064 +.[0][2066]=2065 +.[0][2067]=2066 +.[0][2068]=2067 +.[0][2069]=2068 +.[0][2070]=2069 +.[0][2071]=2070 +.[0][2072]=2071 +.[0][2073]=2072 +.[0][2074]=2073 +.[0][2075]=2074 +.[0][2076]=2075 +.[0][2077]=2076 +.[0][2078]=2077 +.[0][2079]=2078 +.[0][2080]=2079 +.[0][2081]=2080 +.[0][2082]=2081 +.[0][2083]=2082 +.[0][2084]=2083 +.[0][2085]=2084 +.[0][2086]=2085 +.[0][2087]=2086 +.[0][2088]=2087 +.[0][2089]=2088 +.[0][2090]=2089 +.[0][2091]=2090 +.[0][2092]=2091 +.[0][2093]=2092 +.[0][2094]=2093 +.[0][2095]=2094 +.[0][2096]=2095 +.[0][2097]=2096 +.[0][2098]=2097 +.[0][2099]=2098 +.[0][2100]=2099 +.[0][2101]=2100 +.[0][2102]=2101 +.[0][2103]=2102 +.[0][2104]=2103 +.[0][2105]=2104 +.[0][2106]=2105 +.[0][2107]=2106 +.[0][2108]=2107 +.[0][2109]=2108 +.[0][2110]=2109 +.[0][2111]=2110 +.[0][2112]=2111 +.[0][2113]=2112 +.[0][2114]=2113 +.[0][2115]=2114 +.[0][2116]=2115 +.[0][2117]=2116 +.[0][2118]=2117 +.[0][2119]=2118 diff --git a/cxx/jsoncpp/test/data/test_large_01.json b/cxx/jsoncpp/test/data/test_large_01.json new file mode 100644 index 0000000..e4ab4cd --- /dev/null +++ b/cxx/jsoncpp/test/data/test_large_01.json @@ -0,0 +1,2 @@ +[["A",0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118] +] \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_object_01.expected b/cxx/jsoncpp/test/data/test_object_01.expected new file mode 100644 index 0000000..67444e5 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_01.expected @@ -0,0 +1 @@ +.={} diff --git a/cxx/jsoncpp/test/data/test_object_01.json b/cxx/jsoncpp/test/data/test_object_01.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_01.json @@ -0,0 +1 @@ +{} diff --git a/cxx/jsoncpp/test/data/test_object_02.expected b/cxx/jsoncpp/test/data/test_object_02.expected new file mode 100644 index 0000000..79391c2 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_02.expected @@ -0,0 +1,2 @@ +.={} +.count=1234 diff --git a/cxx/jsoncpp/test/data/test_object_02.json b/cxx/jsoncpp/test/data/test_object_02.json new file mode 100644 index 0000000..d0f2fac --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_02.json @@ -0,0 +1 @@ +{ "count" : 1234 } diff --git a/cxx/jsoncpp/test/data/test_object_03.expected b/cxx/jsoncpp/test/data/test_object_03.expected new file mode 100644 index 0000000..5e96113 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_03.expected @@ -0,0 +1,4 @@ +.={} +.attribute="random" +.count=1234 +.name="test" diff --git a/cxx/jsoncpp/test/data/test_object_03.json b/cxx/jsoncpp/test/data/test_object_03.json new file mode 100644 index 0000000..4fcd4d8 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_03.json @@ -0,0 +1,5 @@ +{ + "count" : 1234, + "name" : "test", + "attribute" : "random" +} diff --git a/cxx/jsoncpp/test/data/test_object_04.expected b/cxx/jsoncpp/test/data/test_object_04.expected new file mode 100644 index 0000000..812965b --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_04.expected @@ -0,0 +1,2 @@ +.={} +.=1234 diff --git a/cxx/jsoncpp/test/data/test_object_04.json b/cxx/jsoncpp/test/data/test_object_04.json new file mode 100644 index 0000000..450762d --- /dev/null +++ b/cxx/jsoncpp/test/data/test_object_04.json @@ -0,0 +1,3 @@ +{ + "" : 1234 +} diff --git a/cxx/jsoncpp/test/data/test_preserve_comment_01.expected b/cxx/jsoncpp/test/data/test_preserve_comment_01.expected new file mode 100644 index 0000000..2797aa7 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_preserve_comment_01.expected @@ -0,0 +1,11 @@ +/* A comment + at the beginning of the file. + */ +.={} +.first=1 +/* Comment before 'second' + */ +.second=2 +/* A comment at + the end of the file. + */ diff --git a/cxx/jsoncpp/test/data/test_preserve_comment_01.json b/cxx/jsoncpp/test/data/test_preserve_comment_01.json new file mode 100644 index 0000000..fabd55d --- /dev/null +++ b/cxx/jsoncpp/test/data/test_preserve_comment_01.json @@ -0,0 +1,14 @@ +/* A comment + at the beginning of the file. + */ +{ + "first" : 1, // comment after 'first' on the same line + +/* Comment before 'second' + */ + "second" : 2 +} + +/* A comment at + the end of the file. + */ diff --git a/cxx/jsoncpp/test/data/test_real_01.expected b/cxx/jsoncpp/test/data/test_real_01.expected new file mode 100644 index 0000000..9514827 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_01.expected @@ -0,0 +1,3 @@ +// 2^33 => out of integer range, switch to double +.=8589934592 + diff --git a/cxx/jsoncpp/test/data/test_real_01.json b/cxx/jsoncpp/test/data/test_real_01.json new file mode 100644 index 0000000..358452d --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_01.json @@ -0,0 +1,3 @@ +// 2^33 => out of integer range, switch to double +8589934592 + diff --git a/cxx/jsoncpp/test/data/test_real_02.expected b/cxx/jsoncpp/test/data/test_real_02.expected new file mode 100644 index 0000000..b80c004 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_02.expected @@ -0,0 +1,3 @@ +// -2^32 => out of signed integer range, switch to double +.=-4294967295 + diff --git a/cxx/jsoncpp/test/data/test_real_02.json b/cxx/jsoncpp/test/data/test_real_02.json new file mode 100644 index 0000000..936c706 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_02.json @@ -0,0 +1,3 @@ +// -2^32 => out of signed integer range, switch to double +-4294967295 + diff --git a/cxx/jsoncpp/test/data/test_real_03.expected b/cxx/jsoncpp/test/data/test_real_03.expected new file mode 100644 index 0000000..b80c004 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_03.expected @@ -0,0 +1,3 @@ +// -2^32 => out of signed integer range, switch to double +.=-4294967295 + diff --git a/cxx/jsoncpp/test/data/test_real_03.json b/cxx/jsoncpp/test/data/test_real_03.json new file mode 100644 index 0000000..936c706 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_03.json @@ -0,0 +1,3 @@ +// -2^32 => out of signed integer range, switch to double +-4294967295 + diff --git a/cxx/jsoncpp/test/data/test_real_04.expected b/cxx/jsoncpp/test/data/test_real_04.expected new file mode 100644 index 0000000..ff71a23 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_04.expected @@ -0,0 +1,3 @@ +// 1.2345678 +.=1.2345678 + diff --git a/cxx/jsoncpp/test/data/test_real_04.json b/cxx/jsoncpp/test/data/test_real_04.json new file mode 100644 index 0000000..a8eb6d0 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_04.json @@ -0,0 +1,3 @@ +// 1.2345678 +12345678e-7 + diff --git a/cxx/jsoncpp/test/data/test_real_05.expected b/cxx/jsoncpp/test/data/test_real_05.expected new file mode 100644 index 0000000..7a46093 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_05.expected @@ -0,0 +1,4 @@ +// 1234567.8 +.=1234567.8 + + diff --git a/cxx/jsoncpp/test/data/test_real_05.json b/cxx/jsoncpp/test/data/test_real_05.json new file mode 100644 index 0000000..f7923ba --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_05.json @@ -0,0 +1,3 @@ +// 1234567.8 +0.12345678e7 + diff --git a/cxx/jsoncpp/test/data/test_real_06.expected b/cxx/jsoncpp/test/data/test_real_06.expected new file mode 100644 index 0000000..a4a004d --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_06.expected @@ -0,0 +1,4 @@ +// -1.2345678 +.=-1.2345678 + + diff --git a/cxx/jsoncpp/test/data/test_real_06.json b/cxx/jsoncpp/test/data/test_real_06.json new file mode 100644 index 0000000..485419a --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_06.json @@ -0,0 +1,3 @@ +// -1.2345678 +-12345678e-7 + diff --git a/cxx/jsoncpp/test/data/test_real_07.expected b/cxx/jsoncpp/test/data/test_real_07.expected new file mode 100644 index 0000000..dc02a89 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_07.expected @@ -0,0 +1,4 @@ +// -1234567.8 +.=-1234567.8 + + diff --git a/cxx/jsoncpp/test/data/test_real_07.json b/cxx/jsoncpp/test/data/test_real_07.json new file mode 100644 index 0000000..8013eb5 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_07.json @@ -0,0 +1,3 @@ +// -1234567.8 +-0.12345678e7 + diff --git a/cxx/jsoncpp/test/data/test_real_08.expected b/cxx/jsoncpp/test/data/test_real_08.expected new file mode 100644 index 0000000..b1deef9 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_08.expected @@ -0,0 +1,4 @@ +// Out of 32-bit integer range, switch to double in 32-bit mode. Length the +// same as UINT_MAX in base 10 and digit less than UINT_MAX's last digit in +// order to catch a bug in the parsing code. +.=4300000001 diff --git a/cxx/jsoncpp/test/data/test_real_08.json b/cxx/jsoncpp/test/data/test_real_08.json new file mode 100644 index 0000000..cca950d --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_08.json @@ -0,0 +1,4 @@ +// Out of 32-bit integer range, switch to double in 32-bit mode. Length the +// same as UINT_MAX in base 10 and digit less than UINT_MAX's last digit in +// order to catch a bug in the parsing code. +4300000001 diff --git a/cxx/jsoncpp/test/data/test_real_09.expected b/cxx/jsoncpp/test/data/test_real_09.expected new file mode 100644 index 0000000..aa2dbb2 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_09.expected @@ -0,0 +1,4 @@ +// Out of 64-bit integer range, switch to double in all modes. Length the same +// as ULONG_MAX in base 10 and digit less than ULONG_MAX's last digit in order +// to catch a bug in the parsing code. +.=1.9e+19 diff --git a/cxx/jsoncpp/test/data/test_real_09.json b/cxx/jsoncpp/test/data/test_real_09.json new file mode 100644 index 0000000..e65d50c --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_09.json @@ -0,0 +1,4 @@ +// Out of 64-bit integer range, switch to double in all modes. Length the same +// as ULONG_MAX in base 10 and digit less than ULONG_MAX's last digit in order +// to catch a bug in the parsing code. +19000000000000000001 diff --git a/cxx/jsoncpp/test/data/test_real_10.expected b/cxx/jsoncpp/test/data/test_real_10.expected new file mode 100644 index 0000000..d28a430 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_10.expected @@ -0,0 +1,4 @@ +// Out of 32-bit signed integer range, switch to double in all modes. Length +// the same as INT_MIN in base 10 and digit less than INT_MIN's last digit in +// order to catch a bug in the parsing code. +.=-2200000001 diff --git a/cxx/jsoncpp/test/data/test_real_10.json b/cxx/jsoncpp/test/data/test_real_10.json new file mode 100644 index 0000000..a6a8bce --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_10.json @@ -0,0 +1,4 @@ +// Out of 32-bit signed integer range, switch to double in all modes. Length +// the same as INT_MIN in base 10 and digit less than INT_MIN's last digit in +// order to catch a bug in the parsing code. +-2200000001 diff --git a/cxx/jsoncpp/test/data/test_real_11.expected b/cxx/jsoncpp/test/data/test_real_11.expected new file mode 100644 index 0000000..2551946 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_11.expected @@ -0,0 +1,4 @@ +// Out of 64-bit signed integer range, switch to double in all modes. Length +// the same as LONG_MIN in base 10 and digit less than LONG_MIN's last digit in +// order to catch a bug in the parsing code. +.=-9.3e+18 diff --git a/cxx/jsoncpp/test/data/test_real_11.json b/cxx/jsoncpp/test/data/test_real_11.json new file mode 100644 index 0000000..63cdb36 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_11.json @@ -0,0 +1,4 @@ +// Out of 64-bit signed integer range, switch to double in all modes. Length +// the same as LONG_MIN in base 10 and digit less than LONG_MIN's last digit in +// order to catch a bug in the parsing code. +-9300000000000000001 diff --git a/cxx/jsoncpp/test/data/test_real_12.expected b/cxx/jsoncpp/test/data/test_real_12.expected new file mode 100644 index 0000000..93e2417 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_12.expected @@ -0,0 +1,2 @@ +// 2^64 -> switch to double. +.=1.844674407370955e+19 diff --git a/cxx/jsoncpp/test/data/test_real_12.json b/cxx/jsoncpp/test/data/test_real_12.json new file mode 100644 index 0000000..0a13eed --- /dev/null +++ b/cxx/jsoncpp/test/data/test_real_12.json @@ -0,0 +1,2 @@ +// 2^64 -> switch to double. +18446744073709551616 diff --git a/cxx/jsoncpp/test/data/test_string_01.expected b/cxx/jsoncpp/test/data/test_string_01.expected new file mode 100644 index 0000000..8fd37b1 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_01.expected @@ -0,0 +1 @@ +.="!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_01.json b/cxx/jsoncpp/test/data/test_string_01.json new file mode 100644 index 0000000..6cd0db4 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_01.json @@ -0,0 +1 @@ +"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" diff --git a/cxx/jsoncpp/test/data/test_string_02.expected b/cxx/jsoncpp/test/data/test_string_02.expected new file mode 100644 index 0000000..0443bc3 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_02.expected @@ -0,0 +1 @@ +.="!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_02.json b/cxx/jsoncpp/test/data/test_string_02.json new file mode 100644 index 0000000..9a7e5dc --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_02.json @@ -0,0 +1 @@ +"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" diff --git a/cxx/jsoncpp/test/data/test_string_03.expected b/cxx/jsoncpp/test/data/test_string_03.expected new file mode 100644 index 0000000..6ed627a --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_03.expected @@ -0,0 +1 @@ +.="http://jsoncpp.sourceforge.net/" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_03.json b/cxx/jsoncpp/test/data/test_string_03.json new file mode 100644 index 0000000..2d38180 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_03.json @@ -0,0 +1 @@ +"http:\/\/jsoncpp.sourceforge.net\/" diff --git a/cxx/jsoncpp/test/data/test_string_04.expected b/cxx/jsoncpp/test/data/test_string_04.expected new file mode 100644 index 0000000..f57d525 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_04.expected @@ -0,0 +1,2 @@ +.=""abc\def"" + diff --git a/cxx/jsoncpp/test/data/test_string_04.json b/cxx/jsoncpp/test/data/test_string_04.json new file mode 100644 index 0000000..01fe752 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_04.json @@ -0,0 +1,2 @@ +"\"abc\\def\"" + diff --git a/cxx/jsoncpp/test/data/test_string_05.expected b/cxx/jsoncpp/test/data/test_string_05.expected new file mode 100644 index 0000000..9794ddd --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_05.expected @@ -0,0 +1,2 @@ +.="\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + diff --git a/cxx/jsoncpp/test/data/test_string_05.json b/cxx/jsoncpp/test/data/test_string_05.json new file mode 100644 index 0000000..e156024 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_05.json @@ -0,0 +1,2 @@ +"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + diff --git a/cxx/jsoncpp/test/data/test_string_unicode_01.expected b/cxx/jsoncpp/test/data/test_string_unicode_01.expected new file mode 100644 index 0000000..1f3be7f --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_01.expected @@ -0,0 +1 @@ +.="a" diff --git a/cxx/jsoncpp/test/data/test_string_unicode_01.json b/cxx/jsoncpp/test/data/test_string_unicode_01.json new file mode 100644 index 0000000..024114b --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_01.json @@ -0,0 +1 @@ +"\u0061" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_unicode_02.expected b/cxx/jsoncpp/test/data/test_string_unicode_02.expected new file mode 100644 index 0000000..1388f53 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_02.expected @@ -0,0 +1 @@ +.="¢" diff --git a/cxx/jsoncpp/test/data/test_string_unicode_02.json b/cxx/jsoncpp/test/data/test_string_unicode_02.json new file mode 100644 index 0000000..4961024 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_02.json @@ -0,0 +1 @@ +"\u00A2" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_unicode_03.expected b/cxx/jsoncpp/test/data/test_string_unicode_03.expected new file mode 100644 index 0000000..9b80b27 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_03.expected @@ -0,0 +1 @@ +.="€" diff --git a/cxx/jsoncpp/test/data/test_string_unicode_03.json b/cxx/jsoncpp/test/data/test_string_unicode_03.json new file mode 100644 index 0000000..e7e1a9e --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_03.json @@ -0,0 +1 @@ +"\u20AC" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_unicode_04.expected b/cxx/jsoncpp/test/data/test_string_unicode_04.expected new file mode 100644 index 0000000..b9e7fe3 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_04.expected @@ -0,0 +1 @@ +.="𝄞" diff --git a/cxx/jsoncpp/test/data/test_string_unicode_04.json b/cxx/jsoncpp/test/data/test_string_unicode_04.json new file mode 100644 index 0000000..dae65c5 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_04.json @@ -0,0 +1 @@ +"\uD834\uDD1E" \ No newline at end of file diff --git a/cxx/jsoncpp/test/data/test_string_unicode_05.expected b/cxx/jsoncpp/test/data/test_string_unicode_05.expected new file mode 100644 index 0000000..c2e67f9 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_05.expected @@ -0,0 +1,2 @@ +.="Zażółć gęślą jaźń" + diff --git a/cxx/jsoncpp/test/data/test_string_unicode_05.json b/cxx/jsoncpp/test/data/test_string_unicode_05.json new file mode 100644 index 0000000..8770410 --- /dev/null +++ b/cxx/jsoncpp/test/data/test_string_unicode_05.json @@ -0,0 +1 @@ +"Zażółć gęślą jaźń" \ No newline at end of file diff --git a/cxx/jsoncpp/test/generate_expected.py b/cxx/jsoncpp/test/generate_expected.py new file mode 100644 index 0000000..e049ab5 --- /dev/null +++ b/cxx/jsoncpp/test/generate_expected.py @@ -0,0 +1,17 @@ +# Copyright 2007 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +from __future__ import print_function +import glob +import os.path +for path in glob.glob('*.json'): + text = file(path,'rt').read() + target = os.path.splitext(path)[0] + '.expected' + if os.path.exists(target): + print('skipping:', target) + else: + print('creating:', target) + file(target,'wt').write(text) + diff --git a/cxx/jsoncpp/test/jsonchecker/fail1.json b/cxx/jsoncpp/test/jsonchecker/fail1.json new file mode 100644 index 0000000..6216b86 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail1.json @@ -0,0 +1 @@ +"A JSON payload should be an object or array, not a string." \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail10.json b/cxx/jsoncpp/test/jsonchecker/fail10.json new file mode 100644 index 0000000..5d8c004 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail11.json b/cxx/jsoncpp/test/jsonchecker/fail11.json new file mode 100644 index 0000000..76eb95b --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail12.json b/cxx/jsoncpp/test/jsonchecker/fail12.json new file mode 100644 index 0000000..77580a4 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail13.json b/cxx/jsoncpp/test/jsonchecker/fail13.json new file mode 100644 index 0000000..379406b --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail14.json b/cxx/jsoncpp/test/jsonchecker/fail14.json new file mode 100644 index 0000000..0ed366b --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail15.json b/cxx/jsoncpp/test/jsonchecker/fail15.json new file mode 100644 index 0000000..fc8376b --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail16.json b/cxx/jsoncpp/test/jsonchecker/fail16.json new file mode 100644 index 0000000..3fe21d4 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail17.json b/cxx/jsoncpp/test/jsonchecker/fail17.json new file mode 100644 index 0000000..62b9214 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail18.json b/cxx/jsoncpp/test/jsonchecker/fail18.json new file mode 100644 index 0000000..edac927 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail19.json b/cxx/jsoncpp/test/jsonchecker/fail19.json new file mode 100644 index 0000000..3b9c46f --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail2.json b/cxx/jsoncpp/test/jsonchecker/fail2.json new file mode 100644 index 0000000..6b7c11e --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail2.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail20.json b/cxx/jsoncpp/test/jsonchecker/fail20.json new file mode 100644 index 0000000..27c1af3 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail21.json b/cxx/jsoncpp/test/jsonchecker/fail21.json new file mode 100644 index 0000000..6247457 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail22.json b/cxx/jsoncpp/test/jsonchecker/fail22.json new file mode 100644 index 0000000..a775258 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail23.json b/cxx/jsoncpp/test/jsonchecker/fail23.json new file mode 100644 index 0000000..494add1 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail24.json b/cxx/jsoncpp/test/jsonchecker/fail24.json new file mode 100644 index 0000000..caff239 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail25.json b/cxx/jsoncpp/test/jsonchecker/fail25.json new file mode 100644 index 0000000..8b7ad23 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail26.json b/cxx/jsoncpp/test/jsonchecker/fail26.json new file mode 100644 index 0000000..845d26a --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail27.json b/cxx/jsoncpp/test/jsonchecker/fail27.json new file mode 100644 index 0000000..6b01a2c --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail28.json b/cxx/jsoncpp/test/jsonchecker/fail28.json new file mode 100644 index 0000000..621a010 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail29.json b/cxx/jsoncpp/test/jsonchecker/fail29.json new file mode 100644 index 0000000..47ec421 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail3.json b/cxx/jsoncpp/test/jsonchecker/fail3.json new file mode 100644 index 0000000..168c81e --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail30.json b/cxx/jsoncpp/test/jsonchecker/fail30.json new file mode 100644 index 0000000..8ab0bc4 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail31.json b/cxx/jsoncpp/test/jsonchecker/fail31.json new file mode 100644 index 0000000..1cce602 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail32.json b/cxx/jsoncpp/test/jsonchecker/fail32.json new file mode 100644 index 0000000..45cba73 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail33.json b/cxx/jsoncpp/test/jsonchecker/fail33.json new file mode 100644 index 0000000..ca5eb19 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail33.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail4.json b/cxx/jsoncpp/test/jsonchecker/fail4.json new file mode 100644 index 0000000..9de168b --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail4.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail5.json b/cxx/jsoncpp/test/jsonchecker/fail5.json new file mode 100644 index 0000000..ddf3ce3 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail5.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail6.json b/cxx/jsoncpp/test/jsonchecker/fail6.json new file mode 100644 index 0000000..ed91580 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail7.json b/cxx/jsoncpp/test/jsonchecker/fail7.json new file mode 100644 index 0000000..8a96af3 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail7.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail8.json b/cxx/jsoncpp/test/jsonchecker/fail8.json new file mode 100644 index 0000000..b28479c --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail8.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/fail9.json b/cxx/jsoncpp/test/jsonchecker/fail9.json new file mode 100644 index 0000000..5815574 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/pass1.json b/cxx/jsoncpp/test/jsonchecker/pass1.json new file mode 100644 index 0000000..70e2685 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/pass2.json b/cxx/jsoncpp/test/jsonchecker/pass2.json new file mode 100644 index 0000000..d3c63c7 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/cxx/jsoncpp/test/jsonchecker/pass3.json b/cxx/jsoncpp/test/jsonchecker/pass3.json new file mode 100644 index 0000000..4528d51 --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/cxx/jsoncpp/test/jsonchecker/readme.txt b/cxx/jsoncpp/test/jsonchecker/readme.txt new file mode 100644 index 0000000..321d89d --- /dev/null +++ b/cxx/jsoncpp/test/jsonchecker/readme.txt @@ -0,0 +1,3 @@ +Test suite from http://json.org/JSON_checker/. + +If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files. diff --git a/cxx/jsoncpp/test/pyjsontestrunner.py b/cxx/jsoncpp/test/pyjsontestrunner.py new file mode 100644 index 0000000..bd749b5 --- /dev/null +++ b/cxx/jsoncpp/test/pyjsontestrunner.py @@ -0,0 +1,71 @@ +# Copyright 2007 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +"""Simple implementation of a json test runner to run the test against +json-py.""" + +from __future__ import print_function +import sys +import os.path +import json +import types + +if len(sys.argv) != 2: + print("Usage: %s input-json-file", sys.argv[0]) + sys.exit(3) + +input_path = sys.argv[1] +base_path = os.path.splitext(input_path)[0] +actual_path = base_path + '.actual' +rewrite_path = base_path + '.rewrite' +rewrite_actual_path = base_path + '.actual-rewrite' + +def valueTreeToString(fout, value, path = '.'): + ty = type(value) + if ty is types.DictType: + fout.write('%s={}\n' % path) + suffix = path[-1] != '.' and '.' or '' + names = value.keys() + names.sort() + for name in names: + valueTreeToString(fout, value[name], path + suffix + name) + elif ty is types.ListType: + fout.write('%s=[]\n' % path) + for index, childValue in zip(xrange(0,len(value)), value): + valueTreeToString(fout, childValue, path + '[%d]' % index) + elif ty is types.StringType: + fout.write('%s="%s"\n' % (path,value)) + elif ty is types.IntType: + fout.write('%s=%d\n' % (path,value)) + elif ty is types.FloatType: + fout.write('%s=%.16g\n' % (path,value)) + elif value is True: + fout.write('%s=true\n' % path) + elif value is False: + fout.write('%s=false\n' % path) + elif value is None: + fout.write('%s=null\n' % path) + else: + assert False and "Unexpected value type" + +def parseAndSaveValueTree(input, actual_path): + root = json.loads(input) + fout = file(actual_path, 'wt') + valueTreeToString(fout, root) + fout.close() + return root + +def rewriteValueTree(value, rewrite_path): + rewrite = json.dumps(value) + #rewrite = rewrite[1:-1] # Somehow the string is quoted ! jsonpy bug ? + file(rewrite_path, 'wt').write(rewrite + '\n') + return rewrite + +input = file(input_path, 'rt').read() +root = parseAndSaveValueTree(input, actual_path) +rewrite = rewriteValueTree(json.write(root), rewrite_path) +rewrite_root = parseAndSaveValueTree(rewrite, rewrite_actual_path) + +sys.exit(0) diff --git a/cxx/jsoncpp/test/runjsontests.py b/cxx/jsoncpp/test/runjsontests.py new file mode 100644 index 0000000..48cfe82 --- /dev/null +++ b/cxx/jsoncpp/test/runjsontests.py @@ -0,0 +1,174 @@ +# Copyright 2007 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +from __future__ import print_function +from __future__ import unicode_literals +from io import open +from glob import glob +import sys +import os +import os.path +import optparse + +VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes ' + +def getStatusOutput(cmd): + """ + Return int, unicode (for both Python 2 and 3). + Note: os.popen().close() would return None for 0. + """ + print(cmd, file=sys.stderr) + pipe = os.popen(cmd) + process_output = pipe.read() + try: + # We have been using os.popen(). When we read() the result + # we get 'str' (bytes) in py2, and 'str' (unicode) in py3. + # Ugh! There must be a better way to handle this. + process_output = process_output.decode('utf-8') + except AttributeError: + pass # python3 + status = pipe.close() + return status, process_output +def compareOutputs(expected, actual, message): + expected = expected.strip().replace('\r','').split('\n') + actual = actual.strip().replace('\r','').split('\n') + diff_line = 0 + max_line_to_compare = min(len(expected), len(actual)) + for index in range(0,max_line_to_compare): + if expected[index].strip() != actual[index].strip(): + diff_line = index + 1 + break + if diff_line == 0 and len(expected) != len(actual): + diff_line = max_line_to_compare+1 + if diff_line == 0: + return None + def safeGetLine(lines, index): + index += -1 + if index >= len(lines): + return '' + return lines[index].strip() + return """ Difference in %s at line %d: + Expected: '%s' + Actual: '%s' +""" % (message, diff_line, + safeGetLine(expected,diff_line), + safeGetLine(actual,diff_line)) + +def safeReadFile(path): + try: + return open(path, 'rt', encoding = 'utf-8').read() + except IOError as e: + return '' % (path,e) + +def runAllTests(jsontest_executable_path, input_dir = None, + use_valgrind=False, with_json_checker=False, + writerClass='StyledWriter'): + if not input_dir: + input_dir = os.path.join(os.getcwd(), 'data') + tests = glob(os.path.join(input_dir, '*.json')) + if with_json_checker: + test_jsonchecker = glob(os.path.join(input_dir, '../jsonchecker', '*.json')) + else: + test_jsonchecker = [] + failed_tests = [] + valgrind_path = use_valgrind and VALGRIND_CMD or '' + for input_path in tests + test_jsonchecker: + expect_failure = os.path.basename(input_path).startswith('fail') + is_json_checker_test = (input_path in test_jsonchecker) or expect_failure + print('TESTING:', input_path, end=' ') + options = is_json_checker_test and '--json-checker' or '' + options += ' --json-writer %s'%writerClass + cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options, + input_path) + status, process_output = getStatusOutput(cmd) + if is_json_checker_test: + if expect_failure: + if not status: + print('FAILED') + failed_tests.append((input_path, 'Parsing should have failed:\n%s' % + safeReadFile(input_path))) + else: + print('OK') + else: + if status: + print('FAILED') + failed_tests.append((input_path, 'Parsing failed:\n' + process_output)) + else: + print('OK') + else: + base_path = os.path.splitext(input_path)[0] + actual_output = safeReadFile(base_path + '.actual') + actual_rewrite_output = safeReadFile(base_path + '.actual-rewrite') + open(base_path + '.process-output', 'wt', encoding = 'utf-8').write(process_output) + if status: + print('parsing failed') + failed_tests.append((input_path, 'Parsing failed:\n' + process_output)) + else: + expected_output_path = os.path.splitext(input_path)[0] + '.expected' + expected_output = open(expected_output_path, 'rt', encoding = 'utf-8').read() + detail = (compareOutputs(expected_output, actual_output, 'input') + or compareOutputs(expected_output, actual_rewrite_output, 'rewrite')) + if detail: + print('FAILED') + failed_tests.append((input_path, detail)) + else: + print('OK') + + if failed_tests: + print() + print('Failure details:') + for failed_test in failed_tests: + print('* Test', failed_test[0]) + print(failed_test[1]) + print() + print('Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests), + len(failed_tests))) + return 1 + else: + print('All %d tests passed.' % len(tests)) + return 0 + +def main(): + from optparse import OptionParser + parser = OptionParser(usage="%prog [options] [test case directory]") + parser.add_option("--valgrind", + action="store_true", dest="valgrind", default=False, + help="run all the tests using valgrind to detect memory leaks") + parser.add_option("-c", "--with-json-checker", + action="store_true", dest="with_json_checker", default=False, + help="run all the tests from the official JSONChecker test suite of json.org") + parser.enable_interspersed_args() + options, args = parser.parse_args() + + if len(args) < 1 or len(args) > 2: + parser.error('Must provides at least path to jsontestrunner executable.') + sys.exit(1) + + jsontest_executable_path = os.path.normpath(os.path.abspath(args[0])) + if len(args) > 1: + input_path = os.path.normpath(os.path.abspath(args[1])) + else: + input_path = None + status = runAllTests(jsontest_executable_path, input_path, + use_valgrind=options.valgrind, + with_json_checker=options.with_json_checker, + writerClass='StyledWriter') + if status: + sys.exit(status) + status = runAllTests(jsontest_executable_path, input_path, + use_valgrind=options.valgrind, + with_json_checker=options.with_json_checker, + writerClass='StyledStreamWriter') + if status: + sys.exit(status) + status = runAllTests(jsontest_executable_path, input_path, + use_valgrind=options.valgrind, + with_json_checker=options.with_json_checker, + writerClass='BuiltStyledStreamWriter') + if status: + sys.exit(status) + +if __name__ == '__main__': + main() diff --git a/cxx/jsoncpp/test/rununittests.py b/cxx/jsoncpp/test/rununittests.py new file mode 100644 index 0000000..6634e72 --- /dev/null +++ b/cxx/jsoncpp/test/rununittests.py @@ -0,0 +1,84 @@ +# Copyright 2009 Baptiste Lepilleur and The JsonCpp Authors +# Distributed under MIT license, or public domain if desired and +# recognized in your jurisdiction. +# See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +from __future__ import print_function +from __future__ import unicode_literals +from io import open +from glob import glob +import sys +import os +import os.path +import subprocess +import optparse + +VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes' + +class TestProxy(object): + def __init__(self, test_exe_path, use_valgrind=False): + self.test_exe_path = os.path.normpath(os.path.abspath(test_exe_path)) + self.use_valgrind = use_valgrind + + def run(self, options): + if self.use_valgrind: + cmd = VALGRIND_CMD.split() + else: + cmd = [] + cmd.extend([self.test_exe_path, '--test-auto'] + options) + try: + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except: + print(cmd) + raise + stdout = process.communicate()[0] + if process.returncode: + return False, stdout + return True, stdout + +def runAllTests(exe_path, use_valgrind=False): + test_proxy = TestProxy(exe_path, use_valgrind=use_valgrind) + status, test_names = test_proxy.run(['--list-tests']) + if not status: + print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr) + return 1 + test_names = [name.strip() for name in test_names.decode('utf-8').strip().split('\n')] + failures = [] + for name in test_names: + print('TESTING %s:' % name, end=' ') + succeed, result = test_proxy.run(['--test', name]) + if succeed: + print('OK') + else: + failures.append((name, result)) + print('FAILED') + failed_count = len(failures) + pass_count = len(test_names) - failed_count + if failed_count: + print() + for name, result in failures: + print(result) + print('%d/%d tests passed (%d failure(s))' % ( pass_count, len(test_names), failed_count)) + return 1 + else: + print('All %d tests passed' % len(test_names)) + return 0 + +def main(): + from optparse import OptionParser + parser = OptionParser(usage="%prog [options] ") + parser.add_option("--valgrind", + action="store_true", dest="valgrind", default=False, + help="run all the tests using valgrind to detect memory leaks") + parser.enable_interspersed_args() + options, args = parser.parse_args() + + if len(args) != 1: + parser.error('Must provides at least path to test_lib_json executable.') + sys.exit(1) + + exit_code = runAllTests(args[0], use_valgrind=options.valgrind) + sys.exit(exit_code) + +if __name__ == '__main__': + main() diff --git a/cxx/jsoncpp/version b/cxx/jsoncpp/version new file mode 100644 index 0000000..a7ee35a --- /dev/null +++ b/cxx/jsoncpp/version @@ -0,0 +1 @@ +1.8.3 diff --git a/cxx/jsoncpp/version.in b/cxx/jsoncpp/version.in new file mode 100644 index 0000000..bfc03f7 --- /dev/null +++ b/cxx/jsoncpp/version.in @@ -0,0 +1 @@ +@JSONCPP_VERSION@ diff --git a/cxx/windows/dirent.h b/cxx/windows/dirent.h new file mode 100644 index 0000000..ab92daf --- /dev/null +++ b/cxx/windows/dirent.h @@ -0,0 +1,1094 @@ +/* + * Dirent interface for Microsoft Visual Studio + * + * Copyright (C) 2006-2012 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. + */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +#define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat(), general mask */ +#if !defined(S_IFMT) +#define S_IFMT _S_IFMT +#endif + +/* Directory bit */ +#if !defined(S_IFDIR) +#define S_IFDIR _S_IFDIR +#endif + +/* Character device bit */ +#if !defined(S_IFCHR) +#define S_IFCHR _S_IFCHR +#endif + +/* Pipe bit */ +#if !defined(S_IFFIFO) +#define S_IFFIFO _S_IFFIFO +#endif + +/* Regular file bit */ +#if !defined(S_IFREG) +#define S_IFREG _S_IFREG +#endif + +/* Read permission */ +#if !defined(S_IREAD) +#define S_IREAD _S_IREAD +#endif + +/* Write permission */ +#if !defined(S_IWRITE) +#define S_IWRITE _S_IWRITE +#endif + +/* Execute permission */ +#if !defined(S_IEXEC) +#define S_IEXEC _S_IEXEC +#endif + +/* Pipe */ +#if !defined(S_IFIFO) +#define S_IFIFO _S_IFIFO +#endif + +/* Block device */ +#if !defined(S_IFBLK) +#define S_IFBLK 0 +#endif + +/* Link */ +#if !defined(S_IFLNK) +#define S_IFLNK 0 +#endif + +/* Socket */ +#if !defined(S_IFSOCK) +#define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +#define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +#define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +#define S_IXUSR 0 +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +#define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +#define S_IWGRP 0 +#endif + +/* Execute group permission */ +#if !defined(S_IXGRP) +#define S_IXGRP 0 +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +#define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +#define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +#define S_IXOTH 0 +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +#define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +#define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +#define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode)&S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#if !defined(S_ISFIFO) +#define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISDIR) +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISLNK) +#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) +#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISCHR) +#define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISBLK) +#define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK) +#endif + +/* Return the exact length of the file name without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX) + 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Wide-character version */ +struct _wdirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX + 1]; +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; +}; +typedef struct _WDIR _WDIR; + +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX + 1]; +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + +/* Dirent functions */ +static DIR *opendir(const char *dirname); +static _WDIR *_wopendir(const wchar_t *dirname); + +static struct dirent *readdir(DIR *dirp); +static struct _wdirent *_wreaddir(_WDIR *dirp); + +static int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r(_WDIR *dirp, struct _wdirent *entry, + struct _wdirent **result); + +static int closedir(DIR *dirp); +static int _wclosedir(_WDIR *dirp); + +static void rewinddir(DIR *dirp); +static void _wrewinddir(_WDIR *dirp); + +static int scandir(const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compare)(const void *, const void *)); + +static int alphasort(const struct dirent **a, const struct dirent **b); + +static int versionsort(const struct dirent **a, const struct dirent **b); + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); + +static int dirent_mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, + size_t sizeInWords, const char *mbstr, + size_t count); + +static int dirent_wcstombs_s(size_t *pReturnValue, char *mbstr, + size_t sizeInBytes, const wchar_t *wcstr, + size_t count); + +static void dirent_set_errno(int error); + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR *_wopendir(const wchar_t *dirname) +{ + _WDIR *dirp = NULL; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno(ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + dirp = (_WDIR *)malloc(sizeof(struct _WDIR)); + if (dirp != NULL) { + DWORD n; + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume its an absolute path. + */ +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + n = wcslen(dirname); +#else + n = GetFullPathNameW(dirname, 0, NULL, NULL); +#endif + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t *)malloc(sizeof(wchar_t) * n + 16); + if (dirp->patt) { + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume its an absolute path. + */ +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + wcsncpy_s(dirp->patt, n + 1, dirname, n); +#else + n = GetFullPathNameW(dirname, n, dirp->patt, NULL); +#endif + if (n > 0) { + wchar_t *p; + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + if (dirp->patt < p) { + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (dirent_first(dirp)) { + /* Directory stream opened successfully */ + error = 0; + } + else { + /* Cannot retrieve first entry */ + error = 1; + dirent_set_errno(ENOENT); + } + } + else { + /* Cannot retrieve full path name */ + dirent_set_errno(ENOENT); + error = 1; + } + } + else { + /* Cannot allocate memory for search pattern */ + error = 1; + } + } + else { + /* Cannot allocate _WDIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + _wclosedir(dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritted by + * subsequent calls to _wreaddir(). + */ +static struct _wdirent *_wreaddir(_WDIR *dirp) +{ + struct _wdirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void)_wreaddir_r(dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int _wreaddir_r(_WDIR *dirp, struct _wdirent *entry, + struct _wdirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next(dirp); + if (datap) { + size_t n; + DWORD attr; + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n < PATH_MAX && datap->cFileName[n] != 0) { + entry->d_name[n] = datap->cFileName[n]; + n++; + } + entry->d_name[n] = 0; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n; + + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } + else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof(struct _wdirent); + + /* Set result address */ + *result = entry; + } + else { + + /* Return NULL to indicate end of directory */ + *result = NULL; + } + + return /*OK*/ 0; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int _wclosedir(_WDIR *dirp) +{ + int ok; + if (dirp) { + + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose(dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + } + + /* Release search pattern */ + if (dirp->patt) { + free(dirp->patt); + dirp->patt = NULL; + } + + /* Release directory structure */ + free(dirp); + ok = /*success*/ 0; + } + else { + + /* Invalid directory stream */ + dirent_set_errno(EBADF); + ok = /*failure*/ -1; + } + return ok; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void _wrewinddir(_WDIR *dirp) +{ + if (dirp) { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose(dirp->handle); + } + + /* Open new search handle */ + dirent_first(dirp); + } +} + +/* Get first directory entry (internal) */ +static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileExW(dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); + if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + } + else { + + /* Failed to re-open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + } + return datap; +} + +/* + * Get next directory entry (internal). + * + * Returns + */ +static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp) +{ + WIN32_FIND_DATAW *p; + + /* Get next directory entry */ + if (dirp->cached != 0) { + + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + } + else if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* Get the next directory entry from stream */ + if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) { + /* Got a file */ + p = &dirp->data; + } + else { + /* The very last entry has been processed or an error occured */ + FindClose(dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + } + else { + + /* End of directory stream reached */ + p = NULL; + } + + return p; +} + +/* + * Open directory stream using plain old C-string. + */ +static DIR *opendir(const char *dirname) +{ + struct DIR *dirp; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno(ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + dirp = (DIR *)malloc(sizeof(struct DIR)); + if (dirp) { + wchar_t wname[PATH_MAX + 1]; + size_t n; + + /* Convert directory name to wide-character string */ + error = + dirent_mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (!error) { + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir(wname); + if (dirp->wdirp) { + /* Directory stream opened */ + error = 0; + } + else { + /* Failed to open directory stream */ + error = 1; + } + } + else { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + error = 1; + } + } + else { + /* Cannot allocate DIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + free(dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. + */ +static struct dirent *readdir(DIR *dirp) +{ + struct dirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void)readdir_r(dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on sucess. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next(dirp->wdirp); + if (datap) { + size_t n; + int error; + + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s(&n, entry->d_name, PATH_MAX + 1, + datap->cFileName, PATH_MAX + 1); + + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = dirent_wcstombs_s(&n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); + } + + if (!error) { + DWORD attr; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n - 1; + + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } + else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof(struct dirent); + } + else { + + /* + * Cannot convert file name to multi-byte string so construct + * an errornous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + } + + /* Return pointer to directory entry */ + *result = entry; + } + else { + + /* No more directory entries */ + *result = NULL; + } + + return /*OK*/ 0; +} + +/* + * Close directory stream. + */ +static int closedir(DIR *dirp) +{ + int ok; + if (dirp) { + + /* Close wide-character directory stream */ + ok = _wclosedir(dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free(dirp); + } + else { + + /* Invalid directory stream */ + dirent_set_errno(EBADF); + ok = /*failure*/ -1; + } + return ok; +} + +/* + * Rewind directory stream to beginning. + */ +static void rewinddir(DIR *dirp) +{ + /* Rewind wide-character string directory stream */ + _wrewinddir(dirp->wdirp); +} + +/* + * Scan directory for entries. + */ +static int scandir(const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compare)(const void *, const void *)) +{ + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + const size_t init_size = 1; + DIR *dir = NULL; + struct dirent *entry; + struct dirent *tmp = NULL; + size_t i; + int result = 0; + + /* Open directory stream */ + dir = opendir(dirname); + if (dir) { + + /* Read directory entries to memory */ + while (1) { + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + void *p; + size_t num_entries; + + /* Compute number of entries in the enlarged pointer table */ + if (size < init_size) { + /* Allocate initial pointer table */ + num_entries = init_size; + } + else { + /* Double the size */ + num_entries = size * 2; + } + + /* Allocate first pointer table or enlarge existing table */ + p = realloc(files, sizeof(void *) * num_entries); + if (p != NULL) { + /* Got the memory */ + files = (dirent **)p; + allocated = num_entries; + } + else { + /* Out of memory */ + result = -1; + break; + } + } + + /* Allocate room for temporary directory entry */ + if (tmp == NULL) { + tmp = (struct dirent *)malloc(sizeof(struct dirent)); + if (tmp == NULL) { + /* Cannot allocate temporary directory entry */ + result = -1; + break; + } + } + + /* Read directory entry to temporary area */ + if (readdir_r(dir, tmp, &entry) == /*OK*/ 0) { + + /* Did we got an entry? */ + if (entry != NULL) { + int pass; + + /* Determine whether to include the entry in result */ + if (filter) { + /* Let the filter function decide */ + pass = filter(tmp); + } + else { + /* No filter function, include everything */ + pass = 1; + } + + if (pass) { + /* Store the temporary entry to pointer table */ + files[size++] = tmp; + tmp = NULL; + + /* Keep up with the number of files */ + result++; + } + } + else { + + /* + * End of directory stream reached => sort entries and + * exit. + */ + qsort(files, size, sizeof(void *), compare); + break; + } + } + else { + /* Error reading directory entry */ + result = /*Error*/ -1; + break; + } + } + } + else { + /* Cannot open directory */ + result = /*Error*/ -1; + } + + /* Release temporary directory entry */ + if (tmp) { + free(tmp); + } + + /* Release allocated memory on error */ + if (result < 0) { + for (i = 0; i < size; i++) { + free(files[i]); + } + free(files); + files = NULL; + } + + /* Close directory stream */ + if (dir) { + closedir(dir); + } + + /* Pass pointer table to caller */ + if (namelist) { + *namelist = files; + } + return result; +} + +/* Alphabetical sorting */ +static int alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcoll((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int versionsort(const struct dirent **a, const struct dirent **b) +{ + /* FIXME: implement strverscmp and use that */ + return alphasort(a, b); +} + +/* Convert multi-byte string to wide character string */ +static int dirent_mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, + size_t sizeInWords, const char *mbstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to wide-character string (or count characters) */ + n = mbstowcs(wcstr, mbstr, sizeInWords); + if (!wcstr || n < count) { + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) { + n = sizeInWords - 1; + } + wcstr[n] = 0; + } + + /* Length of resuting multi-byte string WITH zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + } + else { + + /* Could not convert string */ + error = 1; + } + +#endif + + return error; +} + +/* Convert wide-character string to multi-byte string */ +static int dirent_wcstombs_s(size_t *pReturnValue, char *mbstr, + size_t sizeInBytes, /* max size of mbstr */ + const wchar_t *wcstr, size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to multi-byte string (or count the number of bytes needed) */ + n = wcstombs(mbstr, wcstr, sizeInBytes); + if (!mbstr || n < count) { + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Length of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + } + else { + + /* Cannot convert string */ + error = 1; + } + +#endif + + return error; +} + +/* Set errno variable */ +static void dirent_set_errno(int error) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 and later */ + _set_errno(error); + +#else + + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; + +#endif +} + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ diff --git a/cxx/windows/getopt.h b/cxx/windows/getopt.h new file mode 100644 index 0000000..d188f78 --- /dev/null +++ b/cxx/windows/getopt.h @@ -0,0 +1,641 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ +/* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma warning(disable : 4996) + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +// extern int optind; /* index of first non-option in argv */ +// extern int optopt; /* single option character, as parsed */ +// extern int opterr; /* flag to enable built-in diagnostics... */ +// /* (user may set to zero, to suppress) */ +// +// extern char *optarg; /* pointer to argument of current option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) * __progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char *const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char *const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char *const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void _vwarnx(const char *fmt, va_list ap) +{ + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); +} + +static void warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _vwarnx(fmt, ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void permute_args(int panonopt_start, int panonopt_end, int opt_end, + char *const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end + i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **)nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int getopt(int nargc, char *const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +// extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +#define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int parse_long_options(char *const *nargv, const char *options, + const struct option *long_options, int *idx, + int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } + else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) && + (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } + else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } + else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int getopt_internal(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx, + int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, nargv); + nonopt_start = optind - (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = + parse_long_options(nargv, options, long_options, idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = (char *)strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } + else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } + else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } + else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int getopt_long(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int getopt_long_only(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE | FLAG_LONGONLY)); +} + +// extern int getopt_long(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +// extern int getopt_long_only(int nargc, char * const *nargv, const char +// *options, +// const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +#define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ \ No newline at end of file diff --git a/cxx/windows/libgen.h b/cxx/windows/libgen.h new file mode 100644 index 0000000..8c80e02 --- /dev/null +++ b/cxx/windows/libgen.h @@ -0,0 +1,27 @@ +// +// Created by biqt on 10/20/17. +// + +#ifndef BIQT_LIBGEN_H +#define BIQT_LIBGEN_H + +/** + * Provides an implementation of dirname() for Windows + * + * @param path The path to find the directory name for. If path does not contain + * / or \, "." is returned. This may modify the contents of path, so be sure to + * pass a copy if this value needs to be preserved. + */ +static char *dirname(char *path) +{ + int i; + for (i = strlen(path) - 2; i >= 0; --i) { + if (path[i] == '\\' || path[i] == '/') { + path[i] = '\0'; + return path; + } + } + return "."; +} + +#endif // BIQT_LIBGEN_H diff --git a/doc/biqt.png b/doc/biqt.png new file mode 100644 index 0000000000000000000000000000000000000000..30b63dcb87b7e9de04d1486eb82b3cec2086c901 GIT binary patch literal 9635 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 apeJ~xJ2UIy{NQ30lb(*TcD|;~<^KU4qNqy% literal 0 HcmV?d00001 diff --git a/doc/biqt.vsd b/doc/biqt.vsd new file mode 100644 index 0000000000000000000000000000000000000000..45c149a0020d274e89d467a1e03aef9df6ed15c5 GIT binary patch literal 61440 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 F_+KzjNJ; + + 4.0.0 + org.mitre + biqt + 0.1 + + UTF-8 + 0.1 + + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + org.apache.logging.log4j + log4j-core + 2.10.0 + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.0.2 + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/alternateLocation + false + false + true + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.0 + + biqt-${biqt.version} + ${output.directory} + + jar-with-dependencies + + false + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-site-plugin + + true + + + + + diff --git a/java/src/c/CMakeLists.txt b/java/src/c/CMakeLists.txt new file mode 100644 index 0000000..6bcb406 --- /dev/null +++ b/java/src/c/CMakeLists.txt @@ -0,0 +1,26 @@ +# ####################################################################### +# NOTICE +# +# This software (or technical data) was produced for the U.S. Government +# under contract, and is subject to the Rights in Data-General Clause +# 52.227-14, Alt. IV (DEC 2007). +# +# Copyright 2019 The MITRE Corporation. All Rights Reserved. +# ####################################################################### + +cmake_minimum_required(VERSION 3.1) +project(biqt) +set(CMAKE_CXX_STANDARD 11) + +set(BIQT_JAVA_SOURCE_FILES jnihelper.c + org_mitre_biqt_BIQT.cpp) + +add_library(biqt_java SHARED ${BIQT_JAVA_SOURCE_FILES}) + +target_link_libraries(biqt_java biqtapi ${CMAKE_DL_LIBS}) + +if(WIN32) + install(TARGETS biqt_java LIBRARY DESTINATION bin) +else() + install(TARGETS biqt_java LIBRARY DESTINATION lib) +endif() diff --git a/java/src/c/java_provider.cpp b/java/src/c/java_provider.cpp new file mode 100644 index 0000000..1db7326 --- /dev/null +++ b/java/src/c/java_provider.cpp @@ -0,0 +1,140 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#include + +#include "jnihelper.h" +#include "org_mitre_biqt_BIQT.h" +#include "java_provider.h" + +#define CLASSPATH "providers/BIQTDummy/biqt-0.1-dev.jar:providers/BIQTDummy/json-simple-1.1.1.jar" + +/** + * Initializes the Java Virtual Machine. + * + * @param jvm An uninitialized pointer to a pointer to the JVM + * @param env An uninitialized pointer to a pointer to the JNI environment + * @param cls An uninitialized pointer for the Java class + * @param className The name of the java class to load into the JVM + * @return + */ +int init_jvm(JavaVM **jvm, JNIEnv **env, jclass *cls, std::string className, + std::string classPath) +{ + char classPathOption[2048] = "-Djava.class.path="; + strncpy(classPathOption+18, classPath.c_str(), 2030); + /* ================= prepare loading of Java VM ========================== */ + JavaVMInitArgs vm_args; // Initialization arguments + JavaVMOption *options = new JavaVMOption[1]; // JVM invocation options + options[0].optionString = classPathOption; + vm_args.version = JNI_VERSION_1_6; // minimum Java version + vm_args.nOptions = 1; // number of options + vm_args.options = options; + vm_args.ignoreUnrecognized = false; // invalid options make the init fail + /* ============ load and initialize Java VM and JNI interface =========== */ + jint rc = JNI_CreateJavaVM(jvm, (void**)env, &vm_args); // YES !! + delete options; // we then no longer need the initialization options. + /* ============== Check for initialization errors ======================= */ + if (rc != JNI_OK) { + // TO DO: error processing... + std::cerr << "Unable to initialize the JVM" << std::endl; + return -1; + } + + *cls = (*env)->FindClass(className.c_str()); + if (*cls == nullptr) { + std::cerr << "Unable to locate the class " << className << std::endl; + return -1; + } + +// /* ============== Display JVM version ================================= */ +// std::cout << "JVM load succeeded: Version "; +// jint ver = env->GetVersion(); +// std::cout << ((ver>>16)&0x0f) << "."<<(ver&0x0f) << std::endl; + + return 0; +} + +void destroy_jvm(JavaVM *jvm) +{ + jvm->DestroyJavaVM(); +} + +/** + * A function to begin provider analysis. + * + * @param filePath The path to the input file. + * @param providerName This should be the provider *directory* name where the + * jar files can be found. + * @param className The name of the Provider class to use for evaluation. This + * should be the fully qualified class name, e.g. + * org/mitre/biqt/IrisProvider + * @param classPath The java class path required for this provider. + * + * @return The return status of the provider. + */ +const char *java_provider_eval(const char *filePath, const char *providerName, + const char *className, const char *classPath) +{ + JavaVM *jvm; + JNIEnv *env; + jclass cls, jsonObject; + jobject provider, jsonResult; + jstring jfilename, jresultStr; + jmethodID constructor, execMethod, toStringMethod; + const char *result; + char *returnvalue; + + if (init_jvm(&jvm, &env, &cls, className, classPath)) { + return nullptr; + } + if (!(constructor = jni_get_method(env, cls, "", "()V"))) { + // log the error; + std::cerr << "Unable to locate the constructor for" << className + << std::endl; + return nullptr; + } + if (!(execMethod = jni_get_method(env, cls, "evaluate", + "(Ljava/lang/String;)" + "Lorg/json/simple/JSONObject;"))) { + // log error + std::cerr << "Unable to locate the evaluate method for " << className + << std::endl; + return nullptr; + } + jfilename = env->NewStringUTF(filePath); + provider = env->NewObject(cls, constructor); + jsonResult = env->CallObjectMethod(provider, execMethod, jfilename); + env->ReleaseStringUTFChars(jfilename, NULL); + + jsonObject = env->FindClass("org/json/simple/JSONObject"); + if (!jsonObject) { + std::cerr << "Unable to locate the class org/json/simple/JSONObject" + << std::endl; + return nullptr; + } + + if (!(toStringMethod = jni_get_method(env, jsonObject, "toString", + "()Ljava/lang/String;"))) { + // log error + std::cerr << "Unable to locate the toString method for" + " org/json/simple/JSONObject" << std::endl; + return nullptr; + } + jresultStr = (jstring)(env->CallObjectMethod(jsonResult, toStringMethod)); + + result = env->GetStringUTFChars(jresultStr, NULL); + returnvalue = new char[strlen(result)]; + strcpy(returnvalue, result); + env->ReleaseStringUTFChars(jresultStr, NULL); + destroy_jvm(jvm); + return returnvalue; +} + diff --git a/java/src/c/java_provider.h b/java/src/c/java_provider.h new file mode 100644 index 0000000..68de35a --- /dev/null +++ b/java/src/c/java_provider.h @@ -0,0 +1,26 @@ +// +// Created by biqt on 1/4/18. +// + +#ifndef BIQT_JAVA_PROVIDER_H +#define BIQT_JAVA_PROVIDER_H + +#include "ProviderInterface.h" + +/** + * A function to begin provider analysis. + * + * @param filePath The path to the input file. + * @param providerName This should be the provider *directory* name where the + * jar files can be found. + * @param className The name of the Provider class to use for evaluation. This + * should be the fully qualified class name, e.g. + * org/mitre/biqt/IrisProvider + * @param classPath The java class path required for this provider. + * + * @return The return status of the provider. + */ +const char *java_provider_eval(const char *filePath, const char *providerName, + const char *className, const char *classPath); + +#endif //BIQT_JAVA_PROVIDER_H diff --git a/java/src/c/jnihelper.c b/java/src/c/jnihelper.c new file mode 100644 index 0000000..d9173f3 --- /dev/null +++ b/java/src/c/jnihelper.c @@ -0,0 +1,120 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#include + +#include "jnihelper.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +/** + * Gets a pointer from the java object (stored as a long). + * + * @param env The java environment + * @param obj The object to retrieve the pointer from + * @param name The name of the java long storing the pointer value + * + * @return The retrieved pointer. + */ +void *jni_get_pointer(JNIEnv *env, jobject obj, const char *name) +{ + void *ptr; + + jclass jcls = (*env)->GetObjectClass(env, obj); + jfieldID ptr_id = (*env)->GetFieldID(env, jcls, name, "J"); + ptr = (void *)((*env)->GetLongField(env, obj, ptr_id)); + + return ptr; +} + +/** + * Sets a pointer in the java object (stored as a long. + * + * @param env The java environment + * @param obj The object to set the pointer inside + * @param name The name of the long which will store the pointer value. + * @param ptr The pointer to be stored. + */ +void jni_set_pointer(JNIEnv *env, jobject obj, const char *name, void *ptr) +{ + jclass jcls = (*env)->GetObjectClass(env, obj); + jfieldID ptr_id = (*env)->GetFieldID(env, jcls, name, "J"); + (*env)->SetLongField(env, obj, ptr_id, (long)ptr); +} + +/** + * Throws a java exception once java regains control. Best practice is to return + * from native code immediately after calling this method. Not doing so may have + * undesired results. + * + * @param env The java environment + * @param exception The type of exception to be thrown, e.g. + * "java/io/IOException" + * @param message The accompanying message for the exception + * + * @return 0 on success, a negative value on failure. + */ +jint jni_throw_exception(JNIEnv *env, const char *exception, + const char *message) +{ + jclass ex = NULL; + + if (exception != NULL) { + ex = (*env)->FindClass(env, exception); + } + if (ex == NULL) { + ex = (*env)->FindClass(env, "java/lang/Exception"); + } + + return (*env)->ThrowNew(env, ex, message); +} + +/** + * Gets a reference to a java class with the provided path, e.g. + * java/lang/String + * + * @param env The Java environment + * @param class_name The name of the class to retrieve a reference to + * @return + */ +jclass jni_get_class(JNIEnv *env, const char *class_name) +{ + jclass class_ptr; + char message[1024]; + + class_ptr = (*env)->FindClass(env, class_name); + if (!class_ptr) { + snprintf(message, 1024, "Unable to locate class %s", class_name); + jni_throw_exception(env, "java/lang/ClassNotFoundException", message); + return NULL; + } + return class_ptr; +} + +jmethodID jni_get_method(JNIEnv *env, jclass class_ptr, const char *method_name, + const char *signature) +{ + jmethodID method; + char message[1024]; + + if (!class_ptr) { + return NULL; + } + method = (*env)->GetMethodID(env, class_ptr, method_name, signature); + if (!method) { + snprintf(message, 1024, "Unable to locate method %s with signature %s", + method_name, signature); + jni_throw_exception(env, "java/lang/NoSuchMethodException", message); + return NULL; + } + return method; +} diff --git a/java/src/c/jnihelper.h b/java/src/c/jnihelper.h new file mode 100644 index 0000000..77dae3b --- /dev/null +++ b/java/src/c/jnihelper.h @@ -0,0 +1,31 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#ifndef JNI_HELPER_H +#define JNI_HELPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *jni_get_pointer(JNIEnv *, jobject, const char *name); +void jni_set_pointer(JNIEnv *, jobject, const char *name, void *ptr); +jint jni_throw_exception(JNIEnv *, const char *exception, const char *message); +jclass jni_get_class(JNIEnv *, const char *class_name); +jmethodID jni_get_method(JNIEnv *, jclass, const char *method_name, + const char *signature); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/java/src/c/org_mitre_biqt_BIQT.cpp b/java/src/c/org_mitre_biqt_BIQT.cpp new file mode 100644 index 0000000..82a204d --- /dev/null +++ b/java/src/c/org_mitre_biqt_BIQT.cpp @@ -0,0 +1,160 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#include +#include "org_mitre_biqt_BIQT.h" +#include "BIQT.h" +#include "ProviderInterface.h" +#include "jnihelper.h" + +/** + * Initializes a Java BIQT object. + * + * @param env The Java environment + * @param biqt The Java BIQT object + */ +JNIEXPORT void JNICALL +Java_org_mitre_biqt_BIQT_initialize(JNIEnv *env, jobject biqt) +{ + BIQT *app = new BIQT(); // create the object on the heap. + jni_set_pointer(env, biqt, "biqt_ptr", (void *)app); +} + +/** + * Gets a list of available providers + * + * @param env The Java environment + * @param biqt The Java BIQT object + */ +JNIEXPORT jobject JNICALL +Java_org_mitre_biqt_BIQT_getProviders(JNIEnv *env, jobject biqt) +{ + jstring name, version, description, modality; + jclass piClass, listClass; + jmethodID piConstructor, listConstructor, listAdd; + jobject providerInfo, list; + + BIQT *app = (BIQT *)jni_get_pointer(env, biqt, "biqt_ptr"); + std::vector providers = app->getProviders(); + + listClass = jni_get_class(env, "java/util/ArrayList"); + piClass = jni_get_class(env, "org/mitre/biqt/ProviderInfo"); + + if (!(listConstructor = jni_get_method(env, listClass, "", "()V"))) + return nullptr; + if (!(listAdd = + jni_get_method(env, listClass, "add", "(Ljava/lang/Object;)Z"))) + return nullptr; + if (!(piConstructor = + jni_get_method(env, piClass, "", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/" + "String;Ljava/lang/String;)V"))) + return nullptr; + + list = env->NewObject(listClass, listConstructor); + + for (const auto p : providers) { + // iterate through each provider and insert them into an ArrayList + name = env->NewStringUTF(p->name.c_str()); + version = env->NewStringUTF(p->version.c_str()); + description = env->NewStringUTF(p->description.c_str()); + modality = env->NewStringUTF(p->modality.c_str()); + providerInfo = env->NewObject(piClass, piConstructor, name, version, + description, modality); + env->CallBooleanMethod(list, listAdd, providerInfo); + } + return list; +} + +/** + * Runs a provider with the provided name. + * + * @param env The Java environment + * @param biqt The Java BIQT object + * @param jprovider A Java String containing the provider name. + * @param jinputFile A Java String containing the input file for the provider. + */ +JNIEXPORT jstring JNICALL Java_org_mitre_biqt_BIQT_runProvider( + JNIEnv *env, jobject biqt, jstring jprovider, jstring jinputFile) +{ + const char *provider; + const char *inputFile; + Provider::EvaluationResult result; + BIQT *app = (BIQT *)jni_get_pointer(env, biqt, "biqt_ptr"); + + /* Get the strings from the java types */ + provider = env->GetStringUTFChars(jprovider, NULL); + inputFile = env->GetStringUTFChars(jinputFile, NULL); + + result = app->runProvider(std::string(provider), std::string(inputFile)); + std::unique_ptr resultStr(Provider::serializeResult(result)); + jstring jresult = env->NewStringUTF(resultStr.get()); + + /* Release the strings back to java */ + env->ReleaseStringUTFChars(jprovider, provider); + env->ReleaseStringUTFChars(jinputFile, inputFile); + + return jresult; +} + +/** + * Runs all providers with the given modality + * + * @param env The Java environment + * @param biqt The Java BIQT object + * @param jmodality A Java String containing the modality of the provider(s) to + * run + * @param jinputFile A Java String containing the path to the input file to + * analyze + */ +JNIEXPORT jstring JNICALL Java_org_mitre_biqt_BIQT_runModality( + JNIEnv *env, jobject biqt, jstring jmodality, jstring jinputFile) +{ + const char *modality; + const char *inputFile; + std::string resultStr; + std::map result; + BIQT *app = (BIQT *)jni_get_pointer(env, biqt, "biqt_ptr"); + + /* Get the strings from the java types */ + modality = env->GetStringUTFChars(jmodality, NULL); + inputFile = env->GetStringUTFChars(jinputFile, NULL); + + result = app->runModality(std::string(modality), std::string(inputFile)); + for (const auto &iter : result) { + if (resultStr.length()) { + resultStr = resultStr + ","; + } + char* serialized_result = Provider::serializeResult(iter.second); + resultStr = resultStr + serialized_result; + delete[] serialized_result; + } + jstring jresult = env->NewStringUTF(resultStr.c_str()); + + /* Release the strings back to java */ + env->ReleaseStringUTFChars(jmodality, modality); + env->ReleaseStringUTFChars(jinputFile, inputFile); + return jresult; +} + +/** + * Cleans up any allocated memory. This should only be called when you are + * finished with the Java BIQT object. + * + * @param env The Java environment + * @param biqt The Java BIQT object + */ +JNIEXPORT void JNICALL Java_org_mitre_biqt_BIQT_cleanup(JNIEnv *env, + jobject biqt) +{ + BIQT *app = (BIQT *)jni_get_pointer(env, biqt, "biqt_ptr"); + delete app; + jni_set_pointer(env, biqt, "biqt_ptr", (void *)NULL); +} diff --git a/java/src/c/org_mitre_biqt_BIQT.h b/java/src/c/org_mitre_biqt_BIQT.h new file mode 100644 index 0000000..4d04319 --- /dev/null +++ b/java/src/c/org_mitre_biqt_BIQT.h @@ -0,0 +1,63 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_mitre_biqt_BIQT */ + +#ifndef _Included_org_mitre_biqt_BIQT +#define _Included_org_mitre_biqt_BIQT +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_mitre_biqt_BIQT + * Method: initialize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_mitre_biqt_BIQT_initialize(JNIEnv *, + jobject); + +/* + * Class: org_mitre_biqt_BIQT + * Method: getProviders + * Signature: ()Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL +Java_org_mitre_biqt_BIQT_getProviders(JNIEnv *env, jobject biqt); + +/* + * Class: org_mitre_biqt_BIQT + * Method: runProvider + * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_mitre_biqt_BIQT_runProvider( + JNIEnv *, jobject, jstring, jstring); + +/* + * Class: org_mitre_biqt_BIQT + * Method: runModality + * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_mitre_biqt_BIQT_runModality( + JNIEnv *, jobject, jstring, jstring); + +/* + * Class: org_mitre_biqt_BIQT + * Method: cleanup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_mitre_biqt_BIQT_cleanup(JNIEnv *, + jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/java/src/main/java/cz/adamh/utils/NativeUtils.java b/java/src/main/java/cz/adamh/utils/NativeUtils.java new file mode 100644 index 0000000..4b31c60 --- /dev/null +++ b/java/src/main/java/cz/adamh/utils/NativeUtils.java @@ -0,0 +1,151 @@ +/* + * Class NativeUtils is published under the The MIT License: + * + * Copyright (c) 2012 Adam Heinrich + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package cz.adamh.utils; + +import java.io.*; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.ProviderNotFoundException; +import java.nio.file.StandardCopyOption; + +/** + * A simple library class which helps with loading dynamic libraries stored in + * the JAR archive. These libraries usualy contain implementation of some + * methods in native code (using JNI - Java Native Interface). + * + * @see + * http://adamheinrich.com/blog/2012/how-to-load-native-jni-library-from-jar + * @see https://github.com/adamheinrich/native-utils + * + */ +public class NativeUtils { + + /** + * The minimum length a prefix for a file has to have according to {@link + * File#createTempFile(String, String)}}. + */ + private static final int MIN_PREFIX_LENGTH = 3; + + /** + * Temporary directory which will contain the DLLs. + */ + private static File temporaryDir; + + /** + * Private constructor - this class will never be instanced + */ + private NativeUtils() {} + + /** + * Loads library from current JAR archive + * + * The file from JAR is copied into system temporary directory and then + * loaded. The temporary file is deleted after exiting. Method uses String as + * filename because the pathname is "abstract", not system-dependent. + * + * @param path The path of file inside JAR as absolute path (beginning with + * '/'), e.g. /package/File.ext + * @throws IOException If temporary file creation or read/write operation + * fails + * @throws IllegalArgumentException If source file (param path) does not exist + * @throws IllegalArgumentException If the path is not absolute or if the + * filename is shorter than three characters (restriction of {@link + * File#createTempFile(java.lang.String, java.lang.String)}). + * @throws FileNotFoundException If the file could not be found inside the + * JAR. + */ + public static void loadLibraryFromJar(String path) throws IOException { + + if (!path.startsWith("/")) { + throw new IllegalArgumentException( + "The path has to be absolute (start with '/')."); + } + + // Obtain filename from path + String[] parts = path.split("/"); + String filename = (parts.length > 1) ? parts[parts.length - 1] : null; + + // Check if the filename is okay + if (filename == null || filename.length() < MIN_PREFIX_LENGTH) { + throw new IllegalArgumentException( + "The filename has to be at least 3 characters long."); + } + + // Prepare temporary file + if (temporaryDir == null) { + temporaryDir = createTempDirectory("nativeutils"); + temporaryDir.deleteOnExit(); + } + + File temp = new File(temporaryDir, filename); + + try (InputStream is = NativeUtils.class.getResourceAsStream(path)) { + Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + temp.delete(); + throw e; + } catch (NullPointerException e) { + temp.delete(); + throw new FileNotFoundException("File " + path + + " was not found inside JAR."); + } + + try { + System.load(temp.getAbsolutePath()); + } finally { + if (isPosixCompliant()) { + // Assume POSIX compliant file system, can be deleted after loading + temp.delete(); + } else { + // Assume non-POSIX, and don't delete until last file descriptor closed + temp.deleteOnExit(); + } + } + } + + private static boolean isPosixCompliant() { + try { + if (FileSystems.getDefault().supportedFileAttributeViews().contains( + "posix")) { + return true; + } + return false; + } catch (FileSystemNotFoundException | ProviderNotFoundException | + SecurityException e) { + return false; + } + } + + private static File createTempDirectory(String prefix) throws IOException { + String tempDir = System.getProperty("java.io.tmpdir"); + File generatedDir = new File(tempDir, prefix + System.nanoTime()); + + if (!generatedDir.mkdir()) + throw new IOException("Failed to create temp directory " + + generatedDir.getName()); + + return generatedDir; + } +} diff --git a/java/src/main/java/org/mitre/biqt/BIQT.java b/java/src/main/java/org/mitre/biqt/BIQT.java new file mode 100644 index 0000000..2987a21 --- /dev/null +++ b/java/src/main/java/org/mitre/biqt/BIQT.java @@ -0,0 +1,163 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +package org.mitre.biqt; + +import java.util.List; +import java.util.ArrayList; +import java.io.IOException; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import cz.adamh.utils.NativeUtils; + +/** + * A new instance of BIQT which can be used to run available providers. + */ +public class BIQT { + private static final Logger logger = LogManager.getLogger(); + private static final String os = System.getProperty("os.name"); + + /* Loads the necessary native code libraries from the jar file */ + static { + try { + if (os.startsWith("Windows")) { + NativeUtils.loadLibraryFromJar("/biqtapi.dll"); + NativeUtils.loadLibraryFromJar("/biqt_java.dll"); + } else if (os.startsWith("Mac")) { + NativeUtils.loadLibraryFromJar("/libbiqtapi.dylib"); + NativeUtils.loadLibraryFromJar("/libbiqt_java.dylib"); + } else { + NativeUtils.loadLibraryFromJar("/libbiqtapi.so"); + NativeUtils.loadLibraryFromJar("/libbiqt_java.so"); + } + } catch (IOException e) { + System.loadLibrary("biqtapi"); + System.loadLibrary("biqt_java"); + logger.error(e); + } + } + + /** Used in native code for storing a pointer to a BIQT instance */ + private long biqt_ptr; + + /** + * Creates a new BIQT instance + */ + public BIQT() { this.initialize(); } + + public native List getProviders(); + + /** + * Initializes the necessary variables in native code + */ + public native void initialize(); + + /** + * Runs one or more providers based on modality + * + * @param modality The modality of the provider to run, e.g. "iris" + * @param inputFiles The files to analyze for quality with the specified + * providers. + * + * @return A list of JSONObjects containing the provider results. + */ + public List runModality(String modality, + List inputFiles) { + String result; + JSONParser parser = new JSONParser(); + List results = new ArrayList(); + for (String inputFile : inputFiles) { + result = runModality(modality, inputFile); + try { + JSONObject json = (JSONObject)parser.parse(result); + results.add(json); + } catch (ParseException e) { + logger.error(e); + logger.error( + String.format("BIQT response for file '%s' was malformed: \n%s", + inputFile, result)); + } + } + return results; + } + + /** + * Runs the specified provider + * + * @param provider The ProviderInfo related to the provider to run. + * @param inputFiles The files to analyze for quality with the specified + * providers. + * + * @return A list of JSONObjects containing the provider results. + */ + public List runProvider(ProviderInfo provider, + List inputFiles) { + return this.runProvider(provider.getName(), inputFiles); + } + + /** + * Runs a provider with the specified name + * + * @param provider The name of the provider to run. + * @param inputFiles The files to analyze for quality with the specified + * providers. + * + * @return A list of JSONObjects containing the provider results. + */ + public List runProvider(String provider, + List inputFiles) { + String result; + JSONParser parser = new JSONParser(); + List results = new ArrayList(); + + for (String inputFile : inputFiles) { + result = runProvider(provider, inputFile); + try { + JSONObject json = (JSONObject)parser.parse(result); + results.add(json); + } catch (ParseException e) { + logger.error( + String.format("BIQT response for file '%s' was malformed: \n%s", + inputFile, result)); + } + } + return results; + } + + /** + * Calls the specified provider in native code. + * + * @param provider The name of the provider to be run. + * @param inputFile The file to analyze with the given provider. + */ + private native String runProvider(String provider, String inputFile); + + /** + * Calls a provider with the specified modality in native code. + * + * @param provider The name of the provider to be run. + * @param inputFile The file to analyze with the given provider. + */ + private native String runModality(String modality, String inputfile); + + /** + * Cleans up and frees any memory allocated in native code. This is + * automatically called by the Java garbage collector. + */ + protected void finalize() { this.cleanup(); } + + /** + * Cleans up and frees any memory allocated in native code. + */ + private native void cleanup(); +} diff --git a/java/src/main/java/org/mitre/biqt/Provider.java b/java/src/main/java/org/mitre/biqt/Provider.java new file mode 100644 index 0000000..ec226d1 --- /dev/null +++ b/java/src/main/java/org/mitre/biqt/Provider.java @@ -0,0 +1,60 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +package org.mitre.biqt; + +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +public abstract class Provider { + private String providerName; + private String message; + private int errorCode; + + protected Provider() { + this.providerName = this.getClass().getSimpleName(); + } + + /** + * Evaluates an image file and returns a JSON String + * + * @param filename The path to the file to be evaluated. + * + * @return A JSON String representation of the result + */ + public JSONObject evaluate(String filename) { + JSONObject jsonResult = new JSONObject(); + JSONObject providerObject = new JSONObject(); + JSONObject resultObject = new JSONObject(); + JSONArray resultNameArray = new JSONArray(); + JSONObject features = new JSONObject(); + JSONObject metrics = new JSONObject(); + resultNameArray.add(resultObject); + resultObject.put("features", features); + resultObject.put("metrics", metrics); + providerObject.put(this.providerName, resultObject); + this.setResults(filename, features, metrics); + jsonResult.put("errorCode", this.errorCode); + jsonResult.put("message", this.message); + jsonResult.put("provider", this.providerName); + jsonResult.put("qualityResult", providerObject); + + return jsonResult; + } + + protected abstract void setResults(String filename, JSONObject features, + JSONObject metrics); + + public static List getProviders() { + return null; + } +} diff --git a/java/src/main/java/org/mitre/biqt/ProviderInfo.java b/java/src/main/java/org/mitre/biqt/ProviderInfo.java new file mode 100644 index 0000000..4c6bdfd --- /dev/null +++ b/java/src/main/java/org/mitre/biqt/ProviderInfo.java @@ -0,0 +1,64 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +package org.mitre.biqt; + +public class ProviderInfo { + + private String name; + private String version; + private String description; + private String modality; + + /** + * Creates a new instance of the provider. Intended to be called from native + * code, and should not be instantiated from Java. + * + * @param name The name of the provider + * @param version The version number of the provider + * @param description The description of the provider + * @param modality The modality type of the provider + */ + private ProviderInfo(String name, String version, String description, + String modality) { + this.name = name; + this.version = version; + this.description = description; + this.modality = modality; + } + + /** + * Gets the name for this provider + * + * @return The name of this provider as a String + */ + public String getName() { return this.name; } + + /** + * Gets the version number of this provider + * + * @return The version number as a String + */ + public String getVersion() { return this.version; } + + /** + * Gets the description of the provider + * + * @return The description of this provider as a String + */ + public String getDescription() { return this.description; } + + /** + * Gets the modality of the provider + * + * @return The modality of the provider as a String + */ + public String getModality() { return this.modality; } +} diff --git a/java/src/test/java/org/mitre/biqt/TestBIQT.java b/java/src/test/java/org/mitre/biqt/TestBIQT.java new file mode 100644 index 0000000..748f8d7 --- /dev/null +++ b/java/src/test/java/org/mitre/biqt/TestBIQT.java @@ -0,0 +1,44 @@ +package org.mitre.biqt; + +import org.json.simple.JSONObject; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import java.util.List; +import java.util.ArrayList; + +public class TestBIQT { + + @Test + public void testGetProviders() { + BIQT app = new BIQT(); + int foundCount = 0; + List providers = app.getProviders(); + assertTrue(providers.size() >= 2); + + for (ProviderInfo p : providers) { + if (p.getName().equals("BIQTFace") || p.getName().equals("BIQTIris")) { + foundCount++; + } + } + assertEquals(2, foundCount); + } + + @Test + public void testRunProvider() { + BIQT app = new BIQT(); + ArrayList inputFiles = new ArrayList(); + inputFiles.add(System.getenv("BIQT_HOME") + "/../images/iris1.bmp"); + List results = app.runProvider("BIQTIris", inputFiles); + assertTrue("Received an empty result set", results.size() > 0); + } + + @Test + public void testRunModality() { + BIQT app = new BIQT(); + ArrayList inputFiles = new ArrayList(); + inputFiles.add(System.getenv("BIQT_HOME") + "/../images/iris1.bmp"); + List results = app.runModality("iris", inputFiles); + assertTrue("Received an empty result set", results.size() > 0); + } +} diff --git a/setup_provider.py b/setup_provider.py new file mode 100644 index 0000000..899b31e --- /dev/null +++ b/setup_provider.py @@ -0,0 +1,57 @@ +# ####################################################################### +# NOTICE +# +# This software (or technical data) was produced for the U.S. Government +# under contract, and is subject to the Rights in Data-General Clause +# 52.227-14, Alt. IV (DEC 2007). +# +# Copyright 2019 The MITRE Corporation. All Rights Reserved. +# ####################################################################### + +import os +import re +import argparse +import sys + +if not os.environ['BIQT_HOME']: + sys.exit("Error: The BIQT_HOME environment variable is not set. This script requires BIQT_HOME to be assigned to the installation directory of BIQT.") + +def instantiate_template(pname, template_name, out_file_name): + with open(os.environ['BIQT_HOME'] + '/scripts/templates/' + template_name, 'r') as template_file, open(pname + '/' + out_file_name, 'w') as provider_file: + template_data = template_file.read() + provider_data = template_data.replace('NewProvider', pname) + provider_data = provider_data.replace('NEWPROVIDER_H', pname.upper() + '_H') + provider_file.write(provider_data) + +def main(): + # Parse command line arguments + parser = argparse.ArgumentParser() + parser.add_argument('pname', type=str, help='Name of new provider algorithm.') + args = parser.parse_args() + + # Is pname ok? Can only contain alphanumeric characters (A-Z, a-z, 0-9) or underscore (_) or dash(-) + if not (re.match(r'^[A-Za-z0-9_-]+$', args.pname)): + sys.exit("ERROR: The provider name you entered was not valid. The provider name should only contain alphanumeric characters, dashes, and underscores.") + + # Setup the provider directory structure + prodir = args.pname + "/" + for d in [prodir, prodir+'src', prodir+'config']: + if not os.path.isdir(d): + os.mkdir(d) + + # Create provider interface files + if not os.path.exists(prodir + args.pname + '.h'): + instantiate_template(args.pname, 'Provider.h', args.pname + '.h') + if not os.path.exists(prodir + args.pname + '.cpp'): + instantiate_template(args.pname, 'Provider.cpp', args.pname + '.cpp') + + # Create descriptor file + if not os.path.exists(prodir + 'descriptor.json'): + instantiate_template(args.pname, 'descriptor.json', 'descriptor.json') + + # Create CMakeLists.txt + if not os.path.exists(prodir + 'CMakeLists.txt'): + instantiate_template(args.pname, 'CMakeLists.txt', 'CMakeLists.txt') + +if __name__ == '__main__': + main() diff --git a/templates/CMakeLists.txt b/templates/CMakeLists.txt new file mode 100644 index 0000000..2bfad26 --- /dev/null +++ b/templates/CMakeLists.txt @@ -0,0 +1,75 @@ +# ####################################################################### +# NOTICE +# +# This software (or technical data) was produced for the U.S. Government +# under contract, and is subject to the Rights in Data-General Clause +# 52.227-14, Alt. IV (DEC 2007). +# +# Copyright 2019 The MITRE Corporation. All Rights Reserved. +# ####################################################################### + +cmake_minimum_required(VERSION 3.1) +project(NewProvider) +set(CMAKE_CXX_STANDARD 11) + +OPTION(BUILD_SHARED_LIBS "Builds shared libraries for certain dependencies. Recommended: ON" ON) +OPTION(BUILD_STATIC_LIBS "Builds static libraries for certain dependencies. Recommended: OFF" OFF) + +if(NOT WIN32) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + set(CMAKE_CXX_FLAGS "-g -fPIC") +endif() + +if(DEFINED ENV{BIQT_HOME}) + if(BIQT_HOME) + message(WARNING "Both -DBIQT_HOME and a BIQT_HOME environment variable are defined. Using -DBIQT_HOME (${BIQT_HOME}).") + else() + set(BIQT_HOME "$ENV{BIQT_HOME}") + endif() +endif() + +if(NOT BIQT_HOME) + message(FATAL_ERROR "BIQT_HOME must be defined as an environment variable or passed to CMake as a parameter using -DBIQT_HOME.") +else() + set(TO_CMAKE_PATH ${BIQT_HOME} BIQT_HOME) +endif() + +if(CMAKE_INSTALL_PREFIX) + # Ignore CMAKE_INSTALL_PREFIX, but let the user know about it. + message(WARNING "Overriding provided CMAKE_INSTALL_PREFIX with ${BIQT_HOME}/providers.") +endif() + +set(CMAKE_INSTALL_PREFIX "${BIQT_HOME}/providers") + +find_library(JSONCPP NAMES libjsoncpp jsoncpp HINTS ${BIQT_HOME}/lib ${BIQT_HOME}/lib64 ${BIQT_HOME}/bin ${BIQT_HOME}/../../lib ${BIQT_HOME}/../../lib64 ${BIQT_HOME}/../../bin) +find_library(BIQTAPI NAMES libbiqtapi biqtapi HINTS ${BIQT_HOME}/lib ${BIQT_HOME}/lib64 ${BIQT_HOME}/bin ${BIQT_HOME}/../../lib ${BIQT_HOME}/../../lib64 ${BIQT_HOME}/../../bin) + +if(NOT JSONCPP) + message(FATAL_ERROR "Failed to find library: jsoncpp.") +endif() + +if(NOT BIQTAPI) + message(FATAL_ERROR "Failed to find library: biqtapi.") +endif() + +# TODO: Include any additional packages. +# find_package(...) + +# TODO: Append any additional include files. +# set(EXTRA_INCLUDES "3rdparty") +include_directories(. "include" ${BIQT_HOME}/include ${BIQT_HOME}/../../include ${EXTRA_INCLUDES}) + +# Create the provider library +file(GLOB SOURCE_FILES "*.cpp") + +# TODO: Add any other source files. +# set(EXTRA_FILES MyFile.cpp) +add_library(NewProvider SHARED ${SOURCE_FILES} ${EXTRA_FILES}) + +target_link_libraries(NewProvider ${JSONCPP} ${BIQTAPI}) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/descriptor.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +# Set installation rules +install(TARGETS NewProvider DESTINATION "${CMAKE_PROJECT_NAME}") +install(FILES descriptor.json DESTINATION "${CMAKE_PROJECT_NAME}") diff --git a/templates/Provider.cpp b/templates/Provider.cpp new file mode 100644 index 0000000..995dc24 --- /dev/null +++ b/templates/Provider.cpp @@ -0,0 +1,54 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#include +#include +#include + +NewProvider::NewProvider() +{ + // Initialize metadata + std::string biqt_home = getenv("BIQT_HOME"); + std::ifstream desc_file(biqt_home + + "/providers/NewProvider/descriptor.json", + std::ifstream::binary); + desc_file >> DescriptorObject; + + // TODO: Instantiate any additional objects needed for your algorithm +} + +NewProvider::~NewProvider() +{ + // TODO: If needed, populate the destructor +} + +Provider::EvaluationResult NewProvider::evaluate(const std::string &file) +{ + // Initialize some variables + Provider::EvaluationResult evalResult; + Provider::QualityResult qualityResult; + + // TODO: Read the input image 'file' (string indicating file path to image) + + // TODO: Populate metrics and features maps. + qualityResult.metrics["quality"] = 555.55; + qualityResult.features["left_eye_x"] = 1; + + evalResult.qualityResult.push_back(std::move(qualityResult)); + return evalResult; +} + +DLL_EXPORT const char *provider_eval(const char *cFilePath) +{ + NewProvider p; + std::string filePath(cFilePath); + Provider::EvaluationResult result = p.evaluate(filePath); + return Provider::serializeResult(result); +} diff --git a/templates/Provider.h b/templates/Provider.h new file mode 100644 index 0000000..1732fbd --- /dev/null +++ b/templates/Provider.h @@ -0,0 +1,28 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +#ifndef NEWPROVIDER_H +#define NEWPROVIDER_H + +#include +#include +#include +#include +// TODO: Include any additional header files + +class NewProvider : public Provider { + + public: + NewProvider(); + ~NewProvider() override; + Provider::EvaluationResult evaluate(const std::string &file) override; +}; + +#endif diff --git a/templates/descriptor.json b/templates/descriptor.json new file mode 100644 index 0000000..42c5f8b --- /dev/null +++ b/templates/descriptor.json @@ -0,0 +1,27 @@ +// ####################################################################### +// NOTICE +// +// This software (or technical data) was produced for the U.S. Government +// under contract, and is subject to the Rights in Data-General Clause +// 52.227-14, Alt. IV (DEC 2007). +// +// Copyright 2019 The MITRE Corporation. All Rights Reserved. +// ####################################################################### + +{ + "name" : "NewProvider", + "description": "TODO: Provide a description.", + "version" : "TODO: Set a version", + "sourceLanguage" : "c++", + "modality": "TODO: Set a modality.", // E.g., "face", "iris", etc. + + "attributes": [ + /* Example */ + { + "name": "quality", + "description": "TODO: Describe this metric.", + "type": "DOUBLE", // one of {'INTEGER', 'DOUBLE', 'FLOAT', 'BOOLEAN', ...} + "defaultValue": "123.45" + } + ] +}