rj_schema 0.2.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rj_schema/rapidjson/bin/unittestschema/address.json +139 -0
  3. data/ext/rj_schema/rapidjson/bin/unittestschema/allOf_address.json +7 -0
  4. data/ext/rj_schema/rapidjson/bin/unittestschema/anyOf_address.json +7 -0
  5. data/ext/rj_schema/rapidjson/bin/unittestschema/oneOf_address.json +7 -0
  6. data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +118 -0
  7. data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +5 -5
  8. data/ext/rj_schema/rapidjson/include/rapidjson/cursorstreamwrapper.h +1 -1
  9. data/ext/rj_schema/rapidjson/include/rapidjson/document.h +17 -12
  10. data/ext/rj_schema/rapidjson/include/rapidjson/encodedstream.h +1 -1
  11. data/ext/rj_schema/rapidjson/include/rapidjson/encodings.h +1 -1
  12. data/ext/rj_schema/rapidjson/include/rapidjson/error/en.h +49 -1
  13. data/ext/rj_schema/rapidjson/include/rapidjson/error/error.h +56 -1
  14. data/ext/rj_schema/rapidjson/include/rapidjson/filereadstream.h +1 -1
  15. data/ext/rj_schema/rapidjson/include/rapidjson/filewritestream.h +1 -1
  16. data/ext/rj_schema/rapidjson/include/rapidjson/fwd.h +1 -1
  17. data/ext/rj_schema/rapidjson/include/rapidjson/internal/biginteger.h +1 -1
  18. data/ext/rj_schema/rapidjson/include/rapidjson/internal/clzll.h +4 -4
  19. data/ext/rj_schema/rapidjson/include/rapidjson/internal/diyfp.h +1 -1
  20. data/ext/rj_schema/rapidjson/include/rapidjson/internal/dtoa.h +1 -1
  21. data/ext/rj_schema/rapidjson/include/rapidjson/internal/ieee754.h +1 -1
  22. data/ext/rj_schema/rapidjson/include/rapidjson/internal/itoa.h +1 -1
  23. data/ext/rj_schema/rapidjson/include/rapidjson/internal/meta.h +1 -1
  24. data/ext/rj_schema/rapidjson/include/rapidjson/internal/pow10.h +1 -1
  25. data/ext/rj_schema/rapidjson/include/rapidjson/internal/regex.h +1 -1
  26. data/ext/rj_schema/rapidjson/include/rapidjson/internal/stack.h +1 -1
  27. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +1 -1
  28. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strtod.h +1 -1
  29. data/ext/rj_schema/rapidjson/include/rapidjson/internal/swap.h +1 -1
  30. data/ext/rj_schema/rapidjson/include/rapidjson/istreamwrapper.h +1 -1
  31. data/ext/rj_schema/rapidjson/include/rapidjson/memorybuffer.h +1 -1
  32. data/ext/rj_schema/rapidjson/include/rapidjson/memorystream.h +1 -1
  33. data/ext/rj_schema/rapidjson/include/rapidjson/ostreamwrapper.h +1 -1
  34. data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +1 -1
  35. data/ext/rj_schema/rapidjson/include/rapidjson/prettywriter.h +1 -1
  36. data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +17 -1
  37. data/ext/rj_schema/rapidjson/include/rapidjson/reader.h +17 -9
  38. data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +311 -159
  39. data/ext/rj_schema/rapidjson/include/rapidjson/stream.h +1 -1
  40. data/ext/rj_schema/rapidjson/include/rapidjson/stringbuffer.h +1 -1
  41. data/ext/rj_schema/rapidjson/include/rapidjson/writer.h +3 -3
  42. data/ext/rj_schema/rapidjson/readme.md +3 -3
  43. data/ext/rj_schema/rapidjson/readme.zh-cn.md +2 -2
  44. data/ext/rj_schema/rapidjson/test/perftest/misctest.cpp +1 -1
  45. data/ext/rj_schema/rapidjson/test/perftest/perftest.cpp +1 -1
  46. data/ext/rj_schema/rapidjson/test/perftest/perftest.h +1 -1
  47. data/ext/rj_schema/rapidjson/test/perftest/platformtest.cpp +1 -1
  48. data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +1 -1
  49. data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +1 -0
  50. data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +1 -1
  51. data/ext/rj_schema/rapidjson/test/unittest/bigintegertest.cpp +1 -1
  52. data/ext/rj_schema/rapidjson/test/unittest/clzlltest.cpp +34 -0
  53. data/ext/rj_schema/rapidjson/test/unittest/cursorstreamwrappertest.cpp +1 -1
  54. data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +1 -1
  55. data/ext/rj_schema/rapidjson/test/unittest/dtoatest.cpp +1 -1
  56. data/ext/rj_schema/rapidjson/test/unittest/encodedstreamtest.cpp +1 -1
  57. data/ext/rj_schema/rapidjson/test/unittest/encodingstest.cpp +1 -1
  58. data/ext/rj_schema/rapidjson/test/unittest/filestreamtest.cpp +1 -1
  59. data/ext/rj_schema/rapidjson/test/unittest/fwdtest.cpp +1 -1
  60. data/ext/rj_schema/rapidjson/test/unittest/istreamwrappertest.cpp +1 -1
  61. data/ext/rj_schema/rapidjson/test/unittest/itoatest.cpp +1 -1
  62. data/ext/rj_schema/rapidjson/test/unittest/jsoncheckertest.cpp +1 -1
  63. data/ext/rj_schema/rapidjson/test/unittest/namespacetest.cpp +1 -1
  64. data/ext/rj_schema/rapidjson/test/unittest/ostreamwrappertest.cpp +1 -1
  65. data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +33 -1
  66. data/ext/rj_schema/rapidjson/test/unittest/prettywritertest.cpp +1 -1
  67. data/ext/rj_schema/rapidjson/test/unittest/readertest.cpp +4 -1
  68. data/ext/rj_schema/rapidjson/test/unittest/regextest.cpp +1 -1
  69. data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +593 -78
  70. data/ext/rj_schema/rapidjson/test/unittest/simdtest.cpp +1 -1
  71. data/ext/rj_schema/rapidjson/test/unittest/strfunctest.cpp +1 -1
  72. data/ext/rj_schema/rapidjson/test/unittest/stringbuffertest.cpp +1 -1
  73. data/ext/rj_schema/rapidjson/test/unittest/strtodtest.cpp +1 -1
  74. data/ext/rj_schema/rapidjson/test/unittest/unittest.cpp +1 -1
  75. data/ext/rj_schema/rapidjson/test/unittest/unittest.h +1 -1
  76. data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +1 -1
  77. data/ext/rj_schema/rapidjson/test/unittest/writertest.cpp +1 -1
  78. data/ext/rj_schema/rj_schema.cpp +160 -16
  79. data/lib/rj_schema.rb +1 -1
  80. metadata +8 -3
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -65,6 +65,54 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
65
65
  }
