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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rj_schema/rapidjson/CMakeLists.txt +23 -1
  3. data/ext/rj_schema/rapidjson/appveyor.yml +49 -1
  4. data/ext/rj_schema/rapidjson/bin/types/alotofkeys.json +502 -0
  5. data/ext/rj_schema/rapidjson/bin/unittestschema/idandref.json +69 -0
  6. data/ext/rj_schema/rapidjson/doc/stream.md +7 -7
  7. data/ext/rj_schema/rapidjson/doc/stream.zh-cn.md +1 -1
  8. data/ext/rj_schema/rapidjson/doc/tutorial.md +15 -15
  9. data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +2 -0
  10. data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
  11. data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +460 -52
  12. data/ext/rj_schema/rapidjson/include/rapidjson/document.h +350 -60
  13. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +14 -0
  14. data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +68 -1
  15. data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +60 -11
  16. data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +249 -102
  17. data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
  18. data/ext/rj_schema/rapidjson/test/perftest/perftest.h +5 -4
  19. data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +20 -2
  20. data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +2 -0
  21. data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +193 -1
  22. data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +2 -0
  23. data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
  24. data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +62 -2
  25. data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +372 -7
  26. data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
  27. data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +12 -2
  28. data/ext/rj_schema/rj_schema.cpp +1 -1
  29. data/lib/rj_schema.rb +1 -1
  30. 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_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
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 __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
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 defined(__clang__)
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 defined(__clang__)
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 /* 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
- #if defined(__has_cpp_attribute)
604
- # if __has_cpp_attribute(fallthrough)
605
- # define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
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
- if (const ValueType* v = GetMember(value, GetNotString())) {
510
- schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
511
- notValidatorIndex_ = validatorCount_;
512
- validatorCount_++;
530
+ if (const ValueType* v = GetMember(value, GetNotString())) {
531
+ schemaDocument->CreateSchema(&not_, 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
- // Only check allOf etc if we have validators
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 (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
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, Allocator> URIType;
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 AddRefSchema() if there are $ref.
1625
- CreateSchemaRecursive(&root_, PointerType(), document, document);
1626
-
1627
- // Resolve $ref
1628
- while (!schemaRef_.Empty()) {
1629
- SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1630
- if (const SchemaType* s = GetSchema(refEntry->target)) {
1631
- if (refEntry->schema)
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 URIType& GetURI() const { return uri_; }
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
- struct SchemaRefEntry {
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
- void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1714
- if (schema)
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
- const SchemaType* s = GetSchema(pointer);
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
- void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
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 (!HandleRefSchema(pointer, schema, v, document)) {
1734
- SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
1735
- new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
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
- bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
1743
- static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
1744
- static const ValueType kRefValue(kRefString, 4);
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
- const Ch* s = itr->value.GetString();
1754
- SizeType i = 0;
1755
- while (i < len && s[i] != '#') // Find the first #
1756
- i++;
1757
-
1758
- if (i > 0) { // Remote reference, resolve immediately
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(s, i)) {
1761
- PointerType pointer(&s[i], len - i, allocator_);
1762
- if (pointer.IsValid()) {
1763
- if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1764
- if (schema)
1765
- *schema = sc;
1766
- new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc), false, allocator_);
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
- else if (s[i] == '#') { // Local reference, defer resolution
1774
- PointerType pointer(&s[i], len - i, allocator_);
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
- new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1781
- return true;
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 and schema which holds the $ref
1815
- URIType uri_;
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.