rj_schema 0.2.5 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/rj_schema/rapidjson/CMakeLists.txt +23 -1
- data/ext/rj_schema/rapidjson/appveyor.yml +49 -1
- data/ext/rj_schema/rapidjson/bin/types/alotofkeys.json +502 -0
- data/ext/rj_schema/rapidjson/bin/unittestschema/address.json +139 -0
- data/ext/rj_schema/rapidjson/bin/unittestschema/allOf_address.json +7 -0
- data/ext/rj_schema/rapidjson/bin/unittestschema/anyOf_address.json +7 -0
- data/ext/rj_schema/rapidjson/bin/unittestschema/idandref.json +69 -0
- data/ext/rj_schema/rapidjson/bin/unittestschema/oneOf_address.json +7 -0
- data/ext/rj_schema/rapidjson/doc/stream.md +7 -7
- data/ext/rj_schema/rapidjson/doc/stream.zh-cn.md +1 -1
- data/ext/rj_schema/rapidjson/doc/tutorial.md +15 -15
- data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +120 -0
- data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
- data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +464 -56
- data/ext/rj_schema/rapidjson/include/rapidjson/cursorstreamwrapper.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/document.h +367 -72
- data/ext/rj_schema/rapidjson/include/rapidjson/encodedstream.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/encodings.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/error/en.h +49 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/error/error.h +56 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/filereadstream.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/filewritestream.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/fwd.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/biginteger.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/clzll.h +4 -4
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/diyfp.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/dtoa.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/ieee754.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/itoa.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/meta.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/pow10.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/regex.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/stack.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +15 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/strtod.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/swap.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/istreamwrapper.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/memorybuffer.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/memorystream.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/ostreamwrapper.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +69 -2
- data/ext/rj_schema/rapidjson/include/rapidjson/prettywriter.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +77 -12
- data/ext/rj_schema/rapidjson/include/rapidjson/reader.h +17 -9
- data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +558 -259
- data/ext/rj_schema/rapidjson/include/rapidjson/stream.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/stringbuffer.h +1 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
- data/ext/rj_schema/rapidjson/include/rapidjson/writer.h +3 -3
- data/ext/rj_schema/rapidjson/readme.md +3 -3
- data/ext/rj_schema/rapidjson/readme.zh-cn.md +2 -2
- data/ext/rj_schema/rapidjson/test/perftest/misctest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/perftest/perftest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/perftest/perftest.h +6 -5
- data/ext/rj_schema/rapidjson/test/perftest/platformtest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +21 -3
- data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +3 -0
- data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +194 -2
- data/ext/rj_schema/rapidjson/test/unittest/bigintegertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/clzlltest.cpp +34 -0
- data/ext/rj_schema/rapidjson/test/unittest/cursorstreamwrappertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +3 -1
- data/ext/rj_schema/rapidjson/test/unittest/dtoatest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/encodedstreamtest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/encodingstest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/filestreamtest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/fwdtest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/istreamwrappertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/itoatest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/jsoncheckertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/namespacetest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/ostreamwrappertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
- data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +95 -3
- data/ext/rj_schema/rapidjson/test/unittest/prettywritertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/readertest.cpp +4 -1
- data/ext/rj_schema/rapidjson/test/unittest/regextest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +961 -81
- data/ext/rj_schema/rapidjson/test/unittest/simdtest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/strfunctest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/stringbuffertest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/strtodtest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/unittest.cpp +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/unittest.h +1 -1
- data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
- data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +13 -3
- data/ext/rj_schema/rapidjson/test/unittest/writertest.cpp +1 -1
- data/ext/rj_schema/rj_schema.cpp +162 -18
- data/lib/rj_schema.rb +1 -1
- metadata +14 -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.
|
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.
|
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
|
@@ -124,6 +124,19 @@
|
|
124
124
|
#define RAPIDJSON_NAMESPACE_END }
|
125
125
|
#endif
|
126
126
|
|
127
|
+
///////////////////////////////////////////////////////////////////////////////
|
128
|
+
// __cplusplus macro
|
129
|
+
|
130
|
+
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
131
|
+
|
132
|
+
#if defined(_MSC_VER)
|
133
|
+
#define RAPIDJSON_CPLUSPLUS _MSVC_LANG
|
134
|
+
#else
|
135
|
+
#define RAPIDJSON_CPLUSPLUS __cplusplus
|
136
|
+
#endif
|
137
|
+
|
138
|
+
//!@endcond
|
139
|
+
|
127
140
|
///////////////////////////////////////////////////////////////////////////////
|
128
141
|
// RAPIDJSON_HAS_STDSTRING
|
129
142
|
|
@@ -149,6 +162,24 @@
|
|
149
162
|
#include <string>
|
150
163
|
#endif // RAPIDJSON_HAS_STDSTRING
|
151
164
|
|
165
|
+
///////////////////////////////////////////////////////////////////////////////
|
166
|
+
// RAPIDJSON_USE_MEMBERSMAP
|
167
|
+
|
168
|
+
/*! \def RAPIDJSON_USE_MEMBERSMAP
|
169
|
+
\ingroup RAPIDJSON_CONFIG
|
170
|
+
\brief Enable RapidJSON support for object members handling in a \c std::multimap
|
171
|
+
|
172
|
+
By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object
|
173
|
+
members are stored in a \c std::multimap for faster lookup and deletion times, a
|
174
|
+
trade off with a slightly slower insertion time and a small object allocat(or)ed
|
175
|
+
memory overhead.
|
176
|
+
|
177
|
+
\hideinitializer
|
178
|
+
*/
|
179
|
+
#ifndef RAPIDJSON_USE_MEMBERSMAP
|
180
|
+
#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default
|
181
|
+
#endif
|
182
|
+
|
152
183
|
///////////////////////////////////////////////////////////////////////////////
|
153
184
|
// RAPIDJSON_NO_INT64DEFINE
|
154
185
|
|
@@ -411,7 +442,7 @@ RAPIDJSON_NAMESPACE_END
|
|
411
442
|
|
412
443
|
// Prefer C++11 static_assert, if available
|
413
444
|
#ifndef RAPIDJSON_STATIC_ASSERT
|
414
|
-
#if
|
445
|
+
#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
|
415
446
|
#define RAPIDJSON_STATIC_ASSERT(x) \
|
416
447
|
static_assert(x, RAPIDJSON_STRINGIFY(x))
|
417
448
|
#endif // C++11
|
@@ -541,8 +572,14 @@ RAPIDJSON_NAMESPACE_END
|
|
541
572
|
///////////////////////////////////////////////////////////////////////////////
|
542
573
|
// C++11 features
|
543
574
|
|
575
|
+
#ifndef RAPIDJSON_HAS_CXX11
|
576
|
+
#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L)
|
577
|
+
#endif
|
578
|
+
|
544
579
|
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
545
|
-
#if
|
580
|
+
#if RAPIDJSON_HAS_CXX11
|
581
|
+
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
582
|
+
#elif defined(__clang__)
|
546
583
|
#if __has_feature(cxx_rvalue_references) && \
|
547
584
|
(defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
548
585
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
@@ -559,8 +596,14 @@ RAPIDJSON_NAMESPACE_END
|
|
559
596
|
#endif
|
560
597
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
561
598
|
|
599
|
+
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
600
|
+
#include <utility> // std::move
|
601
|
+
#endif
|
602
|
+
|
562
603
|
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
563
|
-
#if
|
604
|
+
#if RAPIDJSON_HAS_CXX11
|
605
|
+
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
606
|
+
#elif defined(__clang__)
|
564
607
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
565
608
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
566
609
|
(defined(_MSC_VER) && _MSC_VER >= 1900) || \
|
@@ -570,11 +613,13 @@ RAPIDJSON_NAMESPACE_END
|
|
570
613
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
571
614
|
#endif
|
572
615
|
#endif
|
616
|
+
#ifndef RAPIDJSON_NOEXCEPT
|
573
617
|
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
574
618
|
#define RAPIDJSON_NOEXCEPT noexcept
|
575
619
|
#else
|
576
|
-
#define RAPIDJSON_NOEXCEPT
|
620
|
+
#define RAPIDJSON_NOEXCEPT throw()
|
577
621
|
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
622
|
+
#endif
|
578
623
|
|
579
624
|
// no automatic detection, yet
|
580
625
|
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
@@ -600,9 +645,17 @@ RAPIDJSON_NAMESPACE_END
|
|
600
645
|
///////////////////////////////////////////////////////////////////////////////
|
601
646
|
// C++17 features
|
602
647
|
|
603
|
-
#
|
604
|
-
#
|
605
|
-
#
|
648
|
+
#ifndef RAPIDJSON_HAS_CXX17
|
649
|
+
#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)
|
650
|
+
#endif
|
651
|
+
|
652
|
+
#if RAPIDJSON_HAS_CXX17
|
653
|
+
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
|
654
|
+
#elif defined(__has_cpp_attribute)
|
655
|
+
# if __has_cpp_attribute(clang::fallthrough)
|
656
|
+
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
|
657
|
+
# elif __has_cpp_attribute(fallthrough)
|
658
|
+
# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
|
606
659
|
# else
|
607
660
|
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
|
608
661
|
# endif
|
@@ -628,17 +681,29 @@ RAPIDJSON_NAMESPACE_END
|
|
628
681
|
|
629
682
|
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
|
630
683
|
#ifdef RAPIDJSON_ASSERT_THROWS
|
631
|
-
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
632
|
-
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
|
633
|
-
#else
|
634
684
|
#include <cassert>
|
635
685
|
#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
|
636
|
-
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
637
686
|
#else
|
638
687
|
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
|
639
688
|
#endif // RAPIDJSON_ASSERT_THROWS
|
640
689
|
#endif // RAPIDJSON_NOEXCEPT_ASSERT
|
641
690
|
|
691
|
+
///////////////////////////////////////////////////////////////////////////////
|
692
|
+
// malloc/realloc/free
|
693
|
+
|
694
|
+
#ifndef RAPIDJSON_MALLOC
|
695
|
+
///! customization point for global \c malloc
|
696
|
+
#define RAPIDJSON_MALLOC(size) std::malloc(size)
|
697
|
+
#endif
|
698
|
+
#ifndef RAPIDJSON_REALLOC
|
699
|
+
///! customization point for global \c realloc
|
700
|
+
#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
|
701
|
+
#endif
|
702
|
+
#ifndef RAPIDJSON_FREE
|
703
|
+
///! customization point for global \c free
|
704
|
+
#define RAPIDJSON_FREE(ptr) std::free(ptr)
|
705
|
+
#endif
|
706
|
+
|
642
707
|
///////////////////////////////////////////////////////////////////////////////
|
643
708
|
// new/delete
|
644
709
|
|
@@ -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.
|
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 <=
|
1027
|
-
//
|
1028
|
-
if (
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
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
|
-
|
1042
|
+
}
|
1035
1043
|
}
|
1036
1044
|
TEncoding::Encode(os, codepoint);
|
1037
1045
|
}
|
@@ -18,6 +18,8 @@
|
|
18
18
|
#include "document.h"
|
19
19
|
#include "pointer.h"
|
20
20
|
#include "stringbuffer.h"
|
21
|
+
#include "error/en.h"
|
22
|
+
#include "uri.h"
|
21
23
|
#include <cmath> // abs, floor
|
22
24
|
|
23
25
|
#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
|
@@ -113,13 +115,36 @@ inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar
|
|
113
115
|
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
|
114
116
|
#endif
|
115
117
|
|
116
|
-
#define RAPIDJSON_INVALID_KEYWORD_RETURN(
|
118
|
+
#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
|
117
119
|
RAPIDJSON_MULTILINEMACRO_BEGIN\
|
118
|
-
context.
|
119
|
-
|
120
|
+
context.invalidCode = code;\
|
121
|
+
context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
|
122
|
+
RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
|
120
123
|
return false;\
|
121
124
|
RAPIDJSON_MULTILINEMACRO_END
|
122
125
|
|
126
|
+
///////////////////////////////////////////////////////////////////////////////
|
127
|
+
// ValidateFlag
|
128
|
+
|
129
|
+
/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS
|
130
|
+
\ingroup RAPIDJSON_CONFIG
|
131
|
+
\brief User-defined kValidateDefaultFlags definition.
|
132
|
+
|
133
|
+
User can define this as any \c ValidateFlag combinations.
|
134
|
+
*/
|
135
|
+
#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
|
136
|
+
#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
|
137
|
+
#endif
|
138
|
+
|
139
|
+
//! Combination of validate flags
|
140
|
+
/*! \see
|
141
|
+
*/
|
142
|
+
enum ValidateFlag {
|
143
|
+
kValidateNoFlags = 0, //!< No flags are set.
|
144
|
+
kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error.
|
145
|
+
kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
|
146
|
+
};
|
147
|
+
|
123
148
|
///////////////////////////////////////////////////////////////////////////////
|
124
149
|
// Forward declarations
|
125
150
|
|
@@ -138,6 +163,8 @@ class ISchemaValidator {
|
|
138
163
|
public:
|
139
164
|
virtual ~ISchemaValidator() {}
|
140
165
|
virtual bool IsValid() const = 0;
|
166
|
+
virtual void SetValidateFlags(unsigned flags) = 0;
|
167
|
+
virtual unsigned GetValidateFlags() const = 0;
|
141
168
|
};
|
142
169
|
|
143
170
|
///////////////////////////////////////////////////////////////////////////////
|
@@ -147,7 +174,7 @@ template <typename SchemaType>
|
|
147
174
|
class ISchemaStateFactory {
|
148
175
|
public:
|
149
176
|
virtual ~ISchemaStateFactory() {}
|
150
|
-
virtual ISchemaValidator* CreateSchemaValidator(const SchemaType
|
177
|
+
virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
|
151
178
|
virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
|
152
179
|
virtual void* CreateHasher() = 0;
|
153
180
|
virtual uint64_t GetHashCode(void* hasher) = 0;
|
@@ -201,13 +228,13 @@ public:
|
|
201
228
|
virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
|
202
229
|
virtual bool EndDependencyErrors() = 0;
|
203
230
|
|
204
|
-
virtual void DisallowedValue() = 0;
|
231
|
+
virtual void DisallowedValue(const ValidateErrorCode code) = 0;
|
205
232
|
virtual void StartDisallowedType() = 0;
|
206
233
|
virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
|
207
234
|
virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
|
208
235
|
virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
209
236
|
virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
210
|
-
virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
237
|
+
virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0;
|
211
238
|
virtual void Disallowed() = 0;
|
212
239
|
};
|
213
240
|
|
@@ -332,6 +359,7 @@ struct SchemaValidationContext {
|
|
332
359
|
schema(s),
|
333
360
|
valueSchema(),
|
334
361
|
invalidKeyword(),
|
362
|
+
invalidCode(),
|
335
363
|
hasher(),
|
336
364
|
arrayElementHashCodes(),
|
337
365
|
validators(),
|
@@ -372,6 +400,7 @@ struct SchemaValidationContext {
|
|
372
400
|
const SchemaType* schema;
|
373
401
|
const SchemaType* valueSchema;
|
374
402
|
const Ch* invalidKeyword;
|
403
|
+
ValidateErrorCode invalidCode;
|
375
404
|
void* hasher; // Only validator access
|
376
405
|
void* arrayElementHashCodes; // Only validator access this
|
377
406
|
ISchemaValidator** validators;
|
@@ -404,11 +433,13 @@ public:
|
|
404
433
|
typedef Schema<SchemaDocumentType> SchemaType;
|
405
434
|
typedef GenericValue<EncodingType, AllocatorType> SValue;
|
406
435
|
typedef IValidationErrorHandler<Schema> ErrorHandler;
|
436
|
+
typedef GenericUri<ValueType, AllocatorType> UriType;
|
407
437
|
friend class GenericSchemaDocument<ValueType, AllocatorType>;
|
408
438
|
|
409
|
-
Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
|
439
|
+
Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) :
|
410
440
|
allocator_(allocator),
|
411
441
|
uri_(schemaDocument->GetURI(), *allocator),
|
442
|
+
id_(id),
|
412
443
|
pointer_(p, allocator),
|
413
444
|
typeless_(schemaDocument->GetTypeless()),
|
414
445
|
enum_(),
|
@@ -446,9 +477,28 @@ public:
|
|
446
477
|
typedef typename ValueType::ConstValueIterator ConstValueIterator;
|
447
478
|
typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
|
448
479
|
|
480
|
+
// PR #1393
|
481
|
+
// Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite
|
482
|
+
// recursion (with recursive schemas), since schemaDocument->getSchema() is always
|
483
|
+
// checked before creating a new one. Don't cache typeless_, though.
|
484
|
+
if (this != typeless_) {
|
485
|
+
typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
|
486
|
+
SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
|
487
|
+
new (entry) SchemaEntry(pointer_, this, true, allocator_);
|
488
|
+
schemaDocument->AddSchemaRefs(this);
|
489
|
+
}
|
490
|
+
|
449
491
|
if (!value.IsObject())
|
450
492
|
return;
|
451
493
|
|
494
|
+
// If we have an id property, resolve it with the in-scope id
|
495
|
+
if (const ValueType* v = GetMember(value, GetIdString())) {
|
496
|
+
if (v->IsString()) {
|
497
|
+
UriType local(*v, allocator);
|
498
|
+
id_ = local.Resolve(id_, allocator);
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
452
502
|
if (const ValueType* v = GetMember(value, GetTypeString())) {
|
453
503
|
type_ = 0;
|
454
504
|
if (v->IsString())
|
@@ -458,7 +508,7 @@ public:
|
|
458
508
|
AddType(*itr);
|
459
509
|
}
|
460
510
|
|
461
|
-
if (const ValueType* v = GetMember(value, GetEnumString()))
|
511
|
+
if (const ValueType* v = GetMember(value, GetEnumString())) {
|
462
512
|
if (v->IsArray() && v->Size() > 0) {
|
463
513
|
enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
|
464
514
|
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
|
@@ -470,17 +520,18 @@ public:
|
|
470
520
|
enum_[enumCount_++] = h.GetHashCode();
|
471
521
|
}
|
472
522
|
}
|
523
|
+
}
|
473
524
|
|
474
525
|
if (schemaDocument) {
|
475
526
|
AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
|
476
527
|
AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
|
477
528
|
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
|
478
|
-
}
|
479
529
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
530
|
+
if (const ValueType* v = GetMember(value, GetNotString())) {
|
531
|
+
schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_);
|
532
|
+
notValidatorIndex_ = validatorCount_;
|
533
|
+
validatorCount_++;
|
534
|
+
}
|
484
535
|
}
|
485
536
|
|
486
537
|
// Object
|
@@ -495,7 +546,7 @@ public:
|
|
495
546
|
if (properties && properties->IsObject())
|
496
547
|
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
|
497
548
|
AddUniqueElement(allProperties, itr->name);
|
498
|
-
|
549
|
+
|
499
550
|
if (required && required->IsArray())
|
500
551
|
for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
|
501
552
|
if (itr->IsString())
|
@@ -526,7 +577,7 @@ public:
|
|
526
577
|
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
|
527
578
|
SizeType index;
|
528
579
|
if (FindPropertyIndex(itr->name, &index))
|
529
|
-
schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
|
580
|
+
schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
|
530
581
|
}
|
531
582
|
}
|
532
583
|
|
@@ -538,7 +589,7 @@ public:
|
|
538
589
|
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
|
539
590
|
new (&patternProperties_[patternPropertyCount_]) PatternProperty();
|
540
591
|
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
|
541
|
-
schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
|
592
|
+
schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
|
542
593
|
patternPropertyCount_++;
|
543
594
|
}
|
544
595
|
}
|
@@ -570,7 +621,7 @@ public:
|
|
570
621
|
}
|
571
622
|
else if (itr->value.IsObject()) {
|
572
623
|
hasSchemaDependencies_ = true;
|
573
|
-
schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
|
624
|
+
schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
|
574
625
|
properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
|
575
626
|
validatorCount_++;
|
576
627
|
}
|
@@ -582,7 +633,7 @@ public:
|
|
582
633
|
if (v->IsBool())
|
583
634
|
additionalProperties_ = v->GetBool();
|
584
635
|
else if (v->IsObject())
|
585
|
-
schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
|
636
|
+
schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
|
586
637
|
}
|
587
638
|
|
588
639
|
AssignIfExist(minProperties_, value, GetMinPropertiesString());
|
@@ -592,12 +643,12 @@ public:
|
|
592
643
|
if (const ValueType* v = GetMember(value, GetItemsString())) {
|
593
644
|
PointerType q = p.Append(GetItemsString(), allocator_);
|
594
645
|
if (v->IsObject()) // List validation
|
595
|
-
schemaDocument->CreateSchema(&itemsList_, q, *v, document);
|
646
|
+
schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
|
596
647
|
else if (v->IsArray()) { // Tuple validation
|
597
648
|
itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
|
598
649
|
SizeType index = 0;
|
599
650
|
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
|
600
|
-
schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
|
651
|
+
schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
|
601
652
|
}
|
602
653
|
}
|
603
654
|
|
@@ -608,7 +659,7 @@ public:
|
|
608
659
|
if (v->IsBool())
|
609
660
|
additionalItems_ = v->GetBool();
|
610
661
|
else if (v->IsObject())
|
611
|
-
schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
|
662
|
+
schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
|
612
663
|
}
|
613
664
|
|
614
665
|
AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
|
@@ -668,6 +719,10 @@ public:
|
|
668
719
|
return uri_;
|
669
720
|
}
|
670
721
|
|
722
|
+
const UriType& GetId() const {
|
723
|
+
return id_;
|
724
|
+
}
|
725
|
+
|
671
726
|
const PointerType& GetPointer() const {
|
672
727
|
return pointer_;
|
673
728
|
}
|
@@ -688,7 +743,11 @@ public:
|
|
688
743
|
context.valueSchema = typeless_;
|
689
744
|
else {
|
690
745
|
context.error_handler.DisallowedItem(context.arrayElementIndex);
|
691
|
-
|
746
|
+
// Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
|
747
|
+
context.valueSchema = typeless_;
|
748
|
+
// Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
|
749
|
+
context.arrayElementIndex++;
|
750
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
|
692
751
|
}
|
693
752
|
}
|
694
753
|
else
|
@@ -700,6 +759,7 @@ public:
|
|
700
759
|
}
|
701
760
|
|
702
761
|
RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
|
762
|
+
// Only check pattern properties if we have validators
|
703
763
|
if (context.patternPropertiesValidatorCount > 0) {
|
704
764
|
bool otherValid = false;
|
705
765
|
SizeType count = context.patternPropertiesValidatorCount;
|
@@ -716,66 +776,70 @@ public:
|
|
716
776
|
if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
|
717
777
|
if (!patternValid) {
|
718
778
|
context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
|
719
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
779
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
|
720
780
|
}
|
721
781
|
}
|
722
782
|
else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
|
723
783
|
if (!patternValid || !otherValid) {
|
724
784
|
context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
|
725
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
785
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
|
726
786
|
}
|
727
787
|
}
|
728
788
|
else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
|
729
789
|
context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
|
730
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
790
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
|
731
791
|
}
|
732
792
|
}
|
733
793
|
|
734
|
-
if
|
794
|
+
// For enums only check if we have a hasher
|
795
|
+
if (enum_ && context.hasher) {
|
735
796
|
const uint64_t h = context.factory.GetHashCode(context.hasher);
|
736
797
|
for (SizeType i = 0; i < enumCount_; i++)
|
737
798
|
if (enum_[i] == h)
|
738
799
|
goto foundEnum;
|
739
|
-
context.error_handler.DisallowedValue();
|
740
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
800
|
+
context.error_handler.DisallowedValue(kValidateErrorEnum);
|
801
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
|
741
802
|
foundEnum:;
|
742
803
|
}
|
743
804
|
|
744
|
-
if
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
805
|
+
// Only check allOf etc if we have validators
|
806
|
+
if (context.validatorCount > 0) {
|
807
|
+
if (allOf_.schemas)
|
808
|
+
for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
|
809
|
+
if (!context.validators[i]->IsValid()) {
|
810
|
+
context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
|
811
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
|
812
|
+
}
|
813
|
+
|
814
|
+
if (anyOf_.schemas) {
|
815
|
+
for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
|
816
|
+
if (context.validators[i]->IsValid())
|
817
|
+
goto foundAny;
|
818
|
+
context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
|
819
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
|
820
|
+
foundAny:;
|
821
|
+
}
|
822
|
+
|
823
|
+
if (oneOf_.schemas) {
|
824
|
+
bool oneValid = false;
|
825
|
+
for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
|
826
|
+
if (context.validators[i]->IsValid()) {
|
827
|
+
if (oneValid) {
|
828
|
+
context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true);
|
829
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
|
830
|
+
} else
|
831
|
+
oneValid = true;
|
832
|
+
}
|
833
|
+
if (!oneValid) {
|
834
|
+
context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false);
|
835
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
|
769
836
|
}
|
770
|
-
if (!oneValid) {
|
771
|
-
context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
|
772
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
|
773
837
|
}
|
774
|
-
}
|
775
838
|
|
776
|
-
|
777
|
-
|
778
|
-
|
839
|
+
if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
|
840
|
+
context.error_handler.Disallowed();
|
841
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
|
842
|
+
}
|
779
843
|
}
|
780
844
|
|
781
845
|
return true;
|
@@ -784,15 +848,15 @@ public:
|
|
784
848
|
bool Null(Context& context) const {
|
785
849
|
if (!(type_ & (1 << kNullSchemaType))) {
|
786
850
|
DisallowedType(context, GetNullString());
|
787
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
851
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
788
852
|
}
|
789
853
|
return CreateParallelValidator(context);
|
790
854
|
}
|
791
|
-
|
855
|
+
|
792
856
|
bool Bool(Context& context, bool) const {
|
793
857
|
if (!(type_ & (1 << kBooleanSchemaType))) {
|
794
858
|
DisallowedType(context, GetBooleanString());
|
795
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
859
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
796
860
|
}
|
797
861
|
return CreateParallelValidator(context);
|
798
862
|
}
|
@@ -824,7 +888,7 @@ public:
|
|
824
888
|
bool Double(Context& context, double d) const {
|
825
889
|
if (!(type_ & (1 << kNumberSchemaType))) {
|
826
890
|
DisallowedType(context, GetNumberString());
|
827
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
891
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
828
892
|
}
|
829
893
|
|
830
894
|
if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
|
@@ -832,17 +896,17 @@ public:
|
|
832
896
|
|
833
897
|
if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
|
834
898
|
return false;
|
835
|
-
|
899
|
+
|
836
900
|
if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
|
837
901
|
return false;
|
838
|
-
|
902
|
+
|
839
903
|
return CreateParallelValidator(context);
|
840
904
|
}
|
841
|
-
|
905
|
+
|
842
906
|
bool String(Context& context, const Ch* str, SizeType length, bool) const {
|
843
907
|
if (!(type_ & (1 << kStringSchemaType))) {
|
844
908
|
DisallowedType(context, GetStringString());
|
845
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
909
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
846
910
|
}
|
847
911
|
|
848
912
|
if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
|
@@ -850,18 +914,18 @@ public:
|
|
850
914
|
if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
|
851
915
|
if (count < minLength_) {
|
852
916
|
context.error_handler.TooShort(str, length, minLength_);
|
853
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
917
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
|
854
918
|
}
|
855
919
|
if (count > maxLength_) {
|
856
920
|
context.error_handler.TooLong(str, length, maxLength_);
|
857
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
921
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
|
858
922
|
}
|
859
923
|
}
|
860
924
|
}
|
861
925
|
|
862
926
|
if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
|
863
927
|
context.error_handler.DoesNotMatch(str, length);
|
864
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
928
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
|
865
929
|
}
|
866
930
|
|
867
931
|
return CreateParallelValidator(context);
|
@@ -870,7 +934,7 @@ public:
|
|
870
934
|
bool StartObject(Context& context) const {
|
871
935
|
if (!(type_ & (1 << kObjectSchemaType))) {
|
872
936
|
DisallowedType(context, GetObjectString());
|
873
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
937
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
874
938
|
}
|
875
939
|
|
876
940
|
if (hasDependencies_ || hasRequired_) {
|
@@ -887,7 +951,7 @@ public:
|
|
887
951
|
|
888
952
|
return CreateParallelValidator(context);
|
889
953
|
}
|
890
|
-
|
954
|
+
|
891
955
|
bool Key(Context& context, const Ch* str, SizeType len, bool) const {
|
892
956
|
if (patternProperties_) {
|
893
957
|
context.patternPropertiesSchemaCount = 0;
|
@@ -915,7 +979,7 @@ public:
|
|
915
979
|
}
|
916
980
|
|
917
981
|
if (additionalPropertiesSchema_) {
|
918
|
-
if (
|
982
|
+
if (context.patternPropertiesSchemaCount > 0) {
|
919
983
|
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
|
920
984
|
context.valueSchema = typeless_;
|
921
985
|
context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
|
@@ -930,8 +994,10 @@ public:
|
|
930
994
|
}
|
931
995
|
|
932
996
|
if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
|
997
|
+
// Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
|
998
|
+
context.valueSchema = typeless_;
|
933
999
|
context.error_handler.DisallowedProperty(str, len);
|
934
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1000
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
|
935
1001
|
}
|
936
1002
|
|
937
1003
|
return true;
|
@@ -945,17 +1011,17 @@ public:
|
|
945
1011
|
if (properties_[index].schema->defaultValueLength_ == 0 )
|
946
1012
|
context.error_handler.AddMissingProperty(properties_[index].name);
|
947
1013
|
if (context.error_handler.EndMissingProperties())
|
948
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1014
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
|
949
1015
|
}
|
950
1016
|
|
951
1017
|
if (memberCount < minProperties_) {
|
952
1018
|
context.error_handler.TooFewProperties(memberCount, minProperties_);
|
953
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1019
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
|
954
1020
|
}
|
955
1021
|
|
956
1022
|
if (memberCount > maxProperties_) {
|
957
1023
|
context.error_handler.TooManyProperties(memberCount, maxProperties_);
|
958
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1024
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
|
959
1025
|
}
|
960
1026
|
|
961
1027
|
if (hasDependencies_) {
|
@@ -978,40 +1044,78 @@ public:
|
|
978
1044
|
}
|
979
1045
|
}
|
980
1046
|
if (context.error_handler.EndDependencyErrors())
|
981
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1047
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
|
982
1048
|
}
|
983
1049
|
|
984
1050
|
return true;
|
985
1051
|
}
|
986
1052
|
|
987
1053
|
bool StartArray(Context& context) const {
|
1054
|
+
context.arrayElementIndex = 0;
|
1055
|
+
context.inArray = true; // Ensure we note that we are in an array
|
1056
|
+
|
988
1057
|
if (!(type_ & (1 << kArraySchemaType))) {
|
989
1058
|
DisallowedType(context, GetArrayString());
|
990
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1059
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
991
1060
|
}
|
992
1061
|
|
993
|
-
context.arrayElementIndex = 0;
|
994
|
-
context.inArray = true;
|
995
|
-
|
996
1062
|
return CreateParallelValidator(context);
|
997
1063
|
}
|
998
1064
|
|
999
1065
|
bool EndArray(Context& context, SizeType elementCount) const {
|
1000
1066
|
context.inArray = false;
|
1001
|
-
|
1067
|
+
|
1002
1068
|
if (elementCount < minItems_) {
|
1003
1069
|
context.error_handler.TooFewItems(elementCount, minItems_);
|
1004
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1070
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
|
1005
1071
|
}
|
1006
|
-
|
1072
|
+
|
1007
1073
|
if (elementCount > maxItems_) {
|
1008
1074
|
context.error_handler.TooManyItems(elementCount, maxItems_);
|
1009
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1075
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
|
1010
1076
|
}
|
1011
1077
|
|
1012
1078
|
return true;
|
1013
1079
|
}
|
1014
1080
|
|
1081
|
+
static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
|
1082
|
+
switch (validateErrorCode) {
|
1083
|
+
case kValidateErrorMultipleOf: return GetMultipleOfString();
|
1084
|
+
case kValidateErrorMaximum: return GetMaximumString();
|
1085
|
+
case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same
|
1086
|
+
case kValidateErrorMinimum: return GetMinimumString();
|
1087
|
+
case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same
|
1088
|
+
|
1089
|
+
case kValidateErrorMaxLength: return GetMaxLengthString();
|
1090
|
+
case kValidateErrorMinLength: return GetMinLengthString();
|
1091
|
+
case kValidateErrorPattern: return GetPatternString();
|
1092
|
+
|
1093
|
+
case kValidateErrorMaxItems: return GetMaxItemsString();
|
1094
|
+
case kValidateErrorMinItems: return GetMinItemsString();
|
1095
|
+
case kValidateErrorUniqueItems: return GetUniqueItemsString();
|
1096
|
+
case kValidateErrorAdditionalItems: return GetAdditionalItemsString();
|
1097
|
+
|
1098
|
+
case kValidateErrorMaxProperties: return GetMaxPropertiesString();
|
1099
|
+
case kValidateErrorMinProperties: return GetMinPropertiesString();
|
1100
|
+
case kValidateErrorRequired: return GetRequiredString();
|
1101
|
+
case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString();
|
1102
|
+
case kValidateErrorPatternProperties: return GetPatternPropertiesString();
|
1103
|
+
case kValidateErrorDependencies: return GetDependenciesString();
|
1104
|
+
|
1105
|
+
case kValidateErrorEnum: return GetEnumString();
|
1106
|
+
case kValidateErrorType: return GetTypeString();
|
1107
|
+
|
1108
|
+
case kValidateErrorOneOf: return GetOneOfString();
|
1109
|
+
case kValidateErrorOneOfMatch: return GetOneOfString(); // Same
|
1110
|
+
case kValidateErrorAllOf: return GetAllOfString();
|
1111
|
+
case kValidateErrorAnyOf: return GetAnyOfString();
|
1112
|
+
case kValidateErrorNot: return GetNotString();
|
1113
|
+
|
1114
|
+
default: return GetNullString();
|
1115
|
+
}
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
|
1015
1119
|
// Generate functions for string literal according to Ch
|
1016
1120
|
#define RAPIDJSON_STRING_(name, ...) \
|
1017
1121
|
static const ValueType& Get##name##String() {\
|
@@ -1054,6 +1158,15 @@ public:
|
|
1054
1158
|
RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
|
1055
1159
|
RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
|
1056
1160
|
RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
|
1161
|
+
RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
|
1162
|
+
RAPIDJSON_STRING_(Id, 'i', 'd')
|
1163
|
+
|
1164
|
+
RAPIDJSON_STRING_(SchemeEnd, ':')
|
1165
|
+
RAPIDJSON_STRING_(AuthStart, '/', '/')
|
1166
|
+
RAPIDJSON_STRING_(QueryStart, '?')
|
1167
|
+
RAPIDJSON_STRING_(FragStart, '#')
|
1168
|
+
RAPIDJSON_STRING_(Slash, '/')
|
1169
|
+
RAPIDJSON_STRING_(Dot, '.')
|
1057
1170
|
|
1058
1171
|
#undef RAPIDJSON_STRING_
|
1059
1172
|
|
@@ -1119,7 +1232,7 @@ private:
|
|
1119
1232
|
out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
|
1120
1233
|
memset(out.schemas, 0, sizeof(Schema*)* out.count);
|
1121
1234
|
for (SizeType i = 0; i < out.count; i++)
|
1122
|
-
schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
|
1235
|
+
schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
|
1123
1236
|
out.begin = validatorCount_;
|
1124
1237
|
validatorCount_ += out.count;
|
1125
1238
|
}
|
@@ -1190,31 +1303,32 @@ private:
|
|
1190
1303
|
context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
|
1191
1304
|
context.validatorCount = validatorCount_;
|
1192
1305
|
|
1306
|
+
// Always return after first failure for these sub-validators
|
1193
1307
|
if (allOf_.schemas)
|
1194
|
-
CreateSchemaValidators(context, allOf_);
|
1308
|
+
CreateSchemaValidators(context, allOf_, false);
|
1195
1309
|
|
1196
1310
|
if (anyOf_.schemas)
|
1197
|
-
CreateSchemaValidators(context, anyOf_);
|
1198
|
-
|
1311
|
+
CreateSchemaValidators(context, anyOf_, false);
|
1312
|
+
|
1199
1313
|
if (oneOf_.schemas)
|
1200
|
-
CreateSchemaValidators(context, oneOf_);
|
1201
|
-
|
1314
|
+
CreateSchemaValidators(context, oneOf_, false);
|
1315
|
+
|
1202
1316
|
if (not_)
|
1203
|
-
context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
|
1204
|
-
|
1317
|
+
context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
|
1318
|
+
|
1205
1319
|
if (hasSchemaDependencies_) {
|
1206
1320
|
for (SizeType i = 0; i < propertyCount_; i++)
|
1207
1321
|
if (properties_[i].dependenciesSchema)
|
1208
|
-
context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
|
1322
|
+
context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
|
1209
1323
|
}
|
1210
1324
|
}
|
1211
1325
|
|
1212
1326
|
return true;
|
1213
1327
|
}
|
1214
1328
|
|
1215
|
-
void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
|
1329
|
+
void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
|
1216
1330
|
for (SizeType i = 0; i < schemas.count; i++)
|
1217
|
-
context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
|
1331
|
+
context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
|
1218
1332
|
}
|
1219
1333
|
|
1220
1334
|
// O(n)
|
@@ -1222,7 +1336,7 @@ private:
|
|
1222
1336
|
SizeType len = name.GetStringLength();
|
1223
1337
|
const Ch* str = name.GetString();
|
1224
1338
|
for (SizeType index = 0; index < propertyCount_; index++)
|
1225
|
-
if (properties_[index].name.GetStringLength() == len &&
|
1339
|
+
if (properties_[index].name.GetStringLength() == len &&
|
1226
1340
|
(std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
|
1227
1341
|
{
|
1228
1342
|
*outIndex = index;
|
@@ -1234,19 +1348,19 @@ private:
|
|
1234
1348
|
bool CheckInt(Context& context, int64_t i) const {
|
1235
1349
|
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
|
1236
1350
|
DisallowedType(context, GetIntegerString());
|
1237
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1351
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
1238
1352
|
}
|
1239
1353
|
|
1240
1354
|
if (!minimum_.IsNull()) {
|
1241
1355
|
if (minimum_.IsInt64()) {
|
1242
1356
|
if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
|
1243
1357
|
context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
|
1244
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1358
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
|
1245
1359
|
}
|
1246
1360
|
}
|
1247
1361
|
else if (minimum_.IsUint64()) {
|
1248
1362
|
context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
|
1249
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1363
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
|
1250
1364
|
}
|
1251
1365
|
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
|
1252
1366
|
return false;
|
@@ -1256,7 +1370,7 @@ private:
|
|
1256
1370
|
if (maximum_.IsInt64()) {
|
1257
1371
|
if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
|
1258
1372
|
context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
|
1259
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1373
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
|
1260
1374
|
}
|
1261
1375
|
}
|
1262
1376
|
else if (maximum_.IsUint64()) { }
|
@@ -1269,7 +1383,7 @@ private:
|
|
1269
1383
|
if (multipleOf_.IsUint64()) {
|
1270
1384
|
if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
|
1271
1385
|
context.error_handler.NotMultipleOf(i, multipleOf_);
|
1272
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1386
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
|
1273
1387
|
}
|
1274
1388
|
}
|
1275
1389
|
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
|
@@ -1282,14 +1396,14 @@ private:
|
|
1282
1396
|
bool CheckUint(Context& context, uint64_t i) const {
|
1283
1397
|
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
|
1284
1398
|
DisallowedType(context, GetIntegerString());
|
1285
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1399
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
1286
1400
|
}
|
1287
1401
|
|
1288
1402
|
if (!minimum_.IsNull()) {
|
1289
1403
|
if (minimum_.IsUint64()) {
|
1290
1404
|
if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
|
1291
1405
|
context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
|
1292
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1406
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
|
1293
1407
|
}
|
1294
1408
|
}
|
1295
1409
|
else if (minimum_.IsInt64())
|
@@ -1302,12 +1416,12 @@ private:
|
|
1302
1416
|
if (maximum_.IsUint64()) {
|
1303
1417
|
if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
|
1304
1418
|
context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
|
1305
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1419
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
|
1306
1420
|
}
|
1307
1421
|
}
|
1308
1422
|
else if (maximum_.IsInt64()) {
|
1309
1423
|
context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
|
1310
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1424
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_
|
1311
1425
|
}
|
1312
1426
|
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
|
1313
1427
|
return false;
|
@@ -1317,7 +1431,7 @@ private:
|
|
1317
1431
|
if (multipleOf_.IsUint64()) {
|
1318
1432
|
if (i % multipleOf_.GetUint64() != 0) {
|
1319
1433
|
context.error_handler.NotMultipleOf(i, multipleOf_);
|
1320
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1434
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
|
1321
1435
|
}
|
1322
1436
|
}
|
1323
1437
|
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
|
@@ -1330,7 +1444,7 @@ private:
|
|
1330
1444
|
bool CheckDoubleMinimum(Context& context, double d) const {
|
1331
1445
|
if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
|
1332
1446
|
context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
|
1333
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1447
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
|
1334
1448
|
}
|
1335
1449
|
return true;
|
1336
1450
|
}
|
@@ -1338,7 +1452,7 @@ private:
|
|
1338
1452
|
bool CheckDoubleMaximum(Context& context, double d) const {
|
1339
1453
|
if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
|
1340
1454
|
context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
|
1341
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1455
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
|
1342
1456
|
}
|
1343
1457
|
return true;
|
1344
1458
|
}
|
@@ -1349,7 +1463,7 @@ private:
|
|
1349
1463
|
double r = a - q * b;
|
1350
1464
|
if (r > 0.0) {
|
1351
1465
|
context.error_handler.NotMultipleOf(d, multipleOf_);
|
1352
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(
|
1466
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
|
1353
1467
|
}
|
1354
1468
|
return true;
|
1355
1469
|
}
|
@@ -1383,7 +1497,7 @@ private:
|
|
1383
1497
|
|
1384
1498
|
struct PatternProperty {
|
1385
1499
|
PatternProperty() : schema(), pattern() {}
|
1386
|
-
~PatternProperty() {
|
1500
|
+
~PatternProperty() {
|
1387
1501
|
if (pattern) {
|
1388
1502
|
pattern->~RegexType();
|
1389
1503
|
AllocatorType::Free(pattern);
|
@@ -1395,6 +1509,7 @@ private:
|
|
1395
1509
|
|
1396
1510
|
AllocatorType* allocator_;
|
1397
1511
|
SValue uri_;
|
1512
|
+
UriType id_;
|
1398
1513
|
PointerType pointer_;
|
1399
1514
|
const SchemaType* typeless_;
|
1400
1515
|
uint64_t* enum_;
|
@@ -1437,7 +1552,7 @@ private:
|
|
1437
1552
|
SValue multipleOf_;
|
1438
1553
|
bool exclusiveMinimum_;
|
1439
1554
|
bool exclusiveMaximum_;
|
1440
|
-
|
1555
|
+
|
1441
1556
|
SizeType defaultValueLength_;
|
1442
1557
|
};
|
1443
1558
|
|
@@ -1480,9 +1595,12 @@ template <typename SchemaDocumentType>
|
|
1480
1595
|
class IGenericRemoteSchemaDocumentProvider {
|
1481
1596
|
public:
|
1482
1597
|
typedef typename SchemaDocumentType::Ch Ch;
|
1598
|
+
typedef typename SchemaDocumentType::ValueType ValueType;
|
1599
|
+
typedef typename SchemaDocumentType::AllocatorType AllocatorType;
|
1483
1600
|
|
1484
1601
|
virtual ~IGenericRemoteSchemaDocumentProvider() {}
|
1485
1602
|
virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
|
1603
|
+
virtual const SchemaDocumentType* GetRemoteDocument(GenericUri<ValueType, AllocatorType> uri) { return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); }
|
1486
1604
|
};
|
1487
1605
|
|
1488
1606
|
///////////////////////////////////////////////////////////////////////////////
|
@@ -1507,7 +1625,8 @@ public:
|
|
1507
1625
|
typedef typename EncodingType::Ch Ch;
|
1508
1626
|
typedef internal::Schema<GenericSchemaDocument> SchemaType;
|
1509
1627
|
typedef GenericPointer<ValueType, Allocator> PointerType;
|
1510
|
-
typedef GenericValue<EncodingType,
|
1628
|
+
typedef GenericValue<EncodingType, AllocatorType> SValue;
|
1629
|
+
typedef GenericUri<ValueType, Allocator> UriType;
|
1511
1630
|
friend class internal::Schema<GenericSchemaDocument>;
|
1512
1631
|
template <typename, typename, typename>
|
1513
1632
|
friend class GenericSchemaValidator;
|
@@ -1521,9 +1640,11 @@ public:
|
|
1521
1640
|
\param uriLength Length of \c name, in code points.
|
1522
1641
|
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
|
1523
1642
|
\param allocator An optional allocator instance for allocating memory. Can be null.
|
1643
|
+
\param pointer An optional JSON pointer to the start of the schema document
|
1524
1644
|
*/
|
1525
1645
|
explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
|
1526
|
-
IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0
|
1646
|
+
IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
|
1647
|
+
const PointerType& pointer = PointerType()) : // PR #1393
|
1527
1648
|
remoteProvider_(remoteProvider),
|
1528
1649
|
allocator_(allocator),
|
1529
1650
|
ownAllocator_(),
|
@@ -1537,30 +1658,20 @@ public:
|
|
1537
1658
|
|
1538
1659
|
Ch noUri[1] = {0};
|
1539
1660
|
uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
|
1661
|
+
docId_ = UriType(uri_, allocator_);
|
1540
1662
|
|
1541
1663
|
typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
|
1542
|
-
new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_);
|
1664
|
+
new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_);
|
1543
1665
|
|
1544
1666
|
// Generate root schema, it will call CreateSchema() to create sub-schemas,
|
1545
|
-
// And call
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
*refEntry->schema = s;
|
1554
|
-
|
1555
|
-
// Create entry in map if not exist
|
1556
|
-
if (!GetSchema(refEntry->source)) {
|
1557
|
-
new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
|
1558
|
-
}
|
1559
|
-
}
|
1560
|
-
else if (refEntry->schema)
|
1561
|
-
*refEntry->schema = typeless_;
|
1562
|
-
|
1563
|
-
refEntry->~SchemaRefEntry();
|
1667
|
+
// And call HandleRefSchema() if there are $ref.
|
1668
|
+
// PR #1393 use input pointer if supplied
|
1669
|
+
root_ = typeless_;
|
1670
|
+
if (pointer.GetTokenCount() == 0) {
|
1671
|
+
CreateSchemaRecursive(&root_, pointer, document, document, docId_);
|
1672
|
+
}
|
1673
|
+
else if (const ValueType* v = pointer.Get(document)) {
|
1674
|
+
CreateSchema(&root_, pointer, *v, document, docId_);
|
1564
1675
|
}
|
1565
1676
|
|
1566
1677
|
RAPIDJSON_ASSERT(root_ != 0);
|
@@ -1578,7 +1689,8 @@ public:
|
|
1578
1689
|
typeless_(rhs.typeless_),
|
1579
1690
|
schemaMap_(std::move(rhs.schemaMap_)),
|
1580
1691
|
schemaRef_(std::move(rhs.schemaRef_)),
|
1581
|
-
uri_(std::move(rhs.uri_))
|
1692
|
+
uri_(std::move(rhs.uri_)),
|
1693
|
+
docId_(rhs.docId_)
|
1582
1694
|
{
|
1583
1695
|
rhs.remoteProvider_ = 0;
|
1584
1696
|
rhs.allocator_ = 0;
|
@@ -1600,7 +1712,7 @@ public:
|
|
1600
1712
|
RAPIDJSON_DELETE(ownAllocator_);
|
1601
1713
|
}
|
1602
1714
|
|
1603
|
-
const
|
1715
|
+
const SValue& GetURI() const { return uri_; }
|
1604
1716
|
|
1605
1717
|
//! Get the root schema.
|
1606
1718
|
const SchemaType& GetRoot() const { return *root_; }
|
@@ -1611,12 +1723,7 @@ private:
|
|
1611
1723
|
//! Prohibit assignment
|
1612
1724
|
GenericSchemaDocument& operator=(const GenericSchemaDocument&);
|
1613
1725
|
|
1614
|
-
|
1615
|
-
SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
|
1616
|
-
PointerType source;
|
1617
|
-
PointerType target;
|
1618
|
-
const SchemaType** schema;
|
1619
|
-
};
|
1726
|
+
typedef const PointerType* SchemaRefPtr; // PR #1393
|
1620
1727
|
|
1621
1728
|
struct SchemaEntry {
|
1622
1729
|
SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
|
@@ -1631,79 +1738,197 @@ private:
|
|
1631
1738
|
bool owned;
|
1632
1739
|
};
|
1633
1740
|
|
1634
|
-
|
1635
|
-
|
1636
|
-
*schema = typeless_;
|
1637
|
-
|
1741
|
+
// Changed by PR #1393
|
1742
|
+
void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
1638
1743
|
if (v.GetType() == kObjectType) {
|
1639
|
-
|
1640
|
-
if (!s)
|
1641
|
-
CreateSchema(schema, pointer, v, document);
|
1744
|
+
UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
|
1642
1745
|
|
1643
1746
|
for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
|
1644
|
-
CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
|
1747
|
+
CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
|
1645
1748
|
}
|
1646
1749
|
else if (v.GetType() == kArrayType)
|
1647
1750
|
for (SizeType i = 0; i < v.Size(); i++)
|
1648
|
-
CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
|
1751
|
+
CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
|
1649
1752
|
}
|
1650
1753
|
|
1651
|
-
|
1754
|
+
// Changed by PR #1393
|
1755
|
+
const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
1652
1756
|
RAPIDJSON_ASSERT(pointer.IsValid());
|
1653
1757
|
if (v.IsObject()) {
|
1654
|
-
if (
|
1655
|
-
|
1656
|
-
|
1758
|
+
if (const SchemaType* sc = GetSchema(pointer)) {
|
1759
|
+
if (schema)
|
1760
|
+
*schema = sc;
|
1761
|
+
AddSchemaRefs(const_cast<SchemaType*>(sc));
|
1762
|
+
}
|
1763
|
+
else if (!HandleRefSchema(pointer, schema, v, document, id)) {
|
1764
|
+
// The new schema constructor adds itself and its $ref(s) to schemaMap_
|
1765
|
+
SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id);
|
1657
1766
|
if (schema)
|
1658
1767
|
*schema = s;
|
1768
|
+
return s->GetId();
|
1659
1769
|
}
|
1660
1770
|
}
|
1771
|
+
else {
|
1772
|
+
if (schema)
|
1773
|
+
*schema = typeless_;
|
1774
|
+
AddSchemaRefs(typeless_);
|
1775
|
+
}
|
1776
|
+
return id;
|
1661
1777
|
}
|
1662
1778
|
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
|
1779
|
+
// Changed by PR #1393
|
1780
|
+
// TODO should this return a UriType& ?
|
1781
|
+
bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) {
|
1782
|
+
typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
|
1668
1783
|
if (itr == v.MemberEnd())
|
1669
1784
|
return false;
|
1670
1785
|
|
1786
|
+
// Resolve the source pointer to the $ref'ed schema (finally)
|
1787
|
+
new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
|
1788
|
+
|
1671
1789
|
if (itr->value.IsString()) {
|
1672
1790
|
SizeType len = itr->value.GetStringLength();
|
1673
1791
|
if (len > 0) {
|
1674
|
-
|
1675
|
-
|
1676
|
-
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1792
|
+
// First resolve $ref against the in-scope id
|
1793
|
+
UriType scopeId = UriType(id, allocator_);
|
1794
|
+
UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
|
1795
|
+
// See if the resolved $ref minus the fragment matches a resolved id in this document
|
1796
|
+
// Search from the root. Returns the subschema in the document and its absolute JSON pointer.
|
1797
|
+
PointerType basePointer = PointerType();
|
1798
|
+
const ValueType *base = FindId(document, ref, basePointer, docId_, false);
|
1799
|
+
if (!base) {
|
1800
|
+
// Remote reference - call the remote document provider
|
1680
1801
|
if (remoteProvider_) {
|
1681
|
-
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1802
|
+
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref)) {
|
1803
|
+
const Ch* s = ref.GetFragString();
|
1804
|
+
len = ref.GetFragStringLength();
|
1805
|
+
if (len <= 1 || s[1] == '/') {
|
1806
|
+
// JSON pointer fragment, absolute in the remote schema
|
1807
|
+
const PointerType pointer(s, len, allocator_);
|
1808
|
+
if (pointer.IsValid()) {
|
1809
|
+
// Get the subschema
|
1810
|
+
if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
|
1811
|
+
if (schema)
|
1812
|
+
*schema = sc;
|
1813
|
+
AddSchemaRefs(const_cast<SchemaType *>(sc));
|
1814
|
+
return true;
|
1815
|
+
}
|
1816
|
+
}
|
1817
|
+
} else {
|
1818
|
+
// Plain name fragment, not allowed
|
1819
|
+
}
|
1820
|
+
}
|
1821
|
+
}
|
1822
|
+
}
|
1823
|
+
else { // Local reference
|
1824
|
+
const Ch* s = ref.GetFragString();
|
1825
|
+
len = ref.GetFragStringLength();
|
1826
|
+
if (len <= 1 || s[1] == '/') {
|
1827
|
+
// JSON pointer fragment, relative to the resolved URI
|
1828
|
+
const PointerType relPointer(s, len, allocator_);
|
1829
|
+
if (relPointer.IsValid()) {
|
1830
|
+
// Get the subschema
|
1831
|
+
if (const ValueType *pv = relPointer.Get(*base)) {
|
1832
|
+
// Now get the absolute JSON pointer by adding relative to base
|
1833
|
+
PointerType pointer(basePointer);
|
1834
|
+
for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
|
1835
|
+
pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
|
1836
|
+
//GenericStringBuffer<EncodingType> sb;
|
1837
|
+
//pointer.StringifyUriFragment(sb);
|
1838
|
+
if (pointer.IsValid() && !IsCyclicRef(pointer)) {
|
1839
|
+
// Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
|
1840
|
+
// TODO: cache pointer <-> id mapping
|
1841
|
+
size_t unresolvedTokenIndex;
|
1842
|
+
scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
|
1843
|
+
CreateSchema(schema, pointer, *pv, document, scopeId);
|
1688
1844
|
return true;
|
1689
1845
|
}
|
1690
1846
|
}
|
1691
1847
|
}
|
1848
|
+
} else {
|
1849
|
+
// Plain name fragment, relative to the resolved URI
|
1850
|
+
// See if the fragment matches an id in this document.
|
1851
|
+
// Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer.
|
1852
|
+
PointerType pointer = PointerType();
|
1853
|
+
if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
|
1854
|
+
if (!IsCyclicRef(pointer)) {
|
1855
|
+
//GenericStringBuffer<EncodingType> sb;
|
1856
|
+
//pointer.StringifyUriFragment(sb);
|
1857
|
+
// Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
|
1858
|
+
// TODO: cache pointer <-> id mapping
|
1859
|
+
size_t unresolvedTokenIndex;
|
1860
|
+
scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
|
1861
|
+
CreateSchema(schema, pointer, *pv, document, scopeId);
|
1862
|
+
return true;
|
1863
|
+
}
|
1864
|
+
}
|
1692
1865
|
}
|
1693
1866
|
}
|
1694
|
-
|
1695
|
-
|
1696
|
-
if (pointer.IsValid()) {
|
1697
|
-
if (const ValueType* nv = pointer.Get(document))
|
1698
|
-
if (HandleRefSchema(source, schema, *nv, document))
|
1699
|
-
return true;
|
1867
|
+
}
|
1868
|
+
}
|
1700
1869
|
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1870
|
+
// Invalid/Unknown $ref
|
1871
|
+
if (schema)
|
1872
|
+
*schema = typeless_;
|
1873
|
+
AddSchemaRefs(typeless_);
|
1874
|
+
return true;
|
1875
|
+
}
|
1876
|
+
|
1877
|
+
//! Find the first subschema with a resolved 'id' that matches the specified URI.
|
1878
|
+
// If full specified use all URI else ignore fragment.
|
1879
|
+
// If found, return a pointer to the subschema and its JSON pointer.
|
1880
|
+
// TODO cache pointer <-> id mapping
|
1881
|
+
ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const {
|
1882
|
+
SizeType i = 0;
|
1883
|
+
ValueType* resval = 0;
|
1884
|
+
UriType tempuri = UriType(finduri, allocator_);
|
1885
|
+
UriType localuri = UriType(baseuri, allocator_);
|
1886
|
+
if (doc.GetType() == kObjectType) {
|
1887
|
+
// Establish the base URI of this object
|
1888
|
+
typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
|
1889
|
+
if (m != doc.MemberEnd() && m->value.GetType() == kStringType) {
|
1890
|
+
localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
|
1891
|
+
}
|
1892
|
+
// See if it matches
|
1893
|
+
if (localuri.Match(finduri, full)) {
|
1894
|
+
resval = const_cast<ValueType *>(&doc);
|
1895
|
+
resptr = here;
|
1896
|
+
return resval;
|
1897
|
+
}
|
1898
|
+
// No match, continue looking
|
1899
|
+
for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
|
1900
|
+
if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) {
|
1901
|
+
resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
|
1704
1902
|
}
|
1903
|
+
if (resval) break;
|
1904
|
+
}
|
1905
|
+
} else if (doc.GetType() == kArrayType) {
|
1906
|
+
// Continue looking
|
1907
|
+
for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
|
1908
|
+
if (v->GetType() == kObjectType || v->GetType() == kArrayType) {
|
1909
|
+
resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
|
1910
|
+
}
|
1911
|
+
if (resval) break;
|
1912
|
+
i++;
|
1705
1913
|
}
|
1706
1914
|
}
|
1915
|
+
return resval;
|
1916
|
+
}
|
1917
|
+
|
1918
|
+
// Added by PR #1393
|
1919
|
+
void AddSchemaRefs(SchemaType* schema) {
|
1920
|
+
while (!schemaRef_.Empty()) {
|
1921
|
+
SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
|
1922
|
+
SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
|
1923
|
+
new (entry) SchemaEntry(**ref, schema, false, allocator_);
|
1924
|
+
}
|
1925
|
+
}
|
1926
|
+
|
1927
|
+
// Added by PR #1393
|
1928
|
+
bool IsCyclicRef(const PointerType& pointer) const {
|
1929
|
+
for (const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
|
1930
|
+
if (pointer == **ref)
|
1931
|
+
return true;
|
1707
1932
|
return false;
|
1708
1933
|
}
|
1709
1934
|
|
@@ -1732,8 +1957,9 @@ private:
|
|
1732
1957
|
const SchemaType* root_; //!< Root schema.
|
1733
1958
|
SchemaType* typeless_;
|
1734
1959
|
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
|
1735
|
-
internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref
|
1736
|
-
|
1960
|
+
internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
|
1961
|
+
SValue uri_; // Schema document URI
|
1962
|
+
UriType docId_;
|
1737
1963
|
};
|
1738
1964
|
|
1739
1965
|
//! GenericSchemaDocument using Value type.
|
@@ -1763,8 +1989,7 @@ template <
|
|
1763
1989
|
class GenericSchemaValidator :
|
1764
1990
|
public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
|
1765
1991
|
public internal::ISchemaValidator,
|
1766
|
-
public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
|
1767
|
-
{
|
1992
|
+
public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
|
1768
1993
|
public:
|
1769
1994
|
typedef typename SchemaDocumentType::SchemaType SchemaType;
|
1770
1995
|
typedef typename SchemaDocumentType::PointerType PointerType;
|
@@ -1797,7 +2022,8 @@ public:
|
|
1797
2022
|
error_(kObjectType),
|
1798
2023
|
currentError_(),
|
1799
2024
|
missingDependents_(),
|
1800
|
-
valid_(true)
|
2025
|
+
valid_(true),
|
2026
|
+
flags_(kValidateDefaultFlags)
|
1801
2027
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
1802
2028
|
, depth_(0)
|
1803
2029
|
#endif
|
@@ -1828,7 +2054,8 @@ public:
|
|
1828
2054
|
error_(kObjectType),
|
1829
2055
|
currentError_(),
|
1830
2056
|
missingDependents_(),
|
1831
|
-
valid_(true)
|
2057
|
+
valid_(true),
|
2058
|
+
flags_(kValidateDefaultFlags)
|
1832
2059
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
1833
2060
|
, depth_(0)
|
1834
2061
|
#endif
|
@@ -1846,31 +2073,61 @@ public:
|
|
1846
2073
|
while (!schemaStack_.Empty())
|
1847
2074
|
PopSchema();
|
1848
2075
|
documentStack_.Clear();
|
2076
|
+
ResetError();
|
2077
|
+
}
|
2078
|
+
|
2079
|
+
//! Reset the error state.
|
2080
|
+
void ResetError() {
|
1849
2081
|
error_.SetObject();
|
1850
2082
|
currentError_.SetNull();
|
1851
2083
|
missingDependents_.SetNull();
|
1852
2084
|
valid_ = true;
|
1853
2085
|
}
|
1854
2086
|
|
2087
|
+
//! Implementation of ISchemaValidator
|
2088
|
+
void SetValidateFlags(unsigned flags) {
|
2089
|
+
flags_ = flags;
|
2090
|
+
}
|
2091
|
+
virtual unsigned GetValidateFlags() const {
|
2092
|
+
return flags_;
|
2093
|
+
}
|
2094
|
+
|
1855
2095
|
//! Checks whether the current state is valid.
|
1856
2096
|
// Implementation of ISchemaValidator
|
1857
|
-
virtual bool IsValid() const {
|
2097
|
+
virtual bool IsValid() const {
|
2098
|
+
if (!valid_) return false;
|
2099
|
+
if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
|
2100
|
+
return true;
|
2101
|
+
}
|
1858
2102
|
|
1859
2103
|
//! Gets the error object.
|
1860
2104
|
ValueType& GetError() { return error_; }
|
1861
2105
|
const ValueType& GetError() const { return error_; }
|
1862
2106
|
|
1863
2107
|
//! Gets the JSON pointer pointed to the invalid schema.
|
2108
|
+
// If reporting all errors, the stack will be empty.
|
1864
2109
|
PointerType GetInvalidSchemaPointer() const {
|
1865
2110
|
return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
|
1866
2111
|
}
|
1867
2112
|
|
1868
2113
|
//! Gets the keyword of invalid schema.
|
2114
|
+
// If reporting all errors, the stack will be empty, so return "errors".
|
1869
2115
|
const Ch* GetInvalidSchemaKeyword() const {
|
1870
|
-
|
2116
|
+
if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
|
2117
|
+
if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString();
|
2118
|
+
return 0;
|
2119
|
+
}
|
2120
|
+
|
2121
|
+
//! Gets the error code of invalid schema.
|
2122
|
+
// If reporting all errors, the stack will be empty, so return kValidateErrors.
|
2123
|
+
ValidateErrorCode GetInvalidSchemaCode() const {
|
2124
|
+
if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
|
2125
|
+
if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
|
2126
|
+
return kValidateErrorNone;
|
1871
2127
|
}
|
1872
2128
|
|
1873
2129
|
//! Gets the JSON pointer pointed to the invalid value.
|
2130
|
+
// If reporting all errors, the stack will be empty.
|
1874
2131
|
PointerType GetInvalidDocumentPointer() const {
|
1875
2132
|
if (documentStack_.Empty()) {
|
1876
2133
|
return PointerType();
|
@@ -1881,64 +2138,64 @@ public:
|
|
1881
2138
|
}
|
1882
2139
|
|
1883
2140
|
void NotMultipleOf(int64_t actual, const SValue& expected) {
|
1884
|
-
AddNumberError(
|
2141
|
+
AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
|
1885
2142
|
}
|
1886
2143
|
void NotMultipleOf(uint64_t actual, const SValue& expected) {
|
1887
|
-
AddNumberError(
|
2144
|
+
AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
|
1888
2145
|
}
|
1889
2146
|
void NotMultipleOf(double actual, const SValue& expected) {
|
1890
|
-
AddNumberError(
|
2147
|
+
AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
|
1891
2148
|
}
|
1892
2149
|
void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
|
1893
|
-
AddNumberError(
|
2150
|
+
AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
|
1894
2151
|
exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
|
1895
2152
|
}
|
1896
2153
|
void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
|
1897
|
-
AddNumberError(
|
2154
|
+
AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
|
1898
2155
|
exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
|
1899
2156
|
}
|
1900
2157
|
void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
|
1901
|
-
AddNumberError(
|
2158
|
+
AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
|
1902
2159
|
exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
|
1903
2160
|
}
|
1904
2161
|
void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
|
1905
|
-
AddNumberError(
|
2162
|
+
AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
|
1906
2163
|
exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
|
1907
2164
|
}
|
1908
2165
|
void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
|
1909
|
-
AddNumberError(
|
2166
|
+
AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
|
1910
2167
|
exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
|
1911
2168
|
}
|
1912
2169
|
void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
|
1913
|
-
AddNumberError(
|
2170
|
+
AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
|
1914
2171
|
exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
|
1915
2172
|
}
|
1916
2173
|
|
1917
2174
|
void TooLong(const Ch* str, SizeType length, SizeType expected) {
|
1918
|
-
AddNumberError(
|
2175
|
+
AddNumberError(kValidateErrorMaxLength,
|
1919
2176
|
ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
|
1920
2177
|
}
|
1921
2178
|
void TooShort(const Ch* str, SizeType length, SizeType expected) {
|
1922
|
-
AddNumberError(
|
2179
|
+
AddNumberError(kValidateErrorMinLength,
|
1923
2180
|
ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
|
1924
2181
|
}
|
1925
2182
|
void DoesNotMatch(const Ch* str, SizeType length) {
|
1926
2183
|
currentError_.SetObject();
|
1927
2184
|
currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
|
1928
|
-
AddCurrentError(
|
2185
|
+
AddCurrentError(kValidateErrorPattern);
|
1929
2186
|
}
|
1930
2187
|
|
1931
2188
|
void DisallowedItem(SizeType index) {
|
1932
2189
|
currentError_.SetObject();
|
1933
2190
|
currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
|
1934
|
-
AddCurrentError(
|
2191
|
+
AddCurrentError(kValidateErrorAdditionalItems, true);
|
1935
2192
|
}
|
1936
2193
|
void TooFewItems(SizeType actualCount, SizeType expectedCount) {
|
1937
|
-
AddNumberError(
|
2194
|
+
AddNumberError(kValidateErrorMinItems,
|
1938
2195
|
ValueType(actualCount).Move(), SValue(expectedCount).Move());
|
1939
2196
|
}
|
1940
2197
|
void TooManyItems(SizeType actualCount, SizeType expectedCount) {
|
1941
|
-
AddNumberError(
|
2198
|
+
AddNumberError(kValidateErrorMaxItems,
|
1942
2199
|
ValueType(actualCount).Move(), SValue(expectedCount).Move());
|
1943
2200
|
}
|
1944
2201
|
void DuplicateItems(SizeType index1, SizeType index2) {
|
@@ -1947,15 +2204,15 @@ public:
|
|
1947
2204
|
duplicates.PushBack(index2, GetStateAllocator());
|
1948
2205
|
currentError_.SetObject();
|
1949
2206
|
currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
|
1950
|
-
AddCurrentError(
|
2207
|
+
AddCurrentError(kValidateErrorUniqueItems, true);
|
1951
2208
|
}
|
1952
2209
|
|
1953
2210
|
void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
|
1954
|
-
AddNumberError(
|
2211
|
+
AddNumberError(kValidateErrorMaxProperties,
|
1955
2212
|
ValueType(actualCount).Move(), SValue(expectedCount).Move());
|
1956
2213
|
}
|
1957
2214
|
void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
|
1958
|
-
AddNumberError(
|
2215
|
+
AddNumberError(kValidateErrorMinProperties,
|
1959
2216
|
ValueType(actualCount).Move(), SValue(expectedCount).Move());
|
1960
2217
|
}
|
1961
2218
|
void StartMissingProperties() {
|
@@ -1970,7 +2227,7 @@ public:
|
|
1970
2227
|
ValueType error(kObjectType);
|
1971
2228
|
error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
|
1972
2229
|
currentError_ = error;
|
1973
|
-
AddCurrentError(
|
2230
|
+
AddCurrentError(kValidateErrorRequired);
|
1974
2231
|
return true;
|
1975
2232
|
}
|
1976
2233
|
void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
|
@@ -1980,7 +2237,7 @@ public:
|
|
1980
2237
|
void DisallowedProperty(const Ch* name, SizeType length) {
|
1981
2238
|
currentError_.SetObject();
|
1982
2239
|
currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
|
1983
|
-
AddCurrentError(
|
2240
|
+
AddCurrentError(kValidateErrorAdditionalProperties, true);
|
1984
2241
|
}
|
1985
2242
|
|
1986
2243
|
void StartDependencyErrors() {
|
@@ -1993,9 +2250,20 @@ public:
|
|
1993
2250
|
missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
|
1994
2251
|
}
|
1995
2252
|
void EndMissingDependentProperties(const SValue& sourceName) {
|
1996
|
-
if (!missingDependents_.Empty())
|
1997
|
-
|
1998
|
-
|
2253
|
+
if (!missingDependents_.Empty()) {
|
2254
|
+
// Create equivalent 'required' error
|
2255
|
+
ValueType error(kObjectType);
|
2256
|
+
ValidateErrorCode code = kValidateErrorRequired;
|
2257
|
+
error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
|
2258
|
+
AddErrorCode(error, code);
|
2259
|
+
AddErrorInstanceLocation(error, false);
|
2260
|
+
// When appending to a pointer ensure its allocator is used
|
2261
|
+
PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
|
2262
|
+
AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
|
2263
|
+
ValueType wrapper(kObjectType);
|
2264
|
+
wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
|
2265
|
+
currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
|
2266
|
+
}
|
1999
2267
|
}
|
2000
2268
|
void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
|
2001
2269
|
currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
|
@@ -2007,13 +2275,13 @@ public:
|
|
2007
2275
|
ValueType error(kObjectType);
|
2008
2276
|
error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
|
2009
2277
|
currentError_ = error;
|
2010
|
-
AddCurrentError(
|
2278
|
+
AddCurrentError(kValidateErrorDependencies);
|
2011
2279
|
return true;
|
2012
2280
|
}
|
2013
2281
|
|
2014
|
-
void DisallowedValue() {
|
2282
|
+
void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) {
|
2015
2283
|
currentError_.SetObject();
|
2016
|
-
AddCurrentError(
|
2284
|
+
AddCurrentError(code);
|
2017
2285
|
}
|
2018
2286
|
void StartDisallowedType() {
|
2019
2287
|
currentError_.SetArray();
|
@@ -2026,22 +2294,24 @@ public:
|
|
2026
2294
|
error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
|
2027
2295
|
error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
|
2028
2296
|
currentError_ = error;
|
2029
|
-
AddCurrentError(
|
2297
|
+
AddCurrentError(kValidateErrorType);
|
2030
2298
|
}
|
2031
2299
|
void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2300
|
+
// Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
|
2301
|
+
AddErrorArray(kValidateErrorAllOf, subvalidators, count);
|
2302
|
+
//for (SizeType i = 0; i < count; ++i) {
|
2303
|
+
// MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
|
2304
|
+
//}
|
2035
2305
|
}
|
2036
2306
|
void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
|
2037
|
-
AddErrorArray(
|
2307
|
+
AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
|
2038
2308
|
}
|
2039
|
-
void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
|
2040
|
-
AddErrorArray(
|
2309
|
+
void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) {
|
2310
|
+
AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count);
|
2041
2311
|
}
|
2042
2312
|
void Disallowed() {
|
2043
2313
|
currentError_.SetObject();
|
2044
|
-
AddCurrentError(
|
2314
|
+
AddCurrentError(kValidateErrorNot);
|
2045
2315
|
}
|
2046
2316
|
|
2047
2317
|
#define RAPIDJSON_STRING_(name, ...) \
|
@@ -2058,6 +2328,8 @@ public:
|
|
2058
2328
|
RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
|
2059
2329
|
RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
|
2060
2330
|
RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
|
2331
|
+
RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
|
2332
|
+
RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
|
2061
2333
|
RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
|
2062
2334
|
|
2063
2335
|
#undef RAPIDJSON_STRING_
|
@@ -2075,7 +2347,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|
2075
2347
|
|
2076
2348
|
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
|
2077
2349
|
if (!valid_) return false; \
|
2078
|
-
if (!BeginValue() || !CurrentSchema().method arg1) {\
|
2350
|
+
if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
|
2079
2351
|
RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
|
2080
2352
|
return valid_ = false;\
|
2081
2353
|
}
|
@@ -2093,7 +2365,8 @@ RAPIDJSON_MULTILINEMACRO_END
|
|
2093
2365
|
}
|
2094
2366
|
|
2095
2367
|
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
|
2096
|
-
|
2368
|
+
valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
|
2369
|
+
return valid_;
|
2097
2370
|
|
2098
2371
|
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
|
2099
2372
|
RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
|
@@ -2121,15 +2394,15 @@ RAPIDJSON_MULTILINEMACRO_END
|
|
2121
2394
|
bool Key(const Ch* str, SizeType len, bool copy) {
|
2122
2395
|
if (!valid_) return false;
|
2123
2396
|
AppendToken(str, len);
|
2124
|
-
if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
|
2397
|
+
if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false;
|
2125
2398
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
|
2126
2399
|
return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
|
2127
2400
|
}
|
2128
2401
|
|
2129
|
-
bool EndObject(SizeType memberCount) {
|
2402
|
+
bool EndObject(SizeType memberCount) {
|
2130
2403
|
if (!valid_) return false;
|
2131
2404
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
|
2132
|
-
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
|
2405
|
+
if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false;
|
2133
2406
|
RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
|
2134
2407
|
}
|
2135
2408
|
|
@@ -2142,7 +2415,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|
2142
2415
|
bool EndArray(SizeType elementCount) {
|
2143
2416
|
if (!valid_) return false;
|
2144
2417
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
|
2145
|
-
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
|
2418
|
+
if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false;
|
2146
2419
|
RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
|
2147
2420
|
}
|
2148
2421
|
|
@@ -2152,12 +2425,14 @@ RAPIDJSON_MULTILINEMACRO_END
|
|
2152
2425
|
#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
|
2153
2426
|
|
2154
2427
|
// Implementation of ISchemaStateFactory<SchemaType>
|
2155
|
-
virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
|
2156
|
-
|
2428
|
+
virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
|
2429
|
+
ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
|
2157
2430
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
2158
2431
|
depth_ + 1,
|
2159
2432
|
#endif
|
2160
2433
|
&GetStateAllocator());
|
2434
|
+
sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
|
2435
|
+
return sv;
|
2161
2436
|
}
|
2162
2437
|
|
2163
2438
|
virtual void DestroySchemaValidator(ISchemaValidator* validator) {
|
@@ -2214,7 +2489,8 @@ private:
|
|
2214
2489
|
error_(kObjectType),
|
2215
2490
|
currentError_(),
|
2216
2491
|
missingDependents_(),
|
2217
|
-
valid_(true)
|
2492
|
+
valid_(true),
|
2493
|
+
flags_(kValidateDefaultFlags)
|
2218
2494
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
2219
2495
|
, depth_(depth)
|
2220
2496
|
#endif
|
@@ -2229,6 +2505,10 @@ private:
|
|
2229
2505
|
return *stateAllocator_;
|
2230
2506
|
}
|
2231
2507
|
|
2508
|
+
bool GetContinueOnErrors() const {
|
2509
|
+
return flags_ & kValidateContinueOnErrorFlag;
|
2510
|
+
}
|
2511
|
+
|
2232
2512
|
bool BeginValue() {
|
2233
2513
|
if (schemaStack_.Empty())
|
2234
2514
|
PushSchema(root_);
|
@@ -2236,7 +2516,7 @@ private:
|
|
2236
2516
|
if (CurrentContext().inArray)
|
2237
2517
|
internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
|
2238
2518
|
|
2239
|
-
if (!CurrentSchema().BeginValue(CurrentContext()))
|
2519
|
+
if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
|
2240
2520
|
return false;
|
2241
2521
|
|
2242
2522
|
SizeType count = CurrentContext().patternPropertiesSchemaCount;
|
@@ -2252,7 +2532,7 @@ private:
|
|
2252
2532
|
SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
|
2253
2533
|
va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
|
2254
2534
|
for (SizeType i = 0; i < count; i++)
|
2255
|
-
va[validatorCount++] = CreateSchemaValidator(*sa[i]);
|
2535
|
+
va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError
|
2256
2536
|
}
|
2257
2537
|
|
2258
2538
|
CurrentContext().arrayUniqueness = valueUniqueness;
|
@@ -2261,7 +2541,7 @@ private:
|
|
2261
2541
|
}
|
2262
2542
|
|
2263
2543
|
bool EndValue() {
|
2264
|
-
if (!CurrentSchema().EndValue(CurrentContext()))
|
2544
|
+
if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
|
2265
2545
|
return false;
|
2266
2546
|
|
2267
2547
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
@@ -2272,21 +2552,27 @@ private:
|
|
2272
2552
|
documentStack_.template Pop<Ch>(1);
|
2273
2553
|
internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
|
2274
2554
|
#endif
|
2275
|
-
|
2276
|
-
uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(
|
2555
|
+
void* hasher = CurrentContext().hasher;
|
2556
|
+
uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
|
2277
2557
|
|
2278
2558
|
PopSchema();
|
2279
2559
|
|
2280
2560
|
if (!schemaStack_.Empty()) {
|
2281
2561
|
Context& context = CurrentContext();
|
2282
|
-
if
|
2562
|
+
// Only check uniqueness if there is a hasher
|
2563
|
+
if (hasher && context.valueUniqueness) {
|
2283
2564
|
HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
|
2284
2565
|
if (!a)
|
2285
2566
|
CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
|
2286
2567
|
for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
|
2287
2568
|
if (itr->GetUint64() == h) {
|
2288
2569
|
DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
|
2289
|
-
|
2570
|
+
// Cleanup before returning if continuing
|
2571
|
+
if (GetContinueOnErrors()) {
|
2572
|
+
a->PushBack(h, GetStateAllocator());
|
2573
|
+
while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
|
2574
|
+
}
|
2575
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
|
2290
2576
|
}
|
2291
2577
|
a->PushBack(h, GetStateAllocator());
|
2292
2578
|
}
|
@@ -2327,25 +2613,32 @@ private:
|
|
2327
2613
|
c->~Context();
|
2328
2614
|
}
|
2329
2615
|
|
2330
|
-
void
|
2616
|
+
void AddErrorInstanceLocation(ValueType& result, bool parent) {
|
2331
2617
|
GenericStringBuffer<EncodingType> sb;
|
2332
2618
|
PointerType instancePointer = GetInvalidDocumentPointer();
|
2333
2619
|
((parent && instancePointer.GetTokenCount() > 0)
|
2334
|
-
|
2335
|
-
|
2620
|
+
? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
|
2621
|
+
: instancePointer).StringifyUriFragment(sb);
|
2336
2622
|
ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
|
2337
|
-
|
2623
|
+
GetStateAllocator());
|
2338
2624
|
result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2625
|
+
}
|
2626
|
+
|
2627
|
+
void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
|
2628
|
+
GenericStringBuffer<EncodingType> sb;
|
2629
|
+
SizeType len = CurrentSchema().GetURI().GetStringLength();
|
2630
|
+
if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
|
2631
|
+
if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
|
2632
|
+
else GetInvalidSchemaPointer().StringifyUriFragment(sb);
|
2344
2633
|
ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
|
2345
2634
|
GetStateAllocator());
|
2346
2635
|
result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
|
2347
2636
|
}
|
2348
2637
|
|
2638
|
+
void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
|
2639
|
+
result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
|
2640
|
+
}
|
2641
|
+
|
2349
2642
|
void AddError(ValueType& keyword, ValueType& error) {
|
2350
2643
|
typename ValueType::MemberIterator member = error_.FindMember(keyword);
|
2351
2644
|
if (member == error_.MemberEnd())
|
@@ -2360,9 +2653,11 @@ private:
|
|
2360
2653
|
}
|
2361
2654
|
}
|
2362
2655
|
|
2363
|
-
void AddCurrentError(const
|
2364
|
-
|
2365
|
-
|
2656
|
+
void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
|
2657
|
+
AddErrorCode(currentError_, code);
|
2658
|
+
AddErrorInstanceLocation(currentError_, parent);
|
2659
|
+
AddErrorSchemaLocation(currentError_);
|
2660
|
+
AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
|
2366
2661
|
}
|
2367
2662
|
|
2368
2663
|
void MergeError(ValueType& other) {
|
@@ -2371,24 +2666,24 @@ private:
|
|
2371
2666
|
}
|
2372
2667
|
}
|
2373
2668
|
|
2374
|
-
void AddNumberError(const
|
2669
|
+
void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
|
2375
2670
|
const typename SchemaType::ValueType& (*exclusive)() = 0) {
|
2376
2671
|
currentError_.SetObject();
|
2377
2672
|
currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
|
2378
2673
|
currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
|
2379
2674
|
if (exclusive)
|
2380
2675
|
currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
|
2381
|
-
AddCurrentError(
|
2676
|
+
AddCurrentError(code);
|
2382
2677
|
}
|
2383
2678
|
|
2384
|
-
void AddErrorArray(const
|
2679
|
+
void AddErrorArray(const ValidateErrorCode code,
|
2385
2680
|
ISchemaValidator** subvalidators, SizeType count) {
|
2386
2681
|
ValueType errors(kArrayType);
|
2387
2682
|
for (SizeType i = 0; i < count; ++i)
|
2388
2683
|
errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
|
2389
2684
|
currentError_.SetObject();
|
2390
2685
|
currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
|
2391
|
-
AddCurrentError(
|
2686
|
+
AddCurrentError(code);
|
2392
2687
|
}
|
2393
2688
|
|
2394
2689
|
const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
|
@@ -2408,6 +2703,7 @@ private:
|
|
2408
2703
|
ValueType currentError_;
|
2409
2704
|
ValueType missingDependents_;
|
2410
2705
|
bool valid_;
|
2706
|
+
unsigned flags_;
|
2411
2707
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
2412
2708
|
unsigned depth_;
|
2413
2709
|
#endif
|
@@ -2445,7 +2741,7 @@ public:
|
|
2445
2741
|
\param is Input stream.
|
2446
2742
|
\param sd Schema document.
|
2447
2743
|
*/
|
2448
|
-
SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {}
|
2744
|
+
SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
|
2449
2745
|
|
2450
2746
|
template <typename Handler>
|
2451
2747
|
bool operator()(Handler& handler) {
|
@@ -2463,6 +2759,7 @@ public:
|
|
2463
2759
|
else {
|
2464
2760
|
invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
|
2465
2761
|
invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
|
2762
|
+
invalidSchemaCode_ = validator.GetInvalidSchemaCode();
|
2466
2763
|
invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
|
2467
2764
|
error_.CopyFrom(validator.GetError(), allocator_);
|
2468
2765
|
}
|
@@ -2476,6 +2773,7 @@ public:
|
|
2476
2773
|
const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
|
2477
2774
|
const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
|
2478
2775
|
const ValueType& GetError() const { return error_; }
|
2776
|
+
ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
|
2479
2777
|
|
2480
2778
|
private:
|
2481
2779
|
InputStream& is_;
|
@@ -2485,6 +2783,7 @@ private:
|
|
2485
2783
|
PointerType invalidSchemaPointer_;
|
2486
2784
|
const Ch* invalidSchemaKeyword_;
|
2487
2785
|
PointerType invalidDocumentPointer_;
|
2786
|
+
ValidateErrorCode invalidSchemaCode_;
|
2488
2787
|
StackAllocator allocator_;
|
2489
2788
|
ValueType error_;
|
2490
2789
|
bool isValid_;
|