66
66
  }
67
67
 
68
+ //! Maps error code of validation into error message.
69
+ /*!
70
+ \ingroup RAPIDJSON_ERRORS
71
+ \param validateErrorCode Error code obtained from validator.
72
+ \return the error message.
73
+ \note User can make a copy of this function for localization.
74
+ Using switch-case is safer for future modification of error codes.
75
+ */
76
+ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
77
+ switch (validateErrorCode) {
78
+ case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
79
+ case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
80
+
81
+ case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
82
+ case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
83
+ case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
84
+ case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
85
+ case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
86
+
87
+ case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
88
+ case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
89
+ case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
90
+
91
+ case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
92
+ case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
93
+ case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
94
+ case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
95
+
96
+ case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
97
+ case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
98
+ case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
99
+ case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
100
+ case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
101
+ case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
102
+
103
+ case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
104
+ case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
105
+
106
+ case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
107
+ case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
108
+ case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
109
+ case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
110
+ case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
111
+
112
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
113
+ }
114
+ }
115
+
68
116
  RAPIDJSON_NAMESPACE_END
69
117
 
70
118
  #ifdef __clang__
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -152,6 +152,61 @@ private:
152
152
  */
153
153
  typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
154
154
 
155
+ ///////////////////////////////////////////////////////////////////////////////
156
+ // ValidateErrorCode
157
+
158
+ //! Error codes when validating.
159
+ /*! \ingroup RAPIDJSON_ERRORS
160
+ \see GenericSchemaValidator
161
+ */
162
+ enum ValidateErrorCode {
163
+ kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
164
+ kValidateErrorNone = 0, //!< No error.
165
+
166
+ kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
167
+ kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
168
+ kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
169
+ kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
170
+ kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
171
+
172
+ kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
173
+ kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
174
+ kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
175
+
176
+ kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
177
+ kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
178
+ kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
179
+ kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
180
+
181
+ kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
182
+ kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
183
+ kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
184
+ kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
185
+ kValidateErrorPatternProperties, //!< See other errors.
186
+ kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
187
+
188
+ kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
189
+ kValidateErrorType, //!< Property has a type that is not allowed by the schema..
190
+
191
+ kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
192
+ kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
193
+ kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
194
+ kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
195
+ kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
196
+ };
197
+
198
+ //! Function pointer type of GetValidateError().
199
+ /*! \ingroup RAPIDJSON_ERRORS
200
+
201
+ This is the prototype for \c GetValidateError_X(), where \c X is a locale.
202
+ User can dynamically change locale in runtime, e.g.:
203
+ \code
204
+ GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
205
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
206
+ \endcode
207
+ */
208
+ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
209
+
155
210
  RAPIDJSON_NAMESPACE_END
156
211
 
157
212
  #ifdef __clang__
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -17,7 +17,7 @@
17
17
 
18
18
  #include "../rapidjson.h"
19
19
 
20
- #if defined(_MSC_VER)
20
+ #if defined(_MSC_VER) && !defined(UNDER_CE)
21
21
  #include <intrin.h>
22
22
  #if defined(_WIN64)
23
23
  #pragma intrinsic(_BitScanReverse64)
@@ -34,7 +34,7 @@ inline uint32_t clzll(uint64_t x) {
34
34
  // infinite loop in the software implementation.
35
35
  RAPIDJSON_ASSERT(x != 0);
36
36
 
37
- #if defined(_MSC_VER)
37
+ #if defined(_MSC_VER) && !defined(UNDER_CE)
38
38
  unsigned long r = 0;
39
39
  #if defined(_WIN64)
40
40
  _BitScanReverse64(&r, x);
@@ -53,7 +53,7 @@ inline uint32_t clzll(uint64_t x) {
53
53
  return static_cast<uint32_t>(__builtin_clzll(x));
54
54
  #else
55
55
  // naive version
56
- uint32_t r;
56
+ uint32_t r = 0;
57
57
  while (!(x & (static_cast<uint64_t>(1) << 63))) {
58
58
  x <<= 1;
59
59
  ++r;
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -639,6 +639,22 @@ RAPIDJSON_NAMESPACE_END
639
639
  #endif // RAPIDJSON_ASSERT_THROWS
640
640
  #endif // RAPIDJSON_NOEXCEPT_ASSERT
641
641
 
642
+ ///////////////////////////////////////////////////////////////////////////////
643
+ // malloc/realloc/free
644
+
645
+ #ifndef RAPIDJSON_MALLOC
646
+ ///! customization point for global \c malloc
647
+ #define RAPIDJSON_MALLOC(size) std::malloc(size)
648
+ #endif
649
+ #ifndef RAPIDJSON_REALLOC
650
+ ///! customization point for global \c realloc
651
+ #define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
652
+ #endif
653
+ #ifndef RAPIDJSON_FREE
654
+ ///! customization point for global \c free
655
+ #define RAPIDJSON_FREE(ptr) std::free(ptr)
656
+ #endif
657
+
642
658
  ///////////////////////////////////////////////////////////////////////////////
643
659
  // new/delete
644
660
 
@@ -1,6 +1,6 @@
1
1
  // Tencent is pleased to support the open source community by making RapidJSON available.
2
2
  //
3
- // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3
+ // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
4
  //
5
5
  // Licensed under the MIT License (the "License"); you may not use this file except
6
6
  // in compliance with the License. You may obtain a copy of the License at
@@ -1023,15 +1023,23 @@ private:
1023
1023
  is.Take();
1024
1024
  unsigned codepoint = ParseHex4(is, escapeOffset);
1025
1025
  RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
1026
- if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
1027
- // Handle UTF-16 surrogate pair
1028
- if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
1029
- RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
1030
- unsigned codepoint2 = ParseHex4(is, escapeOffset);
1031
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
1032
- if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
1026
+ if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) {
1027
+ // high surrogate, check if followed by valid low surrogate
1028
+ if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) {
1029
+ // Handle UTF-16 surrogate pair
1030
+ if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
1031
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
1032
+ unsigned codepoint2 = ParseHex4(is, escapeOffset);
1033
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
1034
+ if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
1035
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
1036
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
1037
+ }
1038
+ // single low surrogate
1039
+ else
1040
+ {
1033
1041
  RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
1034
- codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
1042
+ }
1035
1043
  }
1036
1044
  TEncoding::Encode(os, codepoint);
1037
1045
  }
@@ -18,6 +18,7 @@
18
18
  #include "document.h"
19
19
  #include "pointer.h"
20
20
  #include "stringbuffer.h"
21
+ #include "error/en.h"
21
22
  #include <cmath> // abs, floor
22
23
 
23
24
  #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
@@ -113,13 +114,36 @@ inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar
113
114
  #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
114
115
  #endif
115
116
 
116
- #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
117
+ #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
117
118
  RAPIDJSON_MULTILINEMACRO_BEGIN\
