jsoncons 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. data/ext/jsoncons/extconf.rb +43 -0
  3. data/ext/jsoncons/jsoncons.cpp +161 -0
  4. data/ext/jsoncons/jsoncons.h +10 -0
  5. data/jsoncons.gemspec +44 -0
  6. data/lib/jsoncons/jsoncons/examples/input/address-book.json +13 -0
  7. data/lib/jsoncons/jsoncons/examples/input/books.json +28 -0
  8. data/lib/jsoncons/jsoncons/examples/input/countries.json +7 -0
  9. data/lib/jsoncons/jsoncons/examples/input/employees.json +30 -0
  10. data/lib/jsoncons/jsoncons/examples/input/jsonschema/name.json +15 -0
  11. data/lib/jsoncons/jsoncons/examples/input/multiple-json-objects.json +3 -0
  12. data/lib/jsoncons/jsoncons/examples/input/sales.csv +6 -0
  13. data/lib/jsoncons/jsoncons/examples/input/store.json +28 -0
  14. data/lib/jsoncons/jsoncons/examples/input/tasks.csv +6 -0
  15. data/lib/jsoncons/jsoncons/include/jsoncons/allocator_holder.hpp +38 -0
  16. data/lib/jsoncons/jsoncons/include/jsoncons/basic_json.hpp +5905 -0
  17. data/lib/jsoncons/jsoncons/include/jsoncons/bigint.hpp +1611 -0
  18. data/lib/jsoncons/jsoncons/include/jsoncons/byte_string.hpp +820 -0
  19. data/lib/jsoncons/jsoncons/include/jsoncons/config/binary_config.hpp +226 -0
  20. data/lib/jsoncons/jsoncons/include/jsoncons/config/compiler_support.hpp +375 -0
  21. data/lib/jsoncons/jsoncons/include/jsoncons/config/jsoncons_config.hpp +309 -0
  22. data/lib/jsoncons/jsoncons/include/jsoncons/config/version.hpp +40 -0
  23. data/lib/jsoncons/jsoncons/include/jsoncons/conv_error.hpp +218 -0
  24. data/lib/jsoncons/jsoncons/include/jsoncons/decode_json.hpp +209 -0
  25. data/lib/jsoncons/jsoncons/include/jsoncons/decode_traits.hpp +651 -0
  26. data/lib/jsoncons/jsoncons/include/jsoncons/detail/endian.hpp +44 -0
  27. data/lib/jsoncons/jsoncons/include/jsoncons/detail/grisu3.hpp +312 -0
  28. data/lib/jsoncons/jsoncons/include/jsoncons/detail/optional.hpp +483 -0
  29. data/lib/jsoncons/jsoncons/include/jsoncons/detail/parse_number.hpp +1133 -0
  30. data/lib/jsoncons/jsoncons/include/jsoncons/detail/span.hpp +188 -0
  31. data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_view.hpp +537 -0
  32. data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_wrapper.hpp +370 -0
  33. data/lib/jsoncons/jsoncons/include/jsoncons/detail/write_number.hpp +567 -0
  34. data/lib/jsoncons/jsoncons/include/jsoncons/encode_json.hpp +315 -0
  35. data/lib/jsoncons/jsoncons/include/jsoncons/encode_traits.hpp +378 -0
  36. data/lib/jsoncons/jsoncons/include/jsoncons/json.hpp +18 -0
  37. data/lib/jsoncons/jsoncons/include/jsoncons/json_array.hpp +324 -0
  38. data/lib/jsoncons/jsoncons/include/jsoncons/json_content_handler.hpp +12 -0
  39. data/lib/jsoncons/jsoncons/include/jsoncons/json_cursor.hpp +448 -0
  40. data/lib/jsoncons/jsoncons/include/jsoncons/json_decoder.hpp +420 -0
  41. data/lib/jsoncons/jsoncons/include/jsoncons/json_encoder.hpp +1587 -0
  42. data/lib/jsoncons/jsoncons/include/jsoncons/json_error.hpp +156 -0
  43. data/lib/jsoncons/jsoncons/include/jsoncons/json_exception.hpp +241 -0
  44. data/lib/jsoncons/jsoncons/include/jsoncons/json_filter.hpp +653 -0
  45. data/lib/jsoncons/jsoncons/include/jsoncons/json_fwd.hpp +23 -0
  46. data/lib/jsoncons/jsoncons/include/jsoncons/json_object.hpp +1772 -0
  47. data/lib/jsoncons/jsoncons/include/jsoncons/json_options.hpp +862 -0
  48. data/lib/jsoncons/jsoncons/include/jsoncons/json_parser.hpp +2900 -0
  49. data/lib/jsoncons/jsoncons/include/jsoncons/json_reader.hpp +731 -0
  50. data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros.hpp +1072 -0
  51. data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros_deprecated.hpp +144 -0
  52. data/lib/jsoncons/jsoncons/include/jsoncons/json_type.hpp +206 -0
  53. data/lib/jsoncons/jsoncons/include/jsoncons/json_type_traits.hpp +1830 -0
  54. data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor.hpp +1560 -0
  55. data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor2.hpp +2079 -0
  56. data/lib/jsoncons/jsoncons/include/jsoncons/pretty_print.hpp +89 -0
  57. data/lib/jsoncons/jsoncons/include/jsoncons/ser_context.hpp +62 -0
  58. data/lib/jsoncons/jsoncons/include/jsoncons/sink.hpp +289 -0
  59. data/lib/jsoncons/jsoncons/include/jsoncons/source.hpp +777 -0
  60. data/lib/jsoncons/jsoncons/include/jsoncons/source_adaptor.hpp +148 -0
  61. data/lib/jsoncons/jsoncons/include/jsoncons/staj2_cursor.hpp +1189 -0
  62. data/lib/jsoncons/jsoncons/include/jsoncons/staj_cursor.hpp +1254 -0
  63. data/lib/jsoncons/jsoncons/include/jsoncons/staj_iterator.hpp +449 -0
  64. data/lib/jsoncons/jsoncons/include/jsoncons/tag_type.hpp +245 -0
  65. data/lib/jsoncons/jsoncons/include/jsoncons/text_source_adaptor.hpp +144 -0
  66. data/lib/jsoncons/jsoncons/include/jsoncons/traits_extension.hpp +884 -0
  67. data/lib/jsoncons/jsoncons/include/jsoncons/typed_array_view.hpp +250 -0
  68. data/lib/jsoncons/jsoncons/include/jsoncons/unicode_traits.hpp +1330 -0
  69. data/lib/jsoncons/jsoncons/include/jsoncons/uri.hpp +635 -0
  70. data/lib/jsoncons/jsoncons/include/jsoncons/value_converter.hpp +340 -0
  71. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson.hpp +23 -0
  72. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_cursor.hpp +320 -0
  73. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp +865 -0
  74. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_encoder.hpp +585 -0
  75. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_error.hpp +103 -0
  76. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_oid.hpp +245 -0
  77. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_options.hpp +75 -0
  78. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_parser.hpp +645 -0
  79. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_reader.hpp +92 -0
  80. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_type.hpp +44 -0
  81. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/decode_bson.hpp +201 -0
  82. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/encode_bson.hpp +144 -0
  83. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor.hpp +26 -0
  84. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor.hpp +351 -0
  85. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor2.hpp +265 -0
  86. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_detail.hpp +93 -0
  87. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_encoder.hpp +1766 -0
  88. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_error.hpp +105 -0
  89. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_options.hpp +113 -0
  90. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_parser.hpp +1942 -0
  91. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_reader.hpp +116 -0
  92. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/decode_cbor.hpp +203 -0
  93. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/encode_cbor.hpp +151 -0
  94. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv.hpp +17 -0
  95. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_cursor.hpp +358 -0
  96. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_encoder.hpp +954 -0
  97. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_error.hpp +85 -0
  98. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_options.hpp +973 -0
  99. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_parser.hpp +2099 -0
  100. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_reader.hpp +348 -0
  101. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_serializer.hpp +12 -0
  102. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/decode_csv.hpp +208 -0
  103. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/encode_csv.hpp +122 -0
  104. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath.hpp +5215 -0
  105. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath_error.hpp +215 -0
  106. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch.hpp +579 -0
  107. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp +121 -0
  108. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/expression.hpp +3329 -0
  109. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/flatten.hpp +432 -0
  110. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_location.hpp +445 -0
  111. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_query.hpp +115 -0
  112. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath.hpp +13 -0
  113. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_error.hpp +240 -0
  114. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_expression.hpp +2612 -0
  115. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp +1322 -0
  116. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer.hpp +1577 -0
  117. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp +119 -0
  118. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/format_validator.hpp +968 -0
  119. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/json_validator.hpp +120 -0
  120. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema.hpp +13 -0
  121. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_error.hpp +105 -0
  122. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_version.hpp +18 -0
  123. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator.hpp +1745 -0
  124. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator_factory.hpp +556 -0
  125. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_draft7.hpp +198 -0
  126. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_location.hpp +200 -0
  127. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_version.hpp +35 -0
  128. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/subschema.hpp +144 -0
  129. data/lib/jsoncons/jsoncons/include/jsoncons_ext/mergepatch/mergepatch.hpp +103 -0
  130. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/decode_msgpack.hpp +202 -0
  131. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/encode_msgpack.hpp +142 -0
  132. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack.hpp +24 -0
  133. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor.hpp +343 -0
  134. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp +259 -0
  135. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_encoder.hpp +753 -0
  136. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_error.hpp +94 -0
  137. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_options.hpp +74 -0
  138. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_parser.hpp +748 -0
  139. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_reader.hpp +116 -0
  140. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_type.hpp +63 -0
  141. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/decode_ubjson.hpp +201 -0
  142. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/encode_ubjson.hpp +142 -0
  143. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson.hpp +23 -0
  144. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_cursor.hpp +307 -0
  145. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_encoder.hpp +502 -0
  146. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_error.hpp +100 -0
  147. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_options.hpp +87 -0
  148. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_parser.hpp +880 -0
  149. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_reader.hpp +92 -0
  150. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_type.hpp +43 -0
  151. data/lib/jsoncons/version.rb +5 -0
  152. data/lib/jsoncons.rb +33 -0
  153. data/test/jsoncons_test.rb +108 -0
  154. data/test/test_helper.rb +7 -0
  155. metadata +268 -0
