rj_schema 1.0.0 → 1.0.1
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/idandref.json +69 -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 +2 -0
- data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
- data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +460 -52
- data/ext/rj_schema/rapidjson/include/rapidjson/document.h +350 -60
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +14 -0
- data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +68 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +60 -11
- data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +249 -102
- data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
- data/ext/rj_schema/rapidjson/test/perftest/perftest.h +5 -4
- data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +20 -2
- data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +2 -0
- data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +193 -1
- data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +2 -0
- data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
- data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +62 -2
- data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +372 -7
- data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
- data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +12 -2
- data/ext/rj_schema/rj_schema.cpp +1 -1
- data/lib/rj_schema.rb +1 -1
- metadata +9 -3
@@ -45,6 +45,20 @@ inline SizeType StrLen(const wchar_t* s) {
|
|
45
45
|
return SizeType(std::wcslen(s));
|
46
46
|
}
|
47
47
|
|
48
|
+
//! Custom strcmpn() which works on different character types.
|
49
|
+
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
50
|
+
\param s1 Null-terminated input string.
|
51
|
+
\param s2 Null-terminated input string.
|
52
|
+
\return 0 if equal
|
53
|
+
*/
|
54
|
+
template<typename Ch>
|
55
|
+
inline int StrCmp(const Ch* s1, const Ch* s2) {
|
56
|
+
RAPIDJSON_ASSERT(s1 != 0);
|
57
|
+
RAPIDJSON_ASSERT(s2 != 0);
|
58
|
+
while(*s1 && (*s1 == *s2)) { s1++; s2++; }
|
59
|
+
return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
|
60
|
+
}
|
61
|
+
|
48
62
|
//! Returns number of code points in a encoded string.
|
49
63
|
template<typename Encoding>
|
50
64
|
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
@@ -16,6 +16,7 @@
|
|
16
16
|
#define RAPIDJSON_POINTER_H_
|
17
17
|
|
18
18
|
#include "document.h"
|
19
|
+
#include "uri.h"
|
19
20
|
#include "internal/itoa.h"
|
20
21
|
|
21
22
|
#ifdef __clang__
|
@@ -80,6 +81,8 @@ class GenericPointer {
|
|
80
81
|
public:
|
81
82
|
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
|
82
83
|
typedef typename ValueType::Ch Ch; //!< Character type from Value
|
84
|
+
typedef GenericUri<ValueType, Allocator> UriType;
|
85
|
+
|
83
86
|
|
84
87
|
//! A token is the basic units of internal representation.
|
85
88
|
/*!
|
@@ -163,7 +166,7 @@ public:
|
|
163
166
|
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
|
164
167
|
|
165
168
|
//! Copy constructor.
|
166
|
-
GenericPointer(const GenericPointer& rhs) : allocator_(
|
169
|
+
GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
|
167
170
|
*this = rhs;
|
168
171
|
}
|
169
172
|
|
@@ -520,6 +523,70 @@ public:
|
|
520
523
|
|
521
524
|
//@}
|
522
525
|
|
526
|
+
//!@name Compute URI
|
527
|
+
//@{
|
528
|
+
|
529
|
+
//! Compute the in-scope URI for a subtree.
|
530
|
+
// For use with JSON pointers into JSON schema documents.
|
531
|
+
/*!
|
532
|
+
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
|
533
|
+
\param rootUri Root URI
|
534
|
+
\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
|
535
|
+
\param allocator Allocator for Uris
|
536
|
+
\return Uri if it can be resolved. Otherwise null.
|
537
|
+
|
538
|
+
\note
|
539
|
+
There are only 3 situations when a URI cannot be resolved:
|
540
|
+
1. A value in the path is not an array nor object.
|
541
|
+
2. An object value does not contain the token.
|
542
|
+
3. A token is out of range of an array value.
|
543
|
+
|
544
|
+
Use unresolvedTokenIndex to retrieve the token index.
|
545
|
+
*/
|
546
|
+
UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
|
547
|
+
static const Ch kIdString[] = { 'i', 'd', '\0' };
|
548
|
+
static const ValueType kIdValue(kIdString, 2);
|
549
|
+
UriType base = UriType(rootUri, allocator);
|
550
|
+
RAPIDJSON_ASSERT(IsValid());
|
551
|
+
ValueType* v = &root;
|
552
|
+
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
553
|
+
switch (v->GetType()) {
|
554
|
+
case kObjectType:
|
555
|
+
{
|
556
|
+
// See if we have an id, and if so resolve with the current base
|
557
|
+
typename ValueType::MemberIterator m = v->FindMember(kIdValue);
|
558
|
+
if (m != v->MemberEnd() && (m->value).IsString()) {
|
559
|
+
UriType here = UriType(m->value, allocator).Resolve(base, allocator);
|
560
|
+
base = here;
|
561
|
+
}
|
562
|
+
m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
|
563
|
+
if (m == v->MemberEnd())
|
564
|
+
break;
|
565
|
+
v = &m->value;
|
566
|
+
}
|
567
|
+
continue;
|
568
|
+
case kArrayType:
|
569
|
+
if (t->index == kPointerInvalidIndex || t->index >= v->Size())
|
570
|
+
break;
|
571
|
+
v = &((*v)[t->index]);
|
572
|
+
continue;
|
573
|
+
default:
|
574
|
+
break;
|
575
|
+
}
|
576
|
+
|
577
|
+
// Error: unresolved token
|
578
|
+
if (unresolvedTokenIndex)
|
579
|
+
*unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
|
580
|
+
return UriType(allocator);
|
581
|
+
}
|
582
|
+
return base;
|
583
|
+
}
|
584
|
+
|
585
|
+
UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
|
586
|
+
return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex, allocator);
|
587
|
+
}
|
588
|
+
|
589
|
+
|
523
590
|
//!@name Query value
|
524
591
|
//@{
|
525
592
|
|
@@ -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,12 +681,8 @@ 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
|
@@ -19,6 +19,7 @@
|
|
19
19
|
#include "pointer.h"
|
20
20
|
#include "stringbuffer.h"
|
21
21
|
#include "error/en.h"
|
22
|
+
#include "uri.h"
|
22
23
|
#include <cmath> // abs, floor
|
23
24
|
|
24
25
|
#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
|
@@ -432,11 +433,13 @@ public:
|
|
432
433
|
typedef Schema<SchemaDocumentType> SchemaType;
|
433
434
|
typedef GenericValue<EncodingType, AllocatorType> SValue;
|
434
435
|
typedef IValidationErrorHandler<Schema> ErrorHandler;
|
436
|
+
typedef GenericUri<ValueType, AllocatorType> UriType;
|
435
437
|
friend class GenericSchemaDocument<ValueType, AllocatorType>;
|
436
438
|
|
437
|
-
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()) :
|
438
440
|
allocator_(allocator),
|
439
441
|
uri_(schemaDocument->GetURI(), *allocator),
|
442
|
+
id_(id),
|
440
443
|
pointer_(p, allocator),
|
441
444
|
typeless_(schemaDocument->GetTypeless()),
|
442
445
|
enum_(),
|
@@ -474,9 +477,28 @@ public:
|
|
474
477
|
typedef typename ValueType::ConstValueIterator ConstValueIterator;
|
475
478
|
typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
|
476
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
|
+
|
477
491
|
if (!value.IsObject())
|
478
492
|
return;
|
479
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
|
+
|
480
502
|
if (const ValueType* v = GetMember(value, GetTypeString())) {
|
481
503
|
type_ = 0;
|
482
504
|
if (v->IsString())
|
@@ -504,12 +526,12 @@ public:
|
|
504
526
|
AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
|
505
527
|
AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
|
506
528
|
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
|
507
|
-
}
|
508
529
|
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
530
|
+
if (const ValueType* v = GetMember(value, GetNotString())) {
|
531
|
+
schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_);
|
532
|
+
notValidatorIndex_ = validatorCount_;
|
533
|
+
validatorCount_++;
|
534
|
+
}
|
513
535
|
}
|
514
536
|
|
515
537
|
// Object
|
@@ -524,7 +546,7 @@ public:
|
|
524
546
|
if (properties && properties->IsObject())
|
525
547
|
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
|
526
548
|
AddUniqueElement(allProperties, itr->name);
|
527
|
-
|
549
|
+
|
528
550
|
if (required && required->IsArray())
|
529
551
|
for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
|
530
552
|
if (itr->IsString())
|
@@ -555,7 +577,7 @@ public:
|
|
555
577
|
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
|
556
578
|
SizeType index;
|
557
579
|
if (FindPropertyIndex(itr->name, &index))
|
558
|
-
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_);
|
559
581
|
}
|
560
582
|
}
|
561
583
|
|
@@ -567,7 +589,7 @@ public:
|
|
567
589
|
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
|
568
590
|
new (&patternProperties_[patternPropertyCount_]) PatternProperty();
|
569
591
|
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
|
570
|
-
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_);
|
571
593
|
patternPropertyCount_++;
|
572
594
|
}
|
573
595
|
}
|
@@ -599,7 +621,7 @@ public:
|
|
599
621
|
}
|
600
622
|
else if (itr->value.IsObject()) {
|
601
623
|
hasSchemaDependencies_ = true;
|
602
|
-
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_);
|
603
625
|
properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
|
604
626
|
validatorCount_++;
|
605
627
|
}
|
@@ -611,7 +633,7 @@ public:
|
|
611
633
|
if (v->IsBool())
|
612
634
|
additionalProperties_ = v->GetBool();
|
613
635
|
else if (v->IsObject())
|
614
|
-
schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
|
636
|
+
schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
|
615
637
|
}
|
616
638
|
|
617
639
|
AssignIfExist(minProperties_, value, GetMinPropertiesString());
|
@@ -621,12 +643,12 @@ public:
|
|
621
643
|
if (const ValueType* v = GetMember(value, GetItemsString())) {
|
622
644
|
PointerType q = p.Append(GetItemsString(), allocator_);
|
623
645
|
if (v->IsObject()) // List validation
|
624
|
-
schemaDocument->CreateSchema(&itemsList_, q, *v, document);
|
646
|
+
schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
|
625
647
|
else if (v->IsArray()) { // Tuple validation
|
626
648
|
itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
|
627
649
|
SizeType index = 0;
|
628
650
|
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
|
629
|
-
schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
|
651
|
+
schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
|
630
652
|
}
|
631
653
|
}
|
632
654
|
|
@@ -637,7 +659,7 @@ public:
|
|
637
659
|
if (v->IsBool())
|
638
660
|
additionalItems_ = v->GetBool();
|
639
661
|
else if (v->IsObject())
|
640
|
-
schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
|
662
|
+
schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
|
641
663
|
}
|
642
664
|
|
643
665
|
AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
|
@@ -697,6 +719,10 @@ public:
|
|
697
719
|
return uri_;
|
698
720
|
}
|
699
721
|
|
722
|
+
const UriType& GetId() const {
|
723
|
+
return id_;
|
724
|
+
}
|
725
|
+
|
700
726
|
const PointerType& GetPointer() const {
|
701
727
|
return pointer_;
|
702
728
|
}
|
@@ -776,7 +802,7 @@ public:
|
|
776
802
|
foundEnum:;
|
777
803
|
}
|
778
804
|
|
779
|
-
|
805
|
+
// Only check allOf etc if we have validators
|
780
806
|
if (context.validatorCount > 0) {
|
781
807
|
if (allOf_.schemas)
|
782
808
|
for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
|
@@ -826,7 +852,7 @@ public:
|
|
826
852
|
}
|
827
853
|
return CreateParallelValidator(context);
|
828
854
|
}
|
829
|
-
|
855
|
+
|
830
856
|
bool Bool(Context& context, bool) const {
|
831
857
|
if (!(type_ & (1 << kBooleanSchemaType))) {
|
832
858
|
DisallowedType(context, GetBooleanString());
|
@@ -870,13 +896,13 @@ public:
|
|
870
896
|
|
871
897
|
if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
|
872
898
|
return false;
|
873
|
-
|
899
|
+
|
874
900
|
if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
|
875
901
|
return false;
|
876
|
-
|
902
|
+
|
877
903
|
return CreateParallelValidator(context);
|
878
904
|
}
|
879
|
-
|
905
|
+
|
880
906
|
bool String(Context& context, const Ch* str, SizeType length, bool) const {
|
881
907
|
if (!(type_ & (1 << kStringSchemaType))) {
|
882
908
|
DisallowedType(context, GetStringString());
|
@@ -925,7 +951,7 @@ public:
|
|
925
951
|
|
926
952
|
return CreateParallelValidator(context);
|
927
953
|
}
|
928
|
-
|
954
|
+
|
929
955
|
bool Key(Context& context, const Ch* str, SizeType len, bool) const {
|
930
956
|
if (patternProperties_) {
|
931
957
|
context.patternPropertiesSchemaCount = 0;
|
@@ -953,7 +979,7 @@ public:
|
|
953
979
|
}
|
954
980
|
|
955
981
|
if (additionalPropertiesSchema_) {
|
956
|
-
if (
|
982
|
+
if (context.patternPropertiesSchemaCount > 0) {
|
957
983
|
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
|
958
984
|
context.valueSchema = typeless_;
|
959
985
|
context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
|
@@ -1018,7 +1044,7 @@ public:
|
|
1018
1044
|
}
|
1019
1045
|
}
|
1020
1046
|
if (context.error_handler.EndDependencyErrors())
|
1021
|
-
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
|
1047
|
+
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
|
1022
1048
|
}
|
1023
1049
|
|
1024
1050
|
return true;
|
@@ -1038,12 +1064,12 @@ public:
|
|
1038
1064
|
|
1039
1065
|
bool EndArray(Context& context, SizeType elementCount) const {
|
1040
1066
|
context.inArray = false;
|
1041
|
-
|
1067
|
+
|
1042
1068
|
if (elementCount < minItems_) {
|
1043
1069
|
context.error_handler.TooFewItems(elementCount, minItems_);
|
1044
1070
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
|
1045
1071
|
}
|
1046
|
-
|
1072
|
+
|
1047
1073
|
if (elementCount > maxItems_) {
|
1048
1074
|
context.error_handler.TooManyItems(elementCount, maxItems_);
|
1049
1075
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
|
@@ -1132,6 +1158,15 @@ public:
|
|
1132
1158
|
RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
|
1133
1159
|
RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
|
1134
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, '.')
|
1135
1170
|
|
1136
1171
|
#undef RAPIDJSON_STRING_
|
1137
1172
|
|
@@ -1197,7 +1232,7 @@ private:
|
|
1197
1232
|
out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
|
1198
1233
|
memset(out.schemas, 0, sizeof(Schema*)* out.count);
|
1199
1234
|
for (SizeType i = 0; i < out.count; i++)
|
1200
|
-
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_);
|
1201
1236
|
out.begin = validatorCount_;
|
1202
1237
|
validatorCount_ += out.count;
|
1203
1238
|
}
|
@@ -1274,10 +1309,10 @@ private:
|
|
1274
1309
|
|
1275
1310
|
if (anyOf_.schemas)
|
1276
1311
|
CreateSchemaValidators(context, anyOf_, false);
|
1277
|
-
|
1312
|
+
|
1278
1313
|
if (oneOf_.schemas)
|
1279
1314
|
CreateSchemaValidators(context, oneOf_, false);
|
1280
|
-
|
1315
|
+
|
1281
1316
|
if (not_)
|
1282
1317
|
context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
|
1283
1318
|
|
@@ -1301,7 +1336,7 @@ private:
|
|
1301
1336
|
SizeType len = name.GetStringLength();
|
1302
1337
|
const Ch* str = name.GetString();
|
1303
1338
|
for (SizeType index = 0; index < propertyCount_; index++)
|
1304
|
-
if (properties_[index].name.GetStringLength() == len &&
|
1339
|
+
if (properties_[index].name.GetStringLength() == len &&
|
1305
1340
|
(std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
|
1306
1341
|
{
|
1307
1342
|
*outIndex = index;
|
@@ -1462,7 +1497,7 @@ private:
|
|
1462
1497
|
|
1463
1498
|
struct PatternProperty {
|
1464
1499
|
PatternProperty() : schema(), pattern() {}
|
1465
|
-
~PatternProperty() {
|
1500
|
+
~PatternProperty() {
|
1466
1501
|
if (pattern) {
|
1467
1502
|
pattern->~RegexType();
|
1468
1503
|
AllocatorType::Free(pattern);
|
@@ -1474,6 +1509,7 @@ private:
|
|
1474
1509
|
|
1475
1510
|
AllocatorType* allocator_;
|
1476
1511
|
SValue uri_;
|
1512
|
+
UriType id_;
|
1477
1513
|
PointerType pointer_;
|
1478
1514
|
const SchemaType* typeless_;
|
1479
1515
|
uint64_t* enum_;
|
@@ -1516,7 +1552,7 @@ private:
|
|
1516
1552
|
SValue multipleOf_;
|
1517
1553
|
bool exclusiveMinimum_;
|
1518
1554
|
bool exclusiveMaximum_;
|
1519
|
-
|
1555
|
+
|
1520
1556
|
SizeType defaultValueLength_;
|
1521
1557
|
};
|
1522
1558
|
|
@@ -1559,9 +1595,12 @@ template <typename SchemaDocumentType>
|
|
1559
1595
|
class IGenericRemoteSchemaDocumentProvider {
|
1560
1596
|
public:
|
1561
1597
|
typedef typename SchemaDocumentType::Ch Ch;
|
1598
|
+
typedef typename SchemaDocumentType::ValueType ValueType;
|
1599
|
+
typedef typename SchemaDocumentType::AllocatorType AllocatorType;
|
1562
1600
|
|
1563
1601
|
virtual ~IGenericRemoteSchemaDocumentProvider() {}
|
1564
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()); }
|
1565
1604
|
};
|
1566
1605
|
|
1567
1606
|
///////////////////////////////////////////////////////////////////////////////
|
@@ -1586,7 +1625,8 @@ public:
|
|
1586
1625
|
typedef typename EncodingType::Ch Ch;
|
1587
1626
|
typedef internal::Schema<GenericSchemaDocument> SchemaType;
|
1588
1627
|
typedef GenericPointer<ValueType, Allocator> PointerType;
|
1589
|
-
typedef GenericValue<EncodingType,
|
1628
|
+
typedef GenericValue<EncodingType, AllocatorType> SValue;
|
1629
|
+
typedef GenericUri<ValueType, Allocator> UriType;
|
1590
1630
|
friend class internal::Schema<GenericSchemaDocument>;
|
1591
1631
|
template <typename, typename, typename>
|
1592
1632
|
friend class GenericSchemaValidator;
|
@@ -1600,9 +1640,11 @@ public:
|
|
1600
1640
|
\param uriLength Length of \c name, in code points.
|
1601
1641
|
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
|
1602
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
|
1603
1644
|
*/
|
1604
1645
|
explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
|
1605
|
-
IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0
|
1646
|
+
IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
|
1647
|
+
const PointerType& pointer = PointerType()) : // PR #1393
|
1606
1648
|
remoteProvider_(remoteProvider),
|
1607
1649
|
allocator_(allocator),
|
1608
1650
|
ownAllocator_(),
|
@@ -1616,30 +1658,20 @@ public:
|
|
1616
1658
|
|
1617
1659
|
Ch noUri[1] = {0};
|
1618
1660
|
uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
|
1661
|
+
docId_ = UriType(uri_, allocator_);
|
1619
1662
|
|
1620
1663
|
typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
|
1621
|
-
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_);
|
1622
1665
|
|
1623
1666
|
// Generate root schema, it will call CreateSchema() to create sub-schemas,
|
1624
|
-
// And call
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
*refEntry->schema = s;
|
1633
|
-
|
1634
|
-
// Create entry in map if not exist
|
1635
|
-
if (!GetSchema(refEntry->source)) {
|
1636
|
-
new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
|
1637
|
-
}
|
1638
|
-
}
|
1639
|
-
else if (refEntry->schema)
|
1640
|
-
*refEntry->schema = typeless_;
|
1641
|
-
|
1642
|
-
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_);
|
1643
1675
|
}
|
1644
1676
|
|
1645
1677
|
RAPIDJSON_ASSERT(root_ != 0);
|
@@ -1657,7 +1689,8 @@ public:
|
|
1657
1689
|
typeless_(rhs.typeless_),
|
1658
1690
|
schemaMap_(std::move(rhs.schemaMap_)),
|
1659
1691
|
schemaRef_(std::move(rhs.schemaRef_)),
|
1660
|
-
uri_(std::move(rhs.uri_))
|
1692
|
+
uri_(std::move(rhs.uri_)),
|
1693
|
+
docId_(rhs.docId_)
|
1661
1694
|
{
|
1662
1695
|
rhs.remoteProvider_ = 0;
|
1663
1696
|
rhs.allocator_ = 0;
|
@@ -1679,7 +1712,7 @@ public:
|
|
1679
1712
|
RAPIDJSON_DELETE(ownAllocator_);
|
1680
1713
|
}
|
1681
1714
|
|
1682
|
-
const
|
1715
|
+
const SValue& GetURI() const { return uri_; }
|
1683
1716
|
|
1684
1717
|
//! Get the root schema.
|
1685
1718
|
const SchemaType& GetRoot() const { return *root_; }
|
@@ -1690,12 +1723,7 @@ private:
|
|
1690
1723
|
//! Prohibit assignment
|
1691
1724
|
GenericSchemaDocument& operator=(const GenericSchemaDocument&);
|
1692
1725
|
|
1693
|
-
|
1694
|
-
SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
|
1695
|
-
PointerType source;
|
1696
|
-
PointerType target;
|
1697
|
-
const SchemaType** schema;
|
1698
|
-
};
|
1726
|
+
typedef const PointerType* SchemaRefPtr; // PR #1393
|
1699
1727
|
|
1700
1728
|
struct SchemaEntry {
|
1701
1729
|
SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
|
@@ -1710,79 +1738,197 @@ private:
|
|
1710
1738
|
bool owned;
|
1711
1739
|
};
|
1712
1740
|
|
1713
|
-
|
1714
|
-
|
1715
|
-
*schema = typeless_;
|
1716
|
-
|
1741
|
+
// Changed by PR #1393
|
1742
|
+
void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
1717
1743
|
if (v.GetType() == kObjectType) {
|
1718
|
-
|
1719
|
-
if (!s)
|
1720
|
-
CreateSchema(schema, pointer, v, document);
|
1744
|
+
UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
|
1721
1745
|
|
1722
1746
|
for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
|
1723
|
-
CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
|
1747
|
+
CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
|
1724
1748
|
}
|
1725
1749
|
else if (v.GetType() == kArrayType)
|
1726
1750
|
for (SizeType i = 0; i < v.Size(); i++)
|
1727
|
-
CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
|
1751
|
+
CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
|
1728
1752
|
}
|
1729
1753
|
|
1730
|
-
|
1754
|
+
// Changed by PR #1393
|
1755
|
+
const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
1731
1756
|
RAPIDJSON_ASSERT(pointer.IsValid());
|
1732
1757
|
if (v.IsObject()) {
|
1733
|
-
if (
|
1734
|
-
|
1735
|
-
|
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);
|
1736
1766
|
if (schema)
|
1737
1767
|
*schema = s;
|
1768
|
+
return s->GetId();
|
1738
1769
|
}
|
1739
1770
|
}
|
1771
|
+
else {
|
1772
|
+
if (schema)
|
1773
|
+
*schema = typeless_;
|
1774
|
+
AddSchemaRefs(typeless_);
|
1775
|
+
}
|
1776
|
+
return id;
|
1740
1777
|
}
|
1741
1778
|
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
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());
|
1747
1783
|
if (itr == v.MemberEnd())
|
1748
1784
|
return false;
|
1749
1785
|
|
1786
|
+
// Resolve the source pointer to the $ref'ed schema (finally)
|
1787
|
+
new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
|
1788
|
+
|
1750
1789
|
if (itr->value.IsString()) {
|
1751
1790
|
SizeType len = itr->value.GetStringLength();
|
1752
1791
|
if (len > 0) {
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
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
|
1759
1801
|
if (remoteProvider_) {
|
1760
|
-
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
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);
|
1767
1844
|
return true;
|
1768
1845
|
}
|
1769
1846
|
}
|
1770
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
|
+
}
|
1771
1865
|
}
|
1772
1866
|
}
|
1773
|
-
|
1774
|
-
|
1775
|
-
if (pointer.IsValid()) {
|
1776
|
-
if (const ValueType* nv = pointer.Get(document))
|
1777
|
-
if (HandleRefSchema(source, schema, *nv, document))
|
1778
|
-
return true;
|
1867
|
+
}
|
1868
|
+
}
|
1779
1869
|
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
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_));
|
1783
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++;
|
1784
1913
|
}
|
1785
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;
|
1786
1932
|
return false;
|
1787
1933
|
}
|
1788
1934
|
|
@@ -1811,8 +1957,9 @@ private:
|
|
1811
1957
|
const SchemaType* root_; //!< Root schema.
|
1812
1958
|
SchemaType* typeless_;
|
1813
1959
|
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
|
1814
|
-
internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref
|
1815
|
-
|
1960
|
+
internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
|
1961
|
+
SValue uri_; // Schema document URI
|
1962
|
+
UriType docId_;
|
1816
1963
|
};
|
1817
1964
|
|
1818
1965
|
//! GenericSchemaDocument using Value type.
|