118
- context.invalidKeyword = keyword.GetString();\
119
- RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
119
+ context.invalidCode = code;\
120
+ context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
121
+ RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
120
122
  return false;\
121
123
  RAPIDJSON_MULTILINEMACRO_END
122
124
 
125
+ ///////////////////////////////////////////////////////////////////////////////
126
+ // ValidateFlag
127
+
128
+ /*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS
129
+ \ingroup RAPIDJSON_CONFIG
130
+ \brief User-defined kValidateDefaultFlags definition.
131
+
132
+ User can define this as any \c ValidateFlag combinations.
133
+ */
134
+ #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
135
+ #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
136
+ #endif
137
+
138
+ //! Combination of validate flags
139
+ /*! \see
140
+ */
141
+ enum ValidateFlag {
142
+ kValidateNoFlags = 0, //!< No flags are set.
143
+ kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error.
144
+ kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
145
+ };
146
+
123
147
  ///////////////////////////////////////////////////////////////////////////////
124
148
  // Forward declarations
125
149
 
@@ -138,6 +162,8 @@ class ISchemaValidator {
138
162
  public:
139
163
  virtual ~ISchemaValidator() {}
140
164
  virtual bool IsValid() const = 0;
165
+ virtual void SetValidateFlags(unsigned flags) = 0;
166
+ virtual unsigned GetValidateFlags() const = 0;
141
167
  };
142
168
 
143
169
  ///////////////////////////////////////////////////////////////////////////////
@@ -147,7 +173,7 @@ template <typename SchemaType>
147
173
  class ISchemaStateFactory {
148
174
  public:
149
175
  virtual ~ISchemaStateFactory() {}
150
- virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
176
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
151
177
  virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
152
178
  virtual void* CreateHasher() = 0;
153
179
  virtual uint64_t GetHashCode(void* hasher) = 0;
@@ -201,13 +227,13 @@ public:
201
227
  virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
202
228
  virtual bool EndDependencyErrors() = 0;
203
229
 
204
- virtual void DisallowedValue() = 0;
230
+ virtual void DisallowedValue(const ValidateErrorCode code) = 0;
205
231
  virtual void StartDisallowedType() = 0;
206
232
  virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
207
233
  virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
208
234
  virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
209
235
  virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
210
- virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
236
+ virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0;
211
237
  virtual void Disallowed() = 0;
212
238
  };
213
239
 
@@ -332,6 +358,7 @@ struct SchemaValidationContext {
332
358
  schema(s),
333
359
  valueSchema(),
334
360
  invalidKeyword(),
361
+ invalidCode(),
335
362
  hasher(),
336
363
  arrayElementHashCodes(),
337
364
  validators(),
@@ -372,6 +399,7 @@ struct SchemaValidationContext {
372
399
  const SchemaType* schema;
373
400
  const SchemaType* valueSchema;
374
401
  const Ch* invalidKeyword;
402
+ ValidateErrorCode invalidCode;
375
403
  void* hasher; // Only validator access
376
404
  void* arrayElementHashCodes; // Only validator access this
377
405
  ISchemaValidator** validators;
@@ -458,7 +486,7 @@ public:
458
486
  AddType(*itr);
459
487
  }
460
488
 
461
- if (const ValueType* v = GetMember(value, GetEnumString()))
489
+ if (const ValueType* v = GetMember(value, GetEnumString())) {
462
490
  if (v->IsArray() && v->Size() > 0) {
463
491
  enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
464
492
  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
@@ -470,6 +498,7 @@ public:
470
498
  enum_[enumCount_++] = h.GetHashCode();
471
499
  }
472
500
  }
501
+ }
473
502
 
474
503
  if (schemaDocument) {
475
504
  AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
@@ -688,7 +717,11 @@ public:
688
717
  context.valueSchema = typeless_;
689
718
  else {
690
719
  context.error_handler.DisallowedItem(context.arrayElementIndex);
691
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
720
+ // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
721
+ context.valueSchema = typeless_;
722
+ // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
723
+ context.arrayElementIndex++;
724
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
692
725
  }
693
726
  }
694
727
  else
@@ -700,6 +733,7 @@ public:
700
733
  }
701
734
 
702
735
  RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
736
+ // Only check pattern properties if we have validators
703
737
  if (context.patternPropertiesValidatorCount > 0) {
704
738
  bool otherValid = false;
705
739
  SizeType count = context.patternPropertiesValidatorCount;
@@ -716,66 +750,70 @@ public:
716
750
  if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
717
751
  if (!patternValid) {
718
752
  context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
719
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
753
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
720
754
  }
721
755
  }
722
756
  else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
723
757
  if (!patternValid || !otherValid) {
724
758
  context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
725
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
759
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
726
760
  }
727
761
  }
728
762
  else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
729
763
  context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
730
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
764
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
731
765
  }
732
766
  }
733
767
 
734
- if (enum_) {
768
+ // For enums only check if we have a hasher
769
+ if (enum_ && context.hasher) {
735
770
  const uint64_t h = context.factory.GetHashCode(context.hasher);
736
771
  for (SizeType i = 0; i < enumCount_; i++)
737
772
  if (enum_[i] == h)
738
773
  goto foundEnum;
739
- context.error_handler.DisallowedValue();
740
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
774
+ context.error_handler.DisallowedValue(kValidateErrorEnum);
775
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
741
776
  foundEnum:;
742
777
  }
743
778
 
744
- if (allOf_.schemas)
745
- for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
746
- if (!context.validators[i]->IsValid()) {
747
- context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
748
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
749
- }
750
-
751
- if (anyOf_.schemas) {
752
- for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
753
- if (context.validators[i]->IsValid())
754
- goto foundAny;
755
- context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
756
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
757
- foundAny:;
758
- }
759
-
760
- if (oneOf_.schemas) {
761
- bool oneValid = false;
762
- for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
763
- if (context.validators[i]->IsValid()) {
764
- if (oneValid) {
765
- context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
766
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
767
- } else
768
- oneValid = true;
779
+ // Only check allOf etc if we have validators
780
+ if (context.validatorCount > 0) {
781
+ if (allOf_.schemas)
782
+ for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
783
+ if (!context.validators[i]->IsValid()) {
784
+ context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
785
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
786
+ }
787
+
788
+ if (anyOf_.schemas) {
789
+ for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
790
+ if (context.validators[i]->IsValid())
791
+ goto foundAny;
792
+ context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
793
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
794
+ foundAny:;
795
+ }
796
+
797
+ if (oneOf_.schemas) {
798
+ bool oneValid = false;
799
+ for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
800
+ if (context.validators[i]->IsValid()) {
801
+ if (oneValid) {
802
+ context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true);
803
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
804
+ } else
805
+ oneValid = true;
806
+ }
807
+ if (!oneValid) {
808
+ context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false);
809
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
769
810
  }
770
- if (!oneValid) {
771
- context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
772
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
773
811
  }
774
- }
775
812
 
776
- if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
777
- context.error_handler.Disallowed();
778
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
813
+ if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
814
+ context.error_handler.Disallowed();
815
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
816
+ }
779
817
  }
780
818
 
781
819
  return true;
@@ -784,7 +822,7 @@ public:
784
822
  bool Null(Context& context) const {
785
823
  if (!(type_ & (1 << kNullSchemaType))) {
786
824
  DisallowedType(context, GetNullString());
787
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
825
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
788
826
  }
789
827
  return CreateParallelValidator(context);
790
828
  }
@@ -792,7 +830,7 @@ public:
792
830
  bool Bool(Context& context, bool) const {
793
831
  if (!(type_ & (1 << kBooleanSchemaType))) {
794
832
  DisallowedType(context, GetBooleanString());
795
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
833
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
796
834
  }
797
835
  return CreateParallelValidator(context);
798
836
  }
@@ -824,7 +862,7 @@ public:
824
862
  bool Double(Context& context, double d) const {
825
863
  if (!(type_ & (1 << kNumberSchemaType))) {
826
864
  DisallowedType(context, GetNumberString());
827
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
865
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
828
866
  }
829
867
 
830
868
  if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
@@ -842,7 +880,7 @@ public:
842
880
  bool String(Context& context, const Ch* str, SizeType length, bool) const {
843
881
  if (!(type_ & (1 << kStringSchemaType))) {
844
882
  DisallowedType(context, GetStringString());
845
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
883
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
846
884
  }
847
885
 
848
886
  if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
@@ -850,18 +888,18 @@ public:
850
888
  if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
851
889
  if (count < minLength_) {
852
890
  context.error_handler.TooShort(str, length, minLength_);
853
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
891
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
854
892
  }
855
893
  if (count > maxLength_) {
856
894
  context.error_handler.TooLong(str, length, maxLength_);
857
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
895
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
858
896
  }
859
897
  }
860
898
  }
861
899
 
862
900
  if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
863
901
  context.error_handler.DoesNotMatch(str, length);
864
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
902
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
865
903
  }
866
904
 
867
905
  return CreateParallelValidator(context);
@@ -870,7 +908,7 @@ public:
870
908
  bool StartObject(Context& context) const {
871
909
  if (!(type_ & (1 << kObjectSchemaType))) {
872
910
  DisallowedType(context, GetObjectString());
873
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
911
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
874
912
  }
875
913
 
876
914
  if (hasDependencies_ || hasRequired_) {
@@ -930,8 +968,10 @@ public:
930
968
  }
931
969
 
932
970
  if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
971
+ // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
972
+ context.valueSchema = typeless_;
933
973
  context.error_handler.DisallowedProperty(str, len);
934
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
974
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
935
975
  }
936
976
 
937
977
  return true;
@@ -945,17 +985,17 @@ public:
945
985
  if (properties_[index].schema->defaultValueLength_ == 0 )
946
986
  context.error_handler.AddMissingProperty(properties_[index].name);
947
987
  if (context.error_handler.EndMissingProperties())
948
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
988
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
949
989
  }
950
990
 
951
991
  if (memberCount < minProperties_) {
952
992
  context.error_handler.TooFewProperties(memberCount, minProperties_);
953
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
993
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
954
994
  }
955
995
 
956
996
  if (memberCount > maxProperties_) {
957
997
  context.error_handler.TooManyProperties(memberCount, maxProperties_);
958
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
998
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
959
999
  }
960
1000
 
961
1001
  if (hasDependencies_) {
@@ -978,21 +1018,21 @@ public:
978
1018
  }
979
1019
  }
980
1020
  if (context.error_handler.EndDependencyErrors())
981
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
1021
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
982
1022
  }
983
1023
 
984
1024
  return true;
985
1025
  }
986
1026
 
987
1027
  bool StartArray(Context& context) const {
1028
+ context.arrayElementIndex = 0;
1029
+ context.inArray = true; // Ensure we note that we are in an array
1030
+
988
1031
  if (!(type_ & (1 << kArraySchemaType))) {
989
1032
  DisallowedType(context, GetArrayString());
990
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1033
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
991
1034
  }
992
1035
 
993
- context.arrayElementIndex = 0;
994
- context.inArray = true;
995
-
996
1036
  return CreateParallelValidator(context);
997
1037
  }
998
1038
 
@@ -1001,17 +1041,55 @@ public:
1001
1041
 
1002
1042
  if (elementCount < minItems_) {
1003
1043
  context.error_handler.TooFewItems(elementCount, minItems_);
1004
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
1044
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
1005
1045
  }
1006
1046
 
1007
1047
  if (elementCount > maxItems_) {
1008
1048
  context.error_handler.TooManyItems(elementCount, maxItems_);
1009
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
1049
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
1010
1050
  }
1011
1051
 
1012
1052
  return true;
1013
1053
  }
1014
1054
 
1055
+ static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
1056
+ switch (validateErrorCode) {
1057
+ case kValidateErrorMultipleOf: return GetMultipleOfString();
1058
+ case kValidateErrorMaximum: return GetMaximumString();
1059
+ case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same
1060
+ case kValidateErrorMinimum: return GetMinimumString();
1061
+ case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same
1062
+
1063
+ case kValidateErrorMaxLength: return GetMaxLengthString();
1064
+ case kValidateErrorMinLength: return GetMinLengthString();
1065
+ case kValidateErrorPattern: return GetPatternString();
1066
+
1067
+ case kValidateErrorMaxItems: return GetMaxItemsString();
1068
+ case kValidateErrorMinItems: return GetMinItemsString();
1069
+ case kValidateErrorUniqueItems: return GetUniqueItemsString();
1070
+ case kValidateErrorAdditionalItems: return GetAdditionalItemsString();
1071
+
1072
+ case kValidateErrorMaxProperties: return GetMaxPropertiesString();
1073
+ case kValidateErrorMinProperties: return GetMinPropertiesString();
1074
+ case kValidateErrorRequired: return GetRequiredString();
1075
+ case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString();
1076
+ case kValidateErrorPatternProperties: return GetPatternPropertiesString();
1077
+ case kValidateErrorDependencies: return GetDependenciesString();
1078
+
1079
+ case kValidateErrorEnum: return GetEnumString();
1080
+ case kValidateErrorType: return GetTypeString();
1081
+
1082
+ case kValidateErrorOneOf: return GetOneOfString();
1083
+ case kValidateErrorOneOfMatch: return GetOneOfString(); // Same
1084
+ case kValidateErrorAllOf: return GetAllOfString();
1085
+ case kValidateErrorAnyOf: return GetAnyOfString();
1086
+ case kValidateErrorNot: return GetNotString();
1087
+
1088
+ default: return GetNullString();
1089
+ }
1090
+ }
1091
+
1092
+
1015
1093
  // Generate functions for string literal according to Ch
1016
1094
  #define RAPIDJSON_STRING_(name, ...) \
1017
1095
  static const ValueType& Get##name##String() {\
@@ -1190,31 +1268,32 @@ private:
1190
1268
  context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1191
1269
  context.validatorCount = validatorCount_;
1192
1270
 
1271
+ // Always return after first failure for these sub-validators
1193
1272
  if (allOf_.schemas)
1194
- CreateSchemaValidators(context, allOf_);
1273
+ CreateSchemaValidators(context, allOf_, false);
1195
1274
 
1196
1275
  if (anyOf_.schemas)
1197
- CreateSchemaValidators(context, anyOf_);
1276
+ CreateSchemaValidators(context, anyOf_, false);
1198
1277
 
1199
1278
  if (oneOf_.schemas)
1200
- CreateSchemaValidators(context, oneOf_);
1279
+ CreateSchemaValidators(context, oneOf_, false);
1201
1280
 
1202
1281
  if (not_)
1203
- context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1204
-
1282
+ context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
1283
+
1205
1284
  if (hasSchemaDependencies_) {
1206
1285
  for (SizeType i = 0; i < propertyCount_; i++)
1207
1286
  if (properties_[i].dependenciesSchema)
1208
- context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1287
+ context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
1209
1288
  }
1210
1289
  }
1211
1290
 
1212
1291
  return true;
1213
1292
  }
1214
1293
 
1215
- void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
1294
+ void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
1216
1295
  for (SizeType i = 0; i < schemas.count; i++)
1217
- context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1296
+ context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1218
1297
  }
1219
1298
 
1220
1299
  // O(n)
@@ -1234,19 +1313,19 @@ private:
1234
1313
  bool CheckInt(Context& context, int64_t i) const {
1235
1314
  if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1236
1315
  DisallowedType(context, GetIntegerString());
1237
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1316
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1238
1317
  }
1239
1318
 
1240
1319
  if (!minimum_.IsNull()) {
1241
1320
  if (minimum_.IsInt64()) {
1242
1321
  if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1243
1322
  context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1244
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1323
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1245
1324
  }
1246
1325
  }
1247
1326
  else if (minimum_.IsUint64()) {
1248
1327
  context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1249
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
1328
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
1250
1329
  }
1251
1330
  else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1252
1331
  return false;
@@ -1256,7 +1335,7 @@ private:
1256
1335
  if (maximum_.IsInt64()) {
1257
1336
  if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1258
1337
  context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1259
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1338
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1260
1339
  }
1261
1340
  }
1262
1341
  else if (maximum_.IsUint64()) { }
@@ -1269,7 +1348,7 @@ private:
1269
1348
  if (multipleOf_.IsUint64()) {
1270
1349
  if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1271
1350
  context.error_handler.NotMultipleOf(i, multipleOf_);
1272
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1351
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1273
1352
  }
1274
1353
  }
1275
1354
  else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
@@ -1282,14 +1361,14 @@ private:
1282
1361
  bool CheckUint(Context& context, uint64_t i) const {
1283
1362
  if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1284
1363
  DisallowedType(context, GetIntegerString());
1285
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1364
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1286
1365
  }
1287
1366
 
1288
1367
  if (!minimum_.IsNull()) {
1289
1368
  if (minimum_.IsUint64()) {
1290
1369
  if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1291
1370
  context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1292
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1371
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1293
1372
  }
1294
1373
  }
1295
1374
  else if (minimum_.IsInt64())
@@ -1302,12 +1381,12 @@ private:
1302
1381
  if (maximum_.IsUint64()) {
1303
1382
  if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1304
1383
  context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1305
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1384
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1306
1385
  }
1307
1386
  }
1308
1387
  else if (maximum_.IsInt64()) {
1309
1388
  context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1310
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
1389
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_
1311
1390
  }
1312
1391
  else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1313
1392
  return false;
@@ -1317,7 +1396,7 @@ private:
1317
1396
  if (multipleOf_.IsUint64()) {
1318
1397
  if (i % multipleOf_.GetUint64() != 0) {
1319
1398
  context.error_handler.NotMultipleOf(i, multipleOf_);
1320
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1399
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1321
1400
  }
1322
1401
  }
1323
1402
  else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
@@ -1330,7 +1409,7 @@ private:
1330
1409
  bool CheckDoubleMinimum(Context& context, double d) const {
1331
1410
  if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1332
1411
  context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1333
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1412
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1334
1413
  }
1335
1414
  return true;
1336
1415
  }
@@ -1338,7 +1417,7 @@ private:
1338
1417
  bool CheckDoubleMaximum(Context& context, double d) const {
1339
1418
  if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1340
1419
  context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1341
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1420
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1342
1421
  }
1343
1422
  return true;
1344
1423
  }
@@ -1349,7 +1428,7 @@ private:
1349
1428
  double r = a - q * b;
1350
1429
  if (r > 0.0) {
1351
1430
  context.error_handler.NotMultipleOf(d, multipleOf_);
1352
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1431
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1353
1432
  }
1354
1433
  return true;
1355
1434
  }
@@ -1763,8 +1842,7 @@ template <
1763
1842
  class GenericSchemaValidator :
1764
1843
  public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1765
1844
  public internal::ISchemaValidator,
1766
- public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
1767
- {
1845
+ public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
1768
1846
  public:
1769
1847
  typedef typename SchemaDocumentType::SchemaType SchemaType;
1770
1848
  typedef typename SchemaDocumentType::PointerType PointerType;
@@ -1797,7 +1875,8 @@ public:
1797
1875
  error_(kObjectType),
1798
1876
  currentError_(),
1799
1877
  missingDependents_(),
1800
- valid_(true)
1878
+ valid_(true),
1879
+ flags_(kValidateDefaultFlags)
1801
1880
  #if RAPIDJSON_SCHEMA_VERBOSE
1802
1881
  , depth_(0)
1803
1882
  #endif
@@ -1828,7 +1907,8 @@ public:
1828
1907
  error_(kObjectType),
1829
1908
  currentError_(),
1830
1909
  missingDependents_(),
1831
- valid_(true)
1910
+ valid_(true),
1911
+ flags_(kValidateDefaultFlags)
1832
1912
  #if RAPIDJSON_SCHEMA_VERBOSE
1833
1913
  , depth_(0)
1834
1914
  #endif
@@ -1846,31 +1926,61 @@ public:
1846
1926
  while (!schemaStack_.Empty())
1847
1927
  PopSchema();
1848
1928
  documentStack_.Clear();
1929
+ ResetError();
1930
+ }
1931
+
1932
+ //! Reset the error state.
1933
+ void ResetError() {
1849
1934
  error_.SetObject();
1850
1935
  currentError_.SetNull();
1851
1936
  missingDependents_.SetNull();
1852
1937
  valid_ = true;
1853
1938
  }
1854
1939
 
1940
+ //! Implementation of ISchemaValidator
1941
+ void SetValidateFlags(unsigned flags) {
1942
+ flags_ = flags;
1943
+ }
1944
+ virtual unsigned GetValidateFlags() const {
1945
+ return flags_;
1946
+ }
1947
+
1855
1948
  //! Checks whether the current state is valid.
1856
1949
  // Implementation of ISchemaValidator
1857
- virtual bool IsValid() const { return valid_; }
1950
+ virtual bool IsValid() const {
1951
+ if (!valid_) return false;
1952
+ if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
1953
+ return true;
1954
+ }
1858
1955
 
1859
1956
  //! Gets the error object.
1860
1957
  ValueType& GetError() { return error_; }
1861
1958
  const ValueType& GetError() const { return error_; }
1862
1959
 
1863
1960
  //! Gets the JSON pointer pointed to the invalid schema.
1961
+ // If reporting all errors, the stack will be empty.
1864
1962
  PointerType GetInvalidSchemaPointer() const {
1865
1963
  return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1866
1964
  }
1867
1965
 
1868
1966
  //! Gets the keyword of invalid schema.
1967
+ // If reporting all errors, the stack will be empty, so return "errors".
1869
1968
  const Ch* GetInvalidSchemaKeyword() const {
1870
- return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1969
+ if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
1970
+ if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString();
1971
+ return 0;
1972
+ }
1973
+
1974
+ //! Gets the error code of invalid schema.
1975
+ // If reporting all errors, the stack will be empty, so return kValidateErrors.
1976
+ ValidateErrorCode GetInvalidSchemaCode() const {
1977
+ if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
1978
+ if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
1979
+ return kValidateErrorNone;
1871
1980
  }
1872
1981
 
1873
1982
  //! Gets the JSON pointer pointed to the invalid value.
1983
+ // If reporting all errors, the stack will be empty.
1874
1984
  PointerType GetInvalidDocumentPointer() const {
1875
1985
  if (documentStack_.Empty()) {
1876
1986
  return PointerType();
@@ -1881,64 +1991,64 @@ public:
1881
1991
  }
1882
1992
 
1883
1993
  void NotMultipleOf(int64_t actual, const SValue& expected) {
1884
- AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1994
+ AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
1885
1995
  }
1886
1996
  void NotMultipleOf(uint64_t actual, const SValue& expected) {
1887
- AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1997
+ AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
1888
1998
  }
1889
1999
  void NotMultipleOf(double actual, const SValue& expected) {
1890
- AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
2000
+ AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
1891
2001
  }
1892
2002
  void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
1893
- AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
2003
+ AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
1894
2004
  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1895
2005
  }
1896
2006
  void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
1897
- AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
2007
+ AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
1898
2008
  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1899
2009
  }
1900
2010
  void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
1901
- AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
2011
+ AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
1902
2012
  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1903
2013
  }
1904
2014
  void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
1905
- AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
2015
+ AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
1906
2016
  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1907
2017
  }
1908
2018
  void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
1909
- AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
2019
+ AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
1910
2020
  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1911
2021
  }
1912
2022
  void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
1913
- AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
2023
+ AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
1914
2024
  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1915
2025
  }
1916
2026
 
1917
2027
  void TooLong(const Ch* str, SizeType length, SizeType expected) {
1918
- AddNumberError(SchemaType::GetMaxLengthString(),
2028
+ AddNumberError(kValidateErrorMaxLength,
1919
2029
  ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1920
2030
  }
1921
2031
  void TooShort(const Ch* str, SizeType length, SizeType expected) {
1922
- AddNumberError(SchemaType::GetMinLengthString(),
2032
+ AddNumberError(kValidateErrorMinLength,
1923
2033
  ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1924
2034
  }
1925
2035
  void DoesNotMatch(const Ch* str, SizeType length) {
1926
2036
  currentError_.SetObject();
1927
2037
  currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
1928
- AddCurrentError(SchemaType::GetPatternString());
2038
+ AddCurrentError(kValidateErrorPattern);
1929
2039
  }
1930
2040
 
1931
2041
  void DisallowedItem(SizeType index) {
1932
2042
  currentError_.SetObject();
1933
2043
  currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
1934
- AddCurrentError(SchemaType::GetAdditionalItemsString(), true);
2044
+ AddCurrentError(kValidateErrorAdditionalItems, true);
1935
2045
  }
1936
2046
  void TooFewItems(SizeType actualCount, SizeType expectedCount) {
1937
- AddNumberError(SchemaType::GetMinItemsString(),
2047
+ AddNumberError(kValidateErrorMinItems,
1938
2048
  ValueType(actualCount).Move(), SValue(expectedCount).Move());
1939
2049
  }
1940
2050
  void TooManyItems(SizeType actualCount, SizeType expectedCount) {
1941
- AddNumberError(SchemaType::GetMaxItemsString(),
2051
+ AddNumberError(kValidateErrorMaxItems,
1942
2052
  ValueType(actualCount).Move(), SValue(expectedCount).Move());
1943
2053
  }
1944
2054
  void DuplicateItems(SizeType index1, SizeType index2) {
@@ -1947,15 +2057,15 @@ public:
1947
2057
  duplicates.PushBack(index2, GetStateAllocator());
1948
2058
  currentError_.SetObject();
1949
2059
  currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
1950
- AddCurrentError(SchemaType::GetUniqueItemsString(), true);
2060
+ AddCurrentError(kValidateErrorUniqueItems, true);
1951
2061
  }
1952
2062
 
1953
2063
  void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
1954
- AddNumberError(SchemaType::GetMaxPropertiesString(),
2064
+ AddNumberError(kValidateErrorMaxProperties,
1955
2065
  ValueType(actualCount).Move(), SValue(expectedCount).Move());
1956
2066
  }
1957
2067
  void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
1958
- AddNumberError(SchemaType::GetMinPropertiesString(),
2068
+ AddNumberError(kValidateErrorMinProperties,
1959
2069
  ValueType(actualCount).Move(), SValue(expectedCount).Move());
1960
2070
  }
1961
2071
  void StartMissingProperties() {
@@ -1970,7 +2080,7 @@ public:
1970
2080
  ValueType error(kObjectType);
1971
2081
  error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
1972
2082
  currentError_ = error;
1973
- AddCurrentError(SchemaType::GetRequiredString());
2083
+ AddCurrentError(kValidateErrorRequired);
1974
2084
  return true;
1975
2085
  }
1976
2086
  void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
@@ -1980,7 +2090,7 @@ public:
1980
2090
  void DisallowedProperty(const Ch* name, SizeType length) {
1981
2091
  currentError_.SetObject();
1982
2092
  currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
1983
- AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true);
2093
+ AddCurrentError(kValidateErrorAdditionalProperties, true);
1984
2094
  }
1985
2095
 
1986
2096
  void StartDependencyErrors() {
@@ -1993,9 +2103,20 @@ public:
1993
2103
  missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
1994
2104
  }
1995
2105
  void EndMissingDependentProperties(const SValue& sourceName) {
1996
- if (!missingDependents_.Empty())
1997
- currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
1998
- missingDependents_, GetStateAllocator());
2106
+ if (!missingDependents_.Empty()) {
2107
+ // Create equivalent 'required' error
2108
+ ValueType error(kObjectType);
2109
+ ValidateErrorCode code = kValidateErrorRequired;
2110
+ error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2111
+ AddErrorCode(error, code);
2112
+ AddErrorInstanceLocation(error, false);
2113
+ // When appending to a pointer ensure its allocator is used
2114
+ PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2115
+ AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2116
+ ValueType wrapper(kObjectType);
2117
+ wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2118
+ currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2119
+ }
1999
2120
  }
2000
2121
  void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
2001
2122
  currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
@@ -2007,13 +2128,13 @@ public:
2007
2128
  ValueType error(kObjectType);
2008
2129
  error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2009
2130
  currentError_ = error;
2010
- AddCurrentError(SchemaType::GetDependenciesString());
2131
+ AddCurrentError(kValidateErrorDependencies);
2011
2132
  return true;
2012
2133
  }
2013
2134
 
2014
- void DisallowedValue() {
2135
+ void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) {
2015
2136
  currentError_.SetObject();
2016
- AddCurrentError(SchemaType::GetEnumString());
2137
+ AddCurrentError(code);
2017
2138
  }
2018
2139
  void StartDisallowedType() {
2019
2140
  currentError_.SetArray();
@@ -2026,22 +2147,24 @@ public:
2026
2147
  error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2027
2148
  error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2028
2149
  currentError_ = error;
2029
- AddCurrentError(SchemaType::GetTypeString());
2150
+ AddCurrentError(kValidateErrorType);
2030
2151
  }
2031
2152
  void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2032
- for (SizeType i = 0; i < count; ++i) {
2033
- MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2034
- }
2153
+ // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
2154
+ AddErrorArray(kValidateErrorAllOf, subvalidators, count);
2155
+ //for (SizeType i = 0; i < count; ++i) {
2156
+ // MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2157
+ //}
2035
2158
  }
2036
2159
  void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2037
- AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);
2160
+ AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
2038
2161
  }
2039
- void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
2040
- AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);
2162
+ void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) {
2163
+ AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count);
2041
2164
  }
2042
2165
  void Disallowed() {
2043
2166
  currentError_.SetObject();
2044
- AddCurrentError(SchemaType::GetNotString());
2167
+ AddCurrentError(kValidateErrorNot);
2045
2168
  }
2046
2169
 
2047
2170
  #define RAPIDJSON_STRING_(name, ...) \
@@ -2058,6 +2181,8 @@ public:
2058
2181
  RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2059
2182
  RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2060
2183
  RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2184
+ RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2185
+ RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
2061
2186
  RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2062
2187
 
2063
2188
  #undef RAPIDJSON_STRING_
@@ -2075,7 +2200,7 @@ RAPIDJSON_MULTILINEMACRO_END
2075
2200
 
2076
2201
  #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2077
2202
  if (!valid_) return false; \
2078
- if (!BeginValue() || !CurrentSchema().method arg1) {\
2203
+ if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2079
2204
  RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2080
2205
  return valid_ = false;\
2081
2206
  }
@@ -2093,7 +2218,8 @@ RAPIDJSON_MULTILINEMACRO_END
2093
2218
  }
2094
2219
 
2095
2220
  #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2096
- return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
2221
+ valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2222
+ return valid_;
2097
2223
 
2098
2224
  #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2099
2225
  RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
@@ -2121,15 +2247,15 @@ RAPIDJSON_MULTILINEMACRO_END
2121
2247
  bool Key(const Ch* str, SizeType len, bool copy) {
2122
2248
  if (!valid_) return false;
2123
2249
  AppendToken(str, len);
2124
- if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
2250
+ if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false;
2125
2251
  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2126
2252
  return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2127
2253
  }
2128
2254
 
2129
- bool EndObject(SizeType memberCount) {
2255
+ bool EndObject(SizeType memberCount) {
2130
2256
  if (!valid_) return false;
2131
2257
  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2132
- if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
2258
+ if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false;
2133
2259
  RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2134
2260
  }
2135
2261
 
@@ -2142,7 +2268,7 @@ RAPIDJSON_MULTILINEMACRO_END
2142
2268
  bool EndArray(SizeType elementCount) {
2143
2269
  if (!valid_) return false;
2144
2270
  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2145
- if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
2271
+ if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false;
2146
2272
  RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2147
2273
  }
2148
2274
 
@@ -2152,12 +2278,14 @@ RAPIDJSON_MULTILINEMACRO_END
2152
2278
  #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2153
2279
 
2154
2280
  // Implementation of ISchemaStateFactory<SchemaType>
2155
- virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
2156
- return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2281
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
2282
+ ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2157
2283
  #if RAPIDJSON_SCHEMA_VERBOSE
2158
2284
  depth_ + 1,
2159
2285
  #endif
2160
2286
  &GetStateAllocator());
2287
+ sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
2288
+ return sv;
2161
2289
  }
2162
2290
 
2163
2291
  virtual void DestroySchemaValidator(ISchemaValidator* validator) {
@@ -2214,7 +2342,8 @@ private:
2214
2342
  error_(kObjectType),
2215
2343
  currentError_(),
2216
2344
  missingDependents_(),
2217
- valid_(true)
2345
+ valid_(true),
2346
+ flags_(kValidateDefaultFlags)
2218
2347
  #if RAPIDJSON_SCHEMA_VERBOSE
2219
2348
  , depth_(depth)
2220
2349
  #endif
@@ -2229,6 +2358,10 @@ private:
2229
2358
  return *stateAllocator_;
2230
2359
  }
2231
2360
 
2361
+ bool GetContinueOnErrors() const {
2362
+ return flags_ & kValidateContinueOnErrorFlag;
2363
+ }
2364
+
2232
2365
  bool BeginValue() {
2233
2366
  if (schemaStack_.Empty())
2234
2367
  PushSchema(root_);
@@ -2236,7 +2369,7 @@ private:
2236
2369
  if (CurrentContext().inArray)
2237
2370
  internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2238
2371
 
2239
- if (!CurrentSchema().BeginValue(CurrentContext()))
2372
+ if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2240
2373
  return false;
2241
2374
 
2242
2375
  SizeType count = CurrentContext().patternPropertiesSchemaCount;
@@ -2252,7 +2385,7 @@ private:
2252
2385
  SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2253
2386
  va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
2254
2387
  for (SizeType i = 0; i < count; i++)
2255
- va[validatorCount++] = CreateSchemaValidator(*sa[i]);
2388
+ va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError
2256
2389
  }