@@ -0,0 +1,1745 @@
1
+ // Copyright 2020 Daniel Parker
2
+ // Distributed under the Boost license, Version 1.0.
3
+ // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
+
5
+ // See https://github.com/danielaparker/jsoncons for latest version
6
+
7
+ #ifndef JSONCONS_JSONSCHEMA_KEYWORD_VALIDATOR_HPP
8
+ #define JSONCONS_JSONSCHEMA_KEYWORD_VALIDATOR_HPP
9
+
10
+ #include <jsoncons/config/jsoncons_config.hpp>
11
+ #include <jsoncons/uri.hpp>
12
+ #include <jsoncons/json.hpp>
13
+ #include <jsoncons_ext/jsonpointer/jsonpointer.hpp>
14
+ #include <jsoncons_ext/jsonschema/subschema.hpp>
15
+ #include <jsoncons_ext/jsonschema/format_validator.hpp>
16
+ #include <cassert>
17
+ #include <set>
18
+ #include <sstream>
19
+ #include <iostream>
20
+ #include <cassert>
21
+ #if defined(JSONCONS_HAS_STD_REGEX)
22
+ #include <regex>
23
+ #endif
24
+
25
+ namespace jsoncons {
26
+ namespace jsonschema {
27
+
28
+ template <class Json>
29
+ class abstract_keyword_validator_factory
30
+ {
31
+ public:
32
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
33
+
34
+ virtual ~abstract_keyword_validator_factory() = default;
35
+
36
+ virtual validator_pointer make_keyword_validator(const Json& schema,
37
+ const std::vector<schema_location>& uris,
38
+ const std::vector<std::string>& keys) = 0;
39
+ virtual validator_pointer make_required_validator(const std::vector<schema_location>& uris,
40
+ const std::vector<std::string>& items) = 0;
41
+
42
+ virtual validator_pointer make_null_validator(const std::vector<schema_location>& uris) = 0;
43
+
44
+ virtual validator_pointer make_true_validator(const std::vector<schema_location>& uris) = 0;
45
+
46
+ virtual validator_pointer make_false_validator(const std::vector<schema_location>& uris) = 0;
47
+
48
+ virtual validator_pointer make_object_validator(const Json& sch,
49
+ const std::vector<schema_location>& uris) = 0;
50
+
51
+ virtual validator_pointer make_array_validator(const Json& sch,
52
+ const std::vector<schema_location>& uris) = 0;
53
+
54
+ virtual validator_pointer make_string_validator(const Json& sch,
55
+ const std::vector<schema_location>& uris) = 0;
56
+
57
+ virtual validator_pointer make_boolean_validator(const std::vector<schema_location>& uris) = 0;
58
+
59
+ virtual validator_pointer make_integer_validator(const Json& sch,
60
+ const std::vector<schema_location>& uris,
61
+ std::set<std::string>& keywords) = 0;
62
+
63
+ virtual validator_pointer make_number_validator(const Json& sch,
64
+ const std::vector<schema_location>& uris,
65
+ std::set<std::string>& keywords) = 0;
66
+
67
+ virtual validator_pointer make_not_validator(const Json& schema,
68
+ const std::vector<schema_location>& uris) = 0;
69
+
70
+ virtual validator_pointer make_all_of_validator(const Json& schema,
71
+ const std::vector<schema_location>& uris) = 0;
72
+
73
+ virtual validator_pointer make_any_of_validator(const Json& schema,
74
+ const std::vector<schema_location>& uris) = 0;
75
+
76
+ virtual validator_pointer make_one_of_validator(const Json& schema,
77
+ const std::vector<schema_location>& uris) = 0;
78
+
79
+ virtual validator_pointer make_type_validator(const Json& schema,
80
+ const std::vector<schema_location>& uris) = 0;
81
+ };
82
+
83
+ struct collecting_error_reporter : public error_reporter
84
+ {
85
+ std::vector<validation_output> errors;
86
+
87
+ private:
88
+ void do_error(const validation_output& o) override
89
+ {
90
+ errors.push_back(o);
91
+ }
92
+ };
93
+
94
+ // string keyword_validator
95
+
96
+ inline
97
+ std::string make_absolute_keyword_location(const std::vector<schema_location>& uris,
98
+ const std::string& keyword)
99
+ {
100
+ for (auto it = uris.rbegin(); it != uris.rend(); ++it)
101
+ {
102
+ if (!it->has_identifier() && it->is_absolute())
103
+ {
104
+ return it->append(keyword).string();
105
+ }
106
+ }
107
+ return "";
108
+ }
109
+
110
+ template <class Json>
111
+ class string_validator : public keyword_validator<Json>
112
+ {
113
+ jsoncons::optional<std::size_t> max_length_;
114
+ std::string max_length_location_;
115
+ jsoncons::optional<std::size_t> min_length_;
116
+ std::string min_length_location_;
117
+
118
+ #if defined(JSONCONS_HAS_STD_REGEX)
119
+ jsoncons::optional<std::regex> pattern_;
120
+ std::string pattern_string_;
121
+ std::string pattern_location_;
122
+ #endif
123
+
124
+ format_checker format_check_;
125
+ std::string format_location_;
126
+
127
+ jsoncons::optional<std::string> content_encoding_;
128
+ std::string content_encoding_location_;
129
+ jsoncons::optional<std::string> content_media_type_;
130
+ std::string content_media_type_location_;
131
+
132
+ public:
133
+ string_validator(const Json& sch, const std::vector<schema_location>& uris)
134
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), max_length_(), min_length_(),
135
+ #if defined(JSONCONS_HAS_STD_REGEX)
136
+ pattern_(),
137
+ #endif
138
+ content_encoding_(), content_media_type_()
139
+ {
140
+ auto it = sch.find("maxLength");
141
+ if (it != sch.object_range().end())
142
+ {
143
+ max_length_ = it->value().template as<std::size_t>();
144
+ max_length_location_ = make_absolute_keyword_location(uris, "maxLength");
145
+ }
146
+
147
+ it = sch.find("minLength");
148
+ if (it != sch.object_range().end())
149
+ {
150
+ min_length_ = it->value().template as<std::size_t>();
151
+ min_length_location_ = make_absolute_keyword_location(uris, "minLength");
152
+ }
153
+
154
+ it = sch.find("contentEncoding");
155
+ if (it != sch.object_range().end())
156
+ {
157
+ content_encoding_ = it->value().template as<std::string>();
158
+ content_encoding_location_ = make_absolute_keyword_location(uris, "contentEncoding");
159
+ // If "contentEncoding" is set to "binary", a Json value
160
+ // of type json_type::byte_string_value is accepted.
161
+ }
162
+
163
+ it = sch.find("contentMediaType");
164
+ if (it != sch.object_range().end())
165
+ {
166
+ content_media_type_ = it->value().template as<std::string>();
167
+ content_media_type_location_ = make_absolute_keyword_location(uris, "contentMediaType");
168
+ }
169
+
170
+ #if defined(JSONCONS_HAS_STD_REGEX)
171
+ it = sch.find("pattern");
172
+ if (it != sch.object_range().end())
173
+ {
174
+ pattern_string_ = it->value().template as<std::string>();
175
+ pattern_ = std::regex(it->value().template as<std::string>(),std::regex::ECMAScript);
176
+ pattern_location_ = make_absolute_keyword_location(uris, "pattern");
177
+ }
178
+ #endif
179
+
180
+ it = sch.find("format");
181
+ if (it != sch.object_range().end())
182
+ {
183
+ format_location_ = make_absolute_keyword_location(uris, "format");
184
+ std::string format = it->value().template as<std::string>();
185
+ if (format == "date-time")
186
+ {
187
+ format_check_ = rfc3339_date_time_check;
188
+ }
189
+ else if (format == "date")
190
+ {
191
+ format_check_ = rfc3339_date_check;
192
+ }
193
+ else if (format == "time")
194
+ {
195
+ format_check_ = rfc3339_time_check;
196
+ }
197
+ else if (format == "email")
198
+ {
199
+ format_check_ = email_check;
200
+ }
201
+ else if (format == "hostname")
202
+ {
203
+ format_check_ = hostname_check;
204
+ }
205
+ else if (format == "ipv4")
206
+ {
207
+ format_check_ = ipv4_check;
208
+ }
209
+ else if (format == "ipv6")
210
+ {
211
+ format_check_ = ipv6_check;
212
+ }
213
+ else if (format == "regex")
214
+ {
215
+ format_check_ = regex_check;
216
+ }
217
+ else
218
+ {
219
+ // Not supported - ignore
220
+ }
221
+ }
222
+ }
223
+
224
+ private:
225
+
226
+ void do_validate(const Json& instance,
227
+ const jsonpointer::json_pointer& instance_location,
228
+ error_reporter& reporter,
229
+ Json&) const override
230
+ {
231
+ std::string content;
232
+ if (content_encoding_)
233
+ {
234
+ if (*content_encoding_ == "base64")
235
+ {
236
+ auto s = instance.template as<jsoncons::string_view>();
237
+ auto retval = jsoncons::decode_base64(s.begin(), s.end(), content);
238
+ if (retval.ec != jsoncons::conv_errc::success)
239
+ {
240
+ reporter.error(validation_output("contentEncoding",
241
+ content_encoding_location_,
242
+ instance_location.to_uri_fragment(),
243
+ "Content is not a base64 string"));
244
+ if (reporter.fail_early())
245
+ {
246
+ return;
247
+ }
248
+ }
249
+ }
250
+ else if (!content_encoding_->empty())
251
+ {
252
+ reporter.error(validation_output("contentEncoding",
253
+ content_encoding_location_,
254
+ instance_location.to_uri_fragment(),
255
+ "unable to check for contentEncoding '" + *content_encoding_ + "'"));
256
+ if (reporter.fail_early())
257
+ {
258
+ return;
259
+ }
260
+ }
261
+ }
262
+ else
263
+ {
264
+ content = instance.template as<std::string>();
265
+ }
266
+
267
+ if (content_media_type_)
268
+ {
269
+ if (content_media_type_ == "application/Json")
270
+ {
271
+ json_string_reader reader(content);
272
+ std::error_code ec;
273
+ reader.read(ec);
274
+
275
+ if (ec)
276
+ {
277
+ reporter.error(validation_output("contentMediaType",
278
+ content_media_type_location_,
279
+ instance_location.to_uri_fragment(),
280
+ std::string("Content is not JSON: ") + ec.message()));
281
+ }
282
+ }
283
+ }
284
+ else if (instance.type() == json_type::byte_string_value)
285
+ {
286
+ reporter.error(validation_output("contentMediaType",
287
+ content_media_type_location_,
288
+ instance_location.to_uri_fragment(),
289
+ "Expected string, but is byte string"));
290
+ if (reporter.fail_early())
291
+ {
292
+ return;
293
+ }
294
+ }
295
+
296
+ if (instance.type() != json_type::string_value)
297
+ {
298
+ return;
299
+ }
300
+
301
+ if (min_length_)
302
+ {
303
+ std::size_t length = unicode_traits::count_codepoints(content.data(), content.size());
304
+ if (length < *min_length_)
305
+ {
306
+ reporter.error(validation_output("minLength",
307
+ min_length_location_,
308
+ instance_location.to_uri_fragment(),
309
+ std::string("Expected minLength: ") + std::to_string(*min_length_)
310
+ + ", actual: " + std::to_string(length)));
311
+ if (reporter.fail_early())
312
+ {
313
+ return;
314
+ }
315
+ }
316
+ }
317
+
318
+ if (max_length_)
319
+ {
320
+ std::size_t length = unicode_traits::count_codepoints(content.data(), content.size());
321
+ if (length > *max_length_)
322
+ {
323
+ reporter.error(validation_output("maxLength",
324
+ max_length_location_,
325
+ instance_location.to_uri_fragment(),
326
+ std::string("Expected maxLength: ") + std::to_string(*max_length_)
327
+ + ", actual: " + std::to_string(length)));
328
+ if (reporter.fail_early())
329
+ {
330
+ return;
331
+ }
332
+ }
333
+ }
334
+
335
+ #if defined(JSONCONS_HAS_STD_REGEX)
336
+ if (pattern_)
337
+ {
338
+ if (!std::regex_search(content, *pattern_))
339
+ {
340
+ std::string message("String \"");
341
+ message.append(instance.template as<std::string>());
342
+ message.append("\" does not match pattern \"");
343
+ message.append(pattern_string_);
344
+ message.append("\"");
345
+ reporter.error(validation_output("pattern",
346
+ pattern_location_,
347
+ instance_location.to_uri_fragment(),
348
+ std::move(message)));
349
+ if (reporter.fail_early())
350
+ {
351
+ return;
352
+ }
353
+ }
354
+ }
355
+
356
+ #endif
357
+
358
+ if (format_check_ != nullptr)
359
+ {
360
+ format_check_(format_location_, instance_location, content, reporter);
361
+ if (reporter.error_count() > 0 && reporter.fail_early())
362
+ {
363
+ return;
364
+ }
365
+ }
366
+ }
367
+ };
368
+
369
+ // not_validator
370
+
371
+ template <class Json>
372
+ class not_validator : public keyword_validator<Json>
373
+ {
374
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
375
+
376
+ validator_pointer rule_;
377
+
378
+ public:
379
+ not_validator(abstract_keyword_validator_factory<Json>* builder,
380
+ const Json& sch,
381
+ const std::vector<schema_location>& uris)
382
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
383
+ {
384
+ rule_ = builder->make_keyword_validator(sch, uris, {"not"});
385
+ }
386
+
387
+ private:
388
+
389
+ void do_validate(const Json& instance,
390
+ const jsonpointer::json_pointer& instance_location,
391
+ error_reporter& reporter,
392
+ Json& patch) const final
393
+ {
394
+ collecting_error_reporter local_reporter;
395
+ rule_->validate(instance, instance_location, local_reporter, patch);
396
+
397
+ if (local_reporter.errors.empty())
398
+ {
399
+ reporter.error(validation_output("not",
400
+ this->absolute_keyword_location(),
401
+ instance_location.to_uri_fragment(),
402
+ "Instance must not be valid against schema"));
403
+ }
404
+ }
405
+
406
+ jsoncons::optional<Json> get_default_value(const jsonpointer::json_pointer& instance_location,
407
+ const Json& instance,
408
+ error_reporter& reporter) const override
409
+ {
410
+ return rule_->get_default_value(instance_location, instance, reporter);
411
+ }
412
+ };
413
+
414
+ template <class Json>
415
+ struct all_of_criterion
416
+ {
417
+ static const std::string& key()
418
+ {
419
+ static const std::string k("allOf");
420
+ return k;
421
+ }
422
+
423
+ static bool is_complete(const Json&,
424
+ const jsonpointer::json_pointer& instance_location,
425
+ error_reporter& reporter,
426
+ const collecting_error_reporter& local_reporter,
427
+ std::size_t)
428
+ {
429
+ if (!local_reporter.errors.empty())
430
+ reporter.error(validation_output("allOf",
431
+ "",
432
+ instance_location.to_uri_fragment(),
433
+ "At least one schema failed to match, but all are required to match. ",
434
+ local_reporter.errors));
435
+ return !local_reporter.errors.empty();
436
+ }
437
+ };
438
+
439
+ template <class Json>
440
+ struct any_of_criterion
441
+ {
442
+ static const std::string& key()
443
+ {
444
+ static const std::string k("anyOf");
445
+ return k;
446
+ }
447
+
448
+ static bool is_complete(const Json&,
449
+ const jsonpointer::json_pointer&,
450
+ error_reporter&,
451
+ const collecting_error_reporter&,
452
+ std::size_t count)
453
+ {
454
+ return count == 1;
455
+ }
456
+ };
457
+
458
+ template <class Json>
459
+ struct one_of_criterion
460
+ {
461
+ static const std::string& key()
462
+ {
463
+ static const std::string k("oneOf");
464
+ return k;
465
+ }
466
+
467
+ static bool is_complete(const Json&,
468
+ const jsonpointer::json_pointer& instance_location,
469
+ error_reporter& reporter,
470
+ const collecting_error_reporter&,
471
+ std::size_t count)
472
+ {
473
+ if (count > 1)
474
+ {
475
+ std::string message(std::to_string(count));
476
+ message.append(" subschemas matched, but exactly one is required to match");
477
+ reporter.error(validation_output("oneOf",
478
+ "",
479
+ instance_location.to_uri_fragment(),
480
+ std::move(message)));
481
+ }
482
+ return count > 1;
483
+ }
484
+ };
485
+
486
+ template <class Json,class Criterion>
487
+ class combining_validator : public keyword_validator<Json>
488
+ {
489
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
490
+
491
+ std::vector<validator_pointer> subschemas_;
492
+
493
+ public:
494
+ combining_validator(abstract_keyword_validator_factory<Json>* builder,
495
+ const Json& sch,
496
+ const std::vector<schema_location>& uris)
497
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
498
+ {
499
+ size_t c = 0;
500
+ for (const auto& subsch : sch.array_range())
501
+ {
502
+ subschemas_.push_back(builder->make_keyword_validator(subsch, uris, {Criterion::key(), std::to_string(c++)}));
503
+ }
504
+
505
+ // Validate value of allOf, anyOf, and oneOf "MUST be a non-empty array"
506
+ }
507
+
508
+ private:
509
+
510
+ void do_validate(const Json& instance,
511
+ const jsonpointer::json_pointer& instance_location,
512
+ error_reporter& reporter,
513
+ Json& patch) const final
514
+ {
515
+ size_t count = 0;
516
+
517
+ collecting_error_reporter local_reporter;
518
+ for (auto& s : subschemas_)
519
+ {
520
+ std::size_t mark = local_reporter.errors.size();
521
+ s->validate(instance, instance_location, local_reporter, patch);
522
+ if (mark == local_reporter.errors.size())
523
+ count++;
524
+
525
+ if (Criterion::is_complete(instance, instance_location, reporter, local_reporter, count))
526
+ return;
527
+ }
528
+
529
+ if (count == 0)
530
+ {
531
+ reporter.error(validation_output("combined",
532
+ this->absolute_keyword_location(),
533
+ instance_location.to_uri_fragment(),
534
+ "No schema matched, but one of them is required to match",
535
+ local_reporter.errors));
536
+ }
537
+ }
538
+ };
539
+
540
+ template <class T, class Json>
541
+ T get_number(const Json& val, const string_view& keyword)
542
+ {
543
+ if (!val.is_number())
544
+ {
545
+ std::string message(keyword);
546
+ message.append(" must be a number value");
547
+ JSONCONS_THROW(schema_error(message));
548
+ }
549
+ return val.template as<T>();
550
+ }
551
+
552
+ template <class Json,class T>
553
+ class numeric_validator_base : public keyword_validator<Json>
554
+ {
555
+ jsoncons::optional<T> maximum_;
556
+ std::string absolute_maximum_location_;
557
+ jsoncons::optional<T> minimum_;
558
+ std::string absolute_minimum_location_;
559
+ jsoncons::optional<T> exclusive_maximum_;
560
+ std::string absolute_exclusive_maximum_location_;
561
+ jsoncons::optional<T> exclusive_minimum_;
562
+ std::string absolute_exclusive_minimum_location_;
563
+ jsoncons::optional<double> multiple_of_;
564
+ std::string absolute_multiple_of_location_;
565
+
566
+ public:
567
+ numeric_validator_base(const Json& sch,
568
+ const std::vector<schema_location>& uris,
569
+ std::set<std::string>& keywords)
570
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""),
571
+ maximum_(), minimum_(),exclusive_maximum_(), exclusive_minimum_(), multiple_of_()
572
+ {
573
+ auto it = sch.find("maximum");
574
+ if (it != sch.object_range().end())
575
+ {
576
+ maximum_ = get_number<T>(it->value(), "maximum");
577
+ absolute_maximum_location_ = make_absolute_keyword_location(uris,"maximum");
578
+ keywords.insert("maximum");
579
+ }
580
+
581
+ it = sch.find("minimum");
582
+ if (it != sch.object_range().end())
583
+ {
584
+ minimum_ = get_number<T>(it->value(), "minimum");
585
+ absolute_minimum_location_ = make_absolute_keyword_location(uris,"minimum");
586
+ keywords.insert("minimum");
587
+ }
588
+
589
+ it = sch.find("exclusiveMaximum");
590
+ if (it != sch.object_range().end())
591
+ {
592
+ exclusive_maximum_ = get_number<T>(it->value(), "exclusiveMaximum");
593
+ absolute_exclusive_maximum_location_ = make_absolute_keyword_location(uris,"exclusiveMaximum");
594
+ keywords.insert("exclusiveMaximum");
595
+ }
596
+
597
+ it = sch.find("exclusiveMinimum");
598
+ if (it != sch.object_range().end())
599
+ {
600
+ exclusive_minimum_ = get_number<T>(it->value(), "exclusiveMinimum");
601
+ absolute_exclusive_minimum_location_ = make_absolute_keyword_location(uris,"exclusiveMinimum");
602
+ keywords.insert("exclusiveMinimum");
603
+ }
604
+
605
+ it = sch.find("multipleOf");
606
+ if (it != sch.object_range().end())
607
+ {
608
+ multiple_of_ = get_number<double>(it->value(), "multipleOf");
609
+ absolute_multiple_of_location_ = make_absolute_keyword_location(uris,"multipleOf");
610
+ keywords.insert("multipleOf");
611
+ }
612
+ }
613
+
614
+ protected:
615
+
616
+ void apply_kewords(T value,
617
+ const jsonpointer::json_pointer& instance_location,
618
+ const Json& instance,
619
+ error_reporter& reporter) const
620
+ {
621
+ if (multiple_of_ && value != 0) // exclude zero
622
+ {
623
+ if (!is_multiple_of(value, *multiple_of_))
624
+ {
625
+ reporter.error(validation_output("multipleOf",
626
+ absolute_multiple_of_location_,
627
+ instance_location.to_uri_fragment(),
628
+ instance.template as<std::string>() + " is not a multiple of " + std::to_string(*multiple_of_)));
629
+ if (reporter.fail_early())
630
+ {
631
+ return;
632
+ }
633
+ }
634
+ }
635
+
636
+ if (maximum_)
637
+ {
638
+ if (value > *maximum_)
639
+ {
640
+ reporter.error(validation_output("maximum",
641
+ absolute_maximum_location_,
642
+ instance_location.to_uri_fragment(),
643
+ instance.template as<std::string>() + " exceeds maximum of " + std::to_string(*maximum_)));
644
+ if (reporter.fail_early())
645
+ {
646
+ return;
647
+ }
648
+ }
649
+ }
650
+
651
+ if (minimum_)
652
+ {
653
+ if (value < *minimum_)
654
+ {
655
+ reporter.error(validation_output("minimum",
656
+ absolute_minimum_location_,
657
+ instance_location.to_uri_fragment(),
658
+ instance.template as<std::string>() + " is below minimum of " + std::to_string(*minimum_)));
659
+ if (reporter.fail_early())
660
+ {
661
+ return;
662
+ }
663
+ }
664
+ }
665
+
666
+ if (exclusive_maximum_)
667
+ {
668
+ if (value >= *exclusive_maximum_)
669
+ {
670
+ reporter.error(validation_output("exclusiveMaximum",
671
+ absolute_exclusive_maximum_location_,
672
+ instance_location.to_uri_fragment(),
673
+ instance.template as<std::string>() + " exceeds maximum of " + std::to_string(*exclusive_maximum_)));
674
+ if (reporter.fail_early())
675
+ {
676
+ return;
677
+ }
678
+ }
679
+ }
680
+
681
+ if (exclusive_minimum_)
682
+ {
683
+ if (value <= *exclusive_minimum_)
684
+ {
685
+ reporter.error(validation_output("exclusiveMinimum",
686
+ absolute_exclusive_minimum_location_,
687
+ instance_location.to_uri_fragment(),
688
+ instance.template as<std::string>() + " is below minimum of " + std::to_string(*exclusive_minimum_)));
689
+ if (reporter.fail_early())
690
+ {
691
+ return;
692
+ }
693
+ }
694
+ }
695
+ }
696
+ private:
697
+ static bool is_multiple_of(T x, double multiple_of)
698
+ {
699
+ double rem = std::remainder(x, multiple_of);
700
+ double eps = std::nextafter(x, 0) - x;
701
+ return std::fabs(rem) < std::fabs(eps);
702
+ }
703
+ };
704
+
705
+ template <class Json>
706
+ class integer_validator : public numeric_validator_base<Json,int64_t>
707
+ {
708
+ public:
709
+ integer_validator(const Json& sch,
710
+ const std::vector<schema_location>& uris,
711
+ std::set<std::string>& keywords)
712
+ : numeric_validator_base<Json, int64_t>(sch, uris, keywords)
713
+ {
714
+ }
715
+ private:
716
+ void do_validate(const Json& instance,
717
+ const jsonpointer::json_pointer& instance_location,
718
+ error_reporter& reporter,
719
+ Json&) const
720
+ {
721
+ if (!(instance.template is_integer<int64_t>() || (instance.is_double() && static_cast<double>(instance.template as<int64_t>()) == instance.template as<double>())))
722
+ {
723
+ reporter.error(validation_output("integer",
724
+ this->absolute_keyword_location(),
725
+ instance_location.to_uri_fragment(),
726
+ "Instance is not an integer"));
727
+ if (reporter.fail_early())
728
+ {
729
+ return;
730
+ }
731
+ }
732
+ int64_t value = instance.template as<int64_t>();
733
+ this->apply_kewords(value, instance_location, instance, reporter);
734
+ }
735
+ };
736
+
737
+ template <class Json>
738
+ class number_validator : public numeric_validator_base<Json,double>
739
+ {
740
+ public:
741
+ number_validator(const Json& sch,
742
+ const std::vector<schema_location>& uris,
743
+ std::set<std::string>& keywords)
744
+ : numeric_validator_base<Json, double>(sch, uris, keywords)
745
+ {
746
+ }
747
+ private:
748
+ void do_validate(const Json& instance,
749
+ const jsonpointer::json_pointer& instance_location,
750
+ error_reporter& reporter,
751
+ Json&) const
752
+ {
753
+ if (!(instance.template is_integer<int64_t>() || instance.is_double()))
754
+ {
755
+ reporter.error(validation_output("number",
756
+ this->absolute_keyword_location(),
757
+ instance_location.to_uri_fragment(),
758
+ "Instance is not a number"));
759
+ if (reporter.fail_early())
760
+ {
761
+ return;
762
+ }
763
+ }
764
+ double value = instance.template as<double>();
765
+ this->apply_kewords(value, instance_location, instance, reporter);
766
+ }
767
+ };
768
+
769
+ // null_validator
770
+
771
+ template <class Json>
772
+ class null_validator : public keyword_validator<Json>
773
+ {
774
+ public:
775
+ null_validator(const std::vector<schema_location>& uris)
776
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
777
+ {
778
+ }
779
+ private:
780
+ void do_validate(const Json& instance,
781
+ const jsonpointer::json_pointer& instance_location,
782
+ error_reporter& reporter,
783
+ Json&) const override
784
+ {
785
+ if (!instance.is_null())
786
+ {
787
+ reporter.error(validation_output("null",
788
+ this->absolute_keyword_location(),
789
+ instance_location.to_uri_fragment(),
790
+ "Expected to be null"));
791
+ }
792
+ }
793
+ };
794
+
795
+ template <class Json>
796
+ class boolean_validator : public keyword_validator<Json>
797
+ {
798
+ public:
799
+ boolean_validator(const std::vector<schema_location>& uris)
800
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
801
+ {
802
+ }
803
+ private:
804
+ void do_validate(const Json&,
805
+ const jsonpointer::json_pointer&,
806
+ error_reporter&,
807
+ Json&) const override
808
+ {
809
+ }
810
+
811
+ };
812
+
813
+ template <class Json>
814
+ class true_validator : public keyword_validator<Json>
815
+ {
816
+ public:
817
+ true_validator(const std::vector<schema_location>& uris)
818
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
819
+ {
820
+ }
821
+ private:
822
+ void do_validate(const Json&,
823
+ const jsonpointer::json_pointer&,
824
+ error_reporter&,
825
+ Json&) const override
826
+ {
827
+ }
828
+ };
829
+
830
+ template <class Json>
831
+ class false_validator : public keyword_validator<Json>
832
+ {
833
+ public:
834
+ false_validator(const std::vector<schema_location>& uris)
835
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
836
+ {
837
+ }
838
+ private:
839
+ void do_validate(const Json&,
840
+ const jsonpointer::json_pointer& instance_location,
841
+ error_reporter& reporter,
842
+ Json&) const override
843
+ {
844
+ reporter.error(validation_output("false",
845
+ this->absolute_keyword_location(),
846
+ instance_location.to_uri_fragment(),
847
+ "False schema always fails"));
848
+ }
849
+ };
850
+
851
+ template <class Json>
852
+ class required_validator : public keyword_validator<Json>
853
+ {
854
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
855
+
856
+ std::vector<std::string> items_;
857
+
858
+ public:
859
+ required_validator(const std::vector<schema_location>& uris,
860
+ const std::vector<std::string>& items)
861
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), items_(items) {}
862
+ required_validator(const std::string& absolute_keyword_location, const std::vector<std::string>& items)
863
+ : keyword_validator<Json>(absolute_keyword_location), items_(items) {}
864
+
865
+ required_validator(const required_validator&) = delete;
866
+ required_validator(required_validator&&) = default;
867
+ required_validator& operator=(const required_validator&) = delete;
868
+ required_validator& operator=(required_validator&&) = default;
869
+ private:
870
+
871
+ void do_validate(const Json& instance,
872
+ const jsonpointer::json_pointer& instance_location,
873
+ error_reporter& reporter,
874
+ Json&) const override final
875
+ {
876
+ for (const auto& key : items_)
877
+ {
878
+ if (instance.find(key) == instance.object_range().end())
879
+ {
880
+ reporter.error(validation_output("required",
881
+ this->absolute_keyword_location(),
882
+ instance_location.to_uri_fragment(),
883
+ "Required property \"" + key + "\" not found"));
884
+ if (reporter.fail_early())
885
+ {
886
+ return;
887
+ }
888
+ }
889
+ }
890
+ }
891
+ };
892
+
893
+ template <class Json>
894
+ class object_validator : public keyword_validator<Json>
895
+ {
896
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
897
+
898
+ jsoncons::optional<std::size_t> max_properties_;
899
+ std::string absolute_max_properties_location_;
900
+ jsoncons::optional<std::size_t> min_properties_;
901
+ std::string absolute_min_properties_location_;
902
+ jsoncons::optional<required_validator<Json>> required_;
903
+
904
+ std::map<std::string, validator_pointer> properties_;
905
+ #if defined(JSONCONS_HAS_STD_REGEX)
906
+ std::vector<std::pair<std::regex, validator_pointer>> pattern_properties_;
907
+ #endif
908
+ validator_pointer additional_properties_;
909
+
910
+ std::map<std::string, validator_pointer> dependencies_;
911
+
912
+ validator_pointer property_name_validator_;
913
+
914
+ public:
915
+ object_validator(abstract_keyword_validator_factory<Json>* builder,
916
+ const Json& sch,
917
+ const std::vector<schema_location>& uris)
918
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""),
919
+ max_properties_(), min_properties_(),
920
+ additional_properties_(nullptr),
921
+ property_name_validator_(nullptr)
922
+ {
923
+ auto it = sch.find("maxProperties");
924
+ if (it != sch.object_range().end())
925
+ {
926
+ max_properties_ = it->value().template as<std::size_t>();
927
+ absolute_max_properties_location_ = make_absolute_keyword_location(uris, "maxProperties");
928
+ }
929
+
930
+ it = sch.find("minProperties");
931
+ if (it != sch.object_range().end())
932
+ {
933
+ min_properties_ = it->value().template as<std::size_t>();
934
+ absolute_min_properties_location_ = make_absolute_keyword_location(uris, "minProperties");
935
+ }
936
+
937
+ it = sch.find("required");
938
+ if (it != sch.object_range().end())
939
+ {
940
+ auto location = make_absolute_keyword_location(uris, "required");
941
+ required_ = required_validator<Json>(location,
942
+ it->value().template as<std::vector<std::string>>());
943
+ }
944
+
945
+ it = sch.find("properties");
946
+ if (it != sch.object_range().end())
947
+ {
948
+ for (const auto& prop : it->value().object_range())
949
+ properties_.emplace(
950
+ std::make_pair(
951
+ prop.key(),
952
+ builder->make_keyword_validator(prop.value(), uris, {"properties", prop.key()})));
953
+ }
954
+
955
+ #if defined(JSONCONS_HAS_STD_REGEX)
956
+ it = sch.find("patternProperties");
957
+ if (it != sch.object_range().end())
958
+ {
959
+ for (const auto& prop : it->value().object_range())
960
+ pattern_properties_.emplace_back(
961
+ std::make_pair(
962
+ std::regex(prop.key(), std::regex::ECMAScript),
963
+ builder->make_keyword_validator(prop.value(), uris, {prop.key()})));
964
+ }
965
+ #endif
966
+
967
+ it = sch.find("additionalProperties");
968
+ if (it != sch.object_range().end())
969
+ {
970
+ additional_properties_ = builder->make_keyword_validator(it->value(), uris, {"additionalProperties"});
971
+ }
972
+
973
+ it = sch.find("dependencies");
974
+ if (it != sch.object_range().end())
975
+ {
976
+ for (const auto& dep : it->value().object_range())
977
+ {
978
+ switch (dep.value().type())
979
+ {
980
+ case json_type::array_value:
981
+ {
982
+ auto location = make_absolute_keyword_location(uris, "dependencies");
983
+ dependencies_.emplace(dep.key(),
984
+ builder->make_required_validator({location},
985
+ dep.value().template as<std::vector<std::string>>()));
986
+ break;
987
+ }
988
+ default:
989
+ {
990
+ dependencies_.emplace(dep.key(),
991
+ builder->make_keyword_validator(dep.value(), uris, {"dependencies", dep.key()}));
992
+ break;
993
+ }
994
+ }
995
+ }
996
+ }
997
+
998
+ auto property_names_it = sch.find("propertyNames");
999
+ if (property_names_it != sch.object_range().end())
1000
+ {
1001
+ property_name_validator_ = builder->make_keyword_validator(property_names_it->value(), uris, {"propertyNames"});
1002
+ }
1003
+ }
1004
+ private:
1005
+
1006
+ void do_validate(const Json& instance,
1007
+ const jsonpointer::json_pointer& instance_location,
1008
+ error_reporter& reporter,
1009
+ Json& patch) const override
1010
+ {
1011
+ if (max_properties_ && instance.size() > *max_properties_)
1012
+ {
1013
+ std::string message("Maximum properties: " + std::to_string(*max_properties_));
1014
+ message.append(", found: " + std::to_string(instance.size()));
1015
+ reporter.error(validation_output("maxProperties",
1016
+ absolute_max_properties_location_,
1017
+ instance_location.to_uri_fragment(),
1018
+ std::move(message)));
1019
+ if (reporter.fail_early())
1020
+ {
1021
+ return;
1022
+ }
1023
+ }
1024
+
1025
+ if (min_properties_ && instance.size() < *min_properties_)
1026
+ {
1027
+ std::string message("Minimum properties: " + std::to_string(*min_properties_));
1028
+ message.append(", found: " + std::to_string(instance.size()));
1029
+ reporter.error(validation_output("minProperties",
1030
+ absolute_min_properties_location_,
1031
+ instance_location.to_uri_fragment(),
1032
+ std::move(message)));
1033
+ if (reporter.fail_early())
1034
+ {
1035
+ return;
1036
+ }
1037
+ }
1038
+
1039
+ if (required_)
1040
+ required_->validate(instance, instance_location, reporter, patch);
1041
+
1042
+ for (const auto& property : instance.object_range())
1043
+ {
1044
+ if (property_name_validator_)
1045
+ property_name_validator_->validate(property.key(), instance_location, reporter, patch);
1046
+
1047
+ bool a_prop_or_pattern_matched = false;
1048
+ auto properties_it = properties_.find(property.key());
1049
+
1050
+ // check if it is in "properties"
1051
+ if (properties_it != properties_.end())
1052
+ {
1053
+ a_prop_or_pattern_matched = true;
1054
+ jsonpointer::json_pointer pointer(instance_location);
1055
+ pointer /= property.key();
1056
+ properties_it->second->validate(property.value(), pointer, reporter, patch);
1057
+ }
1058
+
1059
+ #if defined(JSONCONS_HAS_STD_REGEX)
1060
+
1061
+ // check all matching "patternProperties"
1062
+ for (auto& schema_pp : pattern_properties_)
1063
+ if (std::regex_search(property.key(), schema_pp.first))
1064
+ {
1065
+ a_prop_or_pattern_matched = true;
1066
+ jsonpointer::json_pointer pointer(instance_location);
1067
+ pointer /= property.key();
1068
+ schema_pp.second->validate(property.value(), pointer, reporter, patch);
1069
+ }
1070
+ #endif
1071
+
1072
+ // finally, check "additionalProperties"
1073
+ if (!a_prop_or_pattern_matched && additional_properties_)
1074
+ {
1075
+ collecting_error_reporter local_reporter;
1076
+
1077
+ jsonpointer::json_pointer pointer(instance_location);
1078
+ pointer /= property.key();
1079
+ additional_properties_->validate(property.value(), pointer, local_reporter, patch);
1080
+ if (!local_reporter.errors.empty())
1081
+ {
1082
+ reporter.error(validation_output("additionalProperties",
1083
+ additional_properties_->absolute_keyword_location(),
1084
+ instance_location.to_uri_fragment(),
1085
+ "Additional property \"" + property.key() + "\" found but was invalid."));
1086
+ if (reporter.fail_early())
1087
+ {
1088
+ return;
1089
+ }
1090
+ }
1091
+ }
1092
+ }
1093
+
1094
+ // reverse search
1095
+ for (auto const& prop : properties_)
1096
+ {
1097
+ const auto finding = instance.find(prop.first);
1098
+ if (finding == instance.object_range().end())
1099
+ {
1100
+ // If property is not in instance
1101
+ auto default_value = prop.second->get_default_value(instance_location, instance, reporter);
1102
+ if (default_value)
1103
+ {
1104
+ // If default value is available, update patch
1105
+ jsonpointer::json_pointer pointer(instance_location);
1106
+ pointer /= prop.first;
1107
+
1108
+ update_patch(patch, pointer, std::move(*default_value));
1109
+ }
1110
+ }
1111
+ }
1112
+
1113
+ for (const auto& dep : dependencies_)
1114
+ {
1115
+ auto prop = instance.find(dep.first);
1116
+ if (prop != instance.object_range().end())
1117
+ {
1118
+ // if dependency-property is present in instance
1119
+ jsonpointer::json_pointer pointer(instance_location);
1120
+ pointer /= dep.first;
1121
+ dep.second->validate(instance, pointer, reporter, patch); // validate
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ void update_patch(Json& patch, const jsonpointer::json_pointer& instance_location, Json&& default_value) const
1127
+ {
1128
+ Json j;
1129
+ j.try_emplace("op", "add");
1130
+ j.try_emplace("path", instance_location.to_uri_fragment());
1131
+ j.try_emplace("value", std::forward<Json>(default_value));
1132
+ patch.push_back(std::move(j));
1133
+ }
1134
+ };
1135
+
1136
+ // array_validator
1137
+
1138
+ template <class Json>
1139
+ class array_validator : public keyword_validator<Json>
1140
+ {
1141
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
1142
+
1143
+ jsoncons::optional<std::size_t> max_items_;
1144
+ std::string absolute_max_items_location_;
1145
+ jsoncons::optional<std::size_t> min_items_;
1146
+ std::string absolute_min_items_location_;
1147
+ bool unique_items_ = false;
1148
+ validator_pointer items_validator_;
1149
+ std::vector<validator_pointer> item_validators_;
1150
+ validator_pointer additional_items_validator_;
1151
+ validator_pointer contains_validator_;
1152
+
1153
+ public:
1154
+ array_validator(abstract_keyword_validator_factory<Json>* builder,
1155
+ const Json& sch,
1156
+ const std::vector<schema_location>& uris)
1157
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""),
1158
+ max_items_(), min_items_(), items_validator_(nullptr), additional_items_validator_(nullptr), contains_validator_(nullptr)
1159
+ {
1160
+ {
1161
+ auto it = sch.find("maxItems");
1162
+ if (it != sch.object_range().end())
1163
+ {
1164
+ max_items_ = it->value().template as<std::size_t>();
1165
+ absolute_max_items_location_ = make_absolute_keyword_location(uris, "maxItems");
1166
+ }
1167
+ }
1168
+
1169
+ {
1170
+ auto it = sch.find("minItems");
1171
+ if (it != sch.object_range().end())
1172
+ {
1173
+ min_items_ = it->value().template as<std::size_t>();
1174
+ absolute_min_items_location_ = make_absolute_keyword_location(uris, "minItems");
1175
+ }
1176
+ }
1177
+
1178
+ {
1179
+ auto it = sch.find("uniqueItems");
1180
+ if (it != sch.object_range().end())
1181
+ {
1182
+ unique_items_ = it->value().template as<bool>();
1183
+ }
1184
+ }
1185
+
1186
+ {
1187
+ auto it = sch.find("items");
1188
+ if (it != sch.object_range().end())
1189
+ {
1190
+
1191
+ if (it->value().type() == json_type::array_value)
1192
+ {
1193
+ size_t c = 0;
1194
+ for (const auto& subsch : it->value().array_range())
1195
+ item_validators_.push_back(builder->make_keyword_validator(subsch, uris, {"items", std::to_string(c++)}));
1196
+
1197
+ auto attr_add = sch.find("additionalItems");
1198
+ if (attr_add != sch.object_range().end())
1199
+ {
1200
+ additional_items_validator_ = builder->make_keyword_validator(attr_add->value(), uris, {"additionalItems"});
1201
+ }
1202
+
1203
+ }
1204
+ else if (it->value().type() == json_type::object_value ||
1205
+ it->value().type() == json_type::bool_value)
1206
+ {
1207
+ items_validator_ = builder->make_keyword_validator(it->value(), uris, {"items"});
1208
+ }
1209
+
1210
+ }
1211
+ }
1212
+
1213
+ {
1214
+ auto it = sch.find("contains");
1215
+ if (it != sch.object_range().end())
1216
+ {
1217
+ contains_validator_ = builder->make_keyword_validator(it->value(), uris, {"contains"});
1218
+ }
1219
+ }
1220
+ }
1221
+ private:
1222
+
1223
+ void do_validate(const Json& instance,
1224
+ const jsonpointer::json_pointer& instance_location,
1225
+ error_reporter& reporter,
1226
+ Json& patch) const override
1227
+ {
1228
+ if (max_items_)
1229
+ {
1230
+ if (instance.size() > *max_items_)
1231
+ {
1232
+ std::string message("Expected maximum item count: " + std::to_string(*max_items_));
1233
+ message.append(", found: " + std::to_string(instance.size()));
1234
+ reporter.error(validation_output("maxItems",
1235
+ absolute_max_items_location_,
1236
+ instance_location.to_uri_fragment(),
1237
+ std::move(message)));
1238
+ if (reporter.fail_early())
1239
+ {
1240
+ return;
1241
+ }
1242
+ }
1243
+ }
1244
+
1245
+ if (min_items_)
1246
+ {
1247
+ if (instance.size() < *min_items_)
1248
+ {
1249
+ std::string message("Expected minimum item count: " + std::to_string(*min_items_));
1250
+ message.append(", found: " + std::to_string(instance.size()));
1251
+ reporter.error(validation_output("minItems",
1252
+ absolute_min_items_location_,
1253
+ instance_location.to_uri_fragment(),
1254
+ std::move(message)));
1255
+ if (reporter.fail_early())
1256
+ {
1257
+ return;
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ if (unique_items_)
1263
+ {
1264
+ if (!array_has_unique_items(instance))
1265
+ {
1266
+ reporter.error(validation_output("uniqueItems",
1267
+ this->absolute_keyword_location(),
1268
+ instance_location.to_uri_fragment(),
1269
+ "Array items are not unique"));
1270
+ if (reporter.fail_early())
1271
+ {
1272
+ return;
1273
+ }
1274
+ }
1275
+ }
1276
+
1277
+ size_t index = 0;
1278
+ if (items_validator_)
1279
+ {
1280
+ for (const auto& i : instance.array_range())
1281
+ {
1282
+ jsonpointer::json_pointer pointer(instance_location);
1283
+ pointer /= index;
1284
+ items_validator_->validate(i, pointer, reporter, patch);
1285
+ index++;
1286
+ }
1287
+ }
1288
+ else
1289
+ {
1290
+ auto validator_it = item_validators_.cbegin();
1291
+ for (const auto& item : instance.array_range())
1292
+ {
1293
+ validator_pointer item_validator = nullptr;
1294
+ if (validator_it != item_validators_.cend())
1295
+ {
1296
+ item_validator = *validator_it;
1297
+ ++validator_it;
1298
+ }
1299
+ else if (additional_items_validator_ != nullptr)
1300
+ {
1301
+ item_validator = additional_items_validator_;
1302
+ }
1303
+ else
1304
+ break;
1305
+
1306
+ jsonpointer::json_pointer pointer(instance_location);
1307
+ pointer /= index;
1308
+ item_validator->validate(item, pointer, reporter, patch);
1309
+ }
1310
+ }
1311
+
1312
+ if (contains_validator_)
1313
+ {
1314
+ bool contained = false;
1315
+ collecting_error_reporter local_reporter;
1316
+ for (const auto& item : instance.array_range())
1317
+ {
1318
+ std::size_t mark = local_reporter.errors.size();
1319
+ contains_validator_->validate(item, instance_location, local_reporter, patch);
1320
+ if (mark == local_reporter.errors.size())
1321
+ {
1322
+ contained = true;
1323
+ break;
1324
+ }
1325
+ }
1326
+ if (!contained)
1327
+ {
1328
+ reporter.error(validation_output("contains",
1329
+ this->absolute_keyword_location(),
1330
+ instance_location.to_uri_fragment(),
1331
+ "Expected at least one array item to match \"contains\" schema",
1332
+ local_reporter.errors));
1333
+ if (reporter.fail_early())
1334
+ {
1335
+ return;
1336
+ }
1337
+ }
1338
+ }
1339
+ }
1340
+
1341
+ static bool array_has_unique_items(const Json& a)
1342
+ {
1343
+ for (auto it = a.array_range().begin(); it != a.array_range().end(); ++it)
1344
+ {
1345
+ for (auto jt = it+1; jt != a.array_range().end(); ++jt)
1346
+ {
1347
+ if (*it == *jt)
1348
+ {
1349
+ return false; // contains duplicates
1350
+ }
1351
+ }
1352
+ }
1353
+ return true; // elements are unique
1354
+ }
1355
+ };
1356
+
1357
+ template <class Json>
1358
+ class conditional_validator : public keyword_validator<Json>
1359
+ {
1360
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
1361
+
1362
+ validator_pointer if_validator_;
1363
+ validator_pointer then_validator_;
1364
+ validator_pointer else_validator_;
1365
+
1366
+ public:
1367
+ conditional_validator(abstract_keyword_validator_factory<Json>* builder,
1368
+ const Json& sch_if,
1369
+ const Json& sch,
1370
+ const std::vector<schema_location>& uris)
1371
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), if_validator_(nullptr), then_validator_(nullptr), else_validator_(nullptr)
1372
+ {
1373
+ auto then_it = sch.find("then");
1374
+ auto else_it = sch.find("else");
1375
+
1376
+ if (then_it != sch.object_range().end() || else_it != sch.object_range().end())
1377
+ {
1378
+ if_validator_ = builder->make_keyword_validator(sch_if, uris, {"if"});
1379
+
1380
+ if (then_it != sch.object_range().end())
1381
+ {
1382
+ then_validator_ = builder->make_keyword_validator(then_it->value(), uris, {"then"});
1383
+ }
1384
+
1385
+ if (else_it != sch.object_range().end())
1386
+ {
1387
+ else_validator_ = builder->make_keyword_validator(else_it->value(), uris, {"else"});
1388
+ }
1389
+ }
1390
+ }
1391
+ private:
1392
+ void do_validate(const Json& instance,
1393
+ const jsonpointer::json_pointer& instance_location,
1394
+ error_reporter& reporter,
1395
+ Json& patch) const final
1396
+ {
1397
+ if (if_validator_)
1398
+ {
1399
+ collecting_error_reporter local_reporter;
1400
+
1401
+ if_validator_->validate(instance, instance_location, local_reporter, patch);
1402
+ if (local_reporter.errors.empty())
1403
+ {
1404
+ if (then_validator_)
1405
+ then_validator_->validate(instance, instance_location, reporter, patch);
1406
+ }
1407
+ else
1408
+ {
1409
+ if (else_validator_)
1410
+ else_validator_->validate(instance, instance_location, reporter, patch);
1411
+ }
1412
+ }
1413
+ }
1414
+ };
1415
+
1416
+ // enum_validator
1417
+
1418
+ template <class Json>
1419
+ class enum_validator : public keyword_validator<Json>
1420
+ {
1421
+ Json enum_validator_;
1422
+
1423
+ public:
1424
+ enum_validator(const Json& sch,
1425
+ const std::vector<schema_location>& uris)
1426
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), enum_validator_(sch)
1427
+ {
1428
+ }
1429
+ private:
1430
+ void do_validate(const Json& instance,
1431
+ const jsonpointer::json_pointer& instance_location,
1432
+ error_reporter& reporter,
1433
+ Json&) const final
1434
+ {
1435
+ bool in_range = false;
1436
+ for (const auto& item : enum_validator_.array_range())
1437
+ {
1438
+ if (item == instance)
1439
+ {
1440
+ in_range = true;
1441
+ break;
1442
+ }
1443
+ }
1444
+
1445
+ if (!in_range)
1446
+ {
1447
+ reporter.error(validation_output("enum",
1448
+ this->absolute_keyword_location(),
1449
+ instance_location.to_uri_fragment(),
1450
+ instance.template as<std::string>() + " is not a valid enum value"));
1451
+ if (reporter.fail_early())
1452
+ {
1453
+ return;
1454
+ }
1455
+ }
1456
+ }
1457
+ };
1458
+
1459
+ // const_keyword
1460
+
1461
+ template <class Json>
1462
+ class const_keyword : public keyword_validator<Json>
1463
+ {
1464
+ Json const_validator_;
1465
+
1466
+ public:
1467
+ const_keyword(const Json& sch, const std::vector<schema_location>& uris)
1468
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), const_validator_(sch)
1469
+ {
1470
+ }
1471
+ private:
1472
+ void do_validate(const Json& instance,
1473
+ const jsonpointer::json_pointer& instance_location,
1474
+ error_reporter& reporter,
1475
+ Json&) const final
1476
+ {
1477
+ if (const_validator_ != instance)
1478
+ reporter.error(validation_output("const",
1479
+ this->absolute_keyword_location(),
1480
+ instance_location.to_uri_fragment(),
1481
+ "Instance is not const"));
1482
+ }
1483
+ };
1484
+
1485
+ template <class Json>
1486
+ class type_validator : public keyword_validator<Json>
1487
+ {
1488
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
1489
+
1490
+ Json default_value_;
1491
+ std::vector<validator_pointer> type_mapping_;
1492
+ jsoncons::optional<enum_validator<Json>> enum_validator_;
1493
+ jsoncons::optional<const_keyword<Json>> const_validator_;
1494
+ std::vector<validator_pointer> combined_validators_;
1495
+ jsoncons::optional<conditional_validator<Json>> conditional_validator_;
1496
+ std::vector<std::string> expected_types_;
1497
+
1498
+ public:
1499
+ type_validator(const type_validator&) = delete;
1500
+ type_validator& operator=(const type_validator&) = delete;
1501
+ type_validator(type_validator&&) = default;
1502
+ type_validator& operator=(type_validator&&) = default;
1503
+
1504
+ type_validator(abstract_keyword_validator_factory<Json>* builder,
1505
+ const Json& sch,
1506
+ const std::vector<schema_location>& uris)
1507
+ : keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), default_value_(jsoncons::null_type()),
1508
+ type_mapping_((uint8_t)(json_type::object_value)+1),
1509
+ enum_validator_(), const_validator_()
1510
+ {
1511
+ //std::cout << uris.size() << " uris: ";
1512
+ //for (const auto& uri : uris)
1513
+ //{
1514
+ // std::cout << uri.string() << ", ";
1515
+ //}
1516
+ //std::cout << "\n";
1517
+ std::set<std::string> known_keywords;
1518
+
1519
+ auto it = sch.find("type");
1520
+ if (it == sch.object_range().end())
1521
+ {
1522
+ initialize_type_mapping(builder, "", sch, uris, known_keywords);
1523
+ }
1524
+ else
1525
+ {
1526
+ switch (it->value().type())
1527
+ {
1528
+ case json_type::string_value:
1529
+ {
1530
+ auto type = it->value().template as<std::string>();
1531
+ initialize_type_mapping(builder, type, sch, uris, known_keywords);
1532
+ expected_types_.emplace_back(std::move(type));
1533
+ break;
1534
+ }
1535
+
1536
+ case json_type::array_value: // "type": ["type1", "type2"]
1537
+ {
1538
+ for (const auto& item : it->value().array_range())
1539
+ {
1540
+ auto type = item.template as<std::string>();
1541
+ initialize_type_mapping(builder, type, sch, uris, known_keywords);
1542
+ expected_types_.emplace_back(std::move(type));
1543
+ }
1544
+ break;
1545
+ }
1546
+ default:
1547
+ break;
1548
+ }
1549
+ }
1550
+
1551
+ const auto default_it = sch.find("default");
1552
+ if (default_it != sch.object_range().end())
1553
+ {
1554
+ default_value_ = default_it->value();
1555
+ }
1556
+
1557
+ it = sch.find("enum");
1558
+ if (it != sch.object_range().end())
1559
+ {
1560
+ enum_validator_ = enum_validator<Json >(it->value(), uris);
1561
+ }
1562
+
1563
+ it = sch.find("const");
1564
+ if (it != sch.object_range().end())
1565
+ {
1566
+ const_validator_ = const_keyword<Json>(it->value(), uris);
1567
+ }
1568
+
1569
+ it = sch.find("not");
1570
+ if (it != sch.object_range().end())
1571
+ {
1572
+ combined_validators_.push_back(builder->make_not_validator(it->value(), uris));
1573
+ }
1574
+
1575
+ it = sch.find("allOf");
1576
+ if (it != sch.object_range().end())
1577
+ {
1578
+ combined_validators_.push_back(builder->make_all_of_validator(it->value(), uris));
1579
+ }
1580
+
1581
+ it = sch.find("anyOf");
1582
+ if (it != sch.object_range().end())
1583
+ {
1584
+ combined_validators_.push_back(builder->make_any_of_validator(it->value(), uris));
1585
+ }
1586
+
1587
+ it = sch.find("oneOf");
1588
+ if (it != sch.object_range().end())
1589
+ {
1590
+ combined_validators_.push_back(builder->make_one_of_validator(it->value(), uris));
1591
+ }
1592
+
1593
+ it = sch.find("if");
1594
+ if (it != sch.object_range().end())
1595
+ {
1596
+ conditional_validator_ = conditional_validator<Json>(builder, it->value(), sch, uris);
1597
+ }
1598
+ }
1599
+ private:
1600
+
1601
+ void do_validate(const Json& instance,
1602
+ const jsonpointer::json_pointer& instance_location,
1603
+ error_reporter& reporter,
1604
+ Json& patch) const override final
1605
+ {
1606
+ auto type = type_mapping_[(uint8_t) instance.type()];
1607
+
1608
+ if (type)
1609
+ type->validate(instance, instance_location, reporter, patch);
1610
+ else
1611
+ {
1612
+ std::ostringstream ss;
1613
+ ss << "Expected ";
1614
+ for (std::size_t i = 0; i < expected_types_.size(); ++i)
1615
+ {
1616
+ if (i > 0)
1617
+ {
1618
+ ss << ", ";
1619
+ if (i+1 == expected_types_.size())
1620
+ {
1621
+ ss << "or ";
1622
+ }
1623
+ }
1624
+ ss << expected_types_[i];
1625
+ }
1626
+ ss << ", found " << instance.type();
1627
+
1628
+ reporter.error(validation_output("type",
1629
+ this->absolute_keyword_location(),
1630
+ instance_location.to_uri_fragment(),
1631
+ ss.str()));
1632
+ if (reporter.fail_early())
1633
+ {
1634
+ return;
1635
+ }
1636
+ }
1637
+
1638
+ if (enum_validator_)
1639
+ {
1640
+ enum_validator_->validate(instance, instance_location, reporter, patch);
1641
+ if (reporter.error_count() > 0 && reporter.fail_early())
1642
+ {
1643
+ return;
1644
+ }
1645
+ }
1646
+
1647
+ if (const_validator_)
1648
+ {
1649
+ const_validator_->validate(instance, instance_location, reporter, patch);
1650
+ if (reporter.error_count() > 0 && reporter.fail_early())
1651
+ {
1652
+ return;
1653
+ }
1654
+ }
1655
+
1656
+ for (const auto& validator : combined_validators_)
1657
+ {
1658
+ validator->validate(instance, instance_location, reporter, patch);
1659
+ if (reporter.error_count() > 0 && reporter.fail_early())
1660
+ {
1661
+ return;
1662
+ }
1663
+ }
1664
+
1665
+
1666
+ if (conditional_validator_)
1667
+ {
1668
+ conditional_validator_->validate(instance, instance_location, reporter, patch);
1669
+ if (reporter.error_count() > 0 && reporter.fail_early())
1670
+ {
1671
+ return;
1672
+ }
1673
+ }
1674
+ }
1675
+
1676
+ jsoncons::optional<Json> get_default_value(const jsonpointer::json_pointer&,
1677
+ const Json&,
1678
+ error_reporter&) const override
1679
+ {
1680
+ return default_value_;
1681
+ }
1682
+
1683
+ void initialize_type_mapping(abstract_keyword_validator_factory<Json>* builder,
1684
+ const std::string& type,
1685
+ const Json& sch,
1686
+ const std::vector<schema_location>& uris,
1687
+ std::set<std::string>& keywords)
1688
+ {
1689
+ if (type == "null")
1690
+ {
1691
+ type_mapping_[(uint8_t)json_type::null_value] = builder->make_null_validator(uris);
1692
+ }
1693
+ else if (type == "object")
1694
+ {
1695
+ type_mapping_[(uint8_t)json_type::object_value] = builder->make_object_validator(sch, uris);
1696
+ }
1697
+ else if (type == "array")
1698
+ {
1699
+ type_mapping_[(uint8_t)json_type::array_value] = builder->make_array_validator(sch, uris);
1700
+ }
1701
+ else if (type == "string")
1702
+ {
1703
+ type_mapping_[(uint8_t)json_type::string_value] = builder->make_string_validator(sch, uris);
1704
+ // For binary types
1705
+ type_mapping_[(uint8_t) json_type::byte_string_value] = type_mapping_[(uint8_t) json_type::string_value];
1706
+ }
1707
+ else if (type == "boolean")
1708
+ {
1709
+ type_mapping_[(uint8_t)json_type::bool_value] = builder->make_boolean_validator(uris);
1710
+ }
1711
+ else if (type == "integer")
1712
+ {
1713
+ type_mapping_[(uint8_t)json_type::int64_value] = builder->make_integer_validator(sch, uris, keywords);
1714
+ type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::int64_value];
1715
+ type_mapping_[(uint8_t)json_type::double_value] = type_mapping_[(uint8_t)json_type::int64_value];
1716
+ }
1717
+ else if (type == "number")
1718
+ {
1719
+ type_mapping_[(uint8_t)json_type::double_value] = builder->make_number_validator(sch, uris, keywords);
1720
+ type_mapping_[(uint8_t)json_type::int64_value] = type_mapping_[(uint8_t)json_type::double_value];
1721
+ type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::double_value];
1722
+ }
1723
+ else if (type.empty())
1724
+ {
1725
+ type_mapping_[(uint8_t)json_type::null_value] = builder->make_null_validator(uris);
1726
+ type_mapping_[(uint8_t)json_type::object_value] = builder->make_object_validator(sch, uris);
1727
+ type_mapping_[(uint8_t)json_type::array_value] = builder->make_array_validator(sch, uris);
1728
+ type_mapping_[(uint8_t)json_type::string_value] = builder->make_string_validator(sch, uris);
1729
+ // For binary types
1730
+ type_mapping_[(uint8_t) json_type::byte_string_value] = type_mapping_[(uint8_t) json_type::string_value];
1731
+ type_mapping_[(uint8_t)json_type::bool_value] = builder->make_boolean_validator(uris);
1732
+ type_mapping_[(uint8_t)json_type::int64_value] = builder->make_integer_validator(sch, uris, keywords);
1733
+ type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::int64_value];
1734
+ type_mapping_[(uint8_t)json_type::double_value] = type_mapping_[(uint8_t)json_type::int64_value];
1735
+ type_mapping_[(uint8_t)json_type::double_value] = builder->make_number_validator(sch, uris, keywords);
1736
+ type_mapping_[(uint8_t)json_type::int64_value] = type_mapping_[(uint8_t)json_type::double_value];
1737
+ type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::double_value];
1738
+ }
1739
+ }
1740
+ };
1741
+
1742
+ } // namespace jsonschema
1743
+ } // namespace jsoncons
1744
+
1745
+ #endif // JSONCONS_JSONSCHEMA_VALUE_RULES_HPP