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