2257
2390
 
2258
2391
  CurrentContext().arrayUniqueness = valueUniqueness;
@@ -2261,7 +2394,7 @@ private:
2261
2394
  }
2262
2395
 
2263
2396
  bool EndValue() {
2264
- if (!CurrentSchema().EndValue(CurrentContext()))
2397
+ if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
2265
2398
  return false;
2266
2399
 
2267
2400
  #if RAPIDJSON_SCHEMA_VERBOSE
@@ -2272,21 +2405,27 @@ private:
2272
2405
  documentStack_.template Pop<Ch>(1);
2273
2406
  internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
2274
2407
  #endif
2275
-
2276
- uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
2408
+ void* hasher = CurrentContext().hasher;
2409
+ uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
2277
2410
 
2278
2411
  PopSchema();
2279
2412
 
2280
2413
  if (!schemaStack_.Empty()) {
2281
2414
  Context& context = CurrentContext();
2282
- if (context.valueUniqueness) {
2415
+ // Only check uniqueness if there is a hasher
2416
+ if (hasher && context.valueUniqueness) {
2283
2417
  HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
2284
2418
  if (!a)
2285
2419
  CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
2286
2420
  for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
2287
2421
  if (itr->GetUint64() == h) {
2288
2422
  DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
2289
- RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
2423
+ // Cleanup before returning if continuing
2424
+ if (GetContinueOnErrors()) {
2425
+ a->PushBack(h, GetStateAllocator());
2426
+ while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
2427
+ }
2428
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
2290
2429
  }
2291
2430
  a->PushBack(h, GetStateAllocator());
2292
2431
  }
@@ -2327,25 +2466,32 @@ private:
2327
2466
  c->~Context();
2328
2467
  }
2329
2468
 
2330
- void AddErrorLocation(ValueType& result, bool parent) {
2469
+ void AddErrorInstanceLocation(ValueType& result, bool parent) {
2331
2470
  GenericStringBuffer<EncodingType> sb;
2332
2471
  PointerType instancePointer = GetInvalidDocumentPointer();
2333
2472
  ((parent && instancePointer.GetTokenCount() > 0)
2334
- ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2335
- : instancePointer).StringifyUriFragment(sb);
2473
+ ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2474
+ : instancePointer).StringifyUriFragment(sb);
2336
2475
  ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2337
- GetStateAllocator());
2476
+ GetStateAllocator());
2338
2477
  result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2339
- sb.Clear();
2340
- memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),
2341
- CurrentSchema().GetURI().GetString(),
2342
- CurrentSchema().GetURI().GetStringLength() * sizeof(Ch));
2343
- GetInvalidSchemaPointer().StringifyUriFragment(sb);
2478
+ }
2479
+
2480
+ void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
2481
+ GenericStringBuffer<EncodingType> sb;
2482
+ SizeType len = CurrentSchema().GetURI().GetStringLength();
2483
+ if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
2484
+ if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
2485
+ else GetInvalidSchemaPointer().StringifyUriFragment(sb);
2344
2486
  ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2345
2487
  GetStateAllocator());
2346
2488
  result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2347
2489
  }
2348
2490
 
2491
+ void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
2492
+ result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
2493
+ }
2494
+
2349
2495
  void AddError(ValueType& keyword, ValueType& error) {
2350
2496
  typename ValueType::MemberIterator member = error_.FindMember(keyword);
2351
2497
  if (member == error_.MemberEnd())
@@ -2360,9 +2506,11 @@ private:
2360
2506
  }
2361
2507
  }
2362
2508
 
2363
- void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) {
2364
- AddErrorLocation(currentError_, parent);
2365
- AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_);
2509
+ void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
2510
+ AddErrorCode(currentError_, code);
2511
+ AddErrorInstanceLocation(currentError_, parent);
2512
+ AddErrorSchemaLocation(currentError_);
2513
+ AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
2366
2514
  }
2367
2515
 
2368
2516
  void MergeError(ValueType& other) {
@@ -2371,24 +2519,24 @@ private:
2371
2519
  }
2372
2520
  }
2373
2521
 
2374
- void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected,
2522
+ void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
2375
2523
  const typename SchemaType::ValueType& (*exclusive)() = 0) {
2376
2524
  currentError_.SetObject();
2377
2525
  currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2378
2526
  currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2379
2527
  if (exclusive)
2380
2528
  currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
2381
- AddCurrentError(keyword);
2529
+ AddCurrentError(code);
2382
2530
  }
2383
2531
 
2384
- void AddErrorArray(const typename SchemaType::ValueType& keyword,
2532
+ void AddErrorArray(const ValidateErrorCode code,
2385
2533
  ISchemaValidator** subvalidators, SizeType count) {
2386
2534
  ValueType errors(kArrayType);
2387
2535
  for (SizeType i = 0; i < count; ++i)
2388
2536
  errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
2389
2537
  currentError_.SetObject();
2390
2538
  currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2391
- AddCurrentError(keyword);
2539
+ AddCurrentError(code);
2392
2540
  }
2393
2541
 
2394
2542
  const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
@@ -2408,6 +2556,7 @@ private:
2408
2556
  ValueType currentError_;
2409
2557
  ValueType missingDependents_;
2410
2558
  bool valid_;
2559
+ unsigned flags_;
2411
2560
  #if RAPIDJSON_SCHEMA_VERBOSE
2412
2561
  unsigned depth_;
2413
2562
  #endif
@@ -2445,7 +2594,7 @@ public:
2445
2594
  \param is Input stream.
2446
2595
  \param sd Schema document.
2447
2596
  */
2448
- SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {}
2597
+ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
2449
2598
 
2450
2599
  template <typename Handler>
2451
2600
  bool operator()(Handler& handler) {
@@ -2463,6 +2612,7 @@ public:
2463
2612
  else {
2464
2613
  invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
2465
2614
  invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
2615
+ invalidSchemaCode_ = validator.GetInvalidSchemaCode();
2466
2616
  invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2467
2617
  error_.CopyFrom(validator.GetError(), allocator_);
2468
2618
  }
@@ -2476,6 +2626,7 @@ public:
2476
2626
  const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
2477
2627
  const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
2478
2628
  const ValueType& GetError() const { return error_; }
2629
+ ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
2479
2630
 
2480
2631
  private:
2481
2632
  InputStream& is_;
@@ -2485,6 +2636,7 @@ private:
2485
2636
  PointerType invalidSchemaPointer_;
2486
2637
  const Ch* invalidSchemaKeyword_;
2487
2638
  PointerType invalidDocumentPointer_;
2639
+ ValidateErrorCode invalidSchemaCode_;
2488
2640
  StackAllocator allocator_;
2489
2641
  ValueType error_;
2490
2642
  bool isValid_;