rj_schema 1.0.0 → 1.0.4
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 +3 -10
- data/lib/rj_schema.rb +1 -1
- metadata +9 -3
@@ -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.
|