jsoncons